/*************************************************************************** kjprefs.cpp - Preferences-Dialog for KJ�ol-Skinloader -------------------------------------------------------- Maintainer: Stefan Gehn ***************************************************************************/ // local includes #include "kjprefs.h" #include "kjprefs.moc" #include "kjloader.h" #include "kjwidget.h" #include "kjvis.h" #include "parser.h" // system includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static TQString expand(TQString s); KJPrefs::KJPrefs(TQObject* parent) : CModule(i18n("K-Jöfol Skins"), i18n("Skin Selection For the K-Jöfol Plugin"), "style", parent) { cfg = TDEGlobal::config(); TQVBoxLayout *vbox = new TQVBoxLayout(this); vbox->setAutoAdd(true); vbox->setSpacing( 0 ); vbox->setMargin( 0 ); mTabWidget = new TQTabWidget( this, "mTabWidget" ); mSkinselectorWidget = new KJSkinselector ( mTabWidget, "mSkinselectorWidget" ); mGuiSettingsWidget = new KJGuiSettings ( mTabWidget, "mGuiSettingsWidget" ); mTabWidget->insertTab( mSkinselectorWidget, i18n("&Skin Selector") ); mTabWidget->insertTab( mGuiSettingsWidget, i18n("O&ther Settings") ); connect ( mSkinselectorWidget->mSkins, TQT_SIGNAL(activated(const TQString&)), TQT_SLOT(showPreview(const TQString&)) ); connect ( mSkinselectorWidget->installButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(installNewSkin()) ); connect ( mSkinselectorWidget->mRemoveButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(removeSelectedSkin()) ); reopen(); // fill the skinlist and draw a preview } void KJPrefs::reopen() // reload config and set stuff in dialog { // kdDebug(66666) << "[KJPrefs] reopen()" << endl; cfg->setGroup("KJofol-Skins"); // mGuiSettingsWidget->timeCountdown->setChecked( cfg->readBoolEntry("TimeCountMode", false) ); mGuiSettingsWidget->displayTooltips->setChecked( cfg->readBoolEntry("DisplayTooltips", true) ); mGuiSettingsWidget->displaySplash->setChecked( cfg->readBoolEntry("DisplaySplashScreen", true) ); mGuiSettingsWidget->minPitch->setValue( cfg->readNumEntry("minimumPitch", 50) ); mGuiSettingsWidget->maxPitch->setValue( cfg->readNumEntry("maximumPitch", 200) ); mGuiSettingsWidget->visTimerValue->setValue( cfg->readNumEntry("VisualizationSpeed", 30) ); mGuiSettingsWidget->useSysFont->setChecked( cfg->readBoolEntry("Use SysFont", false) ); mGuiSettingsWidget->cmbSysFont->setCurrentFont( cfg->readEntry("SysFont Family", TDEGlobalSettings::generalFont().family()) ); TQColor tmpColor = TQColor(255,255,255); mGuiSettingsWidget->cmbSysFontColor->setColor( cfg->readColorEntry("SysFont Color", &tmpColor)); // TODO somehow honor both config-entries, I want a custom mode switch ( cfg->readNumEntry("TitleScrollSpeed", 400 ) ) { case 800: mGuiSettingsWidget->titleScrollSpeed->setValue(1); break; case 400: mGuiSettingsWidget->titleScrollSpeed->setValue(2); break; case 200: mGuiSettingsWidget->titleScrollSpeed->setValue(3); break; } switch ( cfg->readNumEntry("AnalyzerType", KJVisScope::FFT ) ) { case KJVisScope::Null: mGuiSettingsWidget->visNone->setChecked(true); mGuiSettingsWidget->visScope->setChecked(false); mGuiSettingsWidget->visAnalyzer->setChecked(false); break; case KJVisScope::FFT: mGuiSettingsWidget->visNone->setChecked(false); mGuiSettingsWidget->visScope->setChecked(false); mGuiSettingsWidget->visAnalyzer->setChecked(true); break; case KJVisScope::Mono: mGuiSettingsWidget->visNone->setChecked(false); mGuiSettingsWidget->visScope->setChecked(true); mGuiSettingsWidget->visAnalyzer->setChecked(false); break; } TQStringList skins; TQStringList skinLocations = TDEGlobal::dirs()->findDirs("data", "noatun/skins/kjofol"); // iterate through all paths where Noatun is searching for kjofol-skins for (uint i = 0; i < skinLocations.count(); ++i ) { TQStringList skinDirs = TQDir(skinLocations[i]).entryList(); // iterate trough all dirs (normally, users can fsck every dir-struct *g*) containing a skin for (uint k = 2; k < skinDirs.count(); ++k ) { TQDir skinDirCnt = TQDir ( skinLocations[i]+skinDirs[k], "*.rc", TQDir::Name|TQDir::IgnoreCase, TQDir::Files ); // make a list of all .rc-files in a skindir TQStringList rcFiles = skinDirCnt.entryList(); // iterate trough all those rc.-files in a skindir for (uint j = 0; j < rcFiles.count(); j++ ) { // kdDebug(66666) << "found: " << rcFiles[j].latin1() << endl; skins += ( rcFiles[j] ); } } } skins.sort(); TQString loaded = cfg->readEntry("SkinResource", locate("data", "noatun/skins/kjofol/kjofol/kjofol.rc") ); loaded = loaded.mid(loaded.findRev("/")+1); // remove path loaded = loaded.left( loaded.length() - 3 ); // remove ".rc" mSkinselectorWidget->mSkins->clear(); int index = 0; for (TQStringList::Iterator i=skins.begin(); i!=skins.end(); ++i) { *i = (*i).left( (*i).length() - 3 ); mSkinselectorWidget->mSkins->insertItem(*i); if ( (*i) == loaded ) index = mSkinselectorWidget->mSkins->count()-1; // save index no. to set active item later on } mSkinselectorWidget->mSkins->setCurrentItem(index); showPreview( mSkinselectorWidget->mSkins->currentText() ); } void KJPrefs::save() { // kdDebug(66666) << k_funcinfo << "called." << endl; TQString skin=::expand ( mSkinselectorWidget->mSkins->currentText() ); // first load skin and then save config to prevent // reloading a broken skin after a crash KJLoader *l=KJLoader::kjofol; if (l) l->loadSkin(skin); cfg->setGroup("KJofol-Skins"); cfg->writeEntry("SkinResource", skin); // cfg->writeEntry("TimeCountMode", timeCountMode() ); cfg->writeEntry("DisplayTooltips", displayTooltips() ); cfg->writeEntry("DisplaySplashScreen", displaySplash() ); cfg->writeEntry("TitleScrollSpeed", titleMovingUpdates() ); cfg->writeEntry("TitleScrollAmount", titleMovingDistance() ); cfg->writeEntry("AnalyzerType", (int)visType() ); cfg->writeEntry("minimumPitch", minimumPitch() ); cfg->writeEntry("maximumPitch", maximumPitch() ); cfg->writeEntry("VisualizationSpeed", visTimerValue() ); cfg->writeEntry("Use SysFont", mGuiSettingsWidget->useSysFont->isChecked()); cfg->writeEntry("SysFont Family", mGuiSettingsWidget->cmbSysFont->currentFont()); // kdDebug(66666) << k_funcinfo << "currentfont=" << mGuiSettingsWidget->cmbSysFont->currentFont() << endl; cfg->writeEntry("SysFont Color", mGuiSettingsWidget->cmbSysFontColor->color()); cfg->sync(); emit configChanged(); } TQString KJPrefs::skin( void ) const { // return full path to currently loaded skin return ::expand( mSkinselectorWidget->mSkins->currentText() ); } int KJPrefs::minimumPitch( void ) const { return mGuiSettingsWidget->minPitch->value(); } int KJPrefs::maximumPitch( void ) const { return mGuiSettingsWidget->maxPitch->value(); } int KJPrefs::visTimerValue ( void ) const { return mGuiSettingsWidget->visTimerValue->value(); } int KJPrefs::titleMovingUpdates ( void ) const { switch ( mGuiSettingsWidget->titleScrollSpeed->value() ) { case 1: return 800; case 2: return 400; case 3: return 200; default: return 400; // emergency exit :) } } float KJPrefs::titleMovingDistance ( void ) const { switch ( mGuiSettingsWidget->titleScrollSpeed->value() ) { case 1: return 0.2f; case 2: return 0.5f; case 3: return 1.0f; default: return 0.5f; // emergency exit :) } } int KJPrefs::visType ( void ) const { if ( mGuiSettingsWidget->visNone->isChecked() ) // No Vis return KJVisScope::Null; else if ( mGuiSettingsWidget->visScope->isChecked() ) // MonoScope return KJVisScope::Mono; else if ( mGuiSettingsWidget->visAnalyzer->isChecked() ) // FFT Analyzer return KJVisScope::FFT; else return KJVisScope::StereoFFT; //Null; // emergency exit :) } void KJPrefs::setVisType ( int vis ) { switch ( vis ) { case KJVisScope::Null: mGuiSettingsWidget->visNone->setChecked(true); mGuiSettingsWidget->visScope->setChecked(false); mGuiSettingsWidget->visAnalyzer->setChecked(false); break; case KJVisScope::FFT: mGuiSettingsWidget->visNone->setChecked(false); mGuiSettingsWidget->visScope->setChecked(false); mGuiSettingsWidget->visAnalyzer->setChecked(true); break; case KJVisScope::StereoFFT: mGuiSettingsWidget->visNone->setChecked(false); mGuiSettingsWidget->visScope->setChecked(false); mGuiSettingsWidget->visAnalyzer->setChecked(false); break; case KJVisScope::Mono: mGuiSettingsWidget->visNone->setChecked(false); mGuiSettingsWidget->visScope->setChecked(true); mGuiSettingsWidget->visAnalyzer->setChecked(false); break; } save(); // not sure if that's a good idea or doing saving by hand in here } bool KJPrefs::useSysFont( void ) const { return mGuiSettingsWidget->useSysFont->isChecked(); } void KJPrefs::setUseSysFont( bool mode ) { mGuiSettingsWidget->useSysFont->setChecked( mode ); save(); // not sure if that's a good idea or doing saving by hand in here } TQFont KJPrefs::sysFont(void) const { TQString family = mGuiSettingsWidget->cmbSysFont->currentFont(); // kdDebug(66666) << k_funcinfo << "family=" << family << endl; return TQFont( family ); } void KJPrefs::setSysFont(TQFont &fnt) { mGuiSettingsWidget->cmbSysFont->setCurrentFont( fnt.family() ); } TQColor KJPrefs::sysFontColor(void) const { return mGuiSettingsWidget->cmbSysFontColor->color(); } void KJPrefs::sysFontColor(TQColor &c) { mGuiSettingsWidget->cmbSysFontColor->setColor( c ); } bool KJPrefs::displayTooltips( void ) const { return mGuiSettingsWidget->displayTooltips->isChecked(); } bool KJPrefs::displaySplash( void ) const { return mGuiSettingsWidget->displaySplash->isChecked(); } void KJPrefs::showPreview(const TQString &_skin) { Parser p; p.open( ::expand(_skin) ); TQImage image = p.image(p["BackgroundImage"][1]); if (!image.isNull()) { mPixmap.convertFromImage(image); mPixmap.setMask( KJWidget::getMask(image) ); } else mPixmap=TQPixmap(); mSkinselectorWidget->mPreview->setPixmap(mPixmap); mSkinselectorWidget->mAboutText->setText(p.about()); mSkinselectorWidget->updateGeometry(); } /* =================================================================================== */ void KJPrefs::installNewSkin( void ) { bool skinInstalled = false; // flag showing wether a skindir got installed KURL src, dst; // sourcedir and destinationdir for skin-installation KURL srcFile ( mSkinselectorWidget->mSkinRequester->url() ); //kdDebug(66666) << "file to work on: " << srcFile.path().latin1() << endl; if ( !srcFile.isValid() || srcFile.isEmpty() ) // stop working on broken URLs { kdDebug(66666) << "srcFile is malformed or empty !!!" << endl; return; } if ( !srcFile.isLocalFile() ) // TODO: Download file into tmp dir + unpack afterwards { KMessageBox::sorry ( this, i18n("Non-Local files are not supported yet") ); return; } // Determine file-format trough mimetype (no stupid .ext test) KMimeMagicResult * result = KMimeMagic::self()->findFileType( srcFile.path() ); if ( !result->isValid() ) { kdDebug(66666) << "Could not determine filetype of srcFile !!!" << endl; return; } if ( result->mimeType() != "application/x-zip" ) { KMessageBox::error ( this, i18n("The selected file does not appear to be a valid zip-archive") ); return; } // create a dir with name of the skinarchive // path to unpack to: pathToTmp/filename.ext/ TQString tmpUnpackPath = locateLocal("tmp", srcFile.fileName()+"/" ); kdDebug(66666) << "tmpUnpackPath: " << tmpUnpackPath.latin1() << endl; // Our extract-process, TODO: wanna have tdeio_(un)zip instead :) KShellProcess proc; // "unzip -d whereToUnpack whatToUnpack" proc << "unzip -d " << proc.quote(tmpUnpackPath) << " " << proc.quote(srcFile.path()); kdDebug(66666) << "unzip -d " << tmpUnpackPath.latin1() << " " << srcFile.path().latin1() << endl; proc.start( TDEProcess::Block, TDEProcess::NoCommunication ); // "unzip" spits out errorcodes > 0 only, 0 on success if ( proc.exitStatus() != 0 ) { KMessageBox::error ( this, i18n("Extracting skin-archive failed") ); // FIXME: Do I have to wait for the job to finish? // I'd say no because I don't care about the temp-dir // anyway after leaving this method :) TDEIO::del( tmpUnpackPath ); return; } TQDir tmpCnt = TQDir ( tmpUnpackPath ); tmpCnt.setFilter ( TQDir::Dirs ); TQStringList dirList = tmpCnt.entryList(); // Iterate trough all subdirs of tmpUnpackPath (including "."!) for ( unsigned int i = 0; i < dirList.count(); i++ ) { // FIXME: is the following portable? if ( dirList[i] == ".." ) continue; TQDir tmpSubCnt = TQDir( tmpUnpackPath + dirList[i], "*.rc;*.RC;*.Rc;*.rC", TQDir::Name|TQDir::IgnoreCase, TQDir::Files ); kdDebug(66666) << "Searching for *.rc in " << TQString(tmpUnpackPath+dirList[i]).latin1() << endl; // oh, no .rc file in current dir, let's go to next dir in list if ( tmpSubCnt.count() == 0 ) continue; src = KURL::encode_string(tmpUnpackPath+dirList[i]); dst = KURL::encode_string(locateLocal("data","noatun/skins/kjofol/")); // destination to copy skindir into if ( dirList[i] == "." ) // zip did not contain a subdir, we have to create one { // skindir is named like the archive without extension (FIXME: extension is not stripped from name) int dotPos = srcFile.fileName().findRev('.'); if ( dotPos > 0 ) // found a dot -> (hopefully) strip the extension { dst.addPath( srcFile.fileName().left(dotPos) ); } else // we don't seem to have any extension, just append the archivename { dst.addPath( srcFile.fileName() ); } kdDebug(66666) << "want to create: " << dst.path().latin1() << endl; if ( !dst.isValid() ) { KMessageBox::error ( this, i18n("Installing new skin failed: Destination path is invalid.\n" "Please report a bug to the K-Jöfol maintainer") ); TDEIO::del( tmpUnpackPath ); return; } TDEIO::mkdir( dst ); } if ( !src.isValid() || !dst.isValid() ) { KMessageBox::error ( this, i18n("Installing new skin failed: Either source or destination path is invalid.\n" "Please report a bug to the K-Jöfol maintainer") ); } else { kdDebug(66666) << "src: " << src.path().latin1() << endl; kdDebug(66666) << "dst: " << dst.path().latin1() << endl; TDEIO::Job *job = TDEIO::copy(src,dst); connect ( job, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotResult(TDEIO::Job*)) ); skinInstalled = true; } } // END iterate trough dirList if ( !skinInstalled ) { KMessageBox::sorry ( this, i18n("No new skin has been installed.\nMake sure the archive contains a valid K-Jöfol skin") ); } else { KMessageBox::information ( this, i18n("The new skin has been successfully installed") ); } TDEIO::del( tmpUnpackPath ); } void KJPrefs::removeSelectedSkin( void ) { TQString question = i18n("Are you sure you want to remove %1?\n" "This will delete the files installed by this skin "). arg ( mSkinselectorWidget->mSkins->currentText() ); cfg->setGroup("KJofol-Skins"); TQString loadedSkin = cfg->readEntry("SkinResource", "kjofol"); // kdDebug(66666) << "loaded Skin Name: " << TQFileInfo(loadedSkin).baseName().latin1() << endl; int r = KMessageBox::warningContinueCancel ( this, question, i18n("Confirmation"), KStdGuiItem::del() ); if ( r != KMessageBox::Continue ) return; bool deletingCurrentSkin = ( mSkinselectorWidget->mSkins->currentText() == TQFileInfo(loadedSkin).baseName() ); // Now find the dir to delete !!! TQString dirToDelete = TQString (""); TQStringList skinLocations = TDEGlobal::dirs()->findDirs("data", "noatun/skins/kjofol"); // iterate through all paths where Noatun is searching for kjofol-skins for (uint i = 0; i < skinLocations.count(); ++i ) { TQStringList skinDirs = TQDir(skinLocations[i]).entryList(); // iterate trough all dirs containing a skin for (uint k = 0; k < skinDirs.count(); ++k ) { TQDir skinDirCnt = TQDir ( skinLocations[i]+skinDirs[k], "*.rc", TQDir::Name|TQDir::IgnoreCase, TQDir::Files ); // make a list of all .rc-files in a skindir TQStringList rcFiles = skinDirCnt.entryList(); // iterate trough all those rc.-files in a skindir for (uint j = 0; j < rcFiles.count(); j++ ) { if ( rcFiles[j].left(rcFiles[j].length()-3) == mSkinselectorWidget->mSkins->currentText() ) // found skinname.rc :) { dirToDelete = TQString ( skinLocations[i]+skinDirs[k] ); kdDebug(66666) << "FOUND SKIN @ " << dirToDelete.latin1() << endl; } } } } if ( dirToDelete.length() != 0 ) { kdDebug(66666) << "Deleting Skindir: " << dirToDelete.latin1() << endl; TDEIO::Job *job = TDEIO::del( dirToDelete, false, true ); connect ( job, TQT_SIGNAL(result(TDEIO::Job*)), this, TQT_SLOT(slotResult(TDEIO::Job*)) ); } int item = -1; // Fallback to kjofol-skin (the default one) if we've deleted the current skin if ( deletingCurrentSkin ) { for ( int i = 0; i < mSkinselectorWidget->mSkins->count(); i++ ) { // FIXME: no check wether "kjofol" is ever found, well, it HAS to be in the list if ( mSkinselectorWidget->mSkins->text(i) == "kjofol" ) item = i; } } else item = mSkinselectorWidget->mSkins->currentItem(); if ( item != -1 ) mSkinselectorWidget->mSkins->setCurrentItem( item ); // update configuration if ( deletingCurrentSkin ) save(); } void KJPrefs::slotResult(TDEIO::Job *job ) { if ( job->error() ) { job->showErrorDialog(this); } else { // Reload Skinlist reopen(); } } /* =================================================================================== */ // takes name of rc-file without .rc at the end and returns full path to rc-file static TQString expand(TQString s) { // kdDebug(66666) << "expand( "<< s.latin1() << " )" << endl; TQStringList skinLocations = TDEGlobal::dirs()->findDirs("data", "noatun/skins/kjofol"); // iterate through all paths where Noatun is searching for kjofol-skins for (uint i = 0; i < skinLocations.count(); ++i ) { TQStringList skinDirs = TQDir(skinLocations[i]).entryList(); // iterate trough all dirs containing a skin for (uint k = 0; k < skinDirs.count(); ++k ) { TQDir skinDirCnt = TQDir ( skinLocations[i]+skinDirs[k], "*.rc", TQDir::Name|TQDir::IgnoreCase, TQDir::Files ); // make a list of all .rc-files in a skindir TQStringList rcFiles = skinDirCnt.entryList(); // iterate trough all those rc.-files in a skindir for (uint j = 0; j < rcFiles.count(); j++ ) { if ( rcFiles[j].left(rcFiles[j].length()-3) == s ) // found $s.rc :) { // kdDebug(66666) << "expand() found: " << TQString(skinLocations[i]+skinDirs[k]+"/"+rcFiles[j]).latin1() << endl; return (skinLocations[i]+skinDirs[k]+"/"+rcFiles[j]); } } } } return TQString(); } TQString filenameNoCase(const TQString &filename, int badNodes) { TQStringList names=TQStringList::split('/', filename); TQString full; int number=(int)names.count(); for (TQStringList::Iterator i=names.begin(); i!=names.end(); ++i) { full+="/"; if (number<=badNodes) { TQDir d(full); TQStringList files=d.entryList(); files=files.grep(TQRegExp("^"+ (*i) + "$", false)); if (!files.count()) return ""; *i=files.grep(*i, false)[0]; } full+=*i; number--; } if (filename.right(1)=="/") full+="/"; return full; }