~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to plasma/generic/wallpapers/image/image.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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>
 
6
 
 
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.
 
11
*/
 
12
 
 
13
#include "image.h"
 
14
 
 
15
#include <QApplication>
 
16
#include <QPainter>
 
17
#include <QFile>
 
18
#include <QEasingCurve>
 
19
#include <QPropertyAnimation>
 
20
#include <QTimer>
 
21
 
 
22
#include <KDebug>
 
23
#include <KDirSelectDialog>
 
24
#include <KDirWatch>
 
25
#include <KFileDialog>
 
26
#include <KRandom>
 
27
#include <KStandardDirs>
 
28
#include <KIO/Job>
 
29
#include <krun.h>
 
30
#include <knewstuff3/downloaddialog.h>
 
31
 
 
32
#include <Plasma/Theme>
 
33
#include "backgroundlistmodel.h"
 
34
#include "backgrounddelegate.h"
 
35
#include "removebuttonmanager.h"
 
36
#include "ksmserver_interface.h"
 
37
 
 
38
K_EXPORT_PLASMA_WALLPAPER(image, Image)
 
39
 
 
40
Image::Image(QObject *parent, const QVariantList &args)
 
41
    : Plasma::Wallpaper(parent, args),
 
42
      m_fileWatch(new KDirWatch(this)),
 
43
      m_configWidget(0),
 
44
      m_wallpaperPackage(0),
 
45
      m_currentSlide(-1),
 
46
      m_fadeValue(0),
 
47
      m_animation(0),
 
48
      m_model(0),
 
49
      m_dialog(0),
 
50
      m_randomize(true),
 
51
      m_nextWallpaperAction(0),
 
52
      m_openImageAction(0)
 
53
{
 
54
    connect(this, SIGNAL(renderCompleted(QImage)), this, SLOT(updateBackground(QImage)));
 
55
    connect(&m_timer, SIGNAL(timeout()), this, SLOT(nextSlide()));
 
56
    connect(m_fileWatch, SIGNAL(dirty(QString)), this, SLOT(imageFileAltered(QString)));
 
57
    connect(m_fileWatch, SIGNAL(created(QString)), this, SLOT(imageFileAltered(QString)));
 
58
}
 
59
 
 
60
Image::~Image()
 
61
{
 
62
    delete m_animation;
 
63
}
 
64
 
 
65
void Image::init(const KConfigGroup &config)
 
66
{
 
67
    m_timer.stop();
 
68
 
 
69
    if (renderingMode().name().isEmpty()) {
 
70
        m_mode = "SingleImage";
 
71
    } else {
 
72
        m_mode = renderingMode().name();
 
73
    }
 
74
 
 
75
    calculateGeometry();
 
76
 
 
77
    m_delay = config.readEntry("slideTimer", 10);
 
78
    m_resizeMethod = (ResizeMethod)config.readEntry("wallpaperposition", (int)ScaledResize);
 
79
    m_wallpaper = config.readEntry("wallpaper", QString());
 
80
    if (m_wallpaper.isEmpty()) {
 
81
        useSingleImageDefaults();
 
82
    }
 
83
 
 
84
    m_color = config.readEntry("wallpapercolor", QColor(Qt::black));
 
85
    m_usersWallpapers = config.readEntry("userswallpapers", QStringList());
 
86
    m_dirs = config.readEntry("slidepaths", QStringList());
 
87
 
 
88
    if (m_dirs.isEmpty()) {
 
89
        m_dirs << KStandardDirs::installPath("wallpaper");
 
90
    }
 
91
 
 
92
    setUsingRenderingCache(m_mode == "SingleImage");
 
93
 
 
94
    if (m_mode == "SingleImage") {
 
95
        setSingleImage();
 
96
        setContextualActions(QList<QAction*>());
 
97
    } else {
 
98
        m_nextWallpaperAction = new QAction(KIcon("user-desktop"), i18n("Next Wallpaper Image"), this);
 
99
        connect(m_nextWallpaperAction, SIGNAL(triggered(bool)), this, SLOT(nextSlide()));
 
100
        m_openImageAction = new QAction(KIcon("document-open"), i18n("Open Wallpaper Image"), this);
 
101
        connect(m_openImageAction, SIGNAL(triggered(bool)), this, SLOT(openSlide()));
 
102
        QTimer::singleShot(200, this, SLOT(startSlideshow()));
 
103
        QList<QAction*> actions;
 
104
        actions.push_back(m_nextWallpaperAction);
 
105
        actions.push_back(m_openImageAction);
 
106
        setContextualActions(actions);
 
107
        updateWallpaperActions();
 
108
    }
 
109
 
 
110
    m_animation = new QPropertyAnimation(this, "fadeValue");
 
111
    m_animation->setProperty("easingCurve", QEasingCurve::InQuad);
 
112
    m_animation->setProperty("duration", 500);
 
113
    m_animation->setProperty("startValue", 0.0);
 
114
    m_animation->setProperty("endValue", 1.0);
 
115
}
 
116
 
 
117
void Image::useSingleImageDefaults()
 
