• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Plasma

image.cpp

Go to the documentation of this file.
00001 /*
00002   Copyright (c) 2007 by Paolo Capriotti <p.capriotti@gmail.com>
00003   Copyright (c) 2007 by Aaron Seigo <aseigo@kde.org>
00004   Copyright (c) 2008 by Alexis Ménard <darktears31@gmail.com>
00005   Copyright (c) 2008 by Petri Damsten <damu@iki.fi>
00006 
00007   This program is free software; you can redistribute it and/or modify
00008   it under the terms of the GNU General Public License as published by
00009   the Free Software Foundation; either version 2 of the License, or
00010   (at your option) any later version.
00011 */
00012 
00013 #include "image.h"
00014 
00015 #include <QPainter>
00016 #include <QFile>
00017 
00018 #include <KDirSelectDialog>
00019 #include <KDirWatch>
00020 #include <KFileDialog>
00021 #include <KGlobalSettings>
00022 #include <KImageFilePreview>
00023 #include <KNS/Engine>
00024 #include <KRandom>
00025 #include <KStandardDirs>
00026 
00027 #include <Plasma/Theme>
00028 #include "backgroundlistmodel.h"
00029 #include "backgrounddelegate.h"
00030 #include "ksmserver_interface.h"
00031 
00032 
00033 Image::Image(QObject *parent, const QVariantList &args)
00034     : Plasma::Wallpaper(parent, args),
00035       m_currentSlide(-1),
00036       m_model(0),
00037       m_dialog(0),
00038       m_rendererToken(-1),
00039       m_randomize(true)
00040 {
00041     qRegisterMetaType<QImage>("QImage");
00042     connect(&m_renderer, SIGNAL(done(int, QImage)), this, SLOT(updateBackground(int, QImage)));
00043     connect(&m_timer, SIGNAL(timeout()), this, SLOT(nextSlide()));
00044 }
00045 
00046 Image::~Image()
00047 {
00048     qDeleteAll(m_slideshowBackgrounds);
00049 }
00050 
00051 void Image::init(const KConfigGroup &config)
00052 {
00053     m_timer.stop();
00054     m_mode = renderingMode().name();
00055     calculateGeometry();
00056 
00057     m_delay = config.readEntry("slideTimer", 600);
00058     m_resizeMethod = (Background::ResizeMethod)config.readEntry("wallpaperposition",
00059                                                                 (int)Background::Scale);
00060     m_wallpaper = config.readEntry("wallpaper", QString());
00061     if (m_wallpaper.isEmpty()) {
00062         m_wallpaper = Plasma::Theme::defaultTheme()->wallpaperPath();
00063         int index = m_wallpaper.indexOf("/contents/images/");
00064         if (index > -1) { // We have file from package -> get path to package
00065             m_wallpaper = m_wallpaper.left(index);
00066         }
00067     }
00068 
00069     m_color = config.readEntry("wallpapercolor", QColor(56, 111, 150));
00070     m_usersWallpapers = config.readEntry("userswallpapers", QStringList());
00071     m_dirs = config.readEntry("slidepaths", QStringList());
00072 
00073     if (m_dirs.isEmpty()) {
00074         m_dirs << KStandardDirs::installPath("wallpaper");
00075     }
00076 
00077     if (m_mode == "SingleImage") {
00078         setSingleImage();
00079     } else {
00080         startSlideshow();
00081     }
00082 }
00083 
00084 void Image::save(KConfigGroup &config)
00085 {
00086     config.writeEntry("slideTimer", m_delay);
00087     config.writeEntry("wallpaperposition", (int)m_resizeMethod);
00088     config.writeEntry("slidepaths", m_dirs);
00089     config.writeEntry("wallpaper", m_wallpaper);
00090     config.writeEntry("wallpapercolor", m_color);
00091     config.writeEntry("userswallpapers", m_usersWallpapers);
00092 }
00093 
00094 QWidget* Image::createConfigurationInterface(QWidget* parent)
00095 {
00096     m_widget = new QWidget(parent);
00097 
00098     if (m_mode == "SingleImage") {
00099         m_uiImage.setupUi(m_widget);
00100 
00101         m_model = new BackgroundListModel(m_ratio, this);
00102         m_uiImage.m_view->setModel(m_model);
00103         m_uiImage.m_view->setItemDelegate(new BackgroundDelegate(m_uiImage.m_view->view(),
00104                                                                  m_ratio, this));
00105         m_uiImage.m_view->view()->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
00106         m_model->reload(m_usersWallpapers);
00107         int index = m_model->indexOf(m_wallpaper);
00108         if (index != -1) {
00109             m_uiImage.m_view->setCurrentIndex(index);
00110             Background *b = m_model->package(index);
00111             if (b) {
00112                 fillMetaInfo(b);
00113             }
00114         }
00115         connect(m_uiImage.m_view, SIGNAL(currentIndexChanged(int)), this, SLOT(pictureChanged(int)));
00116 
00117         m_uiImage.m_pictureUrlButton->setIcon(KIcon("document-open"));
00118         connect(m_uiImage.m_pictureUrlButton, SIGNAL(clicked()), this, SLOT(showFileDialog()));
00119 
00120         m_uiImage.m_emailLine->setTextInteractionFlags(Qt::TextSelectableByMouse);
00121 
00122         m_uiImage.m_resizeMethod->addItem(i18n("Scaled & Cropped"), Background::ScaleCrop);
00123         m_uiImage.m_resizeMethod->addItem(i18n("Scaled"), Background::Scale);
00124         m_uiImage.m_resizeMethod->addItem(i18n("Scaled, keep proportions"), Background::Maxpect);
00125         m_uiImage.m_resizeMethod->addItem(i18n("Centered"), Background::Center);
00126         m_uiImage.m_resizeMethod->addItem(i18n("Tiled"), Background::Tiled);
00127         m_uiImage.m_resizeMethod->addItem(i18n("Center Tiled"), Background::CenterTiled);
00128         for (int i = 0; i < m_uiImage.m_resizeMethod->count(); ++i) {
00129             if (m_resizeMethod == m_uiImage.m_resizeMethod->itemData(i).value<int>()) {
00130                 m_uiImage.m_resizeMethod->setCurrentIndex(i);
00131                 break;
00132             }
00133         }
00134         connect(m_uiImage.m_resizeMethod, SIGNAL(currentIndexChanged(int)),
00135                 this, SLOT(positioningChanged(int)));
00136 
00137         m_uiImage.m_color->setColor(m_color);
00138         connect(m_uiImage.m_color, SIGNAL(changed(const QColor&)), this, SLOT(colorChanged(const QColor&)));
00139 
00140         connect(m_uiImage.m_newStuff, SIGNAL(clicked()), this, SLOT(getNewWallpaper()));
00141     } else {
00142         m_uiSlideshow.setupUi(m_widget);
00143 
00144         m_uiSlideshow.m_dirlist->clear();
00145         foreach (const QString &dir, m_dirs) {
00146             m_uiSlideshow.m_dirlist->addItem(dir);
00147         }
00148         m_uiSlideshow.m_dirlist->setCurrentRow(0);
00149         updateDirs();
00150         m_uiSlideshow.m_addDir->setIcon(KIcon("list-add"));
00151         connect(m_uiSlideshow.m_addDir, SIGNAL(clicked()), this, SLOT(slotAddDir()));
00152         m_uiSlideshow.m_removeDir->setIcon(KIcon("list-remove"));
00153         connect(m_uiSlideshow.m_removeDir, SIGNAL(clicked()), this, SLOT(slotRemoveDir()));
00154 
00155         QTime time(0, 0, 0);
00156         time = time.addSecs(m_delay);
00157         m_uiSlideshow.m_slideshowDelay->setTime(time);
00158         m_uiSlideshow.m_slideshowDelay->setMinimumTime(QTime(0, 0, 30));
00159         connect(m_uiSlideshow.m_slideshowDelay, SIGNAL(timeChanged(const QTime&)),
00160                 this, SLOT(timeChanged(const QTime&)));
00161 
00162         m_uiSlideshow.m_resizeMethod->addItem(i18n("Scaled & Cropped"), Background::ScaleCrop);
00163         m_uiSlideshow.m_resizeMethod->addItem(i18n("Scaled"), Background::Scale);
00164         m_uiSlideshow.m_resizeMethod->addItem(i18n("Scaled, keep proportions"), Background::Maxpect);
00165         m_uiSlideshow.m_resizeMethod->addItem(i18n("Centered"), Background::Center);
00166         m_uiSlideshow.m_resizeMethod->addItem(i18n("Tiled"), Background::Tiled);
00167         m_uiSlideshow.m_resizeMethod->addItem(i18n("Center Tiled"), Background::CenterTiled);
00168         for (int i = 0; i < m_uiSlideshow.m_resizeMethod->count(); ++i) {
00169             if (m_resizeMethod == m_uiSlideshow.m_resizeMethod->itemData(i).value<int>()) {
00170                 m_uiSlideshow.m_resizeMethod->setCurrentIndex(i);
00171                 break;
00172             }
00173         }
00174         connect(m_uiSlideshow.m_resizeMethod, SIGNAL(currentIndexChanged(int)),
00175                 this, SLOT(positioningChanged(int)));
00176 
00177         m_uiSlideshow.m_color->setColor(m_color);
00178         connect(m_uiSlideshow.m_color, SIGNAL(changed(const QColor&)), this, SLOT(colorChanged(const QColor&)));
00179     }
00180 
00181     return m_widget;
00182 }
00183 
00184 void Image::calculateGeometry()
00185 {
00186     m_size = boundingRect().size().toSize();
00187     m_renderer.setSize(m_size);
00188     m_ratio = boundingRect().width() / boundingRect().height();
00189     m_renderer.setRatio(m_ratio);
00190 }
00191 
00192 void Image::paint(QPainter *painter, const QRectF& exposedRect)
00193 {
00194     // Check if geometry changed
00195     //kDebug() << m_size << boundingRect().size().toSize();
00196     if (m_size != boundingRect().size().toSize()) {
00197         calculateGeometry();
00198         if (!m_img.isEmpty()) { // We have previous image
00199             render();
00200             //kDebug() << "re-rendering";
00201             return;
00202         }
00203     }
00204 
00205     if (m_pixmap.isNull()) {
00206         painter->fillRect(exposedRect, QBrush(m_color));
00207         //kDebug() << "pixmap null";
00208         return;
00209     }
00210 
00211     painter->save();
00212 
00213     if (painter->worldMatrix() == QMatrix()) {
00214         // draw the background untransformed when possible;(saves lots of per-pixel-math)
00215         painter->resetTransform();
00216     }
00217 
00218     // blit the background (saves all the per-pixel-products that blending does)
00219     painter->setCompositionMode(QPainter::CompositionMode_Source);
00220 
00221     // for pixmaps we draw only the exposed part (untransformed since the
00222     // bitmapBackground already has the size of the viewport)
00223     painter->drawPixmap(exposedRect, m_pixmap, exposedRect);
00224 
00225     // restore transformation and composition mode
00226     painter->restore();
00227 }
00228 
00229 void Image::timeChanged(const QTime& time)
00230 {
00231     m_delay = QTime(0, 0, 0).secsTo(time);
00232     if (!m_slideshowBackgrounds.isEmpty()) {
00233         m_timer.start(m_delay * 1000);
00234     }
00235 }
00236 
00237 void Image::slotAddDir()
00238 {
00239     KUrl empty;
00240     KDirSelectDialog dialog(empty, true, m_widget);
00241     if (dialog.exec()) {
00242         QString urlDir = dialog.url().path();
00243         if (!urlDir.isEmpty() && m_uiSlideshow.m_dirlist->findItems(urlDir, Qt::MatchExactly).isEmpty()) {
00244             m_uiSlideshow.m_dirlist->addItem(dialog.url().path());
00245             updateDirs();
00246             startSlideshow();
00247         }
00248     }
00249 }
00250 
00251 void Image::slotRemoveDir()
00252 {
00253     int row = m_uiSlideshow.m_dirlist->currentRow();
00254     if (row != -1) {
00255         m_uiSlideshow.m_dirlist->takeItem(row);
00256         updateDirs();
00257         startSlideshow();
00258     }
00259 }
00260 
00261 void Image::updateDirs()
00262 {
00263     m_dirs.clear();
00264     for (int i = 0; i < m_uiSlideshow.m_dirlist->count(); i++) {
00265         m_dirs.append(m_uiSlideshow.m_dirlist->item(i)->text());
00266     }
00267 
00268     if (m_uiSlideshow.m_dirlist->count() == 0) {
00269         m_uiSlideshow.m_dirlist->hide();
00270     } else {
00271         const int itemHeight = m_uiSlideshow.m_dirlist->visualItemRect(m_uiSlideshow.m_dirlist->item(0)).height();
00272         const int vMargin = m_uiSlideshow.m_dirlist->height() - m_uiSlideshow.m_dirlist->viewport()->height();
00273 
00274         if (m_uiSlideshow.m_dirlist->count() <= 6) {
00275             m_uiSlideshow.m_dirlist->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00276             m_uiSlideshow.m_dirlist->setFixedHeight(itemHeight * m_uiSlideshow.m_dirlist->count() + vMargin);
00277         } else {
00278             m_uiSlideshow.m_dirlist->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00279         }
00280 
00281         if (!m_uiSlideshow.m_dirlist->isVisible()) {
00282             m_uiSlideshow.m_dirlist->setCurrentRow(0);
00283         }
00284 
00285         m_uiSlideshow.m_dirlist->show();
00286         m_uiSlideshow.gridLayout->invalidate();
00287     }
00288 
00289     m_uiSlideshow.m_removeDir->setEnabled(m_uiSlideshow.m_dirlist->currentRow() != -1);
00290 }
00291 
00292 void Image::setSingleImage()
00293 {
00294     QString img;
00295     BackgroundPackage b(m_wallpaper, m_ratio);
00296 
00297     img = b.findBackground(m_size, m_resizeMethod); // isValid() returns true for jpg?
00298     kDebug() << img << m_wallpaper;
00299     if (img.isEmpty()) {
00300         img = m_wallpaper;
00301     }
00302 
00303     render(img);
00304 }
00305 
00306 void Image::startSlideshow()
00307 {
00308     // populate background list
00309     m_timer.stop();
00310     qDeleteAll(m_slideshowBackgrounds);
00311     m_slideshowBackgrounds.clear();
00312     foreach (const QString& dir, m_dirs) {
00313         m_slideshowBackgrounds += BackgroundListModel::findAllBackgrounds(0, dir, m_ratio);
00314     }
00315 
00316     // start slideshow
00317     if (m_slideshowBackgrounds.isEmpty()) {
00318         m_pixmap = QPixmap();
00319         emit update(boundingRect());
00320     } else {
00321         m_currentSlide = -1;
00322         nextSlide();
00323         m_timer.start(m_delay * 1000);
00324     }
00325 }
00326 
00327 void Image::getNewWallpaper()
00328 {
00329     KNS::Engine engine(m_widget);
00330     if (engine.init("wallpaper.knsrc")) {
00331         KNS::Entry::List entries = engine.downloadDialogModal(m_widget);
00332 
00333         if (entries.size() > 0 && m_model) {
00334             m_model->reload();
00335         }
00336     }
00337 }
00338 
00339 void Image::colorChanged(const QColor& color)
00340 {
00341     m_color = color;
00342     setSingleImage();
00343 }
00344 
00345 void Image::pictureChanged(int index)
00346 {
00347     if (index == -1 || !m_model) {
00348         return;
00349     }
00350 
00351     Background *b = m_model->package(index);
00352     if (!b) {
00353         return;
00354     }
00355 
00356     fillMetaInfo(b);
00357     m_wallpaper = b->path();
00358     setSingleImage();
00359 }
00360 
00361 void Image::positioningChanged(int index)
00362 {
00363     if (m_mode == "SingleImage") {
00364         m_resizeMethod =
00365                 (Background::ResizeMethod)m_uiImage.m_resizeMethod->itemData(index).value<int>();
00366         setSingleImage();
00367     } else {
00368         m_resizeMethod =
00369                 (Background::ResizeMethod)m_uiSlideshow.m_resizeMethod->itemData(index).value<int>();
00370         startSlideshow();
00371     }
00372 }
00373 
00374 void Image::fillMetaInfo(Background *b)
00375 {
00376     // Prepare more user-friendly forms of some pieces of data.
00377     // - license by config is more a of a key value,
00378     //   try to get the proper name if one of known licenses.
00379 
00380     // not needed for now...
00381     //QString license = b->license();
00382     /*
00383     KAboutLicense knownLicense = KAboutLicense::byKeyword(license);
00384     if (knownLicense.key() != KAboutData::License_Custom) {
00385         license = knownLicense.name(KAboutData::ShortName);
00386     }
00387     */
00388     // - last ditch attempt to localize author's name, if not such by config
00389     //   (translators can "hook" names from outside if resolute enough).
00390     if (!b->author().isEmpty()) {
00391         QString author = i18nc("Wallpaper info, author name", "%1", b->author());
00392         m_uiImage.m_authorLabel->setAlignment(Qt::AlignRight);
00393         setMetadata(m_uiImage.m_authorLine, author);
00394     } else {
00395         setMetadata(m_uiImage.m_authorLine, QString());
00396         m_uiImage.m_authorLabel->setAlignment(Qt::AlignLeft);
00397     }
00398     setMetadata(m_uiImage.m_licenseLine, QString());
00399     setMetadata(m_uiImage.m_emailLine, QString());
00400     m_uiImage.m_emailLabel->hide();
00401     m_uiImage.m_licenseLabel->hide();
00402 }
00403 
00404 bool Image::setMetadata(QLabel *label, const QString &text)
00405 {
00406     if (text.isEmpty()) {
00407         label->hide();
00408         return false;
00409     }
00410     else {
00411         label->show();
00412         label->setText(text);
00413         return true;
00414     }
00415 }
00416 
00417 void Image::showFileDialog()
00418 {
00419     if (!m_dialog) {
00420         m_dialog = new KFileDialog(KUrl(), "*.png *.jpeg *.jpg *.svg *.svgz", m_widget);
00421         m_dialog->setOperationMode(KFileDialog::Opening);
00422         m_dialog->setInlinePreviewShown(true);
00423         m_dialog->setCaption(i18n("Select Wallpaper Image File"));
00424         m_dialog->setModal(false);
00425     }
00426     m_dialog->show();
00427     m_dialog->raise();
00428     m_dialog->activateWindow();
00429 
00430     connect(m_dialog, SIGNAL(okClicked()), this, SLOT(browse()));
00431 }
00432 
00433 void Image::browse()
00434 {
00435     Q_ASSERT(m_model);
00436 
00437     QString wallpaper = m_dialog->selectedFile();
00438     disconnect(m_dialog, SIGNAL(okClicked()), this, SLOT(browse()));
00439 
00440     if (wallpaper.isEmpty()) {
00441         return;
00442     }
00443 
00444     if (m_model->contains(wallpaper)) {
00445         m_uiImage.m_view->setCurrentIndex(m_model->indexOf(wallpaper));
00446         return;
00447     }
00448 
00449     // add background to the model
00450     m_model->addBackground(wallpaper);
00451 
00452     // select it
00453     int index = m_model->indexOf(wallpaper);
00454     if (index != -1) {
00455         m_uiImage.m_view->setCurrentIndex(index);
00456     }
00457     // save it
00458     m_usersWallpapers << wallpaper;
00459 }
00460 
00461 void Image::nextSlide()
00462 {
00463     if (m_slideshowBackgrounds.size() < 1) {
00464         return;
00465     }
00466 
00467     QString previous;
00468     if (m_currentSlide >= 0 && m_currentSlide < m_slideshowBackgrounds.size()) {
00469         previous = m_slideshowBackgrounds[m_currentSlide]->findBackground(m_size, m_resizeMethod);
00470     }
00471 
00472     if (m_randomize) {
00473         m_currentSlide = KRandom::random() % m_slideshowBackgrounds.size();
00474     } else if (++m_currentSlide >= m_slideshowBackgrounds.size()) {
00475         m_currentSlide = 0;
00476     }
00477 
00478     QString current = m_slideshowBackgrounds[m_currentSlide]->findBackground(m_size, m_resizeMethod);
00479     if (current == previous) {
00480         QFileInfo info(previous);
00481         if (m_previousModified == info.lastModified()) {
00482             // it hasn't changed since we last loaded it, so try the next one instead
00483             if (m_slideshowBackgrounds.count() == 1) {
00484                 // only one slide, same image, continue on
00485                 return;
00486             }
00487 
00488             if (++m_currentSlide >= m_slideshowBackgrounds.size()) {
00489                 m_currentSlide = 0;
00490             }
00491 
00492             current = m_slideshowBackgrounds[m_currentSlide]->findBackground(m_size, m_resizeMethod);
00493         }
00494     }
00495 
00496     QFileInfo info(current);
00497     m_previousModified = info.lastModified();
00498 
00499     render(current);
00500 }
00501 
00502 void Image::render(const QString& image)
00503 {
00504     if (!image.isEmpty()) {
00505         m_img = image;
00506     }
00507     // else re-render previous image
00508     m_rendererToken = m_renderer.render(m_img, m_color, m_resizeMethod,
00509                                         Qt::SmoothTransformation);
00510     suspendStartup(true); // during KDE startup, make ksmserver until the wallpaper is ready
00511 }
00512 
00513 void Image::updateBackground(int token, const QImage &img)
00514 {
00515     if (m_rendererToken == token) {
00516         m_pixmap = QPixmap::fromImage(img);
00517         emit update(boundingRect());
00518         suspendStartup(false);
00519     }
00520 }
00521 
00522 void Image::suspendStartup(bool suspend)
00523 {
00524     org::kde::KSMServerInterface ksmserver("org.kde.ksmserver", "/KSMServer", QDBusConnection::sessionBus());
00525     const QString startupID("desktop wallaper");
00526     if (suspend) {
00527         ksmserver.suspendStartup(startupID);
00528     } else {
00529         ksmserver.resumeStartup(startupID);
00530     }
00531 }
00532 
00533 void Image::updateScreenshot(QPersistentModelIndex index)
00534 {
00535     m_uiImage.m_view->view()->update(index);
00536 }
00537 
00538 void Image::removeBackground(const QString &path)
00539 {
00540     if (m_model) {
00541         m_model->removeBackground(path);
00542     }
00543 }
00544 
00545 #include "image.moc"

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal