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

« back to all changes in this revision

Viewing changes to plasma/generic/wallpapers/image/backgroundlistmodel.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
#ifndef BACKGROUNDLISTMODEL_CPP
 
2
#define BACKGROUNDLISTMODEL_CPP
 
3
/*
 
4
  Copyright (c) 2007 Paolo Capriotti <p.capriotti@gmail.com>
 
5
 
 
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.
 
10
*/
 
11
 
 
12
#include "backgroundlistmodel.h"
 
13
 
 
14
#include <QFile>
 
15
#include <QDir>
 
16
#include <QThreadPool>
 
17
#include <QUuid>
 
18
 
 
19
#include <KDebug>
 
20
#include <KFileMetaInfo>
 
21
#include <KGlobal>
 
22
#include <KIO/PreviewJob>
 
23
#include <KProgressDialog>
 
24
#include <KStandardDirs>
 
25
 
 
26
#include <Plasma/Package>
 
27
#include <Plasma/PackageStructure>
 
28
 
 
29
#include "backgrounddelegate.h"
 
30
#include "image.h"
 
31
 
 
32
ImageSizeFinder::ImageSizeFinder(const QString &path, QObject *parent)
 
33
    : QObject(parent),
 
34
      m_path(path)
 
35
{
 
36
}
 
37
 
 
38
void ImageSizeFinder::run()
 
39
{
 
40
    QImage image(m_path);
 
41
    emit sizeFound(m_path, image.size());
 
42
}
 
43
 
 
44
 
 
45
BackgroundListModel::BackgroundListModel(Plasma::Wallpaper *listener, QObject *parent)
 
46
    : QAbstractListModel(parent),
 
47
      m_structureParent(listener),
 
48
      m_size(0,0),
 
49
      m_resizeMethod(Plasma::Wallpaper::ScaledResize)
 
50
{
 
51
    connect(&m_dirwatch, SIGNAL(deleted(QString)), this, SLOT(removeBackground(QString)));
 
52
    m_previewUnavailablePix.fill(Qt::transparent);
 
53
    //m_previewUnavailablePix = KIcon("unknown").pixmap(m_previewUnavailablePix.size());
 
54
}
 
55
 
 
56
BackgroundListModel::~BackgroundListModel()
 
57
{
 
58
    qDeleteAll(m_packages);
 
59
}
 
60
 
 
61
void BackgroundListModel::removeBackground(const QString &path)
 
62
{
 
63
    QModelIndex index;
 
64
    while ((index = indexOf(path)).isValid()) {
 
65
        beginRemoveRows(QModelIndex(), index.row(), index.row());
 
66
        Plasma::Package *package = m_packages.at(index.row());
 
67
        m_packages.removeAt(index.row());
 
68
        delete package;
 
69
        endRemoveRows();
 
70
    }
 
71
}
 
72
 
 
73
void BackgroundListModel::reload()
 
74
{
 
75
    reload(QStringList());
 
76
}
 
77
 
 
78
void BackgroundListModel::reload(const QStringList &selected)
 
79
{
 
80
    if (!m_packages.isEmpty()) {
 
81
        beginRemoveRows(QModelIndex(), 0, m_packages.count() - 1);
 
82
        qDeleteAll(m_packages);
 
83
        m_packages.clear();
 
84
        endRemoveRows();
 
85
    }
 
86
 
 
87
    if (!selected.isEmpty()) {
 
88
        processPaths(selected);
 
89
    }
 
90
 
 
91
    const QStringList dirs = KGlobal::dirs()->findDirs("wallpaper", "");
 
92
    kDebug() << "going looking in" << dirs;
 
93
    BackgroundFinder *finder = new BackgroundFinder(m_structureParent, dirs);
 
94
    connect(finder, SIGNAL(backgroundsFound(QStringList,QString)), this, SLOT(backgroundsFound(QStringList,QString)));
 
95
    m_findToken = finder->token();
 
96
    finder->start();
 
97
}
 
98
 
 
99
void BackgroundListModel::backgroundsFound(const QStringList &paths, const QString &token)
 
100
{
 
101
    if (token == m_findToken) {
 
102
        processPaths(paths);
 
103
    }
 
104
}
 