118
{
 
119
    m_wallpaper = Plasma::Theme::defaultTheme()->wallpaperPath();
 
120
    int index = m_wallpaper.indexOf("/contents/images/");
 
121
    if (index > -1) { // We have file from package -> get path to package
 
122
        m_wallpaper = m_wallpaper.left(index);
 
123
    }
 
124
}
 
125
 
 
126
void Image::save(KConfigGroup &config)
 
127
{
 
128
    config.writeEntry("slideTimer", m_delay);
 
129
    config.writeEntry("wallpaperposition", (int)m_resizeMethod);
 
130
    config.writeEntry("slidepaths", m_dirs);
 
131
    config.writeEntry("wallpaper", m_wallpaper);
 
132
    config.writeEntry("wallpapercolor", m_color);
 
133
    config.writeEntry("userswallpapers", m_usersWallpapers);
 
134
}
 
135
 
 
136
void Image::configWidgetDestroyed()
 
137
{
 
138
    m_configWidget = 0;
 
139
    m_model = 0;
 
140
}
 
141
 
 
142
QWidget* Image::createConfigurationInterface(QWidget* parent)
 
143
{
 
144
    m_configWidget = new QWidget(parent);
 
145
    connect(m_configWidget, SIGNAL(destroyed(QObject*)), this, SLOT(configWidgetDestroyed()));
 
146
 
 
147
    if (m_mode == "SingleImage") {
 
148
        m_uiImage.setupUi(m_configWidget);
 
149
 
 
150
        m_model = new BackgroundListModel(this, m_configWidget);
 
151
        m_model->setResizeMethod(m_resizeMethod);
 
152
        m_model->setWallpaperSize(m_size);
 
153
        m_model->reload(m_usersWallpapers);
 
154
        QTimer::singleShot(0, this, SLOT(setConfigurationInterfaceModel()));
 
155
        m_uiImage.m_view->setItemDelegate(new BackgroundDelegate(m_uiImage.m_view));
 
156
        //FIXME: setting the minimum width is rather ugly, but this gets us 3 columns of papers
 
157
        //which looks quite good as a default. the magic number 7 at the end of the calculation is
 
158
        //evidently making up for some other PM involved in the QListView that isn't being caught.
 
159
        //if a cleaner way can be found to achieve all this, that would be great
 
160
        m_uiImage.m_view->setMinimumWidth((BackgroundDelegate::SCREENSHOT_SIZE + BackgroundDelegate::MARGIN * 2 +
 
161
                                           BackgroundDelegate::BLUR_INCREMENT) * 3 +
 
162
                                           m_uiImage.m_view->spacing() * 4 +
 
163
                                           QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent) +
 
164
                                           QApplication::style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2 + 7);
 
165
        m_uiImage.m_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
 
166
 
 
167
        RemoveButtonManager *rmManager = new RemoveButtonManager(m_uiImage.m_view, &m_usersWallpapers);
 
168
        connect(rmManager, SIGNAL(removeClicked(QString)), this, SLOT(removeWallpaper(QString)));
 
169
 
 
170
        m_uiImage.m_pictureUrlButton->setIcon(KIcon("document-open"));
 
171
        connect(m_uiImage.m_pictureUrlButton, SIGNAL(clicked()), this, SLOT(showFileDialog()));
 
172
 
 
173
        m_uiImage.m_resizeMethod->addItem(i18n("Scaled & Cropped"), ScaledAndCroppedResize);
 
174
        m_uiImage.m_resizeMethod->addItem(i18n("Scaled"), ScaledResize);
 
175
        m_uiImage.m_resizeMethod->addItem(i18n("Scaled, keep proportions"), MaxpectResize);
 
176
        m_uiImage.m_resizeMethod->addItem(i18n("Centered"), CenteredResize);
 
177
        m_uiImage.m_resizeMethod->addItem(i18n("Tiled"), TiledResize);
 
178
        m_uiImage.m_resizeMethod->addItem(i18n("Center Tiled"), CenterTiledResize);
 
179
        for (int i = 0; i < m_uiImage.m_resizeMethod->count(); ++i) {
 
180
            if (m_resizeMethod == m_uiImage.m_resizeMethod->itemData(i).value<int>()) {
 
181
                m_uiImage.m_resizeMethod->setCurrentIndex(i);
 
182
                break;
 
183
            }
 
184
        }
 
185
        connect(m_uiImage.m_resizeMethod, SIGNAL(currentIndexChanged(int)),
 
186
                this, SLOT(positioningChanged(int)));
 
187
 
 
188
        m_uiImage.m_color->setColor(m_color);
 
189
        //Color button is useless with some resize methods
 
190
        m_uiImage.m_color->setEnabled(m_resizeMethod == MaxpectResize || m_resizeMethod == CenteredResize);
 
191
        connect(m_uiImage.m_color, SIGNAL(changed(const QColor&)), this, SLOT(colorChanged(const QColor&)));
 
192
 
 
193
        m_uiImage.m_newStuff->setIcon(KIcon("get-hot-new-stuff"));
 
194
        connect(m_uiImage.m_newStuff, SIGNAL(clicked()), this, SLOT(getNewWallpaper()));
 
195
 
 
196
        connect(m_uiImage.m_color, SIGNAL(changed(const QColor&)), this, SLOT(modified()));
 
197
        connect(m_uiImage.m_resizeMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(modified()));
 
198
        connect(m_uiImage.m_view, SIGNAL(clicked(const QModelIndex &)), this, SLOT(modified()));
 
199
 
 
200
    } else {
 
201
        m_uiSlideshow.setupUi(m_configWidget);
 
202
        m_uiSlideshow.m_newStuff->setIcon(KIcon("get-hot-new-stuff"));
 
203
        m_uiSlideshow.m_dirlist->clear();
 
204
        m_uiSlideshow.m_systemCheckBox->setChecked(false);
 
205
        m_uiSlideshow.m_downloadedCheckBox->setChecked(false);
 
206
 
 
207
        QString systemPath = KStandardDirs::installPath("wallpaper");
 
208
        QString localPath = KGlobal::dirs()->saveLocation("wallpaper");
 
209
 
 
210
        foreach (const QString &dir, m_dirs) {
 
211
            if (dir == KStandardDirs::installPath("wallpaper")) {
 
212
                m_uiSlideshow.m_systemCheckBox->setChecked(true);
 
213
            } else if (dir == localPath) {
 
214
                m_uiSlideshow.m_downloadedCheckBox->setChecked(true);
 
215
            } else {
 
216
                m_uiSlideshow.m_dirlist->addItem(dir);
 
217
            }
 
218
        }
 
219
        m_uiSlideshow.m_dirlist->setCurrentRow(0);
 
220
        updateDirs();
 
221
        m_uiSlideshow.m_addDir->setIcon(KIcon("list-add"));
 
222
        connect(m_uiSlideshow.m_addDir, SIGNAL(clicked()), this, SLOT(addDir()));
 
223
        m_uiSlideshow.m_removeDir->setIcon(KIcon("list-remove"));
 
224
        connect(m_uiSlideshow.m_removeDir, SIGNAL(clicked()), this, SLOT(removeDir()));
 
225
 
 
226
        QTime time(0, 0, 0);
 
227
        time = time.addSecs(m_delay);
 
228
        m_uiSlideshow.m_slideshowDelay->setTime(time);
 
229
        m_uiSlideshow.m_slideshowDelay->setMinimumTime(QTime(0, 0, 10));
 
230
        connect(m_uiSlideshow.m_slideshowDelay, SIGNAL(timeChanged(const QTime&)),
 
231
                this, SLOT(timeChanged(const QTime&)));
 
232
 
 
233
        m_uiSlideshow.m_resizeMethod->addItem(i18n("Scaled & Cropped"), ScaledAndCroppedResize);
 
234
        m_uiSlideshow.m_resizeMethod->addItem(i18n("Scaled"), ScaledResize);
 
235
        m_uiSlideshow.m_resizeMethod->addItem(i18n("Scaled, keep proportions"), MaxpectResize);
 
236
        m_uiSlideshow.m_resizeMethod->addItem(i18n("Centered"), CenteredResize);
 
237
        m_uiSlideshow.m_resizeMethod->addItem(i18n("Tiled"), TiledResize);
 
238
        m_uiSlideshow.m_resizeMethod->addItem(i18n("Center Tiled"), CenterTiledResize);
 
239
        for (int i = 0; i < m_uiSlideshow.m_resizeMethod->count(); ++i) {
 
240
            if (m_resizeMethod == m_uiSlideshow.m_resizeMethod->itemData(i).value<int>()) {
 
241
                m_uiSlideshow.m_resizeMethod->setCurrentIndex(i);
 
242
                break;
 
243
            }
 
244
        }
 
245
        connect(m_uiSlideshow.m_resizeMethod, SIGNAL(currentIndexChanged(int)),
 
246
                this, SLOT(positioningChanged(int)));
 
247
 
 
248
        m_uiSlideshow.m_color->setColor(m_color);
 
249
        //Color button is useless with some resize methods
 
250
        m_uiSlideshow.m_color->setEnabled(m_resizeMethod == MaxpectResize || m_resizeMethod == CenteredResize);
 
251
        connect(m_uiSlideshow.m_color, SIGNAL(changed(const QColor&)), this, SLOT(colorChanged(const QColor&)));
 
252
        connect(m_uiSlideshow.m_newStuff, SIGNAL(clicked()), this, SLOT(getNewWallpaper()));
 
253
 
 
254
        connect(m_uiSlideshow.m_systemCheckBox, SIGNAL(toggled(bool)),
 
255
                this, SLOT(systemCheckBoxToggled(bool)));
 
256
        connect(m_uiSlideshow.m_downloadedCheckBox, SIGNAL(toggled(bool)),
 
257
                this, SLOT(downloadedCheckBoxToggled(bool)));
 
258
        connect(m_uiSlideshow.m_color, SIGNAL(changed(const QColor&)), this, SLOT(modified()));
 
259
        connect(m_uiSlideshow.m_resizeMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(modified()));
 
260
        connect(m_uiSlideshow.m_addDir, SIGNAL(clicked()), this, SLOT(modified()));
 
261
        connect(m_uiSlideshow.m_removeDir, SIGNAL(clicked()), this, SLOT(modified()));
 
262
        connect(m_uiSlideshow.m_slideshowDelay, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(modified()));
 
263
        connect(m_uiSlideshow.m_dirlist, SIGNAL(currentRowChanged (int)), SLOT(updateDirs()));
 
264
    }
 
