00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "backgroundlistmodel.h"
00011
00012 #include <QFile>
00013 #include <QDir>
00014
00015 #include <KDebug>
00016 #include <KFileMetaInfo>
00017 #include <KGlobal>
00018 #include <KIO/PreviewJob>
00019 #include <KProgressDialog>
00020 #include <KStandardDirs>
00021
00022 #include <Plasma/Package>
00023 #include <Plasma/PackageStructure>
00024
00025 #include "backgrounddelegate.h"
00026 #include "image.h"
00027
00028 BackgroundListModel::BackgroundListModel(float ratio, Plasma::Wallpaper *listener, QObject *parent)
00029 : QAbstractListModel(parent),
00030 m_listener(listener),
00031 m_structureParent(listener),
00032 m_ratio(ratio),
00033 m_size(0,0),
00034 m_resizeMethod(Plasma::Wallpaper::ScaledResize)
00035 {
00036 connect(&m_dirwatch, SIGNAL(deleted(QString)), this, SLOT(removeBackground(QString)));
00037 }
00038
00039 BackgroundListModel::~BackgroundListModel()
00040 {
00041 qDeleteAll(m_packages);
00042 }
00043
00044 void BackgroundListModel::removeBackground(const QString &path)
00045 {
00046 QModelIndex index;
00047 while ((index = indexOf(path)).isValid()) {
00048 beginRemoveRows(QModelIndex(), index.row(), index.row());
00049 Plasma::Package *package = m_packages.at(index.row());
00050 m_packages.removeAt(index.row());
00051 delete package;
00052 endRemoveRows();
00053 }
00054 }
00055
00056 void BackgroundListModel::reload()
00057 {
00058 reload(QStringList());
00059 }
00060
00061 void BackgroundListModel::reload(const QStringList &selected)
00062 {
00063 const QStringList dirs = KGlobal::dirs()->findDirs("wallpaper", "");
00064 QList<Plasma::Package *> tmp;
00065
00066 if (!m_packages.isEmpty()) {
00067 beginRemoveRows(QModelIndex(), 0, m_packages.count() - 1);
00068 qDeleteAll(m_packages);
00069 m_packages.clear();
00070 endRemoveRows();
00071 }
00072
00073 foreach (const QString &file, selected) {
00074 if (!contains(file) && QFile::exists(file)) {
00075 tmp << new Plasma::Package(file, Plasma::Wallpaper::packageStructure(m_structureParent));
00076 }
00077 }
00078
00079 {
00080 const QStringList backgrounds = findAllBackgrounds(m_structureParent, this, dirs);
00081 foreach (const QString &background, backgrounds) {
00082 tmp << new Plasma::Package(background, Plasma::Wallpaper::packageStructure(m_structureParent));
00083 }
00084 }
00085
00086
00087 foreach (Plasma::Package *b, tmp) {
00088 if (!m_dirwatch.contains(b->path())) {
00089 m_dirwatch.addFile(b->path());
00090 }
00091 }
00092
00093 if (!tmp.isEmpty()) {
00094 beginInsertRows(QModelIndex(), 0, tmp.size() - 1);
00095 m_packages = tmp;
00096 endInsertRows();
00097 }
00098 }
00099
00100 QStringList BackgroundFinder::papersFound() const
00101 {
00102 return m_papersFound;
00103 }
00104
00105 void BackgroundListModel::addBackground(const QString& path)
00106 {
00107 if (!contains(path)) {
00108 if (!m_dirwatch.contains(path)) {
00109 m_dirwatch.addFile(path);
00110 }
00111 beginInsertRows(QModelIndex(), 0, 0);
00112 Plasma::PackageStructure::Ptr structure = Plasma::Wallpaper::packageStructure(m_structureParent);
00113 Plasma::Package *pkg = new Plasma::Package(path, structure);
00114 m_packages.prepend(pkg);
00115 endInsertRows();
00116 }
00117 }
00118
00119 QModelIndex BackgroundListModel::indexOf(const QString &path) const
00120 {
00121 for (int i = 0; i < m_packages.size(); i++) {
00122
00123 QString package = m_packages[i]->path();
00124 if (package.at(package.length() - 1) == '/') {
00125 package.truncate(package.length() - 1);
00126 }
00127
00128 if (path.startsWith(package)) {
00129
00130
00131 if ((!m_packages[i]->structure()->contentsPrefix().isEmpty()) ||
00132 (path == m_packages[i]->filePath("preferred"))) {
00133 return index(i, 0);
00134 }
00135 }
00136 }
00137 return QModelIndex();
00138 }
00139
00140 bool BackgroundListModel::contains(const QString &path) const
00141 {
00142 return indexOf(path).isValid();
00143 }
00144
00145 int BackgroundListModel::rowCount(const QModelIndex &) const
00146 {
00147 return m_packages.size();
00148 }
00149
00150 QSize BackgroundListModel::bestSize(Plasma::Package *package) const
00151 {
00152 if (m_sizeCache.contains(package)) {
00153 return m_sizeCache.value(package);
00154 }
00155
00156 const QString image = package->filePath("preferred");
00157 if (image.isEmpty()) {
00158 return QSize();
00159 }
00160
00161 KFileMetaInfo info(image, QString(), KFileMetaInfo::TechnicalInfo);
00162 QSize size(info.item("http://freedesktop.org/standards/xesam/1.0/core#width").value().toInt(),
00163 info.item("http://freedesktop.org/standards/xesam/1.0/core#height").value().toInt());
00164
00165
00166 if (size.width() == 0 || size.height() == 0) {
00167 kDebug() << "fall back to QImage, check your strigi";
00168 size = QImage(image).size();
00169 }
00170
00171 const_cast<BackgroundListModel *>(this)->m_sizeCache.insert(package, size);
00172 return size;
00173 }
00174
00175 QVariant BackgroundListModel::data(const QModelIndex &index, int role) const
00176 {
00177 if (!index.isValid()) {
00178 return QVariant();
00179 }
00180
00181 if (index.row() >= m_packages.size()) {
00182 return QVariant();
00183 }
00184
00185 Plasma::Package *b = package(index.row());
00186 if (!b) {
00187 return QVariant();
00188 }
00189
00190 switch (role) {
00191 case Qt::DisplayRole: {
00192 QString title = b->metadata().name();
00193
00194 if (title.isEmpty()) {
00195 return QFileInfo(b->filePath("preferred")).completeBaseName();
00196 }
00197
00198 return title;
00199 }
00200 break;
00201
00202 case BackgroundDelegate::ScreenshotRole: {
00203 if (m_previews.contains(b)) {
00204 return m_previews.value(b);
00205 }
00206
00207 KUrl file(b->filePath("preferred"));
00208
00209 if (file.isValid()) {
00210 KIO::PreviewJob* job = KIO::filePreview(KUrl::List() << file,
00211 BackgroundDelegate::SCREENSHOT_SIZE,
00212 BackgroundDelegate::SCREENSHOT_SIZE);
00213
00214 connect(job, SIGNAL(gotPreview(const KFileItem&, const QPixmap&)),
00215 this, SLOT(showPreview(const KFileItem&, const QPixmap&)));
00216 connect(job, SIGNAL(failed(const KFileItem&)),
00217 this, SLOT(previewFailed(const KFileItem&)));
00218 const_cast<BackgroundListModel *>(this)->m_previewJobs.insert(file, QPersistentModelIndex(index));
00219 }
00220
00221 QPixmap pix(BackgroundDelegate::SCREENSHOT_SIZE, BackgroundDelegate::SCREENSHOT_SIZE);
00222 pix.fill(Qt::transparent);
00223 const_cast<BackgroundListModel *>(this)->m_previews.insert(b, pix);
00224 return pix;
00225 }
00226 break;
00227
00228 case BackgroundDelegate::AuthorRole:
00229 return b->metadata().author();
00230 break;
00231
00232 case BackgroundDelegate::ResolutionRole:{
00233 QSize size = bestSize(b);
00234
00235 if (size.isValid()) {
00236 return QString("%1x%2").arg(size.width()).arg(size.height());
00237 }
00238
00239 return QString();
00240 }
00241 break;
00242
00243 default:
00244 return QVariant();
00245 break;
00246 }
00247 }
00248
00249 void BackgroundListModel::showPreview(const KFileItem &item, const QPixmap &preview)
00250 {
00251 QPersistentModelIndex index = m_previewJobs.value(item.url());
00252 m_previewJobs.remove(item.url());
00253
00254 if (!index.isValid()) {
00255 return;
00256 }
00257
00258 Plasma::Package *b = package(index.row());
00259 if (!b) {
00260 return;
00261 }
00262
00263 m_previews.insert(b, preview);
00264 static_cast<Image*>(m_listener)->updateScreenshot(index);
00265 }
00266
00267 void BackgroundListModel::previewFailed(const KFileItem &item)
00268 {
00269 m_previewJobs.remove(item.url());
00270 }
00271
00272 Plasma::Package* BackgroundListModel::package(int index) const
00273 {
00274 return m_packages.at(index);
00275 }
00276
00277 QStringList BackgroundListModel::findAllBackgrounds(Plasma::Wallpaper *structureParent,
00278 const BackgroundListModel *container,
00279 const QStringList &p)
00280 {
00281
00282 QEventLoop localEventLoop;
00283 BackgroundFinder finder(structureParent, container, p, &localEventLoop);
00284 connect(&finder, SIGNAL(finished()), &localEventLoop, SLOT(quit()));
00285 QTimer::singleShot(0, &finder, SLOT(start()));
00286 localEventLoop.exec();
00287 return finder.papersFound();
00288 }
00289
00290 BackgroundFinder::BackgroundFinder(Plasma::Wallpaper *structureParent,
00291 const BackgroundListModel *container,
00292 const QStringList &paths,
00293 QEventLoop *eventLoop)
00294 : QObject(0),
00295 m_structureParent(structureParent),
00296 m_container(container),
00297 m_paths(paths),
00298 m_eventLoop(eventLoop)
00299 {
00300 }
00301
00302 void BackgroundFinder::start()
00303 {
00304 KProgressDialog *progress = new KProgressDialog;
00305 progress->setAllowCancel(false);
00306 progress->setModal(true);
00307 progress->setLabelText(i18n("Finding images for the wallpaper slideshow."));
00308 progress->progressBar()->setRange(0, 0);
00309
00310 QSet<QString> suffixes;
00311 suffixes << "png" << "jpeg" << "jpg" << "svg" << "svgz";
00312
00313 QDir dir;
00314 dir.setFilter(QDir::AllDirs | QDir::Files | QDir::Hidden | QDir::Readable);
00315
00316 int count = 0;
00317 int allCount = 0;
00318 bool setLabel = true;
00319 while (!m_paths.isEmpty()) {
00320 QString path = m_paths.takeLast();
00321
00322 dir.setPath(path);
00323 const QFileInfoList files = dir.entryInfoList();
00324 foreach (const QFileInfo &wp, files) {
00325 if (wp.isDir()) {
00326
00327 QString name = wp.fileName();
00328 if (name == "." || name == "..") {
00329
00330 } else if(QFile::exists(wp.filePath() + "/metadata.desktop")) {
00331 Plasma::PackageStructure::Ptr structure = Plasma::Wallpaper::packageStructure(m_structureParent);
00332 Plasma::Package pkg(wp.filePath(), structure);
00333
00334 if (pkg.isValid() && (!m_container || !m_container->contains(pkg.path()))) {
00335 if (setLabel) {
00336 progress->setLabelText(i18n("Finding images for the wallpaper slideshow.") + "\n\n" +
00337 i18n("Adding wallpaper package in %1", name));
00338 }
00339
00340 ++count;
00341 m_papersFound << pkg.path();
00342
00343 } else {
00344 m_paths.append(wp.filePath());
00345 }
00346 } else {
00347 m_paths.append(wp.filePath());
00348 }
00349 } else if (suffixes.contains(wp.suffix().toLower()) && (!m_container || !m_container->contains(wp.filePath()))) {
00350
00351 if (setLabel) {
00352 progress->setLabelText(i18n("Finding images for the wallpaper slideshow.") + "\n\n" +
00353 i18n("Adding image %1", wp.filePath()));
00354 setLabel = false;
00355 }
00356
00357 ++count;
00358 m_papersFound << wp.filePath();
00359 }
00360
00361 ++allCount;
00362 if (allCount % 10 == 0) {
00363 m_eventLoop->processEvents(QEventLoop::ExcludeUserInputEvents);
00364 if (progress->isVisible() && count % 10) {
00365 setLabel = true;
00366 }
00367 }
00368 }
00369 }
00370
00371 delete progress;
00372 emit finished();
00373 }
00374
00375 void BackgroundListModel::setWallpaperSize(QSize size)
00376 {
00377 m_size = size;
00378 }
00379
00380 void BackgroundListModel::setResizeMethod(Plasma::Wallpaper::ResizeMethod resizeMethod)
00381 {
00382 m_resizeMethod = resizeMethod;
00383 }
00384
00385 #include "backgroundlistmodel.moc"
00386
00387