105
 
 
106
void BackgroundListModel::processPaths(const QStringList &paths)
 
107
{
 
108
    QList<Plasma::Package *> newPackages;
 
109
    foreach (const QString &file, paths) {
 
110
        if (!contains(file) && QFile::exists(file)) {
 
111
            Plasma::PackageStructure::Ptr structure = Plasma::Wallpaper::packageStructure(m_structureParent);
 
112
            Plasma::Package *package  = new Plasma::Package(file, structure);
 
113
            if (package->isValid()) {
 
114
                newPackages << package;
 
115
            } else {
 
116
                delete package;
 
117
            }
 
118
        }
 
119
    }
 
120
 
 
121
    // add new files to dirwatch
 
122
    foreach (Plasma::Package *b, newPackages) {
 
123
        if (!m_dirwatch.contains(b->path())) {
 
124
            m_dirwatch.addFile(b->path());
 
125
        }
 
126
    }
 
127
 
 
128
    if (!newPackages.isEmpty()) {
 
129
        const int start = rowCount();
 
130
        beginInsertRows(QModelIndex(), start, start + newPackages.size());
 
131
        m_packages.append(newPackages);
 
132
        endInsertRows();
 
133
    }
 
134
    //kDebug() << t.elapsed();
 
135
}
 
136
 
 
137
void BackgroundListModel::addBackground(const QString& path)
 
138
{
 
139
    if (!contains(path)) {
 
140
        if (!m_dirwatch.contains(path)) {
 
141
            m_dirwatch.addFile(path);
 
142
        }
 
143
        beginInsertRows(QModelIndex(), 0, 0);
 
144
        Plasma::PackageStructure::Ptr structure = Plasma::Wallpaper::packageStructure(m_structureParent);
 
145
        Plasma::Package *pkg = new Plasma::Package(path, structure);
 
146
        m_packages.prepend(pkg);
 
147
        endInsertRows();
 
148
    }
 
149
}
 
150
 
 
151
QModelIndex BackgroundListModel::indexOf(const QString &path) const
 
152
{
 
153
    for (int i = 0; i < m_packages.size(); i++) {
 
154
        // packages will end with a '/', but the path passed in may not
 
155
        QString package = m_packages[i]->path();
 
156
        if (package.at(package.length() - 1) == '/') {
 
157
            package.truncate(package.length() - 1);
 
158
        }
 
159
 
 
160
        if (path.startsWith(package)) {
 
161
            // FIXME: ugly hack to make a difference between local files in the same dir
 
162
            // package->path does not contain the actual file name
 
163
            if ((!m_packages[i]->structure()->contentsPrefixPaths().isEmpty()) ||
 
164
                (path == m_packages[i]->filePath("preferred"))) {
 
165
                return index(i, 0);
 
166
            }
 
167
        }
 
168
    }
 
169
    return QModelIndex();
 
170
}
 
171
 
 
172
bool BackgroundListModel::contains(const QString &path) const
 
173
{
 
174
    return indexOf(path).isValid();
 
175
}
 
176
 
 
177
int BackgroundListModel::rowCount(const QModelIndex &) const
 
178
{
 
179
    return m_packages.size();
 
180
}
 
181
 
 
182
QSize BackgroundListModel::bestSize(Plasma::Package *package) const
 
183
{
 
184
    if (m_sizeCache.contains(package)) {
 
185
        return m_sizeCache.value(package);
 
186
    }
 
187
 
 
188
    const QString image = package->filePath("preferred");
 
189
    if (image.isEmpty()) {
 
190
        return QSize();
 
191
    }
 
192
 
 
193
    KFileMetaInfo info(image, QString(), KFileMetaInfo::TechnicalInfo);
 
194
    QSize size(info.item("http://freedesktop.org/standards/xesam/1.0/core#width").value().toInt(),
 
195
               info.item("http://freedesktop.org/standards/xesam/1.0/core#height").value().toInt());
 
196
    //backup solution if strigi does not work
 
197
    if (size.width() == 0 || size.height() == 0) {
 
198
//        kDebug() << "fall back to QImage, check your strigi";
 
199
        ImageSizeFinder *finder = new ImageSizeFinder(image);
 
200
        connect(finder, SIGNAL(sizeFound(QString,QSize)), this,
 
201
                SLOT(sizeFound(QString,QSize)));
 
202
        QThreadPool::globalInstance()->start(finder);
 
203
        size = QSize(-1, -1);
 
204
    }
 
205
 
 
206
    const_cast<BackgroundListModel *>(this)->m_sizeCache.insert(package, size);
 
207
    return size;
 
208
}
 