265
 
 
266
    connect(this, SIGNAL(settingsChanged(bool)), parent, SLOT(settingsChanged(bool)));
 
267
    return m_configWidget;
 
268
}
 
269
 
 
270
void Image::systemCheckBoxToggled(bool checked)
 
271
{
 
272
    if (checked) {
 
273
        m_dirs << KStandardDirs::installPath("wallpaper");
 
274
    } else {
 
275
        m_dirs.removeAll(KStandardDirs::installPath("wallpaper"));
 
276
    }
 
277
    modified();
 
278
}
 
279
 
 
280
void Image::downloadedCheckBoxToggled(bool checked)
 
281
{
 
282
    if (checked) {
 
283
        m_dirs << KGlobal::dirs()->saveLocation("wallpaper");
 
284
    } else {
 
285
        m_dirs.removeAll(KGlobal::dirs()->saveLocation("wallpaper"));
 
286
    }
 
287
    modified();
 
288
}
 
289
 
 
290
void Image::setConfigurationInterfaceModel()
 
291
{
 
292
    m_uiImage.m_view->setModel(m_model);
 
293
    connect(m_uiImage.m_view->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(pictureChanged(const QModelIndex &)));
 
294
 
 
295
    QModelIndex index = m_model->indexOf(m_wallpaper);
 
296
    if (index.isValid()) {
 
297
        m_uiImage.m_view->setCurrentIndex(index);
 
298
    }
 
299
}
 
