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"
16 #include <QAbstractItemView>
17 #include <QStandardItemModel>
19 #include <KStandardDirs>
20 #include <KDesktopFile>
21 #include <KColorScheme>
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
)
40 Plasma::FrameSvg
*svg
;
43 class ThemeModel
: public QAbstractListModel
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;
58 QMap
<QString
, ThemeInfo
> m_themes
;
61 ThemeModel::ThemeModel( QObject
*parent
)
62 : QAbstractListModel( parent
)
67 ThemeModel::~ThemeModel()
71 void ThemeModel::reload()
74 foreach (const QString
& key
, m_themes
.keys()) {
75 delete m_themes
[key
].svg
;
79 // get all desktop themes
81 QStringList themes
= dirs
.findAllResources("data", "desktoptheme/*/metadata.desktop",
82 KStandardDirs::NoDuplicates
);
83 foreach (const QString
&theme
, themes
) {
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();
96 Plasma::FrameSvg
*svg
= new Plasma::FrameSvg(this);
97 QString svgFile
= themeRoot
+ "/widgets/background.svg";
98 if (QFile::exists(svgFile
)) {
99 svg
->setImagePath(svgFile
);
101 svg
->setImagePath(svgFile
+ "z");
103 svg
->setEnabledBorders(Plasma::FrameSvg::AllBorders
);
105 info
.package
= packageName
;
107 m_themes
[name
] = info
;
110 beginInsertRows(QModelIndex(), 0, m_themes
.size());
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()) {
125 if (index
.row() >= m_themes
.size()) {
129 QMap
<QString
, ThemeInfo
>::const_iterator it
= m_themes
.constBegin();
130 for (int i
= 0; i
< index
.row(); ++i
) {
135 case Qt::DisplayRole
:
137 case PackageNameRole
:
138 return (*it
).package
;
140 return qVariantFromValue((void*)(*it
).svg
);
146 int ThemeModel::indexOf(const QString
&name
) const
148 QMapIterator
<QString
, ThemeInfo
> it(m_themes
);
150 while (it
.hasNext()) {
152 if (it
.next().value().package
== name
) {
161 class ThemeDelegate
: public QAbstractItemDelegate
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;
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
189 if (option
.state
& QStyle::State_Selected
) {
190 painter
->setBrush(option
.palette
.color(QPalette::Highlight
));
192 painter
->setBrush(Qt::gray
);
194 painter
->drawRect(option
.rect
);
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
));
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
);
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
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
);
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();
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),
296 width
- textInner
, height
/ 2,
297 Qt::AlignTop
| Qt::AlignLeft
, description
);
300 const QIcon
& icon
= qVariantValue
<QIcon
>(index
.model()->data(index
, Qt::DecorationRole
));
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
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
);
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
);
323 gradient
.setStart(left
+ width
- FADE_LENGTH
, 0);
324 gradient
.setFinalStop(left
+ width
, 0);
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
);
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
351 return QSize(200, calcItemHeight(option
));
354 BackgroundDialog::BackgroundDialog(const QSize
& res
, Plasma::Containment
*c
, Plasma::View
* view
, QWidget
* parent
)
357 m_containmentModel(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);
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
);
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());
416 BackgroundDialog::~BackgroundDialog()
421 void BackgroundDialog::cleanup()
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;
448 KPluginInfo::List plugins
= Plasma::Containment::listContainments();
449 m_containmentModel
->clear();
451 foreach (const KPluginInfo
& info
, plugins
) {
452 if (!info
.service()->property("X-Plasma-ContainmentCategories").toStringList().contains("desktop")) {
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
;
465 m_containmentComboBox
->setCurrentIndex(containmentIndex
);
466 m_activityName
->setText(m_containment
->activity());
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;
477 // Load wallpaper plugins
478 QString currentPlugin
;
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();
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
) {
504 m_wallpaperMode
->addItem(KIcon(info
.icon()), info
.name(),
505 QVariant::fromValue(WallpaperInfo(info
.pluginName(), QString())));
512 m_wallpaperMode
->setCurrentIndex(wallpaperIndex
);
513 changeBackgroundMode(wallpaperIndex
);
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
)
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
) {
539 m_wallpaper
= Plasma::Wallpaper::load(wallpaperInfo
.first
);
540 m_preview
->setWallpaper(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
);
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();
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());
587 Plasma::Wallpaper
*currentWallpaper
= m_containment
->wallpaper();
588 if (currentWallpaper
) {
589 KConfigGroup cfg
= wallpaperConfig(currentWallpaper
->pluginName());
590 currentWallpaper
->save(cfg
);
594 KConfigGroup cfg
= wallpaperConfig(m_wallpaper
->pluginName());
595 m_wallpaper
->save(cfg
);
598 m_containment
->setWallpaper(wallpaperPlugin
, wallpaperMode
);
601 Plasma::Theme::defaultTheme()->setThemeName(theme
);