209
 
 
210
void BackgroundListModel::sizeFound(const QString &path, const QSize &s)
 
211
{
 
212
    QModelIndex index = indexOf(path);
 
213
    if (index.isValid()) {
 
214
        Plasma::Package *package = m_packages.at(index.row());
 
215
        m_sizeCache.insert(package, s);
 
216
        static_cast<Image *>(m_structureParent)->updateScreenshot(index);
 
217
    }
 
218
}
 
219
 
 
220
QVariant BackgroundListModel::data(const QModelIndex &index, int role) const
 
221
{
 
222
    if (!index.isValid()) {
 
223
        return QVariant();
 
224
    }
 
225
 
 
226
    if (index.row() >= m_packages.size()) {
 
227
        return QVariant();
 
228
    }
 
229
 
 
230
    Plasma::Package *b = package(index.row());
 
231
    if (!b) {
 
232
        return QVariant();
 
233
    }
 
234
 
 
235
    switch (role) {
 
236
    case Qt::DisplayRole: {
 
237
        QString title = b->metadata().name();
 
238
 
 
239
        if (title.isEmpty()) {
 
240
            return QFileInfo(b->filePath("preferred")).completeBaseName();
 
241
        }
 
242
 
 
243
        return title;
 
244
    }
 
245
    break;
 
246
 
 
247
    case BackgroundDelegate::ScreenshotRole: {
 
248
        if (m_previews.contains(b)) {
 
249
            return m_previews.value(b);
 
250
        }
 
251
 
 
252
        KUrl file(b->filePath("preferred"));
 
253
        if (!m_previewJobs.contains(file) && file.isValid()) {
 
254
            KFileItemList list;
 
255
            list.append(KFileItem(file, QString(), 0));
 
256
            KIO::PreviewJob* job = KIO::filePreview(list,
 
257
                                                    QSize(BackgroundDelegate::SCREENSHOT_SIZE,
 
258
                                                    BackgroundDelegate::SCREENSHOT_SIZE/1.6));
 
259
            job->setIgnoreMaximumSize(true);
 
260
            connect(job, SIGNAL(gotPreview(const KFileItem&, const QPixmap&)),
 
261
                    this, SLOT(showPreview(const KFileItem&, const QPixmap&)));
 
262
            connect(job, SIGNAL(failed(const KFileItem&)),
 
263
                    this, SLOT(previewFailed(const KFileItem&)));
 
264
            const_cast<BackgroundListModel *>(this)->m_previewJobs.insert(file, QPersistentModelIndex(index));
 
265
        }
 
266
 
 
267
        const_cast<BackgroundListModel *>(this)->m_previews.insert(b, m_previewUnavailablePix);
 
268
        return m_previewUnavailablePix;
 
269
    }
 
270
    break;
 
271
 
 
272
    case BackgroundDelegate::AuthorRole:
 
273
        return b->metadata().author();
 
274
    break;
 
275
 
 
276
    case BackgroundDelegate::ResolutionRole:{
 
277
        QSize size = bestSize(b);
 
278
 
 
279
        if (size.isValid()) {
 
280
            return QString("%1x%2").arg(size.width()).arg(size.height());
 
281
        }
 
282
 
 
283
        return QString();
 
284
    }
 
285
    break;
 
286
 
 
287
    default:
 
288
        return QVariant();
 
289
    break;
 
290
    }
 
291
}
 
292
 
 
293
void BackgroundListModel::showPreview(const KFileItem &item, const QPixmap &preview)
 