300
 
 
301
void Image::modified()
 
302
{
 
303
    emit settingsChanged(true);
 
304
}
 
305
 
 
306
void Image::calculateGeometry()
 
307
{
 
308
    m_size = boundingRect().size().toSize();
 
309
 
 
310
    if (m_model) {
 
311
        m_model->setWallpaperSize(m_size);
 
312
    }
 
313
}
 
314
 
 
315
void Image::paint(QPainter *painter, const QRectF& exposedRect)
 
316
{
 
317
    // Check if geometry changed
 
318
    //kDebug() << m_size << boundingRect().size().toSize();
 
319
    if (m_size != boundingRect().size().toSize()) {
 
320
        calculateGeometry();
 
321
        if (!m_size.isEmpty() && !m_img.isEmpty()) { // We have previous image
 
322
            painter->fillRect(exposedRect, QBrush(m_color));
 
323
            renderWallpaper();
 
324
            //kDebug() << "re-rendering";
 
325
            return;
 
326
        }
 
327
    }
 
328
 
 
329
    if (m_pixmap.isNull()) {
 
330
        painter->fillRect(exposedRect, QBrush(m_color));
 
331
        //kDebug() << "pixmap null";
 
332
        return;
 
333
    }
 
334
 
 
335
    if (painter->worldMatrix() == QMatrix()) {
 
336
        // draw the background untransformed when possible;(saves lots of per-pixel-math)
 
337
        painter->resetTransform();
 
338
    }
 
339
 
 
340
    // blit the background (saves all the per-pixel-products that blending does)
 
341
    painter->setCompositionMode(QPainter::CompositionMode_Source);
 
342
 
 
343
    // for pixmaps we draw only the exposed part (untransformed since the
 
344
    // bitmapBackground already has the size of the viewport)
 
345
    painter->drawPixmap(exposedRect, m_pixmap, exposedRect.translated(-boundingRect().topLeft()));
 
346
 
 
347
    if (!m_oldFadedPixmap.isNull()) {
 
348
        // Put old faded image on top.
 
349
        painter->setCompositionMode(QPainter::CompositionMode_SourceAtop);
 
350
        painter->drawPixmap(exposedRect, m_oldFadedPixmap,
 
351
                            exposedRect.translated(-boundingRect().topLeft()));
 
352
    }
 
353
}
 
354
 
 
355
void Image::timeChanged(const QTime& time)
 
356
{
 
357
    m_delay = QTime(0, 0, 0).secsTo(time);
 
358
    if (!m_slideshowBackgrounds.isEmpty()) {
 
359
        m_timer.start(m_delay * 1000);
 
360
    }
 
361
}
 
362
 
 
363
void Image::addDir()
 
364
{
 
365
    KUrl empty;
 
366
    KDirSelectDialog *dialog = new KDirSelectDialog(empty, true, m_configWidget);
 
367
    connect(dialog, SIGNAL(finished()), this, SLOT(addDirFromSelectionDialog()));
 
368
    dialog->show();
 
369
}
 
