You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdemultimedia/noatun/modules/kjofol-skin/kjprefs.cpp

659 lines
20 KiB

/***************************************************************************
kjprefs.cpp - Preferences-Dialog for KJ<4B>ol-Skinloader
--------------------------------------------------------
Maintainer: Stefan Gehn <sgehn@gmx.net>
***************************************************************************/
// local includes
#include "kjprefs.h"
#include "kjprefs.moc"
#include "kjloader.h"
#include "kjwidget.h"
#include "kjvis.h"
#include "parser.h"
// system includes
#include <tqcheckbox.h>
#include <tqcombobox.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqpushbutton.h>
#include <tqradiobutton.h>
#include <tqslider.h>
#include <tqpixmap.h>
#include <tqtabwidget.h>
#include <tqtextbrowser.h>
#include <tqfileinfo.h>
#include <tqstringlist.h>
#include <tqregexp.h>
#include <knuminput.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kglobal.h>
#include <kio/job.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kmimemagic.h>
#include <knotifyclient.h>
#include <kprocess.h>
#include <kstandarddirs.h>
#include <kglobalsettings.h>
#include <kfontcombo.h>
#include <kcolorcombo.h>
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 = KGlobal::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", KGlobalSettings::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 = KGlobal::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 kio_(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( KProcess::Block, KProcess::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 :)
KIO::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") );
KIO::del( tmpUnpackPath );
return;
}
KIO::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;
KIO::Job *job = KIO::copy(src,dst);
connect ( job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotResult(KIO::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") );
}
KIO::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 = KGlobal::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;
KIO::Job *job = KIO::del( dirToDelete, false, true );
connect ( job, TQT_SIGNAL(result(KIO::Job*)), this, TQT_SLOT(slotResult(KIO::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(KIO::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 = KGlobal::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;
}