1 /***************************************************************************
2 * Copyright Ravikiran Rajagopal 2003 *
3 * ravi@ee.eng.ohio-state.edu *
4 * Copyright (c) 1998 Stefan Taferner <taferner@kde.org> *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License (version 2) as *
8 * published by the Free Software Foundation. *
10 ***************************************************************************/
21 #include <QHBoxLayout>
23 #include <QVBoxLayout>
24 #include <QDragEnterEvent>
25 #include <QMouseEvent>
26 #include <QScrollArea>
28 #include "installer.h"
31 #include <kfiledialog.h>
32 #include <kglobalsettings.h>
34 #include <kmessagebox.h>
36 #include <kpushbutton.h>
37 #include <kstandarddirs.h>
39 #include <kservicetypetrader.h>
40 #include <kio/netaccess.h>
41 #include <knewstuff2/engine.h>
43 ThemeListBox::ThemeListBox(QWidget
*parent
)
49 void ThemeListBox::dragEnterEvent(QDragEnterEvent
* event
)
51 event
->setAccepted((event
->source() != this) && KUrl::List::canDecode(event
->mimeData()));
54 void ThemeListBox::dragMoveEvent(QDragMoveEvent
* event
)
56 event
->setAccepted((event
->source() != this) && KUrl::List::canDecode(event
->mimeData()));
59 void ThemeListBox::dropEvent(QDropEvent
* event
)
61 KUrl::List urls
= KUrl::List::fromMimeData(event
->mimeData());
64 emit
filesDropped(urls
);
68 void ThemeListBox::mousePressEvent(QMouseEvent
*e
)
70 if ((e
->buttons() & Qt::LeftButton
) != 0)
72 mOldPos
= e
->globalPos();;
74 int cur
= row(itemAt(e
->pos()));
76 mDragFile
= text2path
[item(cur
)->text()];
78 KListWidget::mousePressEvent(e
);
81 void ThemeListBox::mouseMoveEvent(QMouseEvent
*e
)
83 if (((e
->buttons() & Qt::LeftButton
) != 0) && !mDragFile
.isEmpty())
85 int delay
= KGlobalSettings::dndEventDelay();
86 QPoint newPos
= e
->globalPos();
87 if(newPos
.x() > mOldPos
.x()+delay
|| newPos
.x() < mOldPos
.x()-delay
||
88 newPos
.y() > mOldPos
.y()+delay
|| newPos
.y() < mOldPos
.y()-delay
)
91 url
.setPath(mDragFile
);
94 QDrag
*drag
= new QDrag(this);
95 QMimeData
*mime
= new QMimeData();
96 urls
.populateMimeData(mime
);
97 drag
->setMimeData(mime
);
101 KListWidget::mouseMoveEvent(e
);
104 //-----------------------------------------------------------------------------
105 SplashInstaller::SplashInstaller (QWidget
*aParent
, const char *aName
, bool aInit
)
106 : QWidget(aParent
), mGui(!aInit
)
108 setObjectName(aName
);
109 KGlobal::dirs()->addResourceType("ksplashthemes", "data", "ksplash/Themes");
114 QHBoxLayout
* hbox
= new QHBoxLayout( this );
115 hbox
->setMargin( 0 );
117 QVBoxLayout
* leftbox
= new QVBoxLayout( );
118 hbox
->addItem( leftbox
);
119 leftbox
->setSpacing( KDialog::spacingHint() );
120 hbox
->setStretchFactor( leftbox
, 1 );
122 mThemesList
= new ThemeListBox(this);
123 mThemesList
->setSizePolicy( QSizePolicy::Preferred
, QSizePolicy::Expanding
);
124 connect(mThemesList
, SIGNAL(currentRowChanged(int)), SLOT(slotSetTheme(int)));
125 connect(mThemesList
, SIGNAL(filesDropped(const KUrl::List
&)), SLOT(slotFilesDropped(const KUrl::List
&)));
126 leftbox
->addWidget(mThemesList
);
128 mBtnNew
= new KPushButton( KIcon("get-hot-new-stuff"), i18n("Get New Themes..."), this );
129 mBtnNew
->setToolTip(i18n("Get new themes from the Internet"));
130 mBtnNew
->setWhatsThis(i18n("You need to be connected to the Internet to use this action. A dialog will display a list of themes from the http://www.kde.org website. Clicking the Install button associated with a theme will install this theme locally."));
131 leftbox
->addWidget( mBtnNew
);
132 connect(mBtnNew
, SIGNAL(clicked()), SLOT(slotNew()));
134 mBtnAdd
= new KPushButton( KIcon("document-import"), i18n("Install Theme File..."), this );
135 mBtnAdd
->setToolTip(i18n("Install a theme archive file you already have locally"));
136 mBtnAdd
->setWhatsThis(i18n("If you already have a theme archive locally, this button will unpack it and make it available for KDE applications"));
137 leftbox
->addWidget( mBtnAdd
);
138 connect(mBtnAdd
, SIGNAL(clicked()), SLOT(slotAdd()));
140 mBtnRemove
= new KPushButton( KIcon("edit-delete"), i18n("Remove Theme"), this );
141 mBtnRemove
->setToolTip(i18n("Remove the selected theme from your disk"));
142 mBtnRemove
->setWhatsThis(i18n("This will remove the selected theme from your disk."));
143 mBtnRemove
->setEnabled( false );
144 leftbox
->addWidget( mBtnRemove
);
145 connect(mBtnRemove
, SIGNAL(clicked()), SLOT(slotRemove()));
147 mBtnTest
= new KPushButton( KIcon("document-preview"), i18n("Test Theme"), this );
148 mBtnTest
->setToolTip(i18n("Test the selected theme"));
149 mBtnTest
->setWhatsThis(i18n("This will test the selected theme."));
150 mBtnTest
->setEnabled( false );
151 leftbox
->addWidget( mBtnTest
);
152 connect(mBtnTest
, SIGNAL(clicked()), SLOT(slotTest()));
154 QVBoxLayout
* rightbox
= new QVBoxLayout( );
155 hbox
->addItem( rightbox
);
156 rightbox
->setSpacing( KDialog::spacingHint() );
157 hbox
->setStretchFactor( rightbox
, 3 );
159 QScrollArea
* scrollarea
= new QScrollArea(this);
160 scrollarea
->setAlignment(Qt::AlignHCenter
|Qt::AlignVCenter
);
161 mPreview
= new QLabel(this);
162 scrollarea
->setWidget(mPreview
);
163 mPreview
->setSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Expanding
);
164 mPreview
->setFrameStyle(QFrame::Panel
|QFrame::Sunken
);
165 mPreview
->setMinimumSize(QSize(320,240));
166 mPreview
->setAlignment(Qt::AlignHCenter
|Qt::AlignVCenter
);
167 rightbox
->addWidget(scrollarea
);
168 rightbox
->setStretchFactor( scrollarea
, 3 );
170 mText
= new QTextEdit(this);
171 mText
->setSizePolicy( QSizePolicy::Expanding
, QSizePolicy::Preferred
);
172 mText
->setMinimumSize(mText
->sizeHint().width(), 7 * mText
->fontMetrics().height());
173 mText
->setReadOnly(true);
174 rightbox
->addWidget(mText
);
175 rightbox
->setStretchFactor( mText
, 1 );
183 //-----------------------------------------------------------------------------
184 SplashInstaller::~SplashInstaller()
188 int SplashInstaller::addTheme(const QString
&path
, const QString
&name
)
190 //kDebug() << "SplashInstaller::addTheme: " << path << " " << name;
191 QString
tmp(i18n( name
.toUtf8() ));
192 int i
= mThemesList
->count();
193 while((i
> 0) && (mThemesList
->item(i
-1)->text() > tmp
))
195 if ((i
> 0) && (mThemesList
->item(i
-1)->text() == tmp
))
197 mThemesList
->insertItem(i
, tmp
);
198 mThemesList
->text2path
.insert( tmp
, path
+'/'+name
);
202 // Copy theme package into themes directory
203 void SplashInstaller::addNewTheme(const KUrl
&srcURL
)
205 QString dir
= KGlobal::dirs()->saveLocation("ksplashthemes");
208 QStringList themeNames
;
209 QString filename
= srcURL
.fileName();
210 int i
= filename
.lastIndexOf('.');
211 // Convert extension to lower case.
213 filename
= filename
.left(i
)+filename
.mid(i
).toLower();
214 url
.setPath(KStandardDirs::locateLocal("tmp",filename
));
216 // Remove file from temporary directory if it aleady exists - usually the result of a failed install.
217 if ( KIO::NetAccess::exists( url
, KIO::NetAccess::SourceSide
, 0 ) )
218 KIO::NetAccess::del( url
, 0 );
220 if (srcURL
.fileName().toLower() == "theme.rc" ) // uncompressed theme selected
223 // Get the name of the Theme from the theme.rc file
224 KConfig
_cnf(srcURL
.path());
225 KConfigGroup
cnf(&_cnf
, QString("KSplash Theme: %1").arg(themeName
) );
227 // copy directory of theme.rc to ThemesDir
228 KIO::NetAccess::dircopy(KUrl(srcURL
.directory()), KUrl(dir
+ themeName
));
230 themeNames
<< themeName
;
234 bool rc
= KIO::NetAccess::file_copy(srcURL
, url
, 0);
237 kWarning() << "Failed to copy theme " << srcURL
.fileName()
238 << " into temporary directory " << url
.path() << endl
;
242 // Extract into theme directory: we may have multiple themes in one tarball!
243 KTar
tarFile(url
.path());
244 if (!tarFile
.open(QIODevice::ReadOnly
))
246 kWarning() << "Unable to open archive: " << url
.path();
247 KIO::NetAccess::del( url
, 0 );
250 KArchiveDirectory
const *ad
= tarFile
.directory();
252 // Find first directory entry.
253 QStringList entries
= ad
->entries();
254 foreach(const QString
& s
, entries
)
256 if( ad
->entry(s
)->isDirectory() )
258 // each directory may contain one theme
262 if (themeNames
.count() < 1)
264 kWarning() << "No directory in archive: " << url
.path();
266 KIO::NetAccess::del( url
, 0 );
270 // copy the theme into the "ksplashthemes" directory
274 KIO::NetAccess::del( url
, 0 );
279 mThemesList
->setCurrentRow(findTheme(themeNames
.first()));
280 if (mThemesList
->currentItem())
282 mThemesList
->currentItem()->setSelected(true);
286 //-----------------------------------------------------------------------------
287 void SplashInstaller::readThemesList()
289 mThemesList
->clear();
292 QStringList entryList
= KGlobal::dirs()->resourceDirs("ksplashthemes");
293 //kDebug() << "readThemesList: " << entryList;
296 QStringList::ConstIterator name
;
297 for(name
= entryList
.constBegin(); name
!= entryList
.constEnd(); name
++)
302 subdirs
= dir
.entryList( QDir::Dirs
);
303 // kDebug() << "readThemesList: " << subdirs;
304 // TODO: Make sure it contains a *.rc file.
305 for (QStringList::const_iterator l
= subdirs
.constBegin(); l
!= subdirs
.constEnd(); l
++ )
306 if ( !(*l
).startsWith(QString(".")) )
308 mThemesList
->blockSignals( true ); // Don't activate any theme until all themes are loaded.
309 addTheme(dir
.path(),*l
);
310 mThemesList
->blockSignals( false );
315 //-----------------------------------------------------------------------------
316 void SplashInstaller::defaults()
318 mThemesList
->setCurrentRow(findTheme("Default"));
319 emit
changed( true );
322 void SplashInstaller::load()
324 KConfig
_cnf( "ksplashrc" );
325 KConfigGroup
cnf(&_cnf
, "KSplash");
326 QString curTheme
= cnf
.readEntry("Theme","Default");
327 mThemesList
->setCurrentRow(findTheme(curTheme
));
328 emit
changed( false );
331 //-----------------------------------------------------------------------------
332 void SplashInstaller::save()
334 KConfig
_cnf( "ksplashrc" );
335 KConfigGroup
cnf(&_cnf
, "KSplash");
336 int cur
= mThemesList
->currentRow();
339 QString path
= mThemesList
->item(cur
)->text();
340 if ( mThemesList
->text2path
.contains( path
) )
341 path
= mThemesList
->text2path
[path
];
342 cur
= path
.lastIndexOf('/');
343 cnf
.writeEntry("Theme", path
.mid(cur
+1) );
344 // save also the engine, so that it's known at KDE startup which splash implementation to use
345 cnf
.writeEntry("Engine", mEngineOfSelected
);
347 emit
changed( false );
350 //-----------------------------------------------------------------------------
351 void SplashInstaller::slotRemove()
353 int cur
= mThemesList
->currentRow();
358 QString themeName
= mThemesList
->item(cur
)->text();
359 QString themeDir
= mThemesList
->text2path
[themeName
];
360 if (!themeDir
.isEmpty())
363 url
.setPath(themeDir
);
364 if (KMessageBox::warningContinueCancel(this,i18n("Delete folder %1 and its contents?", themeDir
),"",KGuiItem(i18n("&Delete"),"edit-delete"))==KMessageBox::Continue
)
365 rc
= KIO::NetAccess::del(url
,this);
371 KMessageBox::sorry(this, i18n("Failed to remove theme '%1'", themeName
));
374 //mThemesList->removeItem(cur);
376 cur
= (cur
>= mThemesList
->count())?mThemesList
->count()-1:cur
;
377 mThemesList
->setCurrentRow(cur
);
381 //-----------------------------------------------------------------------------
382 void SplashInstaller::slotSetTheme(int id
)
385 QString path
= QString();
390 mPreview
->setText(QString());
391 mText
->setText(QString());
396 QString error
= i18n("(Could not load theme)");
397 path
= mThemesList
->item(id
)->text();
398 if ( mThemesList
->text2path
.contains( path
) )
399 path
= mThemesList
->text2path
[path
];
405 // Make sure the correct plugin is installed.
406 int i
= path
.lastIndexOf('/');
408 themeName
= path
.mid(i
+1);
409 url
.setPath( path
+ "/Theme.rc" );
410 if (!KIO::NetAccess::exists(url
, KIO::NetAccess::SourceSide
, 0))
412 url
.setPath( path
+ "/Theme.RC" );
413 if (!KIO::NetAccess::exists(url
, KIO::NetAccess::SourceSide
, 0))
415 url
.setPath( path
+ "/theme.rc" );
416 if (!KIO::NetAccess::exists(url
, KIO::NetAccess::SourceSide
, 0))
417 url
.setPath( path
+ '/' + themeName
+ ".rc" );
420 if (KIO::NetAccess::exists(url
, KIO::NetAccess::SourceSide
, 0))
422 KConfig
_cnf(url
.path());
423 KConfigGroup
cnf(&_cnf
, QString("KSplash Theme: %1").arg(themeName
) );
425 // Get theme information.
427 if ( cnf
.hasKey( "Name" ) )
428 infoTxt
+= i18n( "<b>Name:</b> %1", cnf
.readEntry( "Name", i18nc( "Unknown name", "Unknown" ) ) ) + "<br />";
429 if ( cnf
.hasKey( "Description" ) )
430 infoTxt
+= i18n( "<b>Description:</b> %1", cnf
.readEntry( "Description", i18nc( "Unknown description", "Unknown" ) ) ) + "<br />";
431 if ( cnf
.hasKey( "Version" ) )
432 infoTxt
+= i18n( "<b>Version:</b> %1", cnf
.readEntry( "Version", i18nc( "Unknown version", "Unknown" ) ) ) + "<br />";
433 if ( cnf
.hasKey( "Author" ) )
434 infoTxt
+= i18n( "<b>Author:</b> %1", cnf
.readEntry( "Author", i18nc( "Unknown author", "Unknown" ) ) ) + "<br />";
435 if ( cnf
.hasKey( "Homepage" ) )
436 infoTxt
+= i18n( "<b>Homepage:</b> %1", cnf
.readEntry( "Homepage", i18nc( "Unknown homepage", "Unknown" ) ) ) + "<br />";
439 QString
pluginName( cnf
.readEntry( "Engine", "KSplashX" ).trimmed() );
440 if( pluginName
== "Simple" || pluginName
== "None" || pluginName
== "KSplashX" )
441 enabled
= true; // these are not plugins
442 else if ((KServiceTypeTrader::self()->query("KSplash/Plugin", QString("[X-KSplash-PluginName] == '%1'").arg(pluginName
))).isEmpty())
445 error
= i18n("This theme requires the plugin %1 which is not installed.", pluginName
);
448 enabled
= true; // Hooray, there is at least one plugin which can handle this theme.
449 mEngineOfSelected
= pluginName
;
453 error
= i18n("Could not load theme configuration file.");
456 mBtnTest
->setEnabled(enabled
&& themeName
!= "None" );
457 mText
->setHtml(infoTxt
);
460 url
.setPath( path
+ '/' + "Preview.png" );
461 if (KIO::NetAccess::exists(url
, KIO::NetAccess::SourceSide
, 0))
462 mPreview
->setPixmap(QPixmap(url
.path()));
464 mPreview
->setText(i18n("(Could not load theme)"));
465 KMessageBox::sorry(this, error
);
469 url
.setPath( path
+ '/' + "Preview.png" );
470 if (KIO::NetAccess::exists(url
, KIO::NetAccess::SourceSide
, 0))
471 mPreview
->setPixmap(QPixmap(url
.path()));
473 mPreview
->setText(i18n("No preview available."));
477 mBtnRemove
->setEnabled( !path
.isEmpty() && QFileInfo(path
).isWritable());
480 //-----------------------------------------------------------------------------
481 void SplashInstaller::slotNew()
483 KNS::Engine
engine(this);
484 if (engine
.init("ksplash.knsrc")) {
485 KNS::Entry::List entries
= engine
.downloadDialogModal(this);
486 if ( !entries
.isEmpty() )
491 //-----------------------------------------------------------------------------
492 void SplashInstaller::slotAdd()
495 if (path
.isEmpty()) path
= QDir::homePath();
497 KFileDialog
dlg(path
, "*.tgz *.tar.gz *.tar.bz2 theme.rc|" + i18n( "KSplash Theme Files" ), this);
498 dlg
.setCaption(i18n("Add Theme"));
502 path
= dlg
.baseUrl().url();
503 addNewTheme(dlg
.selectedUrl());
506 //-----------------------------------------------------------------------------
507 void SplashInstaller::slotFilesDropped(const KUrl::List
&urls
)
509 for(KUrl::List::ConstIterator it
= urls
.begin();
515 //-----------------------------------------------------------------------------
516 int SplashInstaller::findTheme( const QString
&theme
)
518 // theme is untranslated, but the listbox contains translated items
519 QString
tmp(i18n( theme
.toUtf8() ));
520 int id
= mThemesList
->count()-1;
524 if (mThemesList
->item(id
)->text() == tmp
)
532 //-----------------------------------------------------------------------------
533 void SplashInstaller::slotTest()
535 int i
= mThemesList
->currentRow();
538 QString themeName
= mThemesList
->text2path
[mThemesList
->item(i
)->text()];
539 int r
= themeName
.lastIndexOf('/');
541 themeName
= themeName
.mid(r
+1);
543 // special handling for none and simple splashscreens
544 if( mEngineOfSelected
== "None" )
546 else if( mEngineOfSelected
== "Simple" )
549 proc
<< "ksplashsimple" << themeName
<< "--test";
551 KMessageBox::error(this,i18n("Failed to successfully test the splash screen."));
554 else if( mEngineOfSelected
== "KSplashX" )
557 proc
<< "ksplashx" << themeName
<< "--test";
559 KMessageBox::error(this,i18n("Failed to successfully test the splash screen."));
562 else // KSplashML engines
565 proc
<< "ksplash" << "--test" << "--theme" << themeName
;
567 KMessageBox::error(this,i18n("Failed to successfully test the splash screen."));
571 //-----------------------------------------------------------------------------
572 #include "installer.moc"