370
 
 
371
void Image::addDirFromSelectionDialog()
 
372
{
 
373
    KDirSelectDialog *dialog = qobject_cast<KDirSelectDialog *>(sender());
 
374
    if (dialog) {
 
375
        QString urlDir = dialog->url().path();
 
376
        if (!urlDir.isEmpty() && m_uiSlideshow.m_dirlist->findItems(urlDir, Qt::MatchExactly).isEmpty()) {
 
377
            m_uiSlideshow.m_dirlist->addItem(urlDir);
 
378
            updateDirs();
 
379
            startSlideshow();
 
380
        }
 
381
    }
 
382
}
 
383
 
 
384
void Image::removeDir()
 
385
{
 
386
    int row = m_uiSlideshow.m_dirlist->currentRow();
 
387
    if (row != -1) {
 
388
        m_uiSlideshow.m_dirlist->takeItem(row);
 
389
        updateDirs();
 
390
        startSlideshow();
 
391
    }
 
392
}
 
393
 
 
394
void Image::updateDirs()
 
395
{
 
396
    m_dirs.clear();
 
397
 
 
398
    if (m_uiSlideshow.m_systemCheckBox->isChecked()) {
 
399
        m_dirs << KStandardDirs::installPath("wallpaper");
 
400
    }
 
401
    if (m_uiSlideshow.m_downloadedCheckBox->isChecked()) {
 
402
        m_dirs << KGlobal::dirs()->saveLocation("wallpaper");
 
403
    }
 
404
 
 
405
    const int dirCount = m_uiSlideshow.m_dirlist->count();
 
406
    for (int i = 0; i < dirCount; ++i) {
 
407
        m_dirs.append(m_uiSlideshow.m_dirlist->item(i)->text());
 
408
    }
 
409
 
 
410
    m_uiSlideshow.m_removeDir->setEnabled(m_uiSlideshow.m_dirlist->currentRow() != -1);
 
411
}
 
412
 
 
413
void Image::setSingleImage()
 
414
{
 
415
    if (m_wallpaper.isEmpty()) {
 
416
        useSingleImageDefaults();
 
417
    }
 
418
 
 
419
    QString img;
 
420
 
 
421
    if (QDir::isAbsolutePath(m_wallpaper)) {
 
422
        Plasma::Package b(m_wallpaper, packageStructure(this));
 
423
        img = b.filePath("preferred");
 
424
        //kDebug() << img << m_wallpaper;
 
425
 
 
426
        if (img.isEmpty() && QFile::exists(m_wallpaper)) {
 
427
            img = m_wallpaper;
 
428
        }
 
429
    } else {
 
430
        //if it's not an absolute path, check if it's just a wallpaper name
 
431
        const QString path = KStandardDirs::locate("wallpaper", m_wallpaper + "/metadata.desktop");
 
432
 
 
433
        if (!path.isEmpty()) {
 
434
            QDir dir(path);
 
435
            dir.cdUp();
 
436
 
 
437
            Plasma::Package b(dir.path(), packageStructure(this));
 
438
            img = b.filePath("preferred");
 
439
        }
 
440
    }
 
441
 
 
442
    if (img.isEmpty()) {
 
443
        // ok, so the package we have failed to work out; let's try the default
 
444
        // if we have already
 
445
        const QString wallpaper = m_wallpaper;
 
446
        useSingleImageDefaults();
 
447
        if (wallpaper != m_wallpaper) {
 
448
            setSingleImage();
 
449
        }
 
450
    }
 
451
 
 
452
    if (!m_size.isEmpty()) {
 
453
        renderWallpaper(img);
 
454
    }
 
455
}
 
456
 
 
457
void Image::addUrls(const KUrl::List &urls)
 
458
{
 
459
    bool first = true;
 
460
    foreach (const KUrl &url, urls) {
 
461
        // set the first drop as the current paper, just add the rest to the roll
 
462
        addUrl(url, first);
 
463
        first = false;
 
464
    }
 
465
}
 
466
 
 
467
void Image::addUrl(const KUrl &url, bool setAsCurrent)
 
468
{
 
469
    ///kDebug() << "droppage!" << url << url.isLocalFile();
 
470
    if (url.isLocalFile()) {
 
471
        const QString path = url.toLocalFile();
 
472
        if (setAsCurrent) {
 
473
            setWallpaper(path);
 
474
        } else {
 
475
            if (m_wallpaper.isEmpty()) {
 
476
                // it's a slide show, add it to the slide show
 
477
                m_slideshowBackgrounds.append(path);
 
478
            }
 
479
 
 
480
            // always add it to the user papers, though
 
481
            if (!m_usersWallpapers.contains(path)) {
 
482
                m_usersWallpapers.append(path);
 
483
            }
 
484
        }
 
485
    } else {
 
486
        QString wallpaperPath = KGlobal::dirs()->locateLocal("wallpaper", url.fileName());
 
487
 
 
488
        if (!wallpaperPath.isEmpty()) {
 
489
            KIO::FileCopyJob *job = KIO::file_copy(url, KUrl(wallpaperPath));
 
490
            if (setAsCurrent) {
 
491
                connect(job, SIGNAL(result(KJob*)), this, SLOT(setWallpaperRetrieved(KJob*)));
 
492
            } else {
 
493
                connect(job, SIGNAL(result(KJob*)), this, SLOT(addWallpaperRetrieved(KJob*)));
 
494
            }
 
495
        }
 
496
    }
 
497
}
 
