2 Copyright (c) 2007 by Paolo Capriotti <p.capriotti@gmail.com>
3 Copyright (c) 2007 by Aaron Seigo <aseigo@kde.org>
4 Copyright (c) 2008 by Alexis Ménard <darktears31@gmail.com>
5 Copyright (c) 2008 by Petri Damsten <damu@iki.fi>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
18 #include <KDirSelectDialog>
20 #include <KFileDialog>
21 #include <KGlobalSettings>
22 #include <KImageFilePreview>
25 #include <KStandardDirs>
27 #include <Plasma/Theme>
28 #include "backgroundlistmodel.h"
29 #include "backgrounddelegate.h"
30 #include "ksmserver_interface.h"
33 Image::Image(QObject
*parent
, const QVariantList
&args
)
34 : Plasma::Wallpaper(parent
, args
),
41 qRegisterMetaType
<QImage
>("QImage");
42 connect(&m_renderer
, SIGNAL(done(int, QImage
)), this, SLOT(updateBackground(int, QImage
)));
43 connect(&m_timer
, SIGNAL(timeout()), this, SLOT(nextSlide()));
48 qDeleteAll(m_slideshowBackgrounds
);
51 void Image::init(const KConfigGroup
&config
)
54 m_mode
= renderingMode().name();
57 m_delay
= config
.readEntry("slideTimer", 600);
58 m_resizeMethod
= (Background::ResizeMethod
)config
.readEntry("wallpaperposition",
59 (int)Background::Scale
);
60 m_wallpaper
= config
.readEntry("wallpaper", QString());
61 if (m_wallpaper
.isEmpty()) {
62 m_wallpaper
= Plasma::Theme::defaultTheme()->wallpaperPath();
63 int index
= m_wallpaper
.indexOf("/contents/images/");
64 if (index
> -1) { // We have file from package -> get path to package
65 m_wallpaper
= m_wallpaper
.left(index
);
69 m_color
= config
.readEntry("wallpapercolor", QColor(56, 111, 150));
70 m_usersWallpapers
= config
.readEntry("userswallpapers", QStringList());
71 m_dirs
= config
.readEntry("slidepaths", QStringList());
73 if (m_dirs
.isEmpty()) {
74 m_dirs
<< KStandardDirs::installPath("wallpaper");
77 if (m_mode
== "SingleImage") {
84 void Image::save(KConfigGroup
&config
)
86 config
.writeEntry("slideTimer", m_delay
);
87 config
.writeEntry("wallpaperposition", (int)m_resizeMethod
);
88 config
.writeEntry("slidepaths", m_dirs
);
89 config
.writeEntry("wallpaper", m_wallpaper
);
90 config
.writeEntry("wallpapercolor", m_color
);
91 config
.writeEntry("userswallpapers", m_usersWallpapers
);
94 QWidget
* Image::createConfigurationInterface(QWidget
* parent
)
96 m_widget
= new QWidget(parent
);
98 if (m_mode
== "SingleImage") {
99 m_uiImage
.setupUi(m_widget
);
101 m_model
= new BackgroundListModel(m_ratio
, this);
102 m_uiImage
.m_view
->setModel(m_model
);
103 m_uiImage
.m_view
->setItemDelegate(new BackgroundDelegate(m_uiImage
.m_view
->view(),
105 m_uiImage
.m_view
->view()->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel
);
106 m_model
->reload(m_usersWallpapers
);
107 int index
= m_model
->indexOf(m_wallpaper
);
109 m_uiImage
.m_view
->setCurrentIndex(index
);
110 Background
*b
= m_model
->package(index
);
115 connect(m_uiImage
.m_view
, SIGNAL(currentIndexChanged(int)), this, SLOT(pictureChanged(int)));
117 m_uiImage
.m_pictureUrlButton
->setIcon(KIcon("document-open"));
118 connect(m_uiImage
.m_pictureUrlButton
, SIGNAL(clicked()), this, SLOT(showFileDialog()));
120 m_uiImage
.m_emailLine
->setTextInteractionFlags(Qt::TextSelectableByMouse
);
122 m_uiImage
.m_resizeMethod
->addItem(i18n("Scaled & Cropped"), Background::ScaleCrop
);
123 m_uiImage
.m_resizeMethod
->addItem(i18n("Scaled"), Background::Scale
);
124 m_uiImage
.m_resizeMethod
->addItem(i18n("Scaled, keep proportions"), Background::Maxpect
);
125 m_uiImage
.m_resizeMethod
->addItem(i18n("Centered"), Background::Center
);
126 m_uiImage
.m_resizeMethod
->addItem(i18n("Tiled"), Background::Tiled
);
127 m_uiImage
.m_resizeMethod
->addItem(i18n("Center Tiled"), Background::CenterTiled
);
128 for (int i
= 0; i
< m_uiImage
.m_resizeMethod
->count(); ++i
) {
129 if (m_resizeMethod
== m_uiImage
.m_resizeMethod
->itemData(i
).value
<int>()) {
130 m_uiImage
.m_resizeMethod
->setCurrentIndex(i
);
134 connect(m_uiImage
.m_resizeMethod
, SIGNAL(currentIndexChanged(int)),
135 this, SLOT(positioningChanged(int)));
137 m_uiImage
.m_color
->setColor(m_color
);
138 connect(m_uiImage
.m_color
, SIGNAL(changed(const QColor
&)), this, SLOT(colorChanged(const QColor
&)));
140 connect(m_uiImage
.m_newStuff
, SIGNAL(clicked()), this, SLOT(getNewWallpaper()));
142 m_uiSlideshow
.setupUi(m_widget
);
144 m_uiSlideshow
.m_dirlist
->clear();
145 foreach (const QString
&dir
, m_dirs
) {
146 m_uiSlideshow
.m_dirlist
->addItem(dir
);
148 m_uiSlideshow
.m_dirlist
->setCurrentRow(0);
150 m_uiSlideshow
.m_addDir
->setIcon(KIcon("list-add"));
151 connect(m_uiSlideshow
.m_addDir
, SIGNAL(clicked()), this, SLOT(slotAddDir()));
152 m_uiSlideshow
.m_removeDir
->setIcon(KIcon("list-remove"));
153 connect(m_uiSlideshow
.m_removeDir
, SIGNAL(clicked()), this, SLOT(slotRemoveDir()));
156 time
= time
.addSecs(m_delay
);
157 m_uiSlideshow
.m_slideshowDelay
->setTime(time
);
158 m_uiSlideshow
.m_slideshowDelay
->setMinimumTime(QTime(0, 0, 30));
159 connect(m_uiSlideshow
.m_slideshowDelay
, SIGNAL(timeChanged(const QTime
&)),
160 this, SLOT(timeChanged(const QTime
&)));
162 m_uiSlideshow
.m_resizeMethod
->addItem(i18n("Scaled & Cropped"), Background::ScaleCrop
);
163 m_uiSlideshow
.m_resizeMethod
->addItem(i18n("Scaled"), Background::Scale
);
164 m_uiSlideshow
.m_resizeMethod
->addItem(i18n("Scaled, keep proportions"), Background::Maxpect
);
165 m_uiSlideshow
.m_resizeMethod
->addItem(i18n("Centered"), Background::Center
);
166 m_uiSlideshow
.m_resizeMethod
->addItem(i18n("Tiled"), Background::Tiled
);
167 m_uiSlideshow
.m_resizeMethod
->addItem(i18n("Center Tiled"), Background::CenterTiled
);
168 for (int i
= 0; i
< m_uiSlideshow
.m_resizeMethod
->count(); ++i
) {
169 if (m_resizeMethod
== m_uiSlideshow
.m_resizeMethod
->itemData(i
).value
<int>()) {
170 m_uiSlideshow
.m_resizeMethod
->setCurrentIndex(i
);
174 connect(m_uiSlideshow
.m_resizeMethod
, SIGNAL(currentIndexChanged(int)),
175 this, SLOT(positioningChanged(int)));
177 m_uiSlideshow
.m_color
->setColor(m_color
);
178 connect(m_uiSlideshow
.m_color
, SIGNAL(changed(const QColor
&)), this, SLOT(colorChanged(const QColor
&)));
184 void Image::calculateGeometry()
186 m_size
= boundingRect().size().toSize();
187 m_renderer
.setSize(m_size
);
188 m_ratio
= boundingRect().width() / boundingRect().height();
189 m_renderer
.setRatio(m_ratio
);
192 void Image::paint(QPainter
*painter
, const QRectF
& exposedRect
)
194 // Check if geometry changed
195 //kDebug() << m_size << boundingRect().size().toSize();
196 if (m_size
!= boundingRect().size().toSize()) {
198 if (!m_img
.isEmpty()) { // We have previous image
200 //kDebug() << "re-rendering";
205 if (m_pixmap
.isNull()) {
206 painter
->fillRect(exposedRect
, QBrush(m_color
));
207 //kDebug() << "pixmap null";
213 if (painter
->worldMatrix() == QMatrix()) {
214 // draw the background untransformed when possible;(saves lots of per-pixel-math)
215 painter
->resetTransform();
218 // blit the background (saves all the per-pixel-products that blending does)
219 painter
->setCompositionMode(QPainter::CompositionMode_Source
);
221 // for pixmaps we draw only the exposed part (untransformed since the
222 // bitmapBackground already has the size of the viewport)
223 painter
->drawPixmap(exposedRect
, m_pixmap
, exposedRect
);
225 // restore transformation and composition mode
229 void Image::timeChanged(const QTime
& time
)
231 m_delay
= QTime(0, 0, 0).secsTo(time
);
232 if (!m_slideshowBackgrounds
.isEmpty()) {
233 m_timer
.start(m_delay
* 1000);
237 void Image::slotAddDir()
240 KDirSelectDialog
dialog(empty
, true, m_widget
);
242 QString urlDir
= dialog
.url().path();
243 if (!urlDir
.isEmpty() && m_uiSlideshow
.m_dirlist
->findItems(urlDir
, Qt::MatchExactly
).isEmpty()) {
244 m_uiSlideshow
.m_dirlist
->addItem(dialog
.url().path());
251 void Image::slotRemoveDir()
253 int row
= m_uiSlideshow
.m_dirlist
->currentRow();
255 m_uiSlideshow
.m_dirlist
->takeItem(row
);
261 void Image::updateDirs()
264 for (int i
= 0; i
< m_uiSlideshow
.m_dirlist
->count(); i
++) {
265 m_dirs
.append(m_uiSlideshow
.m_dirlist
->item(i
)->text());
268 if (m_uiSlideshow
.m_dirlist
->count() == 0) {
269 m_uiSlideshow
.m_dirlist
->hide();
271 const int itemHeight
= m_uiSlideshow
.m_dirlist
->visualItemRect(m_uiSlideshow
.m_dirlist
->item(0)).height();
272 const int vMargin
= m_uiSlideshow
.m_dirlist
->height() - m_uiSlideshow
.m_dirlist
->viewport()->height();
274 if (m_uiSlideshow
.m_dirlist
->count() <= 6) {
275 m_uiSlideshow
.m_dirlist
->setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Fixed
);
276 m_uiSlideshow
.m_dirlist
->setFixedHeight(itemHeight
* m_uiSlideshow
.m_dirlist
->count() + vMargin
);
278 m_uiSlideshow
.m_dirlist
->setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Expanding
);
281 if (!m_uiSlideshow
.m_dirlist
->isVisible()) {
282 m_uiSlideshow
.m_dirlist
->setCurrentRow(0);
285 m_uiSlideshow
.m_dirlist
->show();
286 m_uiSlideshow
.gridLayout
->invalidate();
289 m_uiSlideshow
.m_removeDir
->setEnabled(m_uiSlideshow
.m_dirlist
->currentRow() != -1);
292 void Image::setSingleImage()
295 BackgroundPackage
b(m_wallpaper
, m_ratio
);
297 img
= b
.findBackground(m_size
, m_resizeMethod
); // isValid() returns true for jpg?
298 kDebug() << img
<< m_wallpaper
;
306 void Image::startSlideshow()
308 // populate background list
310 qDeleteAll(m_slideshowBackgrounds
);
311 m_slideshowBackgrounds
.clear();
312 foreach (const QString
& dir
, m_dirs
) {
313 m_slideshowBackgrounds
+= BackgroundListModel::findAllBackgrounds(0, dir
, m_ratio
);
317 if (m_slideshowBackgrounds
.isEmpty()) {
318 m_pixmap
= QPixmap();
319 emit
update(boundingRect());
323 m_timer
.start(m_delay
* 1000);
327 void Image::getNewWallpaper()
329 KNS::Engine
engine(m_widget
);
330 if (engine
.init("wallpaper.knsrc")) {
331 KNS::Entry::List entries
= engine
.downloadDialogModal(m_widget
);
333 if (entries
.size() > 0 && m_model
) {
339 void Image::colorChanged(const QColor
& color
)
345 void Image::pictureChanged(int index
)
347 if (index
== -1 || !m_model
) {
351 Background
*b
= m_model
->package(index
);
357 m_wallpaper
= b
->path();
361 void Image::positioningChanged(int index
)
363 if (m_mode
== "SingleImage") {
365 (Background::ResizeMethod
)m_uiImage
.m_resizeMethod
->itemData(index
).value
<int>();
369 (Background::ResizeMethod
)m_uiSlideshow
.m_resizeMethod
->itemData(index
).value
<int>();
374 void Image::fillMetaInfo(Background
*b
)
376 // Prepare more user-friendly forms of some pieces of data.
377 // - license by config is more a of a key value,
378 // try to get the proper name if one of known licenses.
380 // not needed for now...
381 //QString license = b->license();
383 KAboutLicense knownLicense = KAboutLicense::byKeyword(license);
384 if (knownLicense.key() != KAboutData::License_Custom) {
385 license = knownLicense.name(KAboutData::ShortName);
388 // - last ditch attempt to localize author's name, if not such by config
389 // (translators can "hook" names from outside if resolute enough).
390 if (!b
->author().isEmpty()) {
391 QString author
= i18nc("Wallpaper info, author name", "%1", b
->author());
392 m_uiImage
.m_authorLabel
->setAlignment(Qt::AlignRight
);
393 setMetadata(m_uiImage
.m_authorLine
, author
);
395 setMetadata(m_uiImage
.m_authorLine
, QString());
396 m_uiImage
.m_authorLabel
->setAlignment(Qt::AlignLeft
);
398 setMetadata(m_uiImage
.m_licenseLine
, QString());
399 setMetadata(m_uiImage
.m_emailLine
, QString());
400 m_uiImage
.m_emailLabel
->hide();
401 m_uiImage
.m_licenseLabel
->hide();
404 bool Image::setMetadata(QLabel
*label
, const QString
&text
)
406 if (text
.isEmpty()) {
412 label
->setText(text
);
417 void Image::showFileDialog()
420 m_dialog
= new KFileDialog(KUrl(), "*.png *.jpeg *.jpg *.svg *.svgz", m_widget
);
421 m_dialog
->setOperationMode(KFileDialog::Opening
);
422 m_dialog
->setInlinePreviewShown(true);
423 m_dialog
->setCaption(i18n("Select Wallpaper Image File"));
424 m_dialog
->setModal(false);
428 m_dialog
->activateWindow();
430 connect(m_dialog
, SIGNAL(okClicked()), this, SLOT(browse()));
437 QString wallpaper
= m_dialog
->selectedFile();
438 disconnect(m_dialog
, SIGNAL(okClicked()), this, SLOT(browse()));
440 if (wallpaper
.isEmpty()) {
444 if (m_model
->contains(wallpaper
)) {
445 m_uiImage
.m_view
->setCurrentIndex(m_model
->indexOf(wallpaper
));
449 // add background to the model
450 m_model
->addBackground(wallpaper
);
453 int index
= m_model
->indexOf(wallpaper
);
455 m_uiImage
.m_view
->setCurrentIndex(index
);
458 m_usersWallpapers
<< wallpaper
;
461 void Image::nextSlide()
463 if (m_slideshowBackgrounds
.size() < 1) {
468 if (m_currentSlide
>= 0 && m_currentSlide
< m_slideshowBackgrounds
.size()) {
469 previous
= m_slideshowBackgrounds
[m_currentSlide
]->findBackground(m_size
, m_resizeMethod
);
473 m_currentSlide
= KRandom::random() % m_slideshowBackgrounds
.size();
474 } else if (++m_currentSlide
>= m_slideshowBackgrounds
.size()) {
478 QString current
= m_slideshowBackgrounds
[m_currentSlide
]->findBackground(m_size
, m_resizeMethod
);
479 if (current
== previous
) {
480 QFileInfo
info(previous
);
481 if (m_previousModified
== info
.lastModified()) {
482 // it hasn't changed since we last loaded it, so try the next one instead
483 if (m_slideshowBackgrounds
.count() == 1) {
484 // only one slide, same image, continue on
488 if (++m_currentSlide
>= m_slideshowBackgrounds
.size()) {
492 current
= m_slideshowBackgrounds
[m_currentSlide
]->findBackground(m_size
, m_resizeMethod
);
496 QFileInfo
info(current
);
497 m_previousModified
= info
.lastModified();
502 void Image::render(const QString
& image
)
504 if (!image
.isEmpty()) {
507 // else re-render previous image
508 m_rendererToken
= m_renderer
.render(m_img
, m_color
, m_resizeMethod
,
509 Qt::SmoothTransformation
);
510 suspendStartup(true); // during KDE startup, make ksmserver until the wallpaper is ready
513 void Image::updateBackground(int token
, const QImage
&img
)
515 if (m_rendererToken
== token
) {
516 m_pixmap
= QPixmap::fromImage(img
);
517 emit
update(boundingRect());
518 suspendStartup(false);
522 void Image::suspendStartup(bool suspend
)
524 org::kde::KSMServerInterface
ksmserver("org.kde.ksmserver", "/KSMServer", QDBusConnection::sessionBus());
525 const QString
startupID("desktop wallaper");
527 ksmserver
.suspendStartup(startupID
);
529 ksmserver
.resumeStartup(startupID
);
533 void Image::updateScreenshot(QPersistentModelIndex index
)
535 m_uiImage
.m_view
->view()->update(index
);
538 void Image::removeBackground(const QString
&path
)
541 m_model
->removeBackground(path
);