/***************************************************************************
* Copyright Ravikiran Rajagopal 2003 *
* ravi @ ee . eng . ohio - state . edu *
* Copyright ( c ) 1998 Stefan Taferner < taferner @ kde . org > *
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License ( version 2 ) as *
* published by the Free Software Foundation . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <unistd.h>
# include <stdlib.h>
# include <tqdir.h>
# include <tqlabel.h>
# include <tqlayout.h>
# include <tqtextedit.h>
# include "installer.h"
# include <kdebug.h>
# include <kfiledialog.h>
# include <kglobalsettings.h>
# include <klocale.h>
# include <kmessagebox.h>
# include <kprocess.h>
# include <kpushbutton.h>
# include <kstandarddirs.h>
# include <ktar.h>
# include <ktrader.h>
# include <kurldrag.h>
# include <kio/netaccess.h>
ThemeListBox : : ThemeListBox ( TQWidget * parent )
: KListBox ( parent )
{
setAcceptDrops ( true ) ;
connect ( this , TQT_SIGNAL ( mouseButtonPressed ( int , TQListBoxItem * , const TQPoint & ) ) ,
this , TQT_SLOT ( slotMouseButtonPressed ( int , TQListBoxItem * , const TQPoint & ) ) ) ;
}
void ThemeListBox : : dragEnterEvent ( TQDragEnterEvent * event )
{
event - > accept ( ( event - > source ( ) ! = this ) & & KURLDrag : : canDecode ( event ) ) ;
}
void ThemeListBox : : dropEvent ( TQDropEvent * event )
{
KURL : : List urls ;
if ( KURLDrag : : decode ( event , urls ) )
{
emit filesDropped ( urls ) ;
}
}
void ThemeListBox : : slotMouseButtonPressed ( int button , TQListBoxItem * item , const TQPoint & p )
{
if ( ( button & Qt : : LeftButton ) = = 0 ) return ;
mOldPos = p ;
mDragFile = TQString : : null ;
int cur = index ( item ) ;
if ( cur > = 0 )
mDragFile = text2path [ text ( cur ) ] ;
}
void ThemeListBox : : mouseMoveEvent ( TQMouseEvent * e )
{
if ( ( ( e - > state ( ) & Qt : : LeftButton ) ! = 0 ) & & ! mDragFile . isEmpty ( ) )
{
int delay = KGlobalSettings : : dndEventDelay ( ) ;
TQPoint newPos = e - > globalPos ( ) ;
if ( newPos . x ( ) > mOldPos . x ( ) + delay | | newPos . x ( ) < mOldPos . x ( ) - delay | |
newPos . y ( ) > mOldPos . y ( ) + delay | | newPos . y ( ) < mOldPos . y ( ) - delay )
{
KURL url ;
url . setPath ( mDragFile ) ;
KURL : : List urls ;
urls . append ( url ) ;
KURLDrag * d = new KURLDrag ( urls , this ) ;
d - > dragCopy ( ) ;
}
}
KListBox : : mouseMoveEvent ( e ) ;
}
//-----------------------------------------------------------------------------
SplashInstaller : : SplashInstaller ( TQWidget * aParent , const char * aName , bool aInit )
: TQWidget ( aParent , aName ) , mGui ( ! aInit )
{
KGlobal : : dirs ( ) - > addResourceType ( " ksplashthemes " , KStandardDirs : : kde_default ( " data " ) + " ksplash/Themes " ) ;
if ( ! mGui )
return ;
TQHBoxLayout * hbox = new TQHBoxLayout ( this , 0 , KDialog : : spacingHint ( ) ) ;
TQVBoxLayout * leftbox = new TQVBoxLayout ( hbox , KDialog : : spacingHint ( ) ) ;
hbox - > setStretchFactor ( leftbox , 1 ) ;
mThemesList = new ThemeListBox ( this ) ;
mThemesList - > setSizePolicy ( TQSizePolicy : : Preferred , TQSizePolicy : : Expanding ) ;
connect ( mThemesList , TQT_SIGNAL ( highlighted ( int ) ) , TQT_SLOT ( slotSetTheme ( int ) ) ) ;
connect ( mThemesList , TQT_SIGNAL ( filesDropped ( const KURL : : List & ) ) , TQT_SLOT ( slotFilesDropped ( const KURL : : List & ) ) ) ;
leftbox - > addWidget ( mThemesList ) ;
mBtnAdd = new KPushButton ( i18n ( " Add... " ) , this ) ;
leftbox - > addWidget ( mBtnAdd ) ;
connect ( mBtnAdd , TQT_SIGNAL ( clicked ( ) ) , TQT_SLOT ( slotAdd ( ) ) ) ;
mBtnRemove = new KPushButton ( i18n ( " Remove " ) , this ) ;
leftbox - > addWidget ( mBtnRemove ) ;
connect ( mBtnRemove , TQT_SIGNAL ( clicked ( ) ) , TQT_SLOT ( slotRemove ( ) ) ) ;
mBtnTest = new KPushButton ( i18n ( " Test " ) , this ) ;
leftbox - > addWidget ( mBtnTest ) ;
connect ( mBtnTest , TQT_SIGNAL ( clicked ( ) ) , TQT_SLOT ( slotTest ( ) ) ) ;
TQVBoxLayout * rightbox = new TQVBoxLayout ( hbox , KDialog : : spacingHint ( ) ) ;
hbox - > setStretchFactor ( rightbox , 3 ) ;
mPreview = new TQLabel ( this ) ;
mPreview - > setSizePolicy ( TQSizePolicy : : Expanding , TQSizePolicy : : Expanding ) ;
mPreview - > setFrameStyle ( TQFrame : : Panel | TQFrame : : Sunken ) ;
mPreview - > setMinimumSize ( TQSize ( 320 , 240 ) ) ;
mPreview - > setAlignment ( Qt : : AlignHCenter | Qt : : AlignVCenter ) ;
rightbox - > addWidget ( mPreview ) ;
rightbox - > setStretchFactor ( mPreview , 3 ) ;
mText = new TQTextEdit ( this ) ;
mText - > setSizePolicy ( TQSizePolicy : : Expanding , TQSizePolicy : : Preferred ) ;
mText - > setMinimumSize ( mText - > sizeHint ( ) ) ;
mText - > setReadOnly ( true ) ;
rightbox - > addWidget ( mText ) ;
rightbox - > setStretchFactor ( mText , 1 ) ;
readThemesList ( ) ;
load ( ) ;
}
//-----------------------------------------------------------------------------
SplashInstaller : : ~ SplashInstaller ( )
{
}
int SplashInstaller : : addTheme ( const TQString & path , const TQString & name )
{
//kdDebug() << "SplashInstaller::addTheme: " << path << " " << name << endl;
TQString tmp ( i18n ( name . utf8 ( ) ) ) ;
int i = mThemesList - > count ( ) ;
while ( ( i > 0 ) & & ( mThemesList - > text ( i - 1 ) > tmp ) )
i - - ;
if ( ( i > 0 ) & & ( mThemesList - > text ( i - 1 ) = = tmp ) )
return i - 1 ;
mThemesList - > insertItem ( tmp , i ) ;
mThemesList - > text2path . insert ( tmp , path + " / " + name ) ;
return i ;
}
// Copy theme package into themes directory
void SplashInstaller : : addNewTheme ( const KURL & srcURL )
{
TQString dir = KGlobal : : dirs ( ) - > saveLocation ( " ksplashthemes " ) ;
KURL url ;
TQString filename = srcURL . fileName ( ) ;
int i = filename . findRev ( ' . ' ) ;
// Convert extension to lower case.
if ( i > = 0 )
filename = filename . left ( i ) + filename . mid ( i ) . lower ( ) ;
url . setPath ( locateLocal ( " tmp " , filename ) ) ;
// Remove file from temporary directory if it aleady exists - usually the result of a failed install.
if ( KIO : : NetAccess : : exists ( url , true , 0 ) )
KIO : : NetAccess : : del ( url , 0 ) ;
bool rc = KIO : : NetAccess : : copy ( srcURL , url , 0 ) ;
if ( ! rc )
{
kdWarning ( ) < < " Failed to copy theme " < < srcURL . fileName ( )
< < " into temporary directory " < < url . path ( ) < < endl ;
return ;
}
// Extract into theme directory: we may have multiple themes in one tarball!
KTar tarFile ( url . path ( ) ) ;
if ( ! tarFile . open ( IO_ReadOnly ) )
{
kdDebug ( ) < < " Unable to open archive: " < < url . path ( ) < < endl ;
return ;
}
KArchiveDirectory const * ad = tarFile . directory ( ) ;
// Find first directory entry.
TQStringList entries = ad - > entries ( ) ;
TQString themeName ( entries . first ( ) ) ;
#if 0
// The isDirectory() call always returns false; why?
for ( TQStringList : : Iterator it = entries . begin ( ) ; it ! = entries . end ( ) ; + + it )
{
if ( ad - > entry ( * it ) - > isDirectory ( ) )
{
themeName = * it ;
break ;
}
}
# endif
// TODO: Make sure we put the entries into a subdirectory if the tarball does not.
// TODO: Warn the user if we overwrite something.
ad - > copyTo ( locateLocal ( " ksplashthemes " , " / " ) ) ;
tarFile . close ( ) ;
KIO : : NetAccess : : del ( url , 0 ) ;
// TODO: Update only the entries from this installation.
readThemesList ( ) ;
mThemesList - > setCurrentItem ( findTheme ( themeName ) ) ;
mThemesList - > setSelected ( mThemesList - > currentItem ( ) , true ) ;
}
//-----------------------------------------------------------------------------
void SplashInstaller : : readThemesList ( )
{
mThemesList - > clear ( ) ;
// Read local themes
TQStringList entryList = KGlobal : : dirs ( ) - > resourceDirs ( " ksplashthemes " ) ;
//kdDebug() << "readThemesList: " << entryList << endl;
TQDir dir ;
TQStringList subdirs ;
TQStringList : : ConstIterator name ;
for ( name = entryList . begin ( ) ; name ! = entryList . end ( ) ; name + + )
{
dir = * name ;
if ( ! dir . exists ( ) )
continue ;
subdirs = dir . entryList ( TQDir : : Dirs ) ;
// kdDebug() << "readThemesList: " << subdirs << endl;
// TODO: Make sure it contains a *.rc file.
for ( TQStringList : : Iterator l = subdirs . begin ( ) ; l ! = subdirs . end ( ) ; l + + )
if ( ! ( * l ) . startsWith ( TQString ( " . " ) ) )
{
mThemesList - > blockSignals ( true ) ; // Don't activate any theme until all themes are loaded.
addTheme ( dir . path ( ) , * l ) ;
mThemesList - > blockSignals ( false ) ;
}
}
}
//-----------------------------------------------------------------------------
void SplashInstaller : : defaults ( )
{
load ( true ) ;
}
void SplashInstaller : : load ( )
{
load ( false ) ;
}
void SplashInstaller : : load ( bool useDefaults )
{
KConfig cnf ( " ksplashrc " ) ;
cnf . setReadDefaults ( useDefaults ) ;
cnf . setGroup ( " KSplash " ) ;
TQString curTheme = cnf . readEntry ( " Theme " , " Default " ) ;
mThemesList - > setCurrentItem ( findTheme ( curTheme ) ) ;
emit changed ( useDefaults ) ;
}
//-----------------------------------------------------------------------------
void SplashInstaller : : save ( )
{
KConfig cnf ( " ksplashrc " ) ;
cnf . setGroup ( " KSplash " ) ;
int cur = mThemesList - > currentItem ( ) ;
if ( cur < 0 )
return ;
TQString path = mThemesList - > text ( cur ) ;
if ( mThemesList - > text2path . contains ( path ) )
path = mThemesList - > text2path [ path ] ;
cur = path . findRev ( ' / ' ) ;
cnf . writeEntry ( " Theme " , path . mid ( cur + 1 ) ) ;
cnf . sync ( ) ;
emit changed ( false ) ;
}
//-----------------------------------------------------------------------------
void SplashInstaller : : slotRemove ( )
{
int cur = mThemesList - > currentItem ( ) ;
if ( cur < 0 )
return ;
bool rc = false ;
TQString themeName = mThemesList - > text ( cur ) ;
TQString themeDir = mThemesList - > text2path [ themeName ] ;
if ( ! themeDir . isEmpty ( ) )
{
KURL url ;
url . setPath ( themeDir ) ;
if ( KMessageBox : : warningContinueCancel ( this , i18n ( " Delete folder %1 and its contents? " ) . arg ( themeDir ) , " " , KGuiItem ( i18n ( " &Delete " ) , " editdelete " ) ) = = KMessageBox : : Continue )
rc = KIO : : NetAccess : : del ( url , this ) ;
else
return ;
}
if ( ! rc )
{
KMessageBox : : sorry ( this , i18n ( " Failed to remove theme '%1' " ) . arg ( themeName ) ) ;
return ;
}
//mThemesList->removeItem(cur);
readThemesList ( ) ;
cur = ( ( unsigned int ) cur > = mThemesList - > count ( ) ) ? mThemesList - > count ( ) - 1 : cur ;
mThemesList - > setCurrentItem ( cur ) ;
}
//-----------------------------------------------------------------------------
void SplashInstaller : : slotSetTheme ( int id )
{
bool enabled ;
TQString path ( TQString : : null ) ;
TQString infoTxt ;
if ( id < 0 )
{
mPreview - > setText ( TQString : : null ) ;
mText - > setText ( TQString : : null ) ;
enabled = false ;
}
else
{
TQString error = i18n ( " (Could not load theme) " ) ;
path = mThemesList - > text ( id ) ;
if ( mThemesList - > text2path . contains ( path ) )
path = mThemesList - > text2path [ path ] ;
enabled = false ;
KURL url ;
TQString themeName ;
if ( ! path . isEmpty ( ) )
{
// Make sure the correct plugin is installed.
int i = path . findRev ( ' / ' ) ;
if ( i > = 0 )
themeName = path . mid ( i + 1 ) ;
url . setPath ( path + " /Theme.rc " ) ;
if ( ! KIO : : NetAccess : : exists ( url , true , 0 ) )
{
url . setPath ( path + " /Theme.RC " ) ;
if ( ! KIO : : NetAccess : : exists ( url , true , 0 ) )
{
url . setPath ( path + " /theme.rc " ) ;
if ( ! KIO : : NetAccess : : exists ( url , true , 0 ) )
url . setPath ( path + " / " + themeName + " .rc " ) ;
}
}
if ( KIO : : NetAccess : : exists ( url , true , 0 ) )
{
KConfig cnf ( url . path ( ) ) ;
cnf . setGroup ( TQString ( " KSplash Theme: %1 " ) . arg ( themeName ) ) ;
// Get theme information.
infoTxt = " <qt> " ;
if ( cnf . hasKey ( " Name " ) )
infoTxt + = i18n ( " <b>Name:</b> %1<br> " ) . arg ( cnf . readEntry ( " Name " , i18n ( " Unknown " ) ) ) ;
if ( cnf . hasKey ( " Description " ) )
infoTxt + = i18n ( " <b>Description:</b> %1<br> " ) . arg ( cnf . readEntry ( " Description " , i18n ( " Unknown " ) ) ) ;
if ( cnf . hasKey ( " Version " ) )
infoTxt + = i18n ( " <b>Version:</b> %1<br> " ) . arg ( cnf . readEntry ( " Version " , i18n ( " Unknown " ) ) ) ;
if ( cnf . hasKey ( " Author " ) )
infoTxt + = i18n ( " <b>Author:</b> %1<br> " ) . arg ( cnf . readEntry ( " Author " , i18n ( " Unknown " ) ) ) ;
if ( cnf . hasKey ( " Homepage " ) )
infoTxt + = i18n ( " <b>Homepage:</b> %1<br> " ) . arg ( cnf . readEntry ( " Homepage " , i18n ( " Unknown " ) ) ) ;
infoTxt + = " </qt> " ;
TQString pluginName ( cnf . readEntry ( " Engine " , " Default " ) ) ; // Perhaps no default is better?
if ( ( KTrader : : self ( ) - > query ( " KSplash/Plugin " , TQString ( " [X-KSplash-PluginName] == '%1' " ) . arg ( pluginName ) ) ) . isEmpty ( ) )
{
enabled = false ;
error = i18n ( " This theme requires the plugin %1 which is not installed. " ) . arg ( pluginName ) ;
}
else
enabled = true ; // Hooray, there is at least one plugin which can handle this theme.
}
else
{
error = i18n ( " Could not load theme configuration file. " ) ;
}
}
mBtnTest - > setEnabled ( enabled & & themeName ! = " None " ) ;
mText - > setText ( infoTxt ) ;
if ( ! enabled )
{
url . setPath ( path + " / " + " Preview.png " ) ;
if ( KIO : : NetAccess : : exists ( url , true , 0 ) )
mPreview - > setPixmap ( TQPixmap ( url . path ( ) ) ) ;
else
mPreview - > setText ( i18n ( " (Could not load theme) " ) ) ;
KMessageBox : : sorry ( this , error ) ;
}
else
{
url . setPath ( path + " / " + " Preview.png " ) ;
if ( KIO : : NetAccess : : exists ( url , true , 0 ) )
mPreview - > setPixmap ( TQPixmap ( url . path ( ) ) ) ;
else
mPreview - > setText ( i18n ( " No preview available. " ) ) ;
emit changed ( true ) ;
}
}
mBtnRemove - > setEnabled ( ! path . isEmpty ( ) & & TQFileInfo ( path ) . isWritable ( ) ) ;
}
//-----------------------------------------------------------------------------
void SplashInstaller : : slotAdd ( )
{
static TQString path ;
if ( path . isEmpty ( ) ) path = TQDir : : homeDirPath ( ) ;
KFileDialog dlg ( path , " *.tgz *.tar.gz *.tar.bz2| " + i18n ( " KSplash Theme Files " ) , 0 , 0 , true ) ;
dlg . setCaption ( i18n ( " Add Theme " ) ) ;
if ( ! dlg . exec ( ) )
return ;
path = dlg . baseURL ( ) . url ( ) ;
addNewTheme ( dlg . selectedURL ( ) ) ;
}
//-----------------------------------------------------------------------------
void SplashInstaller : : slotFilesDropped ( const KURL : : List & urls )
{
for ( KURL : : List : : ConstIterator it = urls . begin ( ) ;
it ! = urls . end ( ) ;
+ + it )
addNewTheme ( * it ) ;
}
//-----------------------------------------------------------------------------
int SplashInstaller : : findTheme ( const TQString & theme )
{
// theme is untranslated, but the listbox contains translated items
TQString tmp ( i18n ( theme . utf8 ( ) ) ) ;
int id = mThemesList - > count ( ) - 1 ;
while ( id > = 0 )
{
if ( mThemesList - > text ( id ) = = tmp )
return id ;
id - - ;
}
return 0 ;
}
//-----------------------------------------------------------------------------
void SplashInstaller : : slotTest ( )
{
int i = mThemesList - > currentItem ( ) ;
if ( i < 0 )
return ;
TQString themeName = mThemesList - > text2path [ mThemesList - > text ( i ) ] ;
int r = themeName . findRev ( ' / ' ) ;
if ( r > = 0 )
themeName = themeName . mid ( r + 1 ) ;
// special handling for none and simple splashscreens
if ( themeName = = " None " )
return ;
if ( themeName = = " Simple " )
{
KProcess proc ;
proc < < " ksplashsimple " < < " --test " ;
if ( ! proc . start ( KProcess : : Block ) )
KMessageBox : : error ( this , i18n ( " Unable to start ksplashsimple. " ) ) ;
return ;
}
KProcess proc ;
proc < < " ksplash " < < " --test " < < " --theme " < < themeName ;
if ( ! proc . start ( KProcess : : Block ) )
KMessageBox : : error ( this , i18n ( " Unable to start ksplash. " ) ) ;
}
//-----------------------------------------------------------------------------
# include "installer.moc"