498
 
 
499
void Image::setWallpaperRetrieved(KJob *job)
 
500
{
 
501
    KIO::FileCopyJob *copyJob = qobject_cast<KIO::FileCopyJob *>(job);
 
502
    if (copyJob && !copyJob->error()) {
 
503
        setWallpaper(copyJob->destUrl().toLocalFile());
 
504
    }
 
505
}
 
506
 
 
507
void Image::addWallpaperRetrieved(KJob *job)
 
508
{
 
509
    KIO::FileCopyJob *copyJob = qobject_cast<KIO::FileCopyJob *>(job);
 
510
    if (copyJob && !copyJob->error()) {
 
511
        addUrl(copyJob->destUrl(), false);
 
512
    }
 
513
}
 
514
 
 
515
void Image::setWallpaper(const QString &path)
 
516
{
 
517
    if (m_wallpaper.isEmpty()) {
 
518
        m_slideshowBackgrounds.append(path);
 
519
        m_currentSlide = m_slideshowBackgrounds.size() - 2;
 
520
        nextSlide();
 
521
        updateWallpaperActions();
 
522
    } else {
 
523
        m_wallpaper = path;
 
524
        setSingleImage();
 
525
    }
 
526
 
 
527
    if (!m_usersWallpapers.contains(path)) {
 
528
        m_usersWallpapers.append(path);
 
529
    }
 
530
}
 
531
 
 
532
void Image::startSlideshow()
 
533
{
 
534
    // populate background list
 
535
    m_timer.stop();
 
536
    m_slideshowBackgrounds.clear();
 
537
    BackgroundFinder *finder = new BackgroundFinder(this, m_dirs);
 
538
    m_findToken = finder->token();
 
539
    connect(finder, SIGNAL(backgroundsFound(QStringList,QString)), this, SLOT(backgroundsFound(QStringList,QString)));
 
540
    finder->start();
 
541
    //TODO: what would be cool: paint on the wallpaper itself a busy widget and perhaps some text
 
542
    //about loading wallpaper slideshow while the thread runs
 
543
}
 
544
 
 
545
void Image::backgroundsFound(const QStringList &paths, const QString &token)
 
546
{
 
547
    if (token != m_findToken) {
 
548
        return;
 
549
    }
 
550
 
 
551
    m_slideshowBackgrounds = paths;
 
552
    updateWallpaperActions();
 
553
    // start slideshow
 
554
    if (m_slideshowBackgrounds.isEmpty()) {
 
555
        m_pixmap = QPixmap();
 
556
        emit update(boundingRect());
 
557
    } else {
 
558
        m_currentSlide = -1;
 
559
        nextSlide();
 
560
        m_timer.start(m_delay * 1000);
 
561
    }
 
562
}
 
563
 
 
564
void Image::updateWallpaperActions()
 
565
{
 
566
    if (m_nextWallpaperAction) {
 
567
        m_nextWallpaperAction->setEnabled(!m_slideshowBackgrounds.isEmpty());
 
568
    }
 
569
 
 
570
    if (m_openImageAction) {
 
571
        m_openImageAction->setEnabled(!m_slideshowBackgrounds.isEmpty());
 
572
    }
 
573
}
 
574
 
 
575
void Image::getNewWallpaper()
 
576
{
 
577
    if (!m_newStuffDialog) {
 
578
        m_newStuffDialog = new KNS3::DownloadDialog( "wallpaper.knsrc", m_configWidget );
 
579
        connect(m_newStuffDialog.data(), SIGNAL(accepted()), SLOT(newStuffFinished()));
 
580
    }
 
581
    m_newStuffDialog.data()->show();
 
582
}
 
583
 
 
584
void Image::newStuffFinished()
 
585
{
 
586
    if (m_model && (!m_newStuffDialog || m_newStuffDialog.data()->changedEntries().size() > 0)) {
 
587
        m_model->reload();
 
588
    }
 
589
}
 
590
 
 
591
void Image::colorChanged(const QColor& color)
 
592
{
 
593
    m_color = color;
 
594
    setSingleImage();
 
595
}
 
596
 
 
597
void Image::pictureChanged(const QModelIndex &index)
 
598
{
 
599
    if (index.row() == -1 || !m_model) {
 
600
        return;
 
601
    }
 
602
 
 
603
    Plasma::Package *b = m_model->package(index.row());
 
604
    if (!b) {
 
605
        return;
 
606
    }
 
607
 
 
608
    if (b->structure()->contentsPrefixPaths().isEmpty()) {
 
609
        // it's not a full package, but a single paper
 
610
        m_wallpaper = b->filePath("preferred");
 
611
    } else {
 
612
        m_wallpaper = b->path();
 
613
    }
 
614
 
 
615
    setSingleImage();
 
616
}
 
