00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "backgrounddialog.h"
00013
00014 #include <QPainter>
00015 #include <QFile>
00016 #include <QAbstractItemView>
00017 #include <QStandardItemModel>
00018
00019 #include <KStandardDirs>
00020 #include <KDesktopFile>
00021 #include <KColorScheme>
00022 #include <KNS/Engine>
00023
00024 #include <Plasma/Containment>
00025 #include <Plasma/FrameSvg>
00026 #include <Plasma/Theme>
00027 #include <Plasma/Wallpaper>
00028 #include <Plasma/View>
00029 #include <Plasma/Corona>
00030
00031 #include "wallpaperpreview.h"
00032
00033 typedef QPair<QString, QString> WallpaperInfo;
00034 Q_DECLARE_METATYPE(WallpaperInfo)
00035
00036 class ThemeInfo
00037 {
00038 public:
00039 QString package;
00040 Plasma::FrameSvg *svg;
00041 };
00042
00043 class ThemeModel : public QAbstractListModel
00044 {
00045 public:
00046 enum { PackageNameRole = Qt::UserRole,
00047 SvgRole = Qt::UserRole + 1
00048 };
00049
00050 ThemeModel(QObject *parent = 0);
00051 virtual ~ThemeModel();
00052
00053 virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
00054 virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
00055 int indexOf(const QString &path) const;
00056 void reload();
00057 private:
00058 QMap<QString, ThemeInfo> m_themes;
00059 };
00060
00061 ThemeModel::ThemeModel( QObject *parent )
00062 : QAbstractListModel( parent )
00063 {
00064 reload();
00065 }
00066
00067 ThemeModel::~ThemeModel()
00068 {
00069 }
00070
00071 void ThemeModel::reload()
00072 {
00073 reset();
00074 foreach (const QString& key, m_themes.keys()) {
00075 delete m_themes[key].svg;
00076 }
00077 m_themes.clear();
00078
00079
00080 KStandardDirs dirs;
00081 QStringList themes = dirs.findAllResources("data", "desktoptheme/*/metadata.desktop",
00082 KStandardDirs::NoDuplicates);
00083 foreach (const QString &theme, themes) {
00084 kDebug() << theme;
00085 int themeSepIndex = theme.lastIndexOf('/', -1);
00086 QString themeRoot = theme.left(themeSepIndex);
00087 int themeNameSepIndex = themeRoot.lastIndexOf('/', -1);
00088 QString packageName = themeRoot.right(themeRoot.length() - themeNameSepIndex - 1);
00089
00090 KDesktopFile df(theme);
00091 QString name = df.readName();
00092 if (name.isEmpty()) {
00093 name = packageName;
00094 }
00095
00096 Plasma::FrameSvg *svg = new Plasma::FrameSvg(this);
00097 QString svgFile = themeRoot + "/widgets/background.svg";
00098 if (QFile::exists(svgFile)) {
00099 svg->setImagePath(svgFile);
00100 } else {
00101 svg->setImagePath(svgFile + "z");
00102 }
00103 svg->setEnabledBorders(Plasma::FrameSvg::AllBorders);
00104 ThemeInfo info;
00105 info.package = packageName;
00106 info.svg = svg;
00107 m_themes[name] = info;
00108 }
00109
00110 beginInsertRows(QModelIndex(), 0, m_themes.size());
00111 endInsertRows();
00112 }
00113
00114 int ThemeModel::rowCount(const QModelIndex &) const
00115 {
00116 return m_themes.size();
00117 }
00118
00119 QVariant ThemeModel::data(const QModelIndex &index, int role) const
00120 {
00121 if (!index.isValid()) {
00122 return QVariant();
00123 }
00124
00125 if (index.row() >= m_themes.size()) {
00126 return QVariant();
00127 }
00128
00129 QMap<QString, ThemeInfo>::const_iterator it = m_themes.constBegin();
00130 for (int i = 0; i < index.row(); ++i) {
00131 ++it;
00132 }
00133
00134 switch (role) {
00135 case Qt::DisplayRole:
00136 return it.key();
00137 case PackageNameRole:
00138 return (*it).package;
00139 case SvgRole:
00140 return qVariantFromValue((void*)(*it).svg);
00141 default:
00142 return QVariant();
00143 }
00144 }
00145
00146 int ThemeModel::indexOf(const QString &name) const
00147 {
00148 QMapIterator<QString, ThemeInfo> it(m_themes);
00149 int i = -1;
00150 while (it.hasNext()) {
00151 ++i;
00152 if (it.next().value().package == name) {
00153 return i;
00154 }
00155 }
00156
00157 return -1;
00158 }
00159
00160
00161 class ThemeDelegate : public QAbstractItemDelegate
00162 {
00163 public:
00164 ThemeDelegate(QObject * parent = 0);
00165
00166 virtual void paint(QPainter *painter,
00167 const QStyleOptionViewItem &option,
00168 const QModelIndex &index) const;
00169 virtual QSize sizeHint(const QStyleOptionViewItem &option,
00170 const QModelIndex &index) const;
00171 private:
00172 static const int MARGIN = 5;
00173 };
00174
00175 ThemeDelegate::ThemeDelegate(QObject* parent)
00176 : QAbstractItemDelegate(parent)
00177 {
00178 }
00179
00180 void ThemeDelegate::paint(QPainter *painter,
00181 const QStyleOptionViewItem &option,
00182 const QModelIndex &index) const
00183 {
00184 QString title = index.model()->data(index, Qt::DisplayRole).toString();
00185 QString package = index.model()->data(index, ThemeModel::PackageNameRole).toString();
00186
00187
00188 painter->save();
00189 if (option.state & QStyle::State_Selected) {
00190 painter->setBrush(option.palette.color(QPalette::Highlight));
00191 } else {
00192 painter->setBrush(Qt::gray);
00193 }
00194 painter->drawRect(option.rect);
00195 painter->restore();
00196
00197
00198 Plasma::FrameSvg *svg = static_cast<Plasma::FrameSvg *>(
00199 index.model()->data(index, ThemeModel::SvgRole).value<void *>());
00200 svg->resizeFrame(QSize(option.rect.width() - (2 * MARGIN), 100 - (2 * MARGIN)));
00201 QRect imgRect = QRect(option.rect.topLeft(),
00202 QSize(option.rect.width() - (2 * MARGIN), 100 - (2 * MARGIN)))
00203 .translated(MARGIN, MARGIN);
00204 svg->paintFrame(painter, QPoint(option.rect.left() + MARGIN, option.rect.top() + MARGIN));
00205
00206
00207 painter->save();
00208 QFont font = painter->font();
00209 font.setWeight(QFont::Bold);
00210 QString colorFile = KStandardDirs::locate("data", "desktoptheme/" + package + "/colors");
00211 if (!colorFile.isEmpty()) {
00212 KSharedConfigPtr colors = KSharedConfig::openConfig(colorFile);
00213 KColorScheme colorScheme(QPalette::Active, KColorScheme::Window, colors);
00214 painter->setPen(colorScheme.foreground(KColorScheme::NormalText).color());
00215 }
00216 painter->setFont(font);
00217 painter->drawText(option.rect, Qt::AlignCenter | Qt::TextWordWrap, title);
00218 painter->restore();
00219 }
00220
00221 QSize ThemeDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
00222 {
00223 return QSize(200, 100);
00224 }
00225
00226
00227 #define EMBLEM_ICON_SIZE 16
00228 #define UNIVERSAL_PADDING 6
00229 #define FADE_LENGTH 32
00230 #define MAIN_ICON_SIZE 48
00231
00232 class AppletDelegate : public QAbstractItemDelegate
00233 {
00234 public:
00235 enum { DescriptionRole = Qt::UserRole + 1, PluginNameRole };
00236
00237 AppletDelegate(QObject * parent = 0);
00238
00239 virtual void paint(QPainter* painter, const QStyleOptionViewItem& option,
00240 const QModelIndex& index) const;
00241 virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
00242 int calcItemHeight(const QStyleOptionViewItem& option) const;
00243 };
00244
00245 AppletDelegate::AppletDelegate(QObject* parent)
00246 : QAbstractItemDelegate(parent)
00247 {
00248 }
00249
00250 void AppletDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
00251 const QModelIndex& index) const
00252 {
00253 QStyleOptionViewItemV4 opt(option);
00254 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
00255 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
00256
00257 const int left = option.rect.left();
00258 const int top = option.rect.top();
00259 const int width = option.rect.width();
00260 const int height = calcItemHeight(option);
00261
00262 bool leftToRight = (painter->layoutDirection() == Qt::LeftToRight);
00263 QIcon::Mode iconMode = QIcon::Normal;
00264
00265 QColor foregroundColor = (option.state.testFlag(QStyle::State_Selected)) ?
00266 option.palette.color(QPalette::HighlightedText) : option.palette.color(QPalette::Text);
00267
00268
00269 QFont titleFont = option.font;
00270 titleFont.setBold(true);
00271 titleFont.setPointSize(titleFont.pointSize() + 2);
00272
00273 QPixmap pixmap(width, height);
00274 pixmap.fill(Qt::transparent);
00275 QPainter p(&pixmap);
00276 p.translate(-option.rect.topLeft());
00277
00278 QLinearGradient gradient;
00279
00280 QString title = index.model()->data(index, Qt::DisplayRole).toString();
00281 QString description = index.model()->data(index, AppletDelegate::DescriptionRole).toString();
00282
00283
00284
00285
00286 int textInner = 2 * UNIVERSAL_PADDING + MAIN_ICON_SIZE;
00287
00288 p.setPen(foregroundColor);
00289 p.setFont(titleFont);
00290 p.drawText(left + (leftToRight ? textInner : 0),
00291 top, width - textInner, height / 2,
00292 Qt::AlignBottom | Qt::AlignLeft, title);
00293 p.setFont(option.font);
00294 p.drawText(left + (leftToRight ? textInner : 0),
00295 top + height / 2,
00296 width - textInner, height / 2,
00297 Qt::AlignTop | Qt::AlignLeft, description);
00298
00299
00300 const QIcon& icon = qVariantValue<QIcon>(index.model()->data(index, Qt::DecorationRole));
00301 icon.paint(&p,
00302 leftToRight ? left + UNIVERSAL_PADDING : left + width - UNIVERSAL_PADDING - MAIN_ICON_SIZE,
00303 top + UNIVERSAL_PADDING, MAIN_ICON_SIZE, MAIN_ICON_SIZE, Qt::AlignCenter, iconMode);
00304
00305
00306 if (leftToRight) {
00307 gradient = QLinearGradient(left + width - UNIVERSAL_PADDING - FADE_LENGTH, 0,
00308 left + width - UNIVERSAL_PADDING, 0);
00309 gradient.setColorAt(0, Qt::white);
00310 gradient.setColorAt(1, Qt::transparent);
00311 } else {
00312 gradient = QLinearGradient(left + UNIVERSAL_PADDING, 0,
00313 left + UNIVERSAL_PADDING + FADE_LENGTH, 0);
00314 gradient.setColorAt(0, Qt::transparent);
00315 gradient.setColorAt(1, Qt::white);
00316 }
00317
00318 QRect paintRect = option.rect;
00319 p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00320 p.fillRect(paintRect, gradient);
00321
00322 if (leftToRight) {
00323 gradient.setStart(left + width - FADE_LENGTH, 0);
00324 gradient.setFinalStop(left + width, 0);
00325 } else {
00326 gradient.setStart(left + UNIVERSAL_PADDING, 0);
00327 gradient.setFinalStop(left + UNIVERSAL_PADDING + FADE_LENGTH, 0);
00328 }
00329 paintRect.setHeight(UNIVERSAL_PADDING + MAIN_ICON_SIZE / 2);
00330 p.fillRect(paintRect, gradient);
00331 p.end();
00332
00333 painter->drawPixmap(option.rect.topLeft(), pixmap);
00334 }
00335
00336 int AppletDelegate::calcItemHeight(const QStyleOptionViewItem& option) const
00337 {
00338
00339 QFont titleFont = option.font;
00340 titleFont.setBold(true);
00341 titleFont.setPointSize(titleFont.pointSize() + 2);
00342
00343 int textHeight = QFontInfo(titleFont).pixelSize() + QFontInfo(option.font).pixelSize();
00344
00345 return qMax(textHeight, MAIN_ICON_SIZE) + 2 * UNIVERSAL_PADDING;
00346 }
00347
00348 QSize AppletDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
00349 {
00350 Q_UNUSED(index)
00351 return QSize(200, calcItemHeight(option));
00352 }
00353
00354 BackgroundDialog::BackgroundDialog(const QSize& res, Plasma::Containment *c, Plasma::View* view, QWidget* parent)
00355 : KDialog(parent),
00356 m_themeModel(0),
00357 m_containmentModel(0),
00358 m_wallpaper(0),
00359 m_view(view),
00360 m_containment(c),
00361 m_preview(0)
00362 {
00363 setWindowIcon(KIcon("preferences-desktop-wallpaper"));
00364 setCaption(i18n("Desktop Settings"));
00365 showButtonSeparator(true);
00366 setButtons(Ok | Cancel | Apply);
00367
00368 QWidget * main = new QWidget(this);
00369 setupUi(main);
00370
00371
00372
00373 qreal previewRatio = (qreal)res.height() / (qreal)res.width();
00374 QSize monitorSize(200, int(200 * previewRatio));
00375
00376 Plasma::FrameSvg *svg = new Plasma::FrameSvg(this);
00377 svg->setImagePath("widgets/monitor");
00378 svg->resizeFrame(monitorSize);
00379 QPixmap monitorPix(monitorSize + QSize(0, svg->elementSize("base").height() - svg->marginSize(Plasma::BottomMargin)));
00380 monitorPix.fill(Qt::transparent);
00381
00382 QPainter painter(&monitorPix);
00383 QPoint standPosition(monitorSize.width()/2 - svg->elementSize("base").width()/2, svg->contentsRect().bottom());
00384 svg->paint(&painter, QRect(standPosition, svg->elementSize("base")), "base");
00385 svg->paintFrame(&painter);
00386 painter.end();
00387
00388 m_monitor->setPixmap(monitorPix);
00389 m_monitor->setWhatsThis(i18n(
00390 "This picture of a monitor contains a preview of "
00391 "what the current settings will look like on your desktop."));
00392 m_preview = new WallpaperPreview(m_monitor);
00393 m_preview->setGeometry(svg->contentsRect().toRect());
00394
00395 connect(m_newThemeButton, SIGNAL(clicked()), this, SLOT(getNewThemes()));
00396
00397 connect(this, SIGNAL(finished(int)), this, SLOT(cleanup()));
00398 connect(this, SIGNAL(okClicked()), this, SLOT(saveConfig()));
00399 connect(this, SIGNAL(applyClicked()), this, SLOT(saveConfig()));
00400 connect(m_containment, SIGNAL(destroyed()), this, SLOT(close()));
00401
00402 m_themeModel = new ThemeModel(this);
00403 m_theme->setModel(m_themeModel);
00404 m_theme->setItemDelegate(new ThemeDelegate(m_theme->view()));
00405 m_theme->view()->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
00406
00407 m_containmentModel = new QStandardItemModel(this);
00408 m_containmentComboBox->setModel(m_containmentModel);
00409 m_containmentComboBox->setItemDelegate(new AppletDelegate());
00410
00411 setMainWidget(main);
00412 reloadConfig();
00413 adjustSize();
00414 }
00415
00416 BackgroundDialog::~BackgroundDialog()
00417 {
00418 cleanup();
00419 }
00420
00421 void BackgroundDialog::cleanup()
00422 {
00423 delete m_wallpaper;
00424 m_wallpaper = 0;
00425 }
00426
00427 void BackgroundDialog::getNewThemes()
00428 {
00429 KNS::Engine engine(this);
00430 if (engine.init("plasma-themes.knsrc")) {
00431 KNS::Entry::List entries = engine.downloadDialogModal(this);
00432
00433 if (entries.size() > 0) {
00434 m_themeModel->reload();
00435 m_theme->setCurrentIndex(m_themeModel->indexOf(
00436 Plasma::Theme::defaultTheme()->themeName()));
00437 }
00438 }
00439 }
00440
00441 void BackgroundDialog::reloadConfig()
00442 {
00443 disconnect(m_wallpaperMode, SIGNAL(currentIndexChanged(int)), this, SLOT(changeBackgroundMode(int)));
00444 int containmentIndex = 0;
00445 int wallpaperIndex = 0;
00446
00447
00448 KPluginInfo::List plugins = Plasma::Containment::listContainments();
00449 m_containmentModel->clear();
00450 int i = 0;
00451 foreach (const KPluginInfo& info, plugins) {
00452 if (!info.service()->property("X-Plasma-ContainmentCategories").toStringList().contains("desktop")) {
00453 continue;
00454 }
00455
00456 QStandardItem* item = new QStandardItem(KIcon(info.icon()), info.name());
00457 item->setData(info.comment(), AppletDelegate::DescriptionRole);
00458 item->setData(info.pluginName(), AppletDelegate::PluginNameRole);
00459 m_containmentModel->appendRow(item);
00460 if (info.pluginName() == m_containment->pluginName()) {
00461 containmentIndex = i;
00462 }
00463 ++i;
00464 }
00465 m_containmentComboBox->setCurrentIndex(containmentIndex);
00466 m_activityName->setText(m_containment->activity());
00467
00468
00469
00470 bool doWallpaper = m_containment->drawWallpaper();
00471 m_wallpaperLabel->setVisible(doWallpaper);
00472 m_wallpaperGroup->setVisible(doWallpaper);
00473 m_monitor->setVisible(doWallpaper);
00474 m_preview->setVisible(doWallpaper);
00475
00476 if (doWallpaper) {
00477
00478 QString currentPlugin;
00479 QString currentMode;
00480
00481 Plasma::Wallpaper *currentWallpaper = m_containment->wallpaper();
00482 if (currentWallpaper) {
00483 currentPlugin = currentWallpaper->pluginName();
00484 currentMode = currentWallpaper->renderingMode().name();
00485 }
00486
00487 plugins = Plasma::Wallpaper::listWallpaperInfo();
00488 m_wallpaperMode->clear();
00489 i = 0;
00490 foreach (const KPluginInfo& info, plugins) {
00491 kDebug() << "doing wallpaper" << info.pluginName();
00492 bool matches = info.pluginName() == currentPlugin;
00493 const QList<KServiceAction>& modes = info.service()->actions();
00494 if (modes.count() > 0) {
00495 foreach (const KServiceAction& mode, modes) {
00496 m_wallpaperMode->addItem(KIcon(mode.icon()), mode.text(),
00497 QVariant::fromValue(WallpaperInfo(info.pluginName(), mode.name())));
00498 if (matches && mode.name() == currentMode) {
00499 wallpaperIndex = i;
00500 }
00501 ++i;
00502 }
00503 } else {
00504 m_wallpaperMode->addItem(KIcon(info.icon()), info.name(),
00505 QVariant::fromValue(WallpaperInfo(info.pluginName(), QString())));
00506 if (matches) {
00507 wallpaperIndex = i;
00508 }
00509 ++i;
00510 }
00511 }
00512 m_wallpaperMode->setCurrentIndex(wallpaperIndex);
00513 changeBackgroundMode(wallpaperIndex);
00514 }
00515
00516
00517 m_themeModel->reload();
00518 m_theme->setCurrentIndex(m_themeModel->indexOf(Plasma::Theme::defaultTheme()->themeName()));
00519
00520 connect(m_wallpaperMode, SIGNAL(currentIndexChanged(int)), this, SLOT(changeBackgroundMode(int)));
00521 }
00522
00523 void BackgroundDialog::changeBackgroundMode(int mode)
00524 {
00525 kDebug();
00526 QWidget* w = 0;
00527 WallpaperInfo wallpaperInfo = m_wallpaperMode->itemData(mode).value<WallpaperInfo>();
00528
00529 if (m_wallpaperGroup->layout()->count() > 1) {
00530 delete dynamic_cast<QWidgetItem*>(m_wallpaperGroup->layout()->takeAt(1))->widget();
00531 }
00532
00533 if (m_wallpaper && m_wallpaper->pluginName() != wallpaperInfo.first) {
00534 delete m_wallpaper;
00535 m_wallpaper = 0;
00536 }
00537
00538 if (!m_wallpaper) {
00539 m_wallpaper = Plasma::Wallpaper::load(wallpaperInfo.first);
00540 m_preview->setWallpaper(m_wallpaper);
00541 }
00542
00543 if (m_wallpaper) {
00544 m_wallpaper->setRenderingMode(wallpaperInfo.second);
00545 KConfigGroup cfg = wallpaperConfig(wallpaperInfo.first);
00546 kDebug() << "making a" << wallpaperInfo.first << "in mode" << wallpaperInfo.second;
00547 m_wallpaper->restore(cfg);
00548 w = m_wallpaper->createConfigurationInterface(m_wallpaperGroup);
00549 }
00550
00551 if (!w) {
00552 w = new QWidget(m_wallpaperGroup);
00553 }
00554
00555 m_wallpaperGroup->layout()->addWidget(w);
00556 }
00557
00558 KConfigGroup BackgroundDialog::wallpaperConfig(const QString &plugin)
00559 {
00560 Q_ASSERT(m_containment);
00561
00562
00563 KConfigGroup cfg = m_containment->config();
00564 cfg = KConfigGroup(&cfg, "Wallpaper");
00565 return KConfigGroup(&cfg, plugin);
00566 }
00567
00568 void BackgroundDialog::saveConfig()
00569 {
00570 QString theme = m_theme->itemData(m_theme->currentIndex(),
00571 ThemeModel::PackageNameRole).toString();
00572 QString wallpaperPlugin = m_wallpaperMode->itemData(m_wallpaperMode->currentIndex()).value<WallpaperInfo>().first;
00573 QString wallpaperMode = m_wallpaperMode->itemData(m_wallpaperMode->currentIndex()).value<WallpaperInfo>().second;
00574 QString containment = m_containmentComboBox->itemData(m_containmentComboBox->currentIndex(),
00575 AppletDelegate::PluginNameRole).toString();
00576
00577
00578 if (m_containment->pluginName() != containment) {
00579 disconnect(m_containment, SIGNAL(destroyed()), this, SLOT(close()));
00580 m_containment = m_view->swapContainment(m_containment, containment);
00581 connect(m_containment, SIGNAL(destroyed()), this, SLOT(close()));
00582 }
00583
00584 m_containment->setActivity(m_activityName->text());
00585
00586
00587 Plasma::Wallpaper *currentWallpaper = m_containment->wallpaper();
00588 if (currentWallpaper) {
00589 KConfigGroup cfg = wallpaperConfig(currentWallpaper->pluginName());
00590 currentWallpaper->save(cfg);
00591 }
00592
00593 if (m_wallpaper) {
00594 KConfigGroup cfg = wallpaperConfig(m_wallpaper->pluginName());
00595 m_wallpaper->save(cfg);
00596 }
00597
00598 m_containment->setWallpaper(wallpaperPlugin, wallpaperMode);
00599
00600
00601 Plasma::Theme::defaultTheme()->setThemeName(theme);
00602 }