not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / plasma / shells / desktop / backgrounddialog.cpp
blob03fd19db78d3da36f1243c36c2e748dec130238a
1 /*
2 Copyright (c) 2007 Paolo Capriotti <p.capriotti@gmail.com>
3 Copyright (C) 2007 Ivan Cukic <ivan.cukic+kde@gmail.com>
4 Copyright (c) 2008 by Petri Damsten <damu@iki.fi>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
12 #include "backgrounddialog.h"
14 #include <QPainter>
15 #include <QFile>
16 #include <QAbstractItemView>
17 #include <QStandardItemModel>
19 #include <KStandardDirs>
20 #include <KDesktopFile>
21 #include <KColorScheme>
22 #include <KNS/Engine>
24 #include <Plasma/Containment>
25 #include <Plasma/FrameSvg>
26 #include <Plasma/Theme>
27 #include <Plasma/Wallpaper>
28 #include <Plasma/View>
29 #include <Plasma/Corona>
31 #include "wallpaperpreview.h"
33 typedef QPair<QString, QString> WallpaperInfo;
34 Q_DECLARE_METATYPE(WallpaperInfo)
36 class ThemeInfo
38 public:
39 QString package;
40 Plasma::FrameSvg *svg;
43 class ThemeModel : public QAbstractListModel
45 public:
46 enum { PackageNameRole = Qt::UserRole,
47 SvgRole = Qt::UserRole + 1
50 ThemeModel(QObject *parent = 0);
51 virtual ~ThemeModel();
53 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
54 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
55 int indexOf(const QString &path) const;
56 void reload();
57 private:
58 QMap<QString, ThemeInfo> m_themes;
61 ThemeModel::ThemeModel( QObject *parent )
62 : QAbstractListModel( parent )
64 reload();
67 ThemeModel::~ThemeModel()
71 void ThemeModel::reload()
73 reset();
74 foreach (const QString& key, m_themes.keys()) {
75 delete m_themes[key].svg;
77 m_themes.clear();
79 // get all desktop themes
80 KStandardDirs dirs;
81 QStringList themes = dirs.findAllResources("data", "desktoptheme/*/metadata.desktop",
82 KStandardDirs::NoDuplicates);
83 foreach (const QString &theme, themes) {
84 kDebug() << theme;
85 int themeSepIndex = theme.lastIndexOf('/', -1);
86 QString themeRoot = theme.left(themeSepIndex);
87 int themeNameSepIndex = themeRoot.lastIndexOf('/', -1);
88 QString packageName = themeRoot.right(themeRoot.length() - themeNameSepIndex - 1);
90 KDesktopFile df(theme);
91 QString name = df.readName();
92 if (name.isEmpty()) {
93 name = packageName;
96 Plasma::FrameSvg *svg = new Plasma::FrameSvg(this);
97 QString svgFile = themeRoot + "/widgets/background.svg";
98 if (QFile::exists(svgFile)) {
99 svg->setImagePath(svgFile);
100 } else {
101 svg->setImagePath(svgFile + "z");
103 svg->setEnabledBorders(Plasma::FrameSvg::AllBorders);
104 ThemeInfo info;
105 info.package = packageName;
106 info.svg = svg;
107 m_themes[name] = info;
110 beginInsertRows(QModelIndex(), 0, m_themes.size());
111 endInsertRows();
114 int ThemeModel::rowCount(const QModelIndex &) const
116 return m_themes.size();
119 QVariant ThemeModel::data(const QModelIndex &index, int role) const
121 if (!index.isValid()) {
122 return QVariant();
125 if (index.row() >= m_themes.size()) {
126 return QVariant();
129 QMap<QString, ThemeInfo>::const_iterator it = m_themes.constBegin();
130 for (int i = 0; i < index.row(); ++i) {
131 ++it;
134 switch (role) {
135 case Qt::DisplayRole:
136 return it.key();
137 case PackageNameRole:
138 return (*it).package;
139 case SvgRole:
140 return qVariantFromValue((void*)(*it).svg);
141 default:
142 return QVariant();
146 int ThemeModel::indexOf(const QString &name) const
148 QMapIterator<QString, ThemeInfo> it(m_themes);
149 int i = -1;
150 while (it.hasNext()) {
151 ++i;
152 if (it.next().value().package == name) {
153 return i;
157 return -1;
161 class ThemeDelegate : public QAbstractItemDelegate
163 public:
164 ThemeDelegate(QObject * parent = 0);
166 virtual void paint(QPainter *painter,
167 const QStyleOptionViewItem &option,
168 const QModelIndex &index) const;
169 virtual QSize sizeHint(const QStyleOptionViewItem &option,
170 const QModelIndex &index) const;
171 private:
172 static const int MARGIN = 5;
175 ThemeDelegate::ThemeDelegate(QObject* parent)
176 : QAbstractItemDelegate(parent)
180 void ThemeDelegate::paint(QPainter *painter,
181 const QStyleOptionViewItem &option,
182 const QModelIndex &index) const
184 QString title = index.model()->data(index, Qt::DisplayRole).toString();
185 QString package = index.model()->data(index, ThemeModel::PackageNameRole).toString();
187 // highlight selected item
188 painter->save();
189 if (option.state & QStyle::State_Selected) {
190 painter->setBrush(option.palette.color(QPalette::Highlight));
191 } else {
192 painter->setBrush(Qt::gray);
194 painter->drawRect(option.rect);
195 painter->restore();
197 // draw image
198 Plasma::FrameSvg *svg = static_cast<Plasma::FrameSvg *>(
199 index.model()->data(index, ThemeModel::SvgRole).value<void *>());
200 svg->resizeFrame(QSize(option.rect.width() - (2 * MARGIN), 100 - (2 * MARGIN)));
201 QRect imgRect = QRect(option.rect.topLeft(),
202 QSize(option.rect.width() - (2 * MARGIN), 100 - (2 * MARGIN)))
203 .translated(MARGIN, MARGIN);
204 svg->paintFrame(painter, QPoint(option.rect.left() + MARGIN, option.rect.top() + MARGIN));
206 // draw text
207 painter->save();
208 QFont font = painter->font();
209 font.setWeight(QFont::Bold);
210 QString colorFile = KStandardDirs::locate("data", "desktoptheme/" + package + "/colors");
211 if (!colorFile.isEmpty()) {
212 KSharedConfigPtr colors = KSharedConfig::openConfig(colorFile);
213 KColorScheme colorScheme(QPalette::Active, KColorScheme::Window, colors);
214 painter->setPen(colorScheme.foreground(KColorScheme::NormalText).color());
216 painter->setFont(font);
217 painter->drawText(option.rect, Qt::AlignCenter | Qt::TextWordWrap, title);
218 painter->restore();
221 QSize ThemeDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
223 return QSize(200, 100);
226 // From kcategorizeditemsviewdelegate by Ivan Cukic
227 #define EMBLEM_ICON_SIZE 16
228 #define UNIVERSAL_PADDING 6
229 #define FADE_LENGTH 32
230 #define MAIN_ICON_SIZE 48
232 class AppletDelegate : public QAbstractItemDelegate
234 public:
235 enum { DescriptionRole = Qt::UserRole + 1, PluginNameRole };
237 AppletDelegate(QObject * parent = 0);
239 virtual void paint(QPainter* painter, const QStyleOptionViewItem& option,
240 const QModelIndex& index) const;
241 virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
242 int calcItemHeight(const QStyleOptionViewItem& option) const;
245 AppletDelegate::AppletDelegate(QObject* parent)
246 : QAbstractItemDelegate(parent)
250 void AppletDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
251 const QModelIndex& index) const
253 QStyleOptionViewItemV4 opt(option);
254 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
255 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
257 const int left = option.rect.left();
258 const int top = option.rect.top();
259 const int width = option.rect.width();
260 const int height = calcItemHeight(option);
262 bool leftToRight = (painter->layoutDirection() == Qt::LeftToRight);
263 QIcon::Mode iconMode = QIcon::Normal;
265 QColor foregroundColor = (option.state.testFlag(QStyle::State_Selected)) ?
266 option.palette.color(QPalette::HighlightedText) : option.palette.color(QPalette::Text);
268 // Painting main column
269 QFont titleFont = option.font;
270 titleFont.setBold(true);
271 titleFont.setPointSize(titleFont.pointSize() + 2);
273 QPixmap pixmap(width, height);
274 pixmap.fill(Qt::transparent);
275 QPainter p(&pixmap);
276 p.translate(-option.rect.topLeft());
278 QLinearGradient gradient;
280 QString title = index.model()->data(index, Qt::DisplayRole).toString();
281 QString description = index.model()->data(index, AppletDelegate::DescriptionRole).toString();
283 // Painting
285 // Text
286 int textInner = 2 * UNIVERSAL_PADDING + MAIN_ICON_SIZE;
288 p.setPen(foregroundColor);
289 p.setFont(titleFont);
290 p.drawText(left + (leftToRight ? textInner : 0),
291 top, width - textInner, height / 2,
292 Qt::AlignBottom | Qt::AlignLeft, title);
293 p.setFont(option.font);
294 p.drawText(left + (leftToRight ? textInner : 0),
295 top + height / 2,
296 width - textInner, height / 2,
297 Qt::AlignTop | Qt::AlignLeft, description);
299 // Main icon
300 const QIcon& icon = qVariantValue<QIcon>(index.model()->data(index, Qt::DecorationRole));
301 icon.paint(&p,
302 leftToRight ? left + UNIVERSAL_PADDING : left + width - UNIVERSAL_PADDING - MAIN_ICON_SIZE,
303 top + UNIVERSAL_PADDING, MAIN_ICON_SIZE, MAIN_ICON_SIZE, Qt::AlignCenter, iconMode);
305 // Gradient part of the background - fading of the text at the end
306 if (leftToRight) {
307 gradient = QLinearGradient(left + width - UNIVERSAL_PADDING - FADE_LENGTH, 0,
308 left + width - UNIVERSAL_PADDING, 0);
309 gradient.setColorAt(0, Qt::white);
310 gradient.setColorAt(1, Qt::transparent);
311 } else {
312 gradient = QLinearGradient(left + UNIVERSAL_PADDING, 0,
313 left + UNIVERSAL_PADDING + FADE_LENGTH, 0);
314 gradient.setColorAt(0, Qt::transparent);
315 gradient.setColorAt(1, Qt::white);
318 QRect paintRect = option.rect;
319 p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
320 p.fillRect(paintRect, gradient);
322 if (leftToRight) {
323 gradient.setStart(left + width - FADE_LENGTH, 0);
324 gradient.setFinalStop(left + width, 0);
325 } else {
326 gradient.setStart(left + UNIVERSAL_PADDING, 0);
327 gradient.setFinalStop(left + UNIVERSAL_PADDING + FADE_LENGTH, 0);
329 paintRect.setHeight(UNIVERSAL_PADDING + MAIN_ICON_SIZE / 2);
330 p.fillRect(paintRect, gradient);
331 p.end();
333 painter->drawPixmap(option.rect.topLeft(), pixmap);
336 int AppletDelegate::calcItemHeight(const QStyleOptionViewItem& option) const
338 // Painting main column
339 QFont titleFont = option.font;
340 titleFont.setBold(true);
341 titleFont.setPointSize(titleFont.pointSize() + 2);
343 int textHeight = QFontInfo(titleFont).pixelSize() + QFontInfo(option.font).pixelSize();
344 //kDebug() << textHeight << qMax(textHeight, MAIN_ICON_SIZE) + 2 * UNIVERSAL_PADDING;
345 return qMax(textHeight, MAIN_ICON_SIZE) + 2 * UNIVERSAL_PADDING;
348 QSize AppletDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
350 Q_UNUSED(index)
351 return QSize(200, calcItemHeight(option));
354 BackgroundDialog::BackgroundDialog(const QSize& res, Plasma::Containment *c, Plasma::View* view, QWidget* parent)
355 : KDialog(parent),
356 m_themeModel(0),
357 m_containmentModel(0),
358 m_wallpaper(0),
359 m_view(view),
360 m_containment(c),
361 m_preview(0)
363 setWindowIcon(KIcon("preferences-desktop-wallpaper"));
364 setCaption(i18n("Desktop Settings"));
365 showButtonSeparator(true);
366 setButtons(Ok | Cancel | Apply);
368 QWidget * main = new QWidget(this);
369 setupUi(main);
371 // Size of monitor image: 200x186
372 // Geometry of "display" part of monitor image: (23,14)-[151x115]
373 qreal previewRatio = (qreal)res.height() / (qreal)res.width();
374 QSize monitorSize(200, int(200 * previewRatio));
376 Plasma::FrameSvg *svg = new Plasma::FrameSvg(this);
377 svg->setImagePath("widgets/monitor");
378 svg->resizeFrame(monitorSize);
379 QPixmap monitorPix(monitorSize + QSize(0, svg->elementSize("base").height() - svg->marginSize(Plasma::BottomMargin)));
380 monitorPix.fill(Qt::transparent);
382 QPainter painter(&monitorPix);
383 QPoint standPosition(monitorSize.width()/2 - svg->elementSize("base").width()/2, svg->contentsRect().bottom());
384 svg->paint(&painter, QRect(standPosition, svg->elementSize("base")), "base");
385 svg->paintFrame(&painter);
386 painter.end();
388 m_monitor->setPixmap(monitorPix);
389 m_monitor->setWhatsThis(i18n(
390 "This picture of a monitor contains a preview of "
391 "what the current settings will look like on your desktop."));
392 m_preview = new WallpaperPreview(m_monitor);
393 m_preview->setGeometry(svg->contentsRect().toRect());
395 connect(m_newThemeButton, SIGNAL(clicked()), this, SLOT(getNewThemes()));
397 connect(this, SIGNAL(finished(int)), this, SLOT(cleanup()));
398 connect(this, SIGNAL(okClicked()), this, SLOT(saveConfig()));
399 connect(this, SIGNAL(applyClicked()), this, SLOT(saveConfig()));
400 connect(m_containment, SIGNAL(destroyed()), this, SLOT(close()));
402 m_themeModel = new ThemeModel(this);
403 m_theme->setModel(m_themeModel);
404 m_theme->setItemDelegate(new ThemeDelegate(m_theme->view()));
405 m_theme->view()->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
407 m_containmentModel = new QStandardItemModel(this);
408 m_containmentComboBox->setModel(m_containmentModel);
409 m_containmentComboBox->setItemDelegate(new AppletDelegate());
411 setMainWidget(main);
412 reloadConfig();
413 adjustSize();
416 BackgroundDialog::~BackgroundDialog()
418 cleanup();
421 void BackgroundDialog::cleanup()
423 delete m_wallpaper;
424 m_wallpaper = 0;
427 void BackgroundDialog::getNewThemes()
429 KNS::Engine engine(this);
430 if (engine.init("plasma-themes.knsrc")) {
431 KNS::Entry::List entries = engine.downloadDialogModal(this);
433 if (entries.size() > 0) {
434 m_themeModel->reload();
435 m_theme->setCurrentIndex(m_themeModel->indexOf(
436 Plasma::Theme::defaultTheme()->themeName()));
441 void BackgroundDialog::reloadConfig()
443 disconnect(m_wallpaperMode, SIGNAL(currentIndexChanged(int)), this, SLOT(changeBackgroundMode(int)));
444 int containmentIndex = 0;
445 int wallpaperIndex = 0;
447 // Containment
448 KPluginInfo::List plugins = Plasma::Containment::listContainments();
449 m_containmentModel->clear();
450 int i = 0;
451 foreach (const KPluginInfo& info, plugins) {
452 if (!info.service()->property("X-Plasma-ContainmentCategories").toStringList().contains("desktop")) {
453 continue;
456 QStandardItem* item = new QStandardItem(KIcon(info.icon()), info.name());
457 item->setData(info.comment(), AppletDelegate::DescriptionRole);
458 item->setData(info.pluginName(), AppletDelegate::PluginNameRole);
459 m_containmentModel->appendRow(item);
460 if (info.pluginName() == m_containment->pluginName()) {
461 containmentIndex = i;
463 ++i;
465 m_containmentComboBox->setCurrentIndex(containmentIndex);
466 m_activityName->setText(m_containment->activity());
469 // Wallpaper
470 bool doWallpaper = m_containment->drawWallpaper();
471 m_wallpaperLabel->setVisible(doWallpaper);
472 m_wallpaperGroup->setVisible(doWallpaper);
473 m_monitor->setVisible(doWallpaper);
474 m_preview->setVisible(doWallpaper);
475 //kDebug() << "do wallpapers?!" << doWallpaper;
476 if (doWallpaper) {
477 // Load wallpaper plugins
478 QString currentPlugin;
479 QString currentMode;
481 Plasma::Wallpaper *currentWallpaper = m_containment->wallpaper();
482 if (currentWallpaper) {
483 currentPlugin = currentWallpaper->pluginName();
484 currentMode = currentWallpaper->renderingMode().name();
487 plugins = Plasma::Wallpaper::listWallpaperInfo();
488 m_wallpaperMode->clear();
489 i = 0;
490 foreach (const KPluginInfo& info, plugins) {
491 kDebug() << "doing wallpaper" << info.pluginName();
492 bool matches = info.pluginName() == currentPlugin;
493 const QList<KServiceAction>& modes = info.service()->actions();
494 if (modes.count() > 0) {
495 foreach (const KServiceAction& mode, modes) {
496 m_wallpaperMode->addItem(KIcon(mode.icon()), mode.text(),
497 QVariant::fromValue(WallpaperInfo(info.pluginName(), mode.name())));
498 if (matches && mode.name() == currentMode) {
499 wallpaperIndex = i;
501 ++i;
503 } else {
504 m_wallpaperMode->addItem(KIcon(info.icon()), info.name(),
505 QVariant::fromValue(WallpaperInfo(info.pluginName(), QString())));
506 if (matches) {
507 wallpaperIndex = i;
509 ++i;
512 m_wallpaperMode->setCurrentIndex(wallpaperIndex);
513 changeBackgroundMode(wallpaperIndex);
516 // Theme
517 m_themeModel->reload();
518 m_theme->setCurrentIndex(m_themeModel->indexOf(Plasma::Theme::defaultTheme()->themeName()));
520 connect(m_wallpaperMode, SIGNAL(currentIndexChanged(int)), this, SLOT(changeBackgroundMode(int)));
523 void BackgroundDialog::changeBackgroundMode(int mode)
525 kDebug();
526 QWidget* w = 0;
527 WallpaperInfo wallpaperInfo = m_wallpaperMode->itemData(mode).value<WallpaperInfo>();
529 if (m_wallpaperGroup->layout()->count() > 1) {
530 delete dynamic_cast<QWidgetItem*>(m_wallpaperGroup->layout()->takeAt(1))->widget();
533 if (m_wallpaper && m_wallpaper->pluginName() != wallpaperInfo.first) {
534 delete m_wallpaper;
535 m_wallpaper = 0;
538 if (!m_wallpaper) {
539 m_wallpaper = Plasma::Wallpaper::load(wallpaperInfo.first);
540 m_preview->setWallpaper(m_wallpaper);
543 if (m_wallpaper) {
544 m_wallpaper->setRenderingMode(wallpaperInfo.second);
545 KConfigGroup cfg = wallpaperConfig(wallpaperInfo.first);
546 kDebug() << "making a" << wallpaperInfo.first << "in mode" << wallpaperInfo.second;
547 m_wallpaper->restore(cfg);
548 w = m_wallpaper->createConfigurationInterface(m_wallpaperGroup);
551 if (!w) {
552 w = new QWidget(m_wallpaperGroup);
555 m_wallpaperGroup->layout()->addWidget(w);
558 KConfigGroup BackgroundDialog::wallpaperConfig(const QString &plugin)
560 Q_ASSERT(m_containment);
562 //FIXME: we have details about the structure of the containment config duplicated here!
563 KConfigGroup cfg = m_containment->config();
564 cfg = KConfigGroup(&cfg, "Wallpaper");
565 return KConfigGroup(&cfg, plugin);
568 void BackgroundDialog::saveConfig()
570 QString theme = m_theme->itemData(m_theme->currentIndex(),
571 ThemeModel::PackageNameRole).toString();
572 QString wallpaperPlugin = m_wallpaperMode->itemData(m_wallpaperMode->currentIndex()).value<WallpaperInfo>().first;
573 QString wallpaperMode = m_wallpaperMode->itemData(m_wallpaperMode->currentIndex()).value<WallpaperInfo>().second;
574 QString containment = m_containmentComboBox->itemData(m_containmentComboBox->currentIndex(),
575 AppletDelegate::PluginNameRole).toString();
577 // Containment
578 if (m_containment->pluginName() != containment) {
579 disconnect(m_containment, SIGNAL(destroyed()), this, SLOT(close()));
580 m_containment = m_view->swapContainment(m_containment, containment);
581 connect(m_containment, SIGNAL(destroyed()), this, SLOT(close()));
584 m_containment->setActivity(m_activityName->text());
586 // Wallpaper
587 Plasma::Wallpaper *currentWallpaper = m_containment->wallpaper();
588 if (currentWallpaper) {
589 KConfigGroup cfg = wallpaperConfig(currentWallpaper->pluginName());
590 currentWallpaper->save(cfg);
593 if (m_wallpaper) {
594 KConfigGroup cfg = wallpaperConfig(m_wallpaper->pluginName());
595 m_wallpaper->save(cfg);
598 m_containment->setWallpaper(wallpaperPlugin, wallpaperMode);
600 // Plasma Theme
601 Plasma::Theme::defaultTheme()->setThemeName(theme);