617
 
 
618
void Image::positioningChanged(int index)
 
619
{
 
620
    if (m_mode == "SingleImage") {
 
621
        m_resizeMethod = (ResizeMethod)m_uiImage.m_resizeMethod->itemData(index).value<int>();
 
622
        setSingleImage();
 
623
 
 
624
        //Color button is useless with some resize methods
 
625
        m_uiImage.m_color->setEnabled(m_resizeMethod == MaxpectResize || m_resizeMethod == CenteredResize);
 
626
 
 
627
    } else {
 
628
        m_resizeMethod = (ResizeMethod)m_uiSlideshow.m_resizeMethod->itemData(index).value<int>();
 
629
        startSlideshow();
 
630
 
 
631
        //Color button is useless with some resize methods
 
632
        m_uiSlideshow.m_color->setEnabled(m_resizeMethod == MaxpectResize || m_resizeMethod == CenteredResize);
 
633
    }
 
634
 
 
635
    setResizeMethodHint(m_resizeMethod);
 
636
 
 
637
    if (m_model) {
 
638
        m_model->setResizeMethod(m_resizeMethod);
 
639
    }
 
640
}
 
641
 
 
642
void Image::showFileDialog()
 
643
{
 
644
    if (!m_dialog) {
 
645
        KUrl baseUrl;
 
646
        if(m_wallpaper.indexOf(QDir::homePath()) > -1){
 
647
            baseUrl = KUrl(m_wallpaper);
 
648
        }
 
649
 
 
650
        m_dialog = new KFileDialog(baseUrl, "*.png *.jpeg *.jpg *.xcf *.svg *.svgz *.bmp", m_configWidget);
 
651
        m_dialog->setOperationMode(KFileDialog::Opening);
 
652
        m_dialog->setInlinePreviewShown(true);
 
653
        m_dialog->setCaption(i18n("Select Wallpaper Image File"));
 
654
        m_dialog->setModal(false);
 
655
 
 
656
        connect(m_dialog, SIGNAL(okClicked()), this, SLOT(wallpaperBrowseCompleted()));
 
657
        connect(m_dialog, SIGNAL(destroyed(QObject*)), this, SLOT(fileDialogFinished()));
 
658
    }
 
659
 
 
660
    m_dialog->show();
 
661
    m_dialog->raise();
 
662
    m_dialog->activateWindow();
 
663
}
 
664
 
 
665
void Image::fileDialogFinished()
 
666
{
 
667
    m_dialog = 0;
 
668
}
 
669
 
 
670
void Image::wallpaperBrowseCompleted()
 
671
{
 
672
    Q_ASSERT(m_model);
 
673
 
 
674
    const QFileInfo info(m_dialog->selectedFile());
 
675
 
 
676
    //the full file path, so it isn't broken when dealing with symlinks
 
677
    const QString wallpaper = info.canonicalFilePath();
 
678
 
 
679
 
 
680
    if (wallpaper.isEmpty()) {
 
681
        return;
 
682
    }
 
683
 
 
684
    if (m_model->contains(wallpaper)) {
 
685
        m_uiImage.m_view->setCurrentIndex(m_model->indexOf(wallpaper));
 
686
        return;
 
687
    }
 
688
 
 
689
    // add background to the model
 
690
    m_model->addBackground(wallpaper);
 
691
 
 
692
    // select it
 
693
    QModelIndex index = m_model->indexOf(wallpaper);
 
694
    if (index.isValid()) {
 
695
        m_uiImage.m_view->setCurrentIndex(index);
 
696
        pictureChanged(index);
 
697
        modified();
 
698
    }
 
699
 
 
700
    // save it
 
701
    m_usersWallpapers << wallpaper;
 
702
}
 
703
 
 
704
void Image::nextSlide()
 
