diff --git a/wallpapers/image/CMakeLists.txt b/wallpapers/image/CMakeLists.txt
index 1cdc0756e..10b4878f5 100644
--- a/wallpapers/image/CMakeLists.txt
+++ b/wallpapers/image/CMakeLists.txt
@@ -1,43 +1,44 @@
add_definitions(-DTRANSLATION_DOMAIN=\"plasma_wallpaper_org.kde.image\")
set(image_SRCS
image.cpp
imageplugin.cpp
backgroundlistmodel.cpp
slidemodel.cpp
+ slidefiltermodel.cpp
)
ecm_qt_declare_logging_category(image_SRCS HEADER debug.h
IDENTIFIER IMAGEWALLPAPER
CATEGORY_NAME kde.wallpapers.image
DEFAULT_SEVERITY Info)
add_library(plasma_wallpaper_imageplugin SHARED ${image_SRCS})
target_link_libraries(plasma_wallpaper_imageplugin
Qt5::Core
Qt5::Quick
Qt5::Qml
KF5::Plasma
KF5::KIOCore
KF5::KIOWidgets
KF5::I18n
KF5::KIOCore
KF5::KIOWidgets # KFileDialog
KF5::NewStuff
)
if(BUILD_TESTING)
add_subdirectory(autotests)
endif()
install(TARGETS plasma_wallpaper_imageplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/wallpapers/image)
install(FILES qmldir DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/plasma/wallpapers/image)
install(FILES wallpaper.knsrc DESTINATION ${KDE_INSTALL_KNSRCDIR})
plasma_install_package(imagepackage org.kde.image wallpapers wallpaper)
plasma_install_package(slideshowpackage org.kde.slideshow wallpapers wallpaper)
install(DIRECTORY imagepackage/contents/ui DESTINATION ${PLASMA_DATA_INSTALL_DIR}/wallpapers/org.kde.slideshow/contents PATTERN .svn EXCLUDE PATTERN CMakeLists.txt EXCLUDE PATTERN Messages.sh EXCLUDE)
diff --git a/wallpapers/image/backgroundlistmodel.h b/wallpapers/image/backgroundlistmodel.h
index 516eb3cae..9ae5a41b5 100644
--- a/wallpapers/image/backgroundlistmodel.h
+++ b/wallpapers/image/backgroundlistmodel.h
@@ -1,152 +1,152 @@
/***************************************************************************
* Copyright 2007 Paolo Capriotti
*
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#ifndef BACKGROUNDLISTMODEL_H
#define BACKGROUNDLISTMODEL_H
#include "image.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class Image;
class ImageSizeFinder : public QObject, public QRunnable
{
Q_OBJECT
public:
explicit ImageSizeFinder(const QString &path, QObject *parent = nullptr);
void run() override;
Q_SIGNALS:
void sizeFound(const QString &path, const QSize &size);
private:
QString m_path;
};
class BackgroundListModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
enum {
AuthorRole = Qt::UserRole,
ScreenshotRole,
ResolutionRole,
PathRole,
PackageNameRole,
RemovableRole,
PendingDeletionRole,
ToggleRole
};
static const int BLUR_INCREMENT = 9;
static const int MARGIN = 6;
BackgroundListModel(Image *listener, QObject *parent);
~BackgroundListModel() override;
QHash roleNames() const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override ;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
KPackage::Package package(int index) const;
void reload();
void reload(const QStringList &selected);
void addBackground(const QString &path);
+ void removeBackground(const QString &path);
Q_INVOKABLE int indexOf(const QString &path) const;
virtual bool contains(const QString &bg) const;
int count() const {return m_packages.size();}
Q_INVOKABLE void openContainingFolder(int rowIndex);
Q_INVOKABLE void setPendingDeletion(int rowIndex, bool pendingDeletion);
const QStringList wallpapersAwaitingDeletion();
Q_SIGNALS:
void countChanged();
protected Q_SLOTS:
- void removeBackground(const QString &path);
void showPreview(const KFileItem &item, const QPixmap &preview);
void previewFailed(const KFileItem &item);
void sizeFound(const QString &path, const QSize &s);
void backgroundsFound(const QStringList &paths, const QString &token);
void processPaths(const QStringList &paths);
protected:
QPointer m_wallpaper;
QString m_findToken;
QList m_packages;
private:
QSize bestSize(const KPackage::Package &package) const;
QSet m_removableWallpapers;
QHash m_sizeCache;
QHash m_previewJobs;
KDirWatch m_dirwatch;
QCache m_imageCache;
int m_screenshotSize;
QHash m_pendingDeletion;
};
class BackgroundFinder : public QThread
{
Q_OBJECT
public:
BackgroundFinder(Image *wallpaper, const QStringList &p);
~BackgroundFinder() override;
QString token() const;
static QStringList suffixes();
static bool isAcceptableSuffix(const QString &suffix);
Q_SIGNALS:
void backgroundsFound(const QStringList &paths, const QString &token);
protected:
void run() override;
private:
QStringList m_paths;
QString m_token;
static QMutex s_suffixMutex;
static QStringList s_suffixes;
};
#endif // BACKGROUNDLISTMODEL_H
diff --git a/wallpapers/image/image.cpp b/wallpapers/image/image.cpp
index 5d9e4c64f..65c05bdbf 100644
--- a/wallpapers/image/image.cpp
+++ b/wallpapers/image/image.cpp
@@ -1,929 +1,923 @@
/***************************************************************************
* Copyright 2007 Paolo Capriotti *
* Copyright 2007 Aaron Seigo *
* Copyright 2008 Petri Damsten *
* Copyright 2008 Alexis Ménard *
* Copyright 2014 Sebastian Kügler *
* Copyright 2015 Kai Uwe Broulik *
+ * Copyright 2019 David Redondo *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#include "image.h"
#include "debug.h"
#include
#include // FLT_MAX
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "backgroundlistmodel.h"
#include "slidemodel.h"
+#include "slidefiltermodel.h"
#include
Image::Image(QObject *parent)
: QObject(parent),
m_ready(false),
m_delay(10),
m_dirWatch(new KDirWatch(this)),
m_mode(SingleImage),
+ m_slideshowMode(Random),
m_currentSlide(-1),
m_model(nullptr),
- m_slideshowModel(nullptr),
+ m_slideshowModel(new SlideModel(this, this)),
+ m_slideFilterModel(new SlideFilterModel(this)),
m_dialog(nullptr)
{
m_wallpaperPackage = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Wallpaper/Images"));
connect(&m_timer, &QTimer::timeout, this, &Image::nextSlide);
connect(m_dirWatch, &KDirWatch::created, this, &Image::pathCreated);
connect(m_dirWatch, &KDirWatch::dirty, this, &Image::pathDirty);
connect(m_dirWatch, &KDirWatch::deleted, this, &Image::pathDeleted);
m_dirWatch->startScan();
+ m_slideFilterModel->setSourceModel(m_slideshowModel);
+ connect(this, &Image::uncheckedSlidesChanged, m_slideFilterModel, &SlideFilterModel::invalidateFilter);
+
useSingleImageDefaults();
+
}
Image::~Image()
{
delete m_dialog;
}
void Image::classBegin()
{
}
void Image::componentComplete()
{
// don't bother loading single image until all properties have settled
// otherwise we would load a too small image (initial view size) just
// to load the proper one afterwards etc etc
m_ready = true;
if (m_mode == SingleImage) {
setSingleImage();
} else if (m_mode == SlideShow) {
startSlideshow();
}
}
QString Image::photosPath() const
{
return QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
}
QUrl Image::wallpaperPath() const
{
return QUrl::fromLocalFile(m_wallpaperPath);
}
void Image::addUrl(const QString &url)
{
addUrl(QUrl(url), true);
}
void Image::addUrls(const QStringList &urls)
{
bool first = true;
for (const QString &url: urls) {
// set the first drop as the current paper, just add the rest to the roll
addUrl(QUrl(url), first);
first = false;
}
}
Image::RenderingMode Image::renderingMode() const
{
return m_mode;
}
void Image::setRenderingMode(RenderingMode mode)
{
if (mode == m_mode) {
return;
}
m_mode = mode;
if (m_mode == SlideShow) {
if (m_slidePaths.isEmpty()) {
m_slidePaths << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("share/wallpapers"), QStandardPaths::LocateDirectory);
}
startSlideshow();
updateDirWatch(m_slidePaths);
updateDirWatch(m_slidePaths);
} else {
// we need to reset the preferred image
setSingleImage();
}
}
+Image::SlideshowMode Image::slideshowMode() const
+{
+ return m_slideshowMode;
+}
+
+void Image::setSlideshowMode(Image::SlideshowMode mode)
+{
+ if (mode == m_slideshowMode) {
+ return;
+ }
+ m_slideshowMode = mode;
+ m_slideFilterModel->setSortingMode(mode);
+ m_slideFilterModel->sort(0);
+ if (m_mode == SlideShow) {
+ startSlideshow();
+ }
+ emit slideshowModeChanged();
+}
+
float distance(const QSize& size, const QSize& desired)
{
// compute difference of areas
float desiredAspectRatio = ( desired.height() > 0 ) ? desired.width() / (float)desired.height() : 0;
float candidateAspectRatio = ( size.height() > 0 ) ? size.width() / (float)size.height() : FLT_MAX;
float delta = size.width() - desired.width();
delta = (delta >= 0.0 ? delta : -delta*2 ); // Penalize for scaling up
return qAbs(candidateAspectRatio - desiredAspectRatio)*25000 + delta;
}
QSize resSize(const QString &str)
{
int index = str.indexOf('x');
if (index != -1) {
return QSize(str.leftRef(index).toInt(),
str.midRef(index + 1).toInt());
}
return QSize();
}
QString Image::findPreferedImage(const QStringList &images)
{
if (images.empty()) {
return QString();
}
//float targetAspectRatio = (m_targetSize.height() > 0 ) ? m_targetSize.width() / (float)m_targetSize.height() : 0;
//qCDebug(IMAGEWALLPAPER) << "wanted" << m_targetSize << "options" << images << "aspect ratio" << targetAspectRatio;
float best = FLT_MAX;
QString bestImage;
foreach (const QString &entry, images) {
QSize candidate = resSize(QFileInfo(entry).baseName());
if (candidate == QSize()) {
continue;
}
//float candidateAspectRatio = (candidate.height() > 0 ) ? candidate.width() / (float)candidate.height() : FLT_MAX;
float dist = distance(candidate, m_targetSize);
//qCDebug(IMAGEWALLPAPER) << "candidate" << candidate << "distance" << dist << "aspect ratio" << candidateAspectRatio;
if (bestImage.isEmpty() || dist < best) {
bestImage = entry;
best = dist;
//qCDebug(IMAGEWALLPAPER) << "best" << bestImage;
}
}
//qCDebug(IMAGEWALLPAPER) << "best image" << bestImage;
return bestImage;
}
void Image::findPreferedImageInPackage(KPackage::Package &package)
{
if (!package.isValid() || !package.filePath("preferred").isEmpty()) {
return;
}
QString preferred = findPreferedImage( package.entryList("images") );
package.removeDefinition("preferred");
package.addFileDefinition("preferred", QStringLiteral("images/") + preferred, i18n("Recommended wallpaper file"));
}
QSize Image::targetSize() const
{
return m_targetSize;
}
void Image::setTargetSize(const QSize &size)
{
bool sizeChanged = m_targetSize != size;
m_targetSize = size;
if (m_mode == SingleImage) {
if (sizeChanged) {
// If screen size was changed, we may want to select a new preferred image
// which has correct aspect ratio for the new screen size.
m_wallpaperPackage.removeDefinition("preferred");
}
setSingleImage();
}
if (sizeChanged) {
emit targetSizeChanged();
}
}
KPackage::Package *Image::package()
{
return &m_wallpaperPackage;
}
void Image::useSingleImageDefaults()
{
Plasma::Theme theme;
m_wallpaper = theme.wallpaperPath();
int index = m_wallpaper.indexOf(QString::fromLatin1("/contents/images/"));
if (index > -1) { // We have file from package -> get path to package
m_wallpaper = m_wallpaper.left(index);
}
}
QAbstractItemModel* Image::wallpaperModel()
{
if (!m_model) {
KConfigGroup cfg = KConfigGroup(KSharedConfig::openConfig(QStringLiteral("plasmarc")),
QStringLiteral("Wallpapers"));
m_usersWallpapers = cfg.readEntry("usersWallpapers", m_usersWallpapers);
m_model = new BackgroundListModel(this, this);
m_model->reload(m_usersWallpapers);
}
return m_model;
}
-QAbstractItemModel* Image::slideshowModel()
-{
- if (!m_slideshowModel) {
- m_slideshowModel = new SlideModel(this, this);
- m_slideshowModel->reload(m_slidePaths);
- }
- return m_slideshowModel;
+QAbstractItemModel * Image::slideFilterModel() {
+ return m_slideFilterModel;
}
-
int Image::slideTimer() const
{
return m_delay;
}
void Image::setSlideTimer(int time)
{
if (time == m_delay) {
return;
}
m_delay = time;
if (m_mode == SlideShow) {
updateDirWatch(m_slidePaths);
startSlideshow();
}
emit slideTimerChanged();
}
QStringList Image::usersWallpapers() const
{
return m_usersWallpapers;
}
void Image::setUsersWallpapers(const QStringList &usersWallpapers)
{
if (usersWallpapers == m_usersWallpapers) {
return;
}
m_usersWallpapers = usersWallpapers;
emit usersWallpapersChanged();
}
QStringList Image::slidePaths() const
{
return m_slidePaths;
}
void Image::setSlidePaths(const QStringList &slidePaths)
{
if (slidePaths == m_slidePaths) {
return;
}
m_slidePaths = slidePaths;
m_slidePaths.removeAll(QString());
if (m_slidePaths.isEmpty()) {
m_slidePaths << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("share/wallpapers"), QStandardPaths::LocateDirectory);
}
if (m_mode == SlideShow) {
updateDirWatch(m_slidePaths);
startSlideshow();
}
if (m_slideshowModel) {
m_slideshowModel->reload(m_slidePaths);
}
emit slidePathsChanged();
}
void Image::showAddSlidePathsDialog()
{
QFileDialog *dialog = new QFileDialog(nullptr, i18n("Directory with the wallpaper to show slides from"), QString());
dialog->setAttribute(Qt::WA_DeleteOnClose, true );
dialog->setOptions(QFileDialog::ShowDirsOnly);
dialog->setAcceptMode(QFileDialog::AcceptOpen);
connect(dialog, &QDialog::accepted, this, &Image::addDirFromSelectionDialog);
dialog->show();
}
void Image::addSlidePath(const QString &path)
{
if (!path.isEmpty() && !m_slidePaths.contains(path)) {
m_slidePaths.append(path);
if (m_mode == SlideShow) {
updateDirWatch(m_slidePaths);
}
if (m_slideshowModel) {
m_slideshowModel->addDirs({m_slidePaths});
}
emit slidePathsChanged();
startSlideshow();
}
}
void Image::removeSlidePath(const QString &path)
{
if (m_slidePaths.contains(path)) {
m_slidePaths.removeAll(path);
if (m_mode == SlideShow) {
updateDirWatch(m_slidePaths);
}
if (m_slideshowModel) {
bool haveParent = false;
QStringList children;
for (const QString& slidePath : m_slidePaths) {
if (path.startsWith(slidePath)) {
haveParent = true;
}
if (slidePath.startsWith(path)) {
children.append(slidePath);
}
}
/*If we have the parent directory do nothing since the directories are recursively searched.
* If we have child directories just reload since removing the parent and then readding the children would
* induce a race.*/
if (!haveParent) {
if (children.size() > 0) {
m_slideshowModel->reload(m_slidePaths);
} else {
m_slideshowModel->removeDir(path);
}
}
}
emit slidePathsChanged();
startSlideshow();
}
}
void Image::pathDirty(const QString& path)
{
updateDirWatch(QStringList(path));
}
void Image::updateDirWatch(const QStringList &newDirs)
{
Q_FOREACH(const QString &oldDir, m_dirs) {
if(!newDirs.contains(oldDir)) {
m_dirWatch->removeDir(oldDir);
}
}
Q_FOREACH(const QString &newDir, newDirs) {
if(!m_dirWatch->contains(newDir)) {
m_dirWatch->addDir(newDir, KDirWatch::WatchSubDirs | KDirWatch::WatchFiles);
}
}
m_dirs = newDirs;
}
void Image::addDirFromSelectionDialog()
{
QFileDialog *dialog = qobject_cast(sender());
if (dialog) {
addSlidePath(dialog->directoryUrl().toLocalFile());
}
}
void Image::syncWallpaperPackage()
{
m_wallpaperPackage.setPath(m_wallpaper);
findPreferedImageInPackage(m_wallpaperPackage);
m_wallpaperPath = m_wallpaperPackage.filePath("preferred");
}
void Image::setSingleImage()
{
if (!m_ready) {
return;
}
// supposedly QSize::isEmpty() is true if "either width or height are >= 0"
if (!m_targetSize.width() || !m_targetSize.height()) {
return;
}
const QString oldPath = m_wallpaperPath;
if (m_wallpaper.isEmpty()) {
useSingleImageDefaults();
}
QString img;
if (QDir::isAbsolutePath(m_wallpaper)) {
syncWallpaperPackage();
if (QFile::exists(m_wallpaperPath)) {
img = m_wallpaperPath;
}
} else {
//if it's not an absolute path, check if it's just a wallpaper name
QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("wallpapers/") + m_wallpaper + QString::fromLatin1("/metadata.json"));
if (path.isEmpty())
path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("wallpapers/") + m_wallpaper + QString::fromLatin1("/metadata.desktop"));
if (!path.isEmpty()) {
QDir dir(path);
dir.cdUp();
syncWallpaperPackage();
img = m_wallpaperPath;
}
}
if (img.isEmpty()) {
// ok, so the package we have failed to work out; let's try the default
useSingleImageDefaults();
syncWallpaperPackage();
}
if (m_wallpaperPath != oldPath) {
Q_EMIT wallpaperPathChanged();
}
}
void Image::addUrls(const QList &urls)
{
bool first = true;
Q_FOREACH (const QUrl &url, urls) {
// set the first drop as the current paper, just add the rest to the roll
addUrl(url, first);
first = false;
}
}
void Image::addUrl(const QUrl &url, bool setAsCurrent)
{
QString path;
if (url.isLocalFile()) {
path = url.toLocalFile();
} else if (url.scheme().isEmpty()) {
if (QDir::isAbsolutePath(url.path())) {
path = url.path();
} else {
path = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
QLatin1String("wallpapers/") + url.path(),
QStandardPaths::LocateDirectory);
}
if (path.isEmpty()) {
return;
}
} else {
QString wallpaperPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("wallpapers/") + url.path();
if (!wallpaperPath.isEmpty()) {
KIO::FileCopyJob *job = KIO::file_copy(url, QUrl(wallpaperPath), -1, KIO::HideProgressInfo);
if (setAsCurrent) {
connect(job, &KJob::result, this, &Image::setWallpaperRetrieved);
} else {
connect(job, &KJob::result, this, &Image::addWallpaperRetrieved);
}
}
return;
}
if (setAsCurrent) {
setWallpaper(path);
} else {
if (m_mode != SingleImage) {
// it's a slide show, add it to the slide show
- m_slideshowBackgrounds.append(path);
- m_unseenSlideshowBackgrounds.append(path);
+ m_slideshowModel->addBackground(path);
}
// always add it to the user papers, though
addUsersWallpaper(path);
}
}
void Image::setWallpaperRetrieved(KJob *job)
{
KIO::FileCopyJob *copyJob = qobject_cast(job);
if (copyJob && !copyJob->error()) {
setWallpaper(copyJob->destUrl().toLocalFile());
}
}
void Image::addWallpaperRetrieved(KJob *job)
{
KIO::FileCopyJob *copyJob = qobject_cast(job);
if (copyJob && !copyJob->error()) {
addUrl(copyJob->destUrl(), false);
}
}
void Image::setWallpaper(const QString &path)
{
if (m_mode == SingleImage) {
m_wallpaper = path;
setSingleImage();
} else {
- m_slideshowBackgrounds.append(path);
- m_unseenSlideshowBackgrounds.clear();
- m_currentSlide = m_slideshowBackgrounds.size() - 2;
+ m_wallpaper = path;
+ m_slideshowModel->addBackground(path);
+ m_currentSlide = m_slideFilterModel->indexOf(path) - 1;
nextSlide();
}
//addUsersWallpaper(path);
}
void Image::startSlideshow()
{
- if (!m_ready) {
+ if (!m_ready || m_slideFilterModel->property("usedInConfig").toBool()) {
return;
}
-
- if(m_findToken.isEmpty()) {
- // populate background list
- m_timer.stop();
- m_slideshowBackgrounds.clear();
- m_unseenSlideshowBackgrounds.clear();
- BackgroundFinder *finder = new BackgroundFinder(this, m_dirs);
- m_findToken = finder->token();
- connect(finder, &BackgroundFinder::backgroundsFound, this, &Image::backgroundsFound);
- finder->start();
- //TODO: what would be cool: paint on the wallpaper itself a busy widget and perhaps some text
- //about loading wallpaper slideshow while the thread runs
- } else {
- m_scanDirty = true;
- }
+ // populate background list
+ m_timer.stop();
+ m_slideshowModel->reload(m_slidePaths);
+ connect(m_slideshowModel, &SlideModel::done, this, &Image::backgroundsFound);
+ //TODO: what would be cool: paint on the wallpaper itself a busy widget and perhaps some text
+ //about loading wallpaper slideshow while the thread runs
}
-void Image::backgroundsFound(const QStringList &paths, const QString &token)
+void Image::backgroundsFound()
{
- if (token != m_findToken) {
- return;
- }
-
- m_findToken.clear();
+ disconnect(m_slideshowModel, &SlideModel::done, this, 0);
if(m_scanDirty) {
m_scanDirty = false;
startSlideshow();
return;
}
- m_slideshowBackgrounds = paths;
- for(const QString &slide : qAsConst(m_uncheckedSlides)) {
- m_slideshowBackgrounds.removeAll(QUrl(slide).path());
- }
- m_unseenSlideshowBackgrounds.clear();
+
// start slideshow
- if (m_slideshowBackgrounds.isEmpty()) {
+ if (m_slideFilterModel->rowCount() == 0) {
// no image has been found, which is quite weird... try again later (this is useful for events which
// are not detected by KDirWatch, like a NFS directory being mounted)
QTimer::singleShot(1000, this, &Image::startSlideshow);
} else {
- m_currentSlide = -1;
+ if (m_currentSlide == -1 && m_slideshowMode != Random) {
+ m_currentSlide = m_slideFilterModel->indexOf(m_wallpaper) - 1;
+ } else {
+ m_currentSlide = -1;
+ }
+ m_slideFilterModel->sort(0);
nextSlide();
m_timer.start(m_delay * 1000);
}
}
void Image::getNewWallpaper(QQuickItem *ctx)
{
if (!m_newStuffDialog) {
m_newStuffDialog = new KNS3::DownloadDialog( QString::fromLatin1("wallpaper.knsrc") );
KNS3::DownloadDialog *strong = m_newStuffDialog.data();
strong->setTitle(i18n("Download Wallpapers"));
connect(m_newStuffDialog.data(), &QDialog::accepted, this, &Image::newStuffFinished);
}
if (ctx && ctx->window()) {
m_newStuffDialog->setWindowModality(Qt::WindowModal);
m_newStuffDialog->winId(); // so it creates the windowHandle();
m_newStuffDialog->windowHandle()->setTransientParent(ctx->window());
}
m_newStuffDialog.data()->show();
}
void Image::newStuffFinished()
{
if (m_model && (!m_newStuffDialog || m_newStuffDialog.data()->changedEntries().size() > 0)) {
m_model->reload(m_usersWallpapers);
}
}
void Image::showFileDialog()
{
if (!m_dialog) {
QUrl baseUrl;
if(m_wallpaper.indexOf(QDir::homePath()) > -1){
baseUrl = QUrl(m_wallpaper);
}
/*
m_dialog = new KFileDialog(baseUrl, QString::fromLatin1("*.png *.jpeg *.jpg *.xcf *.svg *.svgz *.bmp"), 0);
m_dialog->setOperationMode(KFileDialog::Opening);
m_dialog->setInlinePreviewShown(true);
m_dialog->setModal(false);
connect(m_dialog, SIGNAL(okClicked()), this, SLOT(wallpaperBrowseCompleted()));
connect(m_dialog, SIGNAL(destroyed(QObject*)), this, SLOT(fileDialogFinished()));
*/
QString path;
const QStringList &locations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
if (!locations.isEmpty()) {
path = locations.at(0);
} else {
// HomeLocation is guaranteed not to be empty.
path = QStandardPaths::standardLocations(QStandardPaths::HomeLocation).at(0);
}
QMimeDatabase db;
QStringList imageGlobPatterns;
foreach(const QByteArray &mimeType, QImageReader::supportedMimeTypes()) {
QMimeType mime(db.mimeTypeForName(mimeType));
imageGlobPatterns << mime.globPatterns();
}
m_dialog = new QFileDialog(nullptr, i18n("Open Image"),
path,
i18n("Image Files") + " ("+imageGlobPatterns.join(' ') + ')');
//i18n people, this isn't a "word puzzle". there is a specific string format for QFileDialog::setNameFilters
m_dialog->setFileMode(QFileDialog::ExistingFiles);
connect(m_dialog, &QDialog::accepted, this, &Image::wallpaperBrowseCompleted);
}
m_dialog->show();
m_dialog->raise();
m_dialog->activateWindow();
}
void Image::fileDialogFinished()
{
m_dialog = nullptr;
}
void Image::wallpaperBrowseCompleted()
{
Q_ASSERT(m_model);
if (m_dialog && m_dialog->selectedFiles().count() > 0) {
for (const QString image : m_dialog->selectedFiles()) {
addUsersWallpaper(image);
}
emit customWallpaperPicked(m_dialog->selectedFiles().first());
}
}
void Image::addUsersWallpaper(const QString &file)
{
QString f = file;
f.remove(QLatin1String("file:/"));
const QFileInfo info(f); // FIXME
//the full file path, so it isn't broken when dealing with symlinks
const QString wallpaper = info.canonicalFilePath();
if (wallpaper.isEmpty()) {
return;
}
if (m_model) {
if (m_model->contains(wallpaper)) {
return;
}
// add background to the model
m_model->addBackground(wallpaper);
}
// save it
KConfigGroup cfg = KConfigGroup(KSharedConfig::openConfig(QStringLiteral("plasmarc")),
QStringLiteral("Wallpapers"));
m_usersWallpapers = cfg.readEntry("usersWallpapers", m_usersWallpapers);
if (!m_usersWallpapers.contains(wallpaper)) {
m_usersWallpapers.prepend(wallpaper);
cfg.writeEntry("usersWallpapers", m_usersWallpapers);
cfg.sync();
emit usersWallpapersChanged();
}
}
void Image::nextSlide()
{
- if (!m_ready || m_slideshowBackgrounds.isEmpty()) {
+ if (!m_ready || m_slideFilterModel->rowCount() == 0) {
return;
}
-
- QString previousPath;
- if (m_currentSlide > -1 && m_currentSlide < m_unseenSlideshowBackgrounds.size()) {
- previousPath = m_unseenSlideshowBackgrounds.takeAt(m_currentSlide);
+ int previousSlide = m_currentSlide;
+ QUrl previousPath = m_slideFilterModel->index(m_currentSlide, 0).data(BackgroundListModel::PathRole).toUrl();
+ if (m_currentSlide == m_slideFilterModel->rowCount() - 1 || m_currentSlide < 0) {
+ m_currentSlide = 0;
+ } else {
+ m_currentSlide += 1;
}
-
- if (m_unseenSlideshowBackgrounds.isEmpty()) {
- m_unseenSlideshowBackgrounds = m_slideshowBackgrounds;
-
- // We're filling the queue again, make sure we can't pick up again
- // the last one picked from the previous set
- if (!previousPath.isEmpty()) {
- m_unseenSlideshowBackgrounds.removeAll(previousPath);
-
- // prevent empty list
- if (m_unseenSlideshowBackgrounds.isEmpty()) {
- m_unseenSlideshowBackgrounds = m_slideshowBackgrounds;
- }
- }
+ //We are starting again - avoid having the same random order when we restart the slideshow
+ if (m_slideshowMode == Random && previousSlide == m_slideFilterModel->rowCount() - 1) {
+ m_slideFilterModel->invalidate();
+ }
+ QUrl next = m_slideFilterModel->index(m_currentSlide, 0).data(BackgroundListModel::PathRole).toUrl();
+ // And avoid showing the same picture twice
+ if (previousSlide == m_slideFilterModel->rowCount() - 1 && previousPath == next && m_slideFilterModel->rowCount() > 1) {
+ m_currentSlide += 1;
+ next = m_slideFilterModel->index(m_currentSlide, 0).data(BackgroundListModel::PathRole).toUrl();
}
-
- m_currentSlide = KRandom::random() % m_unseenSlideshowBackgrounds.size();
- const QString currentPath = m_unseenSlideshowBackgrounds.at(m_currentSlide);
-
- m_wallpaperPackage.setPath(currentPath);
- findPreferedImageInPackage(m_wallpaperPackage);
-
m_timer.stop();
m_timer.start(m_delay * 1000);
-
- QString current = m_wallpaperPackage.filePath("preferred");
- if (current.isEmpty()) {
- m_wallpaperPath = currentPath;
+ if (next.isEmpty()) {
+ m_wallpaperPath = previousPath.toLocalFile();
} else {
- m_wallpaperPath = current;
+ m_wallpaperPath = next.toLocalFile();
}
-
Q_EMIT wallpaperPathChanged();
}
void Image::openSlide()
{
if (!m_wallpaperPackage.isValid()) {
return;
}
// open in image viewer
QUrl filepath(m_wallpaperPackage.filePath("preferred"));
qCDebug(IMAGEWALLPAPER) << "opening file " << filepath.path();
new KRun(filepath, nullptr);
}
void Image::pathCreated(const QString &path)
{
- if(!m_slideshowBackgrounds.contains(path)) {
+ if(m_slideshowModel->indexOf(path) == -1) {
QFileInfo fileInfo(path);
if(fileInfo.isFile() && BackgroundFinder::isAcceptableSuffix(fileInfo.suffix())) {
- m_slideshowBackgrounds.append(path);
- m_unseenSlideshowBackgrounds.append(path);
- if(m_slideshowBackgrounds.count() == 1) {
+ m_slideshowModel->addBackground(path);
+ if(m_slideFilterModel->rowCount() == 1) {
nextSlide();
}
}
}
}
void Image::pathDeleted(const QString &path)
{
- if(m_slideshowBackgrounds.removeAll(path)) {
- m_unseenSlideshowBackgrounds.removeAll(path);
+ if(m_slideshowModel->indexOf(path) != -1) {
+ m_slideshowModel->removeBackground(path);
if(path == m_img) {
nextSlide();
}
}
}
//FIXME: we have to save the configuration also when the dialog cancel button is clicked.
void Image::removeWallpaper(QString name)
{
QString localWallpapers = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/wallpapers/";
QUrl nameUrl(name);
//Package plugin name
if (!name.contains('/')) {
KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Wallpaper/Images"));
KJob *j = p.uninstall(name, localWallpapers);
connect(j, &KJob::finished, [=] () {
m_model->reload(m_usersWallpapers);
});
//absolute path in the home
} else if (nameUrl.path().startsWith(localWallpapers)) {
QFile f(nameUrl.path());
if (f.exists()) {
f.remove();
}
m_model->reload(m_usersWallpapers);
} else {
// save it
KConfigGroup cfg = KConfigGroup(KSharedConfig::openConfig(QStringLiteral("plasmarc")),
QStringLiteral("Wallpapers"));
m_usersWallpapers = cfg.readEntry("usersWallpapers", m_usersWallpapers);
int wallpaperIndex = -1;
//passed as a path or as a file:// url?
if (nameUrl.isValid()) {
wallpaperIndex = m_usersWallpapers.indexOf(nameUrl.path());
} else {
wallpaperIndex = m_usersWallpapers.indexOf(name);
}
if (wallpaperIndex >= 0){
m_usersWallpapers.removeAt(wallpaperIndex);
m_model->reload(m_usersWallpapers);
cfg.writeEntry("usersWallpapers", m_usersWallpapers);
cfg.sync();
emit usersWallpapersChanged();
Q_EMIT settingsChanged(true);
}
}
}
void Image::commitDeletion()
{
//This is invokable from qml, so at any moment
//we can't be sure the model exists
if (!m_model) {
return;
}
for (const QString &wallpaperCandidate : m_model->wallpapersAwaitingDeletion()) {
removeWallpaper(wallpaperCandidate);
}
}
void Image::openFolder(const QString& path)
{
new KRun(QUrl::fromLocalFile(path), nullptr);
}
void Image::toggleSlide(const QString& path, bool checked)
{
if (checked && m_uncheckedSlides.contains(path)) {
m_uncheckedSlides.removeAll(path);
emit uncheckedSlidesChanged();
startSlideshow();
} else if (!checked && ! m_uncheckedSlides.contains(path)) {
m_uncheckedSlides.append(path);
emit uncheckedSlidesChanged();
startSlideshow();
}
}
QStringList Image::uncheckedSlides() const
{
return m_uncheckedSlides;
}
void Image::setUncheckedSlides(const QStringList &uncheckedSlides)
{
if (uncheckedSlides == m_uncheckedSlides) {
return;
}
m_uncheckedSlides = uncheckedSlides;
emit uncheckedSlidesChanged();
startSlideshow();
}
diff --git a/wallpapers/image/image.h b/wallpapers/image/image.h
index e3526a413..228e3d599 100644
--- a/wallpapers/image/image.h
+++ b/wallpapers/image/image.h
@@ -1,200 +1,217 @@
/***************************************************************************
* Copyright 2007 Paolo Capriotti *
* Copyright 2008 by Petri Damsten *
* Copyright 2014 Sebastian Kügler *
* Copyright 2015 Kai Uwe Broulik *
+ * Copyright 2019 David Redondo *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#ifndef IMAGE_HEADER
#define IMAGE_HEADER
+
#include
#include
#include
#include
#include
#include
#include
#include
#include
class QFileDialog;
class QQuickItem;
class KDirWatch;
class KJob;
namespace KNS3 {
class DownloadDialog;
}
class BackgroundListModel;
class SlideModel;
+class SlideFilterModel;
class Image : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(RenderingMode renderingMode READ renderingMode WRITE setRenderingMode NOTIFY renderingModeChanged)
+ Q_PROPERTY(SlideshowMode slideshowMode READ slideshowMode WRITE setSlideshowMode NOTIFY slideshowModeChanged)
Q_PROPERTY(QUrl wallpaperPath READ wallpaperPath NOTIFY wallpaperPathChanged)
Q_PROPERTY(QAbstractItemModel *wallpaperModel READ wallpaperModel CONSTANT)
- Q_PROPERTY(QAbstractItemModel *slideshowModel READ slideshowModel CONSTANT)
+ Q_PROPERTY(QAbstractItemModel *slideFilterModel READ slideFilterModel CONSTANT)
Q_PROPERTY(int slideTimer READ slideTimer WRITE setSlideTimer NOTIFY slideTimerChanged)
Q_PROPERTY(QStringList usersWallpapers READ usersWallpapers WRITE setUsersWallpapers NOTIFY usersWallpapersChanged)
Q_PROPERTY(QStringList slidePaths READ slidePaths WRITE setSlidePaths NOTIFY slidePathsChanged)
Q_PROPERTY(QSize targetSize READ targetSize WRITE setTargetSize NOTIFY targetSizeChanged)
Q_PROPERTY(QString photosPath READ photosPath CONSTANT)
Q_PROPERTY(QStringList uncheckedSlides READ uncheckedSlides WRITE setUncheckedSlides NOTIFY uncheckedSlidesChanged)
public:
enum RenderingMode {
SingleImage,
SlideShow
};
Q_ENUM(RenderingMode)
+ enum SlideshowMode {
+ Random,
+ Alphabetical,
+ AlphabeticalReversed,
+ Modified,
+ ModifiedReversed
+ };
+ Q_ENUM(SlideshowMode)
+
explicit Image(QObject* parent = nullptr);
~Image() override;
QUrl wallpaperPath() const;
//this is for QML use
Q_INVOKABLE void addUrl(const QString &url);
Q_INVOKABLE void addUrls(const QStringList &urls);
Q_INVOKABLE void addSlidePath(const QString &path);
Q_INVOKABLE void removeSlidePath(const QString &path);
Q_INVOKABLE void openFolder(const QString& path);
Q_INVOKABLE void getNewWallpaper(QQuickItem *ctx = nullptr);
Q_INVOKABLE void showFileDialog();
Q_INVOKABLE void addUsersWallpaper(const QString &file);
Q_INVOKABLE void commitDeletion();
Q_INVOKABLE void toggleSlide(const QString &path, bool checked);
RenderingMode renderingMode() const;
void setRenderingMode(RenderingMode mode);
+ SlideshowMode slideshowMode() const;
+ void setSlideshowMode(SlideshowMode mode);
+
QSize targetSize() const;
void setTargetSize(const QSize &size);
KPackage::Package *package();
QAbstractItemModel* wallpaperModel();
- QAbstractItemModel* slideshowModel();
+ QAbstractItemModel* slideFilterModel();
int slideTimer() const;
void setSlideTimer(int time);
QStringList usersWallpapers() const;
void setUsersWallpapers(const QStringList &usersWallpapers);
QStringList slidePaths() const;
void setSlidePaths(const QStringList &slidePaths);
void findPreferedImageInPackage(KPackage::Package &package);
QString findPreferedImage(const QStringList &images);
void classBegin() override;
void componentComplete() override;
QString photosPath() const;
QStringList uncheckedSlides() const;
void setUncheckedSlides(const QStringList &uncheckedSlides);
public Q_SLOTS:
void nextSlide();
void removeWallpaper(QString name);
Q_SIGNALS:
void settingsChanged(bool);
void wallpaperPathChanged();
void renderingModeChanged();
+ void slideshowModeChanged();
void targetSizeChanged();
void slideTimerChanged();
void usersWallpapersChanged();
void slidePathsChanged();
void resizeMethodChanged();
void customWallpaperPicked(const QString &path);
void uncheckedSlidesChanged();
protected Q_SLOTS:
void showAddSlidePathsDialog();
void wallpaperBrowseCompleted();
/**
* Open the current slide in the default image application
*/
void openSlide();
void startSlideshow();
void fileDialogFinished();
void addUrl(const QUrl &url, bool setAsCurrent);
void addUrls(const QList &urls);
void setWallpaper(const QString &path);
void setWallpaperRetrieved(KJob *job);
void addWallpaperRetrieved(KJob *job);
void newStuffFinished();
void updateDirWatch(const QStringList &newDirs);
void addDirFromSelectionDialog();
void pathCreated(const QString &path);
void pathDeleted(const QString &path);
void pathDirty(const QString &path);
- void backgroundsFound(const QStringList &paths, const QString &token);
+ void backgroundsFound();
protected:
void syncWallpaperPackage();
void setSingleImage();
void useSingleImageDefaults();
private:
-
bool m_ready;
int m_delay;
QStringList m_dirs;
QString m_wallpaper;
QString m_wallpaperPath;
QStringList m_usersWallpapers;
KDirWatch *m_dirWatch;
bool m_scanDirty;
QSize m_targetSize;
RenderingMode m_mode;
+ SlideshowMode m_slideshowMode;
+
KPackage::Package m_wallpaperPackage;
- QStringList m_slideshowBackgrounds;
- QStringList m_unseenSlideshowBackgrounds;
QStringList m_slidePaths;
QStringList m_uncheckedSlides;
QTimer m_timer;
int m_currentSlide;
BackgroundListModel *m_model;
SlideModel* m_slideshowModel;
+ SlideFilterModel* m_slideFilterModel;
QFileDialog *m_dialog;
QString m_img;
QDateTime m_previousModified;
QPointer m_newStuffDialog;
QString m_findToken;
};
#endif
diff --git a/wallpapers/image/imagepackage/contents/ui/WallpaperDelegate.qml b/wallpapers/image/imagepackage/contents/ui/WallpaperDelegate.qml
index 8206f77c2..8d22956bd 100644
--- a/wallpapers/image/imagepackage/contents/ui/WallpaperDelegate.qml
+++ b/wallpapers/image/imagepackage/contents/ui/WallpaperDelegate.qml
@@ -1,132 +1,134 @@
/*
* Copyright 2013 Marco Martin
* Copyright 2014 Sebastian Kügler
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
import QtQuick 2.0
import QtQuick.Controls.Private 1.0
import QtQuick.Controls 2.3 as QtControls2
import QtGraphicalEffects 1.0
import org.kde.kquickcontrolsaddons 2.0
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.kirigami 2.4 as Kirigami
import org.kde.kcm 1.1 as KCM
KCM.GridDelegate {
id: wallpaperDelegate
property alias color: backgroundRect.color
property bool selected: (wallpapersGrid.currentIndex === index)
opacity: model.pendingDeletion ? 0.5 : 1
text: model.display
toolTip: model.author.length > 0 ? i18ndc("plasma_wallpaper_org.kde.image", " by ", "By %1", model.author) : ""
hoverEnabled: true
actions: [
Kirigami.Action {
icon.name: "document-open-folder"
tooltip: i18nd("plasma_wallpaper_org.kde.image", "Open Containing Folder")
onTriggered: imageModel.openContainingFolder(index)
},
Kirigami.Action {
icon.name: "edit-undo"
visible: model.pendingDeletion
tooltip: i18nd("plasma_wallpaper_org.kde.image", "Restore wallpaper")
onTriggered: imageModel.setPendingDeletion(index, !model.pendingDeletion)
},
Kirigami.Action {
icon.name: "edit-delete"
tooltip: i18nd("plasma_wallpaper_org.kde.image", "Remove Wallpaper")
visible: model.removable && !model.pendingDeletion && configDialog.currentWallpaper == "org.kde.image"
onTriggered: {
imageModel.setPendingDeletion(index, true);
if (wallpapersGrid.currentIndex === index) {
- wallpapersGrid.currentIndex = (index + 1) % wallpapersGrid.count;
+ wallpapersGrid.currentIndex = (index + 1) % wallpapersGrid.rowCount();
}
}
}
]
thumbnail: Rectangle {
id: backgroundRect
color: cfg_Color
anchors.fill: parent
QIconItem {
anchors.centerIn: parent
width: units.iconSizes.large
height: width
icon: "view-preview"
visible: !walliePreview.visible
}
QPixmapItem {
id: blurBackgroundSource
visible: cfg_Blur
anchors.fill: parent
smooth: true
pixmap: model.screenshot
fillMode: QPixmapItem.PreserveAspectCrop
}
FastBlur {
visible: cfg_Blur
anchors.fill: parent
source: blurBackgroundSource
radius: 4
}
QPixmapItem {
id: walliePreview
anchors.fill: parent
visible: model.screenshot !== null
smooth: true
pixmap: model.screenshot
fillMode: {
if (cfg_FillMode == Image.Stretch) {
return QPixmapItem.Stretch;
} else if (cfg_FillMode == Image.PreserveAspectFit) {
return QPixmapItem.PreserveAspectFit;
} else if (cfg_FillMode == Image.PreserveAspectCrop) {
return QPixmapItem.PreserveAspectCrop;
} else if (cfg_FillMode == Image.Tile) {
return QPixmapItem.Tile;
} else if (cfg_FillMode == Image.TileVertically) {
return QPixmapItem.TileVertically;
} else if (cfg_FillMode == Image.TileHorizontally) {
return QPixmapItem.TileHorizontally;
}
return QPixmapItem.PreserveAspectFit;
}
}
QtControls2.CheckBox {
visible: configDialog.currentWallpaper == "org.kde.slideshow"
anchors.right: parent.right
anchors.top: parent.top
checked: visible ? model.checked : false
onToggled: imageWallpaper.toggleSlide(model.path, checked)
}
}
onClicked: {
- cfg_Image = model.path;
- wallpapersGrid.forceActiveFocus();
+ if (configDialog.currentWallpaper == "org.kde.image") {
+ cfg_Image = model.path;
+ }
+ view.currentIndex = index;
}
}
diff --git a/wallpapers/image/imagepackage/contents/ui/config.qml b/wallpapers/image/imagepackage/contents/ui/config.qml
index cdab89982..a7442eb23 100644
--- a/wallpapers/image/imagepackage/contents/ui/config.qml
+++ b/wallpapers/image/imagepackage/contents/ui/config.qml
@@ -1,324 +1,374 @@
/*
* Copyright 2013 Marco Martin
* Copyright 2014 Kai Uwe Broulik
+ * Copyright 2019 David Redondo
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
import QtQuick 2.5
import QtQuick.Controls 2.3 as QtControls2
import QtQuick.Layouts 1.0
import QtQuick.Window 2.0 // for Screen
import org.kde.plasma.wallpapers.image 2.0 as Wallpaper
import org.kde.kquickcontrols 2.0 as KQuickControls
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kconfig 1.0 // for KAuthorized
import org.kde.draganddrop 2.0 as DragDrop
import org.kde.kcm 1.1 as KCM
import org.kde.kirigami 2.5 as Kirigami
ColumnLayout {
id: root
property alias cfg_Color: colorButton.color
property string cfg_Image
property int cfg_FillMode
+ property int cfg_SlideshowMode
property alias cfg_Blur: blurRadioButton.checked
property var cfg_SlidePaths: ""
property int cfg_SlideInterval: 0
property var cfg_UncheckedSlides: []
function saveConfig() {
imageWallpaper.commitDeletion();
}
SystemPalette {
id: syspal
}
Wallpaper.Image {
id: imageWallpaper
targetSize: {
if (typeof plasmoid !== "undefined") {
return Qt.size(plasmoid.width, plasmoid.height)
}
// Lock screen configuration case
return Qt.size(Screen.width, Screen.height)
}
onSlidePathsChanged: cfg_SlidePaths = slidePaths
onUncheckedSlidesChanged: cfg_UncheckedSlides = uncheckedSlides
+ onSlideshowModeChanged: cfg_SlideshowMode = slideshowMode
}
onCfg_SlidePathsChanged: {
imageWallpaper.slidePaths = cfg_SlidePaths
}
onCfg_UncheckedSlidesChanged: {
imageWallpaper.uncheckedSlides = cfg_UncheckedSlides
}
+ onCfg_SlideshowModeChanged: {
+ imageWallpaper.slideshowMode = cfg_SlideshowMode
+ }
+
property int hoursIntervalValue: Math.floor(cfg_SlideInterval / 3600)
property int minutesIntervalValue: Math.floor(cfg_SlideInterval % 3600) / 60
property int secondsIntervalValue: cfg_SlideInterval % 3600 % 60
//Rectangle { color: "orange"; x: formAlignment; width: formAlignment; height: 20 }
Kirigami.FormLayout {
twinFormLayouts: parentLayout
QtControls2.ComboBox {
id: resizeComboBox
Kirigami.FormData.label: i18nd("plasma_wallpaper_org.kde.image", "Positioning:")
model: [
{
'label': i18nd("plasma_wallpaper_org.kde.image", "Scaled and Cropped"),
'fillMode': Image.PreserveAspectCrop
},
{
'label': i18nd("plasma_wallpaper_org.kde.image","Scaled"),
'fillMode': Image.Stretch
},
{
'label': i18nd("plasma_wallpaper_org.kde.image","Scaled, Keep Proportions"),
'fillMode': Image.PreserveAspectFit
},
{
'label': i18nd("plasma_wallpaper_org.kde.image", "Centered"),
'fillMode': Image.Pad
},
{
'label': i18nd("plasma_wallpaper_org.kde.image","Tiled"),
'fillMode': Image.Tile
}
]
textRole: "label"
onCurrentIndexChanged: cfg_FillMode = model[currentIndex]["fillMode"]
Component.onCompleted: setMethod();
function setMethod() {
for (var i = 0; i < model.length; i++) {
if (model[i]["fillMode"] === wallpaper.configuration.FillMode) {
resizeComboBox.currentIndex = i;
var tl = model[i]["label"].length;
//resizeComboBox.textLength = Math.max(resizeComboBox.textLength, tl+5);
}
}
}
}
+ QtControls2.ComboBox {
+ id: slideshowComboBox
+ visible: configDialog.currentWallpaper == "org.kde.slideshow"
+ Kirigami.FormData.label: i18nd("plasma_wallpaper_org.kde.image", "Order:")
+ model: [
+ {
+ 'label': i18nd("plasma_wallpaper_org.kde.image", "Random"),
+ 'slideshowMode': Wallpaper.Image.Random
+ },
+ {
+ 'label': i18nd("plasma_wallpaper_org.kde.image", "A to Z"),
+ 'slideshowMode': Wallpaper.Image.Alphabetical
+ },
+ {
+ 'label': i18nd("plasma_wallpaper_org.kde.image", "Z to A"),
+ 'slideshowMode': Wallpaper.Image.AlphabeticalReversed
+ },
+ {
+ 'label': i18nd("plasma_wallpaper_org.kde.image", "Date modified (newest first)"),
+ 'slideshowMode': Wallpaper.Image.ModifiedReversed
+ },
+ {
+ 'label': i18nd("plasma_wallpaper_org.kde.image", "Date modified (oldest first)"),
+ 'slideshowMode': Wallpaper.Image.Modified
+ }
+ ]
+ textRole: "label"
+ onCurrentIndexChanged: {
+ cfg_SlideshowMode = model[currentIndex]["slideshowMode"];
+ }
+ Component.onCompleted: setMethod();
+ function setMethod() {
+ for (var i = 0; i < model.length; i++) {
+ if (model[i]["slideshowMode"] === wallpaper.configuration.SlideshowMode) {
+ slideshowComboBox.currentIndex = i;
+ }
+ }
+ }
+ }
+
QtControls2.ButtonGroup { id: backgroundGroup }
QtControls2.RadioButton {
id: blurRadioButton
visible: cfg_FillMode === Image.PreserveAspectFit || cfg_FillMode === Image.Pad
Kirigami.FormData.label: i18nd("plasma_wallpaper_org.kde.image", "Background:")
text: i18nd("plasma_wallpaper_org.kde.image", "Blur")
QtControls2.ButtonGroup.group: backgroundGroup
}
RowLayout {
id: colorRow
visible: cfg_FillMode === Image.PreserveAspectFit || cfg_FillMode === Image.Pad
QtControls2.RadioButton {
id: colorRadioButton
text: i18nd("plasma_wallpaper_org.kde.image", "Solid color")
checked: !cfg_Blur
QtControls2.ButtonGroup.group: backgroundGroup
}
KQuickControls.ColorButton {
id: colorButton
dialogTitle: i18nd("plasma_wallpaper_org.kde.image", "Select Background Color")
}
}
}
Component {
id: foldersComponent
ColumnLayout {
Connections {
target: root
onHoursIntervalValueChanged: hoursInterval.value = root.hoursIntervalValue
onMinutesIntervalValueChanged: minutesInterval.value = root.minutesIntervalValue
onSecondsIntervalValueChanged: secondsInterval.value = root.secondsIntervalValue
}
//FIXME: there should be only one spinbox: QtControls spinboxes are still too limited for it tough
Kirigami.FormLayout {
twinFormLayouts: parentLayout
RowLayout {
Kirigami.FormData.label: i18nd("plasma_wallpaper_org.kde.image","Change every:")
QtControls2.SpinBox {
id: hoursInterval
value: root.hoursIntervalValue
from: 0
to: 24
editable: true
onValueChanged: cfg_SlideInterval = hoursInterval.value * 3600 + minutesInterval.value * 60 + secondsInterval.value
}
QtControls2.Label {
text: i18nd("plasma_wallpaper_org.kde.image","Hours")
}
QtControls2.SpinBox {
id: minutesInterval
value: root.minutesIntervalValue
from: 0
to: 60
editable: true
onValueChanged: cfg_SlideInterval = hoursInterval.value * 3600 + minutesInterval.value * 60 + secondsInterval.value
}
QtControls2.Label {
text: i18nd("plasma_wallpaper_org.kde.image","Minutes")
}
QtControls2.SpinBox {
id: secondsInterval
value: root.secondsIntervalValue
from: root.hoursIntervalValue === 0 && root.minutesIntervalValue === 0 ? 1 : 0
to: 60
editable: true
onValueChanged: cfg_SlideInterval = hoursInterval.value * 3600 + minutesInterval.value * 60 + secondsInterval.value
}
QtControls2.Label {
text: i18nd("plasma_wallpaper_org.kde.image","Seconds")
}
}
}
Kirigami.Heading {
text: i18nd("plasma_wallpaper_org.kde.image","Folders")
level: 2
}
GridLayout {
columns: 2
Layout.fillWidth: true
Layout.fillHeight: true
columnSpacing: Kirigami.Units.largeSpacing
QtControls2.ScrollView {
id: foldersScroll
Layout.fillHeight: true
Layout.preferredWidth: 0.25 * parent.width
Component.onCompleted: foldersScroll.background.visible = true;
ListView {
id: slidePathsView
anchors.margins: 4
model: imageWallpaper.slidePaths
delegate: Kirigami.SwipeListItem {
id: folderDelegate
actions: [
Kirigami.Action {
iconName: "list-remove"
tooltip: i18nd("plasma_wallpaper_org.kde.image", "Remove Folder")
onTriggered: imageWallpaper.removeSlidePath(modelData)
},
Kirigami.Action {
icon.name: "document-open-folder"
tooltip: i18nd("plasma_wallpaper_org.kde.image", "Open Folder")
onTriggered: imageWallpaper.openFolder(modelData)
}
]
QtControls2.Label {
text: modelData.endsWith("/") ? modelData.split('/').reverse()[1] : modelData.split('/').pop()
Layout.fillWidth: true
QtControls2.ToolTip.text: modelData
QtControls2.ToolTip.visible: folderDelegate.hovered
QtControls2.ToolTip.delay: 1000
QtControls2.ToolTip.timeout: 5000
}
width: slidePathsView.width
height: paintedHeight;
}
}
}
Loader {
sourceComponent: thumbnailsComponent
Layout.fillWidth: true
Layout.fillHeight: true
anchors.fill: undefined
}
QtControls2.Button {
Layout.alignment: Qt.AlignRight
icon.name: "list-add"
text: i18nd("plasma_wallpaper_org.kde.image","Add Folder...")
onClicked: imageWallpaper.showAddSlidePathsDialog()
}
QtControls2.Button {
Layout.alignment: Qt.AlignRight
icon.name: "get-hot-new-stuff"
text: i18nd("plasma_wallpaper_org.kde.image","Get New Wallpapers...")
visible: KAuthorized.authorize("ghns")
onClicked: imageWallpaper.getNewWallpaper(this);
}
}
}
}
Component {
id: thumbnailsComponent
KCM.GridView {
id: wallpapersGrid
anchors.fill: parent
- property var imageModel: (configDialog.currentWallpaper == "org.kde.image")? imageWallpaper.wallpaperModel : imageWallpaper.slideshowModel
+ property var imageModel: (configDialog.currentWallpaper == "org.kde.image")? imageWallpaper.wallpaperModel : imageWallpaper.slideFilterModel
//that min is needed as the module will be populated in an async way
//and only on demand so we can't ensure it already exists
- view.currentIndex: Math.min(imageModel.indexOf(cfg_Image), imageModel.count-1)
+ view.currentIndex: Math.min(imageModel.indexOf(cfg_Image), imageModel.rowCount()-1)
//kill the space for label under thumbnails
view.model: imageModel
+ Component.onCompleted: {
+ imageModel.usedInConfig = true;
+ }
view.delegate: WallpaperDelegate {
color: cfg_Color
}
}
}
DragDrop.DropArea {
Layout.fillWidth: true
Layout.fillHeight: true
onDragEnter: {
if (!event.mimeData.hasUrls) {
event.ignore();
}
}
onDrop: {
event.mimeData.urls.forEach(function (url) {
if (url.indexOf("file://") === 0) {
var path = url.substr(7); // 7 is length of "file://"
if (configDialog.currentWallpaper === "org.kde.image") {
imageWallpaper.addUsersWallpaper(path);
} else {
imageWallpaper.addSlidePath(path);
}
}
});
}
Loader {
anchors.fill: parent
sourceComponent: (configDialog.currentWallpaper == "org.kde.image") ? thumbnailsComponent :
((configDialog.currentWallpaper == "org.kde.slideshow") ? foldersComponent : undefined)
}
}
RowLayout {
id: buttonsRow
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
visible: configDialog.currentWallpaper == "org.kde.image"
QtControls2.Button {
icon.name: "list-add"
text: i18nd("plasma_wallpaper_org.kde.image","Add Image...")
onClicked: imageWallpaper.showFileDialog();
}
QtControls2.Button {
icon.name: "get-hot-new-stuff"
text: i18nd("plasma_wallpaper_org.kde.image","Get New Wallpapers...")
visible: KAuthorized.authorize("ghns")
onClicked: imageWallpaper.getNewWallpaper(this);
}
}
}
diff --git a/wallpapers/image/imagepackage/contents/ui/main.qml b/wallpapers/image/imagepackage/contents/ui/main.qml
index eba89a7ab..a53a519a0 100644
--- a/wallpapers/image/imagepackage/contents/ui/main.qml
+++ b/wallpapers/image/imagepackage/contents/ui/main.qml
@@ -1,169 +1,175 @@
/*
* Copyright 2013 Marco Martin
* Copyright 2014 Sebastian Kügler
* Copyright 2014 Kai Uwe Broulik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
*/
import QtQuick 2.5
import QtQuick.Controls 2.1 as QQC2
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0
import org.kde.plasma.wallpapers.image 2.0 as Wallpaper
import org.kde.plasma.core 2.0 as PlasmaCore
QQC2.StackView {
id: root
readonly property string modelImage: imageWallpaper.wallpaperPath
readonly property string configuredImage: wallpaper.configuration.Image
readonly property int fillMode: wallpaper.configuration.FillMode
readonly property string configColor: wallpaper.configuration.Color
readonly property bool blur: wallpaper.configuration.Blur
readonly property size sourceSize: Qt.size(root.width * Screen.devicePixelRatio, root.height * Screen.devicePixelRatio)
//public API, the C++ part will look for those
function setUrl(url) {
wallpaper.configuration.Image = url
imageWallpaper.addUsersWallpaper(url);
}
function action_next() {
imageWallpaper.nextSlide();
}
function action_open() {
Qt.openUrlExternally(modelImage)
}
//private
onConfiguredImageChanged: {
- imageWallpaper.addUrl(configuredImage)
+ if (modelImage != configuredImage && configuredImage != "") {
+ imageWallpaper.addUrl(configuredImage);
+ }
}
Component.onCompleted: {
if (wallpaper.pluginName === "org.kde.slideshow") {
wallpaper.setAction("open", i18nd("plasma_wallpaper_org.kde.image", "Open Wallpaper Image"), "document-open");
wallpaper.setAction("next", i18nd("plasma_wallpaper_org.kde.image", "Next Wallpaper Image"), "user-desktop");
}
}
Wallpaper.Image {
id: imageWallpaper
//the oneliner of difference between image and slideshow wallpapers
renderingMode: (wallpaper.pluginName === "org.kde.image") ? Wallpaper.Image.SingleImage : Wallpaper.Image.SlideShow
targetSize: root.sourceSize
slidePaths: wallpaper.configuration.SlidePaths
slideTimer: wallpaper.configuration.SlideInterval
+ slideshowMode: wallpaper.configuration.SlideshowMode
uncheckedSlides: wallpaper.configuration.UncheckedSlides
}
onFillModeChanged: Qt.callLater(loadImage);
- onModelImageChanged: Qt.callLater(loadImage);
+ onModelImageChanged:{
+ Qt.callLater(loadImage);
+ wallpaper.configuration.Image = modelImage;
+ }
onConfigColorChanged: Qt.callLater(loadImage);
onBlurChanged: Qt.callLater(loadImage);
onWidthChanged: Qt.callLater(loadImage);
onHeightChanged: Qt.callLater(loadImage);
function loadImage() {
var isFirst = (root.currentItem == undefined);
var pendingImage = baseImage.createObject(root, { "source": root.modelImage,
"fillMode": root.fillMode,
"sourceSize": root.sourceSize,
"color": root.configColor,
"blur": root.blur,
"opacity": isFirst ? 1: 0});
function replaceWhenLoaded() {
if (pendingImage.status !== Image.Loading) {
root.replace(pendingImage, {},
isFirst ? QQC2.StackView.Immediate : QQC2.StackView.Transition);//dont' animate first show
pendingImage.statusChanged.disconnect(replaceWhenLoaded);
}
}
pendingImage.statusChanged.connect(replaceWhenLoaded);
replaceWhenLoaded();
}
Component {
id: baseImage
Image {
id: mainImage
property alias color: backgroundColor.color
property bool blur: false
asynchronous: true
cache: false
autoTransform: true
z: -1
QQC2.StackView.onRemoved: destroy()
Rectangle {
id: backgroundColor
anchors.fill: parent
visible: mainImage.status === Image.Ready && !blurLoader.active
z: -2
}
Loader {
id: blurLoader
anchors.fill: parent
z: -3
active: mainImage.blur && (mainImage.fillMode === Image.PreserveAspectFit || mainImage.fillMode === Image.Pad)
sourceComponent: Item {
Image {
id: blurSource
anchors.fill: parent
asynchronous: true
cache: false
autoTransform: true
fillMode: Image.PreserveAspectCrop
source: mainImage.source
sourceSize: mainImage.sourceSize
visible: false // will be rendered by the blur
}
GaussianBlur {
id: blurEffect
anchors.fill: parent
source: blurSource
radius: 32
samples: 65
visible: blurSource.status === Image.Ready
}
}
}
}
}
replaceEnter: Transition {
OpacityAnimator {
from: 0
to: 1
duration: wallpaper.configuration.TransitionAnimationDuration
}
}
// Keep the old image around till the new one is fully faded in
// If we fade both at the same time you can see the background behind glimpse through
replaceExit: Transition{
PauseAnimation {
duration: wallpaper.configuration.TransitionAnimationDuration
}
}
}
diff --git a/wallpapers/image/slidefiltermodel.cpp b/wallpapers/image/slidefiltermodel.cpp
new file mode 100644
index 000000000..71b87fc5c
--- /dev/null
+++ b/wallpapers/image/slidefiltermodel.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019 David Redondo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
+ */
+
+#include "slidefiltermodel.h"
+
+#include "backgroundlistmodel.h"
+#include "slidemodel.h"
+
+#include
+#include
+
+SlideFilterModel::SlideFilterModel(QObject* parent)
+ : QSortFilterProxyModel{parent}
+ , m_SortingMode{Image::Random}
+ , m_usedInConfig{false}
+{
+ setSortCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
+ connect(this, &SlideFilterModel::usedInConfigChanged, this, &SlideFilterModel::invalidateFilter);
+}
+
+bool SlideFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
+{
+ auto index = sourceModel()->index(source_row, 0, source_parent);
+ return m_usedInConfig || index.data(BackgroundListModel::ToggleRole).toBool();
+}
+
+bool SlideFilterModel::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const
+{
+ switch (m_SortingMode) {
+ case Image::Random:
+ return (*QRandomGenerator::system())() % 2 == 0;
+ case Image::Alphabetical:
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ case Image::AlphabeticalReversed:
+ return !QSortFilterProxyModel::lessThan(source_left, source_right);
+ case Image::Modified: // oldest first
+ {
+ QFileInfo f1(source_left.data(BackgroundListModel::PathRole).toUrl().toLocalFile());
+ QFileInfo f2(source_right.data(BackgroundListModel::PathRole).toUrl().toLocalFile());
+ return f1.lastModified() < f2.lastModified();
+ }
+ case Image::ModifiedReversed: // newest first
+ {
+ QFileInfo f1(source_left.data(BackgroundListModel::PathRole).toUrl().toLocalFile());
+ QFileInfo f2(source_right.data(BackgroundListModel::PathRole).toUrl().toLocalFile());
+ return !(f1.lastModified() < f2.lastModified());
+ }
+ }
+ Q_UNREACHABLE();
+}
+
+void SlideFilterModel::setSortingMode(Image::SlideshowMode mode)
+{
+ m_SortingMode = mode;
+ if (!(m_usedInConfig && mode == Image::Random)) {
+ QSortFilterProxyModel::invalidate();
+ }
+}
+
+void SlideFilterModel::invalidateFilter()
+{
+ QSortFilterProxyModel::invalidateFilter();
+}
+
+int SlideFilterModel::indexOf(const QString& path)
+{
+ auto sourceIndex = sourceModel()->index(static_cast(sourceModel())->indexOf(path), 0);
+ return mapFromSource(sourceIndex).row();
+}
+
+void SlideFilterModel::openContainingFolder(int rowIndex)
+{
+ auto sourceIndex = mapToSource(index(rowIndex, 0));
+ static_cast(sourceModel())->openContainingFolder(sourceIndex.row());
+}
diff --git a/wallpapers/image/slidefiltermodel.h b/wallpapers/image/slidefiltermodel.h
new file mode 100644
index 000000000..2ccd7bd29
--- /dev/null
+++ b/wallpapers/image/slidefiltermodel.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 David Redondo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
+ */
+
+#ifndef SLIDEFILTERMODEL_H
+#define SLIDEFILTERMODEL_H
+
+#include
+
+#include
+
+
+class SlideFilterModel : public QSortFilterProxyModel {
+
+ Q_OBJECT
+
+ Q_PROPERTY(bool usedInConfig MEMBER m_usedInConfig NOTIFY usedInConfigChanged);
+
+public:
+ SlideFilterModel(QObject* parent);
+ bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override;
+ bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
+ void setSortingMode(Image::SlideshowMode mode);
+ void invalidateFilter();
+
+ Q_INVOKABLE int indexOf(const QString& path);
+ Q_INVOKABLE void openContainingFolder(int rowIndex);
+
+Q_SIGNALS:
+ void usedInConfigChanged();
+
+private:
+ Image::SlideshowMode m_SortingMode;
+ bool m_usedInConfig;
+};
+#endif
diff --git a/wallpapers/image/slidemodel.cpp b/wallpapers/image/slidemodel.cpp
index 41c285355..47c0f8de8 100644
--- a/wallpapers/image/slidemodel.cpp
+++ b/wallpapers/image/slidemodel.cpp
@@ -1,59 +1,78 @@
+/*
+ * Copyright 2019 David Redondo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
+ */
+
#include "slidemodel.h"
void SlideModel::reload(const QStringList &selected)
{
if (!m_packages.isEmpty()) {
beginRemoveRows(QModelIndex(), 0, m_packages.count() - 1);
m_packages.clear();
endRemoveRows();
emit countChanged();
}
addDirs(selected);
}
void SlideModel::addDirs(const QStringList &selected)
{
BackgroundFinder *finder = new BackgroundFinder(m_wallpaper.data(), selected);
connect(finder, &BackgroundFinder::backgroundsFound, this, &SlideModel::backgroundsFound);
m_findToken = finder->token();
finder->start();
}
void SlideModel::backgroundsFound(const QStringList& paths, const QString& token)
{
if (token != m_findToken) {
return;
}
processPaths(paths);
+ emit done();
}
void SlideModel::removeDir(const QString &path)
{
BackgroundFinder *finder = new BackgroundFinder(m_wallpaper.data(), QStringList{path});
connect(finder, &BackgroundFinder::backgroundsFound, this, &SlideModel::removeBackgrounds);
finder->start();
}
void SlideModel::removeBackgrounds(const QStringList &paths, const QString &token)
{
Q_FOREACH (const QString &file, paths) {
removeBackground(file);
}
}
QVariant SlideModel::data(const QModelIndex& index, int role) const
{
if (role == ToggleRole) {
return !m_wallpaper.data()->uncheckedSlides().contains(data(index, PathRole).toString());
}
return BackgroundListModel::data(index, role);
}
QHash SlideModel::roleNames() const
{
QHash roleNames = BackgroundListModel::roleNames();
roleNames.insert(ToggleRole, "checked");
return roleNames;
}
diff --git a/wallpapers/image/slidemodel.h b/wallpapers/image/slidemodel.h
index 0d5330cd3..b34f0e062 100644
--- a/wallpapers/image/slidemodel.h
+++ b/wallpapers/image/slidemodel.h
@@ -1,21 +1,43 @@
+/*
+ * Copyright 2019 David Redondo
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
+ */
+
#ifndef SLIDEMODEL_H
#define SLIDEMODEL_H
#include "backgroundlistmodel.h"
class SlideModel : public BackgroundListModel
{
Q_OBJECT
public:
using BackgroundListModel::BackgroundListModel;
void reload(const QStringList &selected);
void addDirs(const QStringList &selected);
void removeDir(const QString &selected);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash roleNames() const override;
+
+Q_SIGNALS:
+ void done();
+
private Q_SLOTS:
void removeBackgrounds(const QStringList &paths, const QString &token);
void backgroundsFound(const QStringList &paths, const QString &token);
};
#endif
diff --git a/wallpapers/image/slideshowpackage/contents/config/main.xml b/wallpapers/image/slideshowpackage/contents/config/main.xml
index 272e568d7..48c3e19e4 100644
--- a/wallpapers/image/slideshowpackage/contents/config/main.xml
+++ b/wallpapers/image/slideshowpackage/contents/config/main.xml
@@ -1,43 +1,46 @@
false
#000000
2
900
1000
+
+
+ 0
+
-