2 * Copyright (c) 2000 Antonio Larrosa <larrosa@kde.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <config-runtime.h>
27 #include <QPushButton>
30 #include <QVBoxLayout>
32 #include <QHBoxLayout>
33 #include <QTreeWidget>
36 #include <kapplication.h>
37 #include <kbuildsycocaprogressdialog.h>
39 #include <kstandarddirs.h>
44 #include <kurlrequesterdialog.h>
45 #include <kmessagebox.h>
46 #include <kiconloader.h>
47 #include <k3icon_p.h> // this private header is only installed for us!
48 #include <kprogressdialog.h>
50 #include <kio/deletejob.h>
51 #include <kio/netaccess.h>
55 #include <ksvgiconengine.h>
58 #include "iconthemes.h"
59 #include <kglobalsettings.h>
61 static const int ThemeNameRole
= Qt::UserRole
+ 1;
63 IconThemesConfig::IconThemesConfig(const KComponentData
&inst
, QWidget
*parent
)
64 : KCModule(inst
, parent
)
66 QVBoxLayout
*topLayout
= new QVBoxLayout(this);
67 topLayout
->setMargin(KDialog::marginHint());
68 topLayout
->setSpacing(KDialog::spacingHint());
70 QFrame
*m_preview
=new QFrame(this);
71 m_preview
->setMinimumHeight(50);
73 QHBoxLayout
*lh2
=new QHBoxLayout( m_preview
);
74 m_previewExec
=new QLabel(m_preview
);
75 m_previewExec
->setPixmap(DesktopIcon("system-run"));
76 m_previewFolder
=new QLabel(m_preview
);
77 m_previewFolder
->setPixmap(DesktopIcon("folder"));
78 m_previewDocument
=new QLabel(m_preview
);
79 m_previewDocument
->setPixmap(DesktopIcon("document"));
82 lh2
->addWidget(m_previewExec
);
84 lh2
->addWidget(m_previewFolder
);
86 lh2
->addWidget(m_previewDocument
);
90 m_iconThemes
=new QTreeWidget(this/*"IconThemeList"*/);
92 columns
.append(i18n("Name"));
93 columns
.append(i18n("Description"));
94 m_iconThemes
->setHeaderLabels(columns
);
95 m_iconThemes
->setAllColumnsShowFocus( true );
96 m_iconThemes
->setRootIsDecorated(false);
97 m_iconThemes
->setSortingEnabled(true);
98 connect(m_iconThemes
,SIGNAL(currentItemChanged(QTreeWidgetItem
*, QTreeWidgetItem
*)),
99 SLOT(themeSelected(QTreeWidgetItem
*)));
101 QPushButton
*installButton
=new QPushButton( i18n("Install New Theme..."), this);
102 installButton
->setObjectName("InstallNewTheme");
103 connect(installButton
,SIGNAL(clicked()),SLOT(installNewTheme()));
104 m_removeButton
=new QPushButton( i18n("Remove Theme"), this);
105 m_removeButton
->setObjectName("RemoveTheme");
106 connect(m_removeButton
,SIGNAL(clicked()),SLOT(removeSelectedTheme()));
108 topLayout
->addWidget(
109 new QLabel(i18n("Select the icon theme you want to use:"), this));
110 topLayout
->addWidget(m_preview
);
111 topLayout
->addWidget(m_iconThemes
);
112 QHBoxLayout
*lg
= new QHBoxLayout();
113 topLayout
->addItem(lg
);
114 lg
->setSpacing(KDialog::spacingHint());
115 lg
->addWidget(installButton
);
116 lg
->addWidget(m_removeButton
);
120 m_defaultTheme
=iconThemeItem(KIconTheme::current());
122 m_iconThemes
->setCurrentItem(m_defaultTheme
);
123 updateRemoveButton();
127 m_iconThemes
->setFocus();
130 IconThemesConfig::~IconThemesConfig()
134 QTreeWidgetItem
*IconThemesConfig::iconThemeItem(const QString
&name
)
136 for (int i
= 0; i
< m_iconThemes
->topLevelItemCount(); ++i
)
137 if (m_iconThemes
->topLevelItem(i
)->data(0, ThemeNameRole
).toString()==name
)
138 return m_iconThemes
->topLevelItem(i
);
143 void IconThemesConfig::loadThemes()
145 m_iconThemes
->clear();
146 QStringList
themelist(KIconTheme::list());
149 QStringList::Iterator it
;
150 QMap
<QString
, QString
> themeNames
;
151 for (it
=themelist
.begin(); it
!= themelist
.end(); ++it
)
153 KIconTheme
icontheme(*it
);
154 if (!icontheme
.isValid()) kDebug() << "notvalid\n";
155 if (icontheme
.isHidden()) continue;
157 name
=icontheme
.name();
160 // Just in case we have duplicated icon theme names on separate directories
161 for (int i
= 2; themeNames
.find(tname
) != themeNames
.end(); ++i
)
162 tname
=QString("%1-%2").arg(name
).arg(i
);
164 QTreeWidgetItem
*newitem
= new QTreeWidgetItem();
165 newitem
->setText(0, name
);
166 newitem
->setText(1, icontheme
.description());
167 newitem
->setData(0, ThemeNameRole
, *it
);
168 m_iconThemes
->addTopLevelItem(newitem
);
170 themeNames
.insert(name
, *it
);
174 void IconThemesConfig::installNewTheme()
176 KUrl themeURL
= KUrlRequesterDialog::getUrl(QString(), this,
177 i18n("Drag or Type Theme URL"));
178 kDebug() << themeURL
.prettyUrl();
180 if (themeURL
.url().isEmpty()) return;
182 QString themeTmpFile
;
183 // themeTmpFile contains the name of the downloaded file
185 if (!KIO::NetAccess::download(themeURL
, themeTmpFile
, this)) {
187 if (themeURL
.isLocalFile())
188 sorryText
= i18n("Unable to find the icon theme archive %1.",
189 themeURL
.prettyUrl());
191 sorryText
= i18n("Unable to download the icon theme archive;\n"
192 "please check that address %1 is correct.",
193 themeURL
.prettyUrl());
194 KMessageBox::sorry(this, sorryText
);
198 QStringList themesNames
= findThemeDirs(themeTmpFile
);
199 if (themesNames
.isEmpty()) {
200 QString
invalidArch(i18n("The file is not a valid icon theme archive."));
201 KMessageBox::error(this, invalidArch
);
203 KIO::NetAccess::removeTempFile(themeTmpFile
);
207 if (!installThemes(themesNames
, themeTmpFile
)) {
208 //FIXME: make me able to know what is wrong....
209 // QStringList instead of bool?
210 QString somethingWrong
=
211 i18n("A problem occurred during the installation process; "
212 "however, most of the themes in the archive have been installed");
213 KMessageBox::error(this, somethingWrong
);
216 KIO::NetAccess::removeTempFile(themeTmpFile
);
218 KIconLoader::global()->newIconLoader();
221 QTreeWidgetItem
*item
=iconThemeItem(KIconTheme::current());
223 m_iconThemes
->setCurrentItem(item
);
224 updateRemoveButton();
227 bool IconThemesConfig::installThemes(const QStringList
&themes
, const QString
&archiveName
)
229 bool everythingOk
= true;
230 QString
localThemesDir(KStandardDirs::locateLocal("icon", "./"));
232 KProgressDialog
progressDiag(this,
233 i18n("Installing icon themes"),
235 progressDiag
.setModal(true);
236 progressDiag
.setAutoClose(true);
237 QProgressBar
* progressBar
= progressDiag
.progressBar();
238 progressBar
->setMaximum(themes
.count());
241 KTar
archive(archiveName
);
242 archive
.open(QIODevice::ReadOnly
);
243 kapp
->processEvents();
245 const KArchiveDirectory
* rootDir
= archive
.directory();
247 KArchiveDirectory
* currentTheme
;
248 for (QStringList::ConstIterator it
= themes
.begin();
251 progressDiag
.setLabelText(
252 i18n("<qt>Installing <strong>%1</strong> theme</qt>",
254 kapp
->processEvents();
256 if (progressDiag
.wasCancelled())
259 currentTheme
= dynamic_cast<KArchiveDirectory
*>(
260 const_cast<KArchiveEntry
*>(
261 rootDir
->entry(*it
)));
262 if (currentTheme
== NULL
) {
263 // we tell back that something went wrong, but try to install as much
265 everythingOk
= false;
269 currentTheme
->copyTo(localThemesDir
+ *it
);
270 progressBar
->setValue(progressBar
->value()+1);
277 QStringList
IconThemesConfig::findThemeDirs(const QString
&archiveName
)
279 QStringList foundThemes
;
281 KTar
archive(archiveName
);
282 archive
.open(QIODevice::ReadOnly
);
283 const KArchiveDirectory
* themeDir
= archive
.directory();
285 KArchiveEntry
* possibleDir
= 0L;
286 KArchiveDirectory
* subDir
= 0L;
288 // iterate all the dirs looking for an index.theme or index.desktop file
289 QStringList entries
= themeDir
->entries();
290 for (QStringList::Iterator it
= entries
.begin();
293 possibleDir
= const_cast<KArchiveEntry
*>(themeDir
->entry(*it
));
294 if (possibleDir
->isDirectory()) {
295 subDir
= dynamic_cast<KArchiveDirectory
*>( possibleDir
);
296 if (subDir
&& (subDir
->entry("index.theme") != NULL
||
297 subDir
->entry("index.desktop") != NULL
))
298 foundThemes
.append(subDir
->name());
306 void IconThemesConfig::removeSelectedTheme()
308 QTreeWidgetItem
*selected
= m_iconThemes
->currentItem();
312 QString question
=i18n("<qt>Are you sure you want to remove the "
313 "<strong>%1</strong> icon theme?<br />"
315 "This will delete the files installed by this theme.</qt>",
318 bool deletingCurrentTheme
=(selected
==iconThemeItem(KIconTheme::current()));
320 int r
=KMessageBox::warningContinueCancel(this,question
,i18n("Confirmation"),KStandardGuiItem::del());
321 if (r
!=KMessageBox::Continue
) return;
323 KIconTheme
icontheme(selected
->data(0, ThemeNameRole
).toString());
325 // delete the index file before the async KIO::del so loadThemes() will
327 unlink(QFile::encodeName(icontheme
.dir()+"/index.theme").data());
328 unlink(QFile::encodeName(icontheme
.dir()+"/index.desktop").data());
329 KIO::del(KUrl( icontheme
.dir() ));
331 KIconLoader::global()->newIconLoader();
335 QTreeWidgetItem
*item
=0L;
336 //Fallback to the default if we've deleted the current theme
337 if (!deletingCurrentTheme
)
338 item
=iconThemeItem(KIconTheme::current());
340 item
=iconThemeItem(KIconTheme::defaultThemeName());
343 m_iconThemes
->setCurrentItem(item
);
344 updateRemoveButton();
346 if (deletingCurrentTheme
) // Change the configuration
350 void IconThemesConfig::updateRemoveButton()
352 QTreeWidgetItem
*selected
= m_iconThemes
->currentItem();
353 bool enabled
= false;
356 QString selectedtheme
= selected
->data(0, ThemeNameRole
).toString();
357 KIconTheme
icontheme(selectedtheme
);
358 QFileInfo
fi(icontheme
.dir());
359 enabled
= fi
.isWritable();
360 // Don't let users remove the current theme.
361 if (selectedtheme
== KIconTheme::current() ||
362 selectedtheme
== KIconTheme::defaultThemeName())
365 m_removeButton
->setEnabled(enabled
);
368 void IconThemesConfig::themeSelected(QTreeWidgetItem
*item
)
373 KSVGIconEngine engine
;
375 QString
dirName(item
->data(0, ThemeNameRole
).toString());
376 KIconTheme
icontheme(dirName
);
377 if (!icontheme
.isValid()) kDebug() << "notvalid\n";
379 updateRemoveButton();
380 const int size
= icontheme
.defaultSize(KIconLoader::Desktop
);
382 K3Icon icon
=icontheme
.iconPath("exec.png", size
, KIconLoader::MatchBest
);
383 if (!icon
.isValid()) {
385 icon
=icontheme
.iconPath("exec.svg", size
, KIconLoader::MatchBest
);
386 if(engine
.load(size
, size
, icon
.path
))
387 m_previewExec
->setPixmap(QPixmap(*engine
.image()));
389 icon
=icontheme
.iconPath("exec.svgz", size
, KIconLoader::MatchBest
);
390 if(engine
.load(size
, size
, icon
.path
))
391 m_previewExec
->setPixmap(QPixmap(*engine
.image()));
396 m_previewExec
->setPixmap(QPixmap(icon
.path
));
398 icon
=icontheme
.iconPath("folder.png",size
,KIconLoader::MatchBest
);
399 if (!icon
.isValid()) {
401 icon
=icontheme
.iconPath("folder.svg", size
, KIconLoader::MatchBest
);
402 if(engine
.load(size
, size
, icon
.path
))
403 m_previewFolder
->setPixmap(QPixmap(*engine
.image()));
405 icon
=icontheme
.iconPath("folder.svgz", size
, KIconLoader::MatchBest
);
406 if(engine
.load(size
, size
, icon
.path
))
407 m_previewFolder
->setPixmap(QPixmap(*engine
.image()));
412 m_previewFolder
->setPixmap(QPixmap(icon
.path
));
414 icon
=icontheme
.iconPath("text-x-generic.png",size
,KIconLoader::MatchBest
);
415 if (!icon
.isValid()) {
417 icon
=icontheme
.iconPath("text-x-generic.svg", size
, KIconLoader::MatchBest
);
418 if(engine
.load(size
, size
, icon
.path
))
419 m_previewDocument
->setPixmap(QPixmap(*engine
.image()));
421 icon
=icontheme
.iconPath("text-x-generic.svgz", size
, KIconLoader::MatchBest
);
422 if(engine
.load(size
, size
, icon
.path
))
423 m_previewDocument
->setPixmap(QPixmap(*engine
.image()));
428 m_previewDocument
->setPixmap(QPixmap(icon
.path
));
434 void IconThemesConfig::load()
440 void IconThemesConfig::save()
444 QTreeWidgetItem
*selected
= m_iconThemes
->currentItem();
448 KConfigGroup
config(KSharedConfig::openConfig("kdeglobals", KConfig::SimpleConfig
), "Icons");
450 config
.writeEntry("Theme", selected
->data(0, ThemeNameRole
).toString());
451 KIconTheme::reconfigure();
454 for (int i
=0; i
<KIconLoader::LastGroup
; i
++)
456 KGlobalSettings::self()->emitChange(KGlobalSettings::IconChanged
, i
);
459 KBuildSycocaProgressDialog::rebuildKSycoca(this);
462 m_removeButton
->setEnabled(false);
465 void IconThemesConfig::defaults()
467 if (m_iconThemes
->currentItem()==m_defaultTheme
) return;
470 m_iconThemes
->setCurrentItem(m_defaultTheme
);
471 updateRemoveButton();
477 #include "iconthemes.moc"