705
{
 
706
    if (m_slideshowBackgrounds.isEmpty()) {
 
707
        return;
 
708
    }
 
709
 
 
710
    QString previous;
 
711
    if (m_currentSlide >= 0 && m_currentSlide < m_slideshowBackgrounds.size()) {
 
712
        m_wallpaperPackage->setPath(m_slideshowBackgrounds.at(m_currentSlide));
 
713
        previous = m_wallpaperPackage->filePath("preferred");
 
714
    }
 
715
 
 
716
    if (m_randomize) {
 
717
        m_currentSlide = KRandom::random() % m_slideshowBackgrounds.size();
 
718
    } else if (++m_currentSlide >= m_slideshowBackgrounds.size()) {
 
719
        m_currentSlide = 0;
 
720
    }
 
721
 
 
722
    if (!m_wallpaperPackage) {
 
723
        m_wallpaperPackage = new Plasma::Package(m_slideshowBackgrounds.at(m_currentSlide),
 
724
                                                 packageStructure(this));
 
725
    } else {
 
726
        m_wallpaperPackage->setPath(m_slideshowBackgrounds.at(m_currentSlide));
 
727
    }
 
728
 
 
729
    QString current = m_wallpaperPackage->filePath("preferred");
 
730
    if (current == previous) {
 
731
        QFileInfo info(previous);
 
732
        if (m_previousModified == info.lastModified()) {
 
733
            // it hasn't changed since we last loaded it, so try the next one instead
 
734
            if (m_slideshowBackgrounds.count() == 1) {
 
735
                // only one slide, same image, continue on
 
736
                return;
 
737
            }
 
738
 
 
739
            if (++m_currentSlide >= m_slideshowBackgrounds.size()) {
 
740
                m_currentSlide = 0;
 
741
            }
 
742
 
 
743
            m_wallpaperPackage->setPath(m_slideshowBackgrounds.at(m_currentSlide));
 
744
            current = m_wallpaperPackage->filePath("preferred");
 
745
        }
 
746
    }
 
747
 
 
748
    QFileInfo info(current);
 
749
    m_previousModified = info.lastModified();
 
750
 
 
751
    m_timer.stop();
 
752
    renderWallpaper(current);
 
753
    m_timer.start(m_delay * 1000);
 
754
}
 
755
 
 
756
void Image::openSlide()
 
757
{
 
758
    if (!m_wallpaperPackage) {
 
759
        return;
 
760
    }
 
761
 
 
762
    // open in image viewer
 
763
    KUrl filepath(m_wallpaperPackage->filePath("preferred"));
 
764
    kDebug() << "opening file " << filepath.path();
 
765
    new KRun(filepath, NULL);
 
766
}
 
767
 
 
768
void Image::renderWallpaper(const QString& image)
 
769
{
 
770
    if (!m_img.isEmpty()) {
 
771
        m_fileWatch->removeFile(m_img);
 
772
    }
 
773
 
 
774
    if (!image.isEmpty()) {
 
775
        m_img = image;
 
776
    }
 
777
 
 
778
    if (m_img.isEmpty()) {
 
779
        return;
 
780
    }
 
781
 
 
782
    m_fileWatch->addFile(m_img);
 
783
    render(m_img, m_size, m_resizeMethod, m_color);
 
784
}
 
785
 
 
786
void Image::imageFileAltered(const QString &path)
 
787
{
 
788
    if (path == m_img) {
 
789
        renderWallpaper(path);
 
790
    } else {
 
791
        // somehow this got added to the dirwatch, but we don't care about it anymore
 
792
        m_fileWatch->removeFile(path);
 
793
    }
 
794
}
 
795
void Image::updateBackground(const QImage &img)
 
796
{
 
797
    m_oldPixmap = m_pixmap;
 
798
    m_oldFadedPixmap = m_oldPixmap;
 
799
    m_pixmap = QPixmap::fromImage(img);
 
800
 
 
801
    if (!m_oldPixmap.isNull()) {
 
802
        m_animation->start();
 
803
    } else {
 
804
        emit update(boundingRect());
 
805
    }
 
806
}
 
807
 
 
808
void Image::updateScreenshot(QPersistentModelIndex index)
 
809
{
 
810
    m_uiImage.m_view->update(index);
 
811
}
 
812
 
 
813
qreal Image::fadeValue() const
 
814
{
 
815
    return m_fadeValue;
 
816
}
 
817
 
 
818
void Image::setFadeValue(qreal value)
 
819
{
 
820
    m_fadeValue = value;
 
821
 
 
822
    //If we are done, delete the pixmaps and don't draw.
 
823
    if (qFuzzyCompare(m_fadeValue, qreal(1.0))) {
 
824
        m_oldFadedPixmap = QPixmap();
 
825
        m_oldPixmap = QPixmap();
 
826
        emit update(boundingRect());
 
827
        return;
 
828
    }
 
829
 
 
830
    //Create the faded image.
 
831
    m_oldFadedPixmap.fill(Qt::transparent);
 
832
 
 
833
    QPainter p;
 
834
    p.begin(&m_oldFadedPixmap);
 
835
    p.drawPixmap(0, 0, m_oldPixmap);
 
836
 
 
837
    p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
 
838
    p.fillRect(m_oldFadedPixmap.rect(), QColor(0, 0, 0, 254 * (1-m_fadeValue)));//255*((150 - m_fadeValue)/150)));
 
839
 
 
840
    p.end();
 
841
 
 
842
    emit update(boundingRect());
 
843
}
 
844
 
 
845
//FIXME: we have to save the configuration also when the dialog cancel button is clicked.
 
846
void Image::removeWallpaper(QString name)
 
847
{
 
848
    int wallpaperIndex = m_usersWallpapers.indexOf(name);
 
849
    if (wallpaperIndex >= 0){
 
850
        m_usersWallpapers.removeAt(wallpaperIndex);
 
851
        m_model->reload(m_usersWallpapers);
 
852
        //TODO: save the configuration in the right way
 
853
        emit settingsChanged(true);
 
854
    }
 
855
}
 
856
 
 
857
#include "image.moc"