294
{
 
295
    QPersistentModelIndex index = m_previewJobs.value(item.url());
 
296
    m_previewJobs.remove(item.url());
 
297
 
 
298
    if (!index.isValid()) {
 
299
        return;
 
300
    }
 
301
 
 
302
    Plasma::Package *b = package(index.row());
 
303
    if (!b) {
 
304
        return;
 
305
    }
 
306
 
 
307
    m_previews.insert(b, preview);
 
308
    //kDebug() << "preview size:" << preview.size();
 
309
    static_cast<Image *>(m_structureParent)->updateScreenshot(index);
 
310
}
 
311
 
 
312
void BackgroundListModel::previewFailed(const KFileItem &item)
 
313
{
 
314
    m_previewJobs.remove(item.url());
 
315
}
 
316
 
 
317
Plasma::Package* BackgroundListModel::package(int index) const
 
318
{
 
319
    return m_packages.at(index);
 
320
}
 
321
 
 
322
void BackgroundListModel::setWallpaperSize(const QSize& size)
 
323
{
 
324
    m_size = size;
 
325
}
 
326
 
 
327
void BackgroundListModel::setResizeMethod(Plasma::Wallpaper::ResizeMethod resizeMethod)
 
328
{
 
329
    m_resizeMethod = resizeMethod;
 
330
}
 
331
 
 
332
BackgroundFinder::BackgroundFinder(Plasma::Wallpaper *structureParent, const QStringList &paths)
 
333
    : QThread(structureParent),
 
334
      m_structure(Plasma::Wallpaper::packageStructure(structureParent)),
 
335
      m_paths(paths),
 
336
      m_token(QUuid().toString())
 
337
{
 
338
}
 
339
 
 
340
BackgroundFinder::~BackgroundFinder()
 
341
{
 
342
    wait();
 
343
}
 
344
 
 
345
QString BackgroundFinder::token() const
 
346
{
 
347
    return m_token;
 
348
}
 
349
 
 
350
void BackgroundFinder::run()
 
351
{
 
352
    //QTime t;
 
353
    //t.start();
 
354
    QSet<QString> suffixes;
 
355
    suffixes << "png" << "jpeg" << "jpg" << "svg" << "svgz";
 
356
 
 
357
    QStringList papersFound;
 
358
    //kDebug() << "starting with" << m_paths;
 
359
 
 
360
    QDir dir;
 
361
    dir.setFilter(QDir::AllDirs | QDir::Files | QDir::Hidden | QDir::Readable);
 
362
    Plasma::Package pkg(QString(), m_structure);
 
363
 
 
364
    int i;
 
365
    for (i = 0; i < m_paths.count(); ++i) {
 
366
        const QString path = m_paths.at(i);
 
367
        //kDebug() << "doing" << path;
 
368
        dir.setPath(path);
 
369
        const QFileInfoList files = dir.entryInfoList();
 
370
        foreach (const QFileInfo &wp, files) {
 
371
            if (wp.isDir()) {
 
372
                //kDebug() << "directory" << wp.fileName() << validPackages.contains(wp.fileName());
 
373
                const QString name = wp.fileName();
 
374
                if (name == "." || name == "..") {
 
375
                    // do nothing
 
376
                    continue;
 
377
                }
 
378
 
 
379
                const QString filePath = wp.filePath();
 
380
                if (QFile::exists(filePath + "/metadata.desktop")) {
 
381
                    pkg.setPath(filePath);
 
382
                    if (pkg.isValid()) {
 
383
                        papersFound << pkg.path();
 
384
                        continue;
 
385
                        //kDebug() << "gots a" << wp.filePath();
 
386
                    }
 
387
                }
 
388
 
 
389
                // add this to the directories we should be looking at
 
390
                m_paths.append(filePath);
 
391
            } else if (suffixes.contains(wp.suffix().toLower())) {
 
392
                //kDebug() << "     adding image file" << wp.filePath();
 
393
                papersFound << wp.filePath();
 
394
            }
 
395
        }
 
396
    }
 
397
 
 
398
    //kDebug() << "background found!" << papersFound.size() << "in" << i << "dirs, taking" << t.elapsed() << "ms";
 
399
    emit backgroundsFound(papersFound, m_token);
 
400
    deleteLater();
 
401
}
 
402
 
 
403
#include "backgroundlistmodel.moc"
 
404
 
 
405
 
 
406
#endif // BACKGROUNDLISTMODEL_CPP