Commit 2003b267 authored by David Redondo's avatar David Redondo Committed by Nate Graham

Image Wallpaper Slideshow - display the list of images that will be shown

Summary:
This shows all the pictures inside the folders added to the Folders list. I also tried to make single pictures excludable via a checkbox on the thumbnail. This is the first time for me programming with QT/QML/Singals-Slots and I tried to use as much existing code as possible. The thumbnail view is the same as for single images and I simply subclassed the listmodel. However even if I tried to do everything like the code for slidePaths it doesn't work correctly. The checking/unchecking of images only applies on restart of plasmashell. Maybe it's a single mistake that is easily spotted by a more experienced programmer otherwise if the thumbnail view is accepted I can also revert all the checkbox stuff.

FEATURE: 403703
FIXED-IN: 5.16.0

{F6595564}

Reviewers: #vdg, ngraham, davidedmundson

Reviewed By: #vdg, ngraham, davidedmundson

Subscribers: filipf, mart, alexde, davidedmundson, ngraham, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D18809
parent 19144ab0
...@@ -4,6 +4,7 @@ set(image_SRCS ...@@ -4,6 +4,7 @@ set(image_SRCS
image.cpp image.cpp
imageplugin.cpp imageplugin.cpp
backgroundlistmodel.cpp backgroundlistmodel.cpp
slidemodel.cpp
) )
ecm_qt_declare_logging_category(image_SRCS HEADER debug.h ecm_qt_declare_logging_category(image_SRCS HEADER debug.h
......
...@@ -105,18 +105,20 @@ protected Q_SLOTS: ...@@ -105,18 +105,20 @@ protected Q_SLOTS:
void backgroundsFound(const QStringList &paths, const QString &token); void backgroundsFound(const QStringList &paths, const QString &token);
void processPaths(const QStringList &paths); void processPaths(const QStringList &paths);
protected:
QPointer<Image> m_wallpaper;
QString m_findToken;
QList<KPackage::Package> m_packages;
private: private:
QSize bestSize(const KPackage::Package &package) const; QSize bestSize(const KPackage::Package &package) const;
QPointer<Image> m_wallpaper;
QList<KPackage::Package> m_packages;
QSet<QString> m_removableWallpapers; QSet<QString> m_removableWallpapers;
QHash<QString, QSize> m_sizeCache; QHash<QString, QSize> m_sizeCache;
QHash<QUrl, QPersistentModelIndex> m_previewJobs; QHash<QUrl, QPersistentModelIndex> m_previewJobs;
KDirWatch m_dirwatch; KDirWatch m_dirwatch;
QCache<QString, QPixmap> m_imageCache; QCache<QString, QPixmap> m_imageCache;
QString m_findToken;
int m_screenshotSize; int m_screenshotSize;
QHash<QString, int> m_pendingDeletion; QHash<QString, int> m_pendingDeletion;
}; };
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include <Plasma/PluginLoader> #include <Plasma/PluginLoader>
#include <qstandardpaths.h> #include <qstandardpaths.h>
#include "backgroundlistmodel.h" #include "backgroundlistmodel.h"
#include "slidemodel.h"
#include <KPackage/PackageLoader> #include <KPackage/PackageLoader>
...@@ -64,6 +65,7 @@ Image::Image(QObject *parent) ...@@ -64,6 +65,7 @@ Image::Image(QObject *parent)
m_mode(SingleImage), m_mode(SingleImage),
m_currentSlide(-1), m_currentSlide(-1),
m_model(nullptr), m_model(nullptr),
m_slideshowModel(nullptr),
m_dialog(nullptr) m_dialog(nullptr)
{ {
m_wallpaperPackage = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Wallpaper/Images")); m_wallpaperPackage = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Wallpaper/Images"));
...@@ -275,6 +277,15 @@ QAbstractItemModel* Image::wallpaperModel() ...@@ -275,6 +277,15 @@ QAbstractItemModel* Image::wallpaperModel()
return m_model; return m_model;
} }
QAbstractItemModel* Image::slideshowModel()
{
if (!m_slideshowModel) {
m_slideshowModel = new SlideModel(this, this);
m_slideshowModel->reload(m_slidePaths);
}
return m_slideshowModel;
}
int Image::slideTimer() const int Image::slideTimer() const
{ {
return m_delay; return m_delay;
...@@ -336,7 +347,9 @@ void Image::setSlidePaths(const QStringList &slidePaths) ...@@ -336,7 +347,9 @@ void Image::setSlidePaths(const QStringList &slidePaths)
updateDirWatch(m_slidePaths); updateDirWatch(m_slidePaths);
startSlideshow(); startSlideshow();
} }
if (m_slideshowModel) {
m_slideshowModel->reload(m_slidePaths);
}
emit slidePathsChanged(); emit slidePathsChanged();
} }
...@@ -357,7 +370,9 @@ void Image::addSlidePath(const QString &path) ...@@ -357,7 +370,9 @@ void Image::addSlidePath(const QString &path)
if (m_mode == SlideShow) { if (m_mode == SlideShow) {
updateDirWatch(m_slidePaths); updateDirWatch(m_slidePaths);
} }
if (m_slideshowModel) {
m_slideshowModel->addDirs({m_slidePaths});
}
emit slidePathsChanged(); emit slidePathsChanged();
startSlideshow(); startSlideshow();
} }
...@@ -370,6 +385,28 @@ void Image::removeSlidePath(const QString &path) ...@@ -370,6 +385,28 @@ void Image::removeSlidePath(const QString &path)
if (m_mode == SlideShow) { if (m_mode == SlideShow) {
updateDirWatch(m_slidePaths); 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(); emit slidePathsChanged();
startSlideshow(); startSlideshow();
...@@ -582,7 +619,6 @@ void Image::backgroundsFound(const QStringList &paths, const QString &token) ...@@ -582,7 +619,6 @@ void Image::backgroundsFound(const QStringList &paths, const QString &token)
startSlideshow(); startSlideshow();
return; return;
} }
m_slideshowBackgrounds = paths; m_slideshowBackgrounds = paths;
m_unseenSlideshowBackgrounds.clear(); m_unseenSlideshowBackgrounds.clear();
// start slideshow // start slideshow
...@@ -856,3 +892,7 @@ void Image::commitDeletion() ...@@ -856,3 +892,7 @@ void Image::commitDeletion()
} }
} }
void Image::openFolder(const QString& path)
{
new KRun(QUrl::fromLocalFile(path), nullptr);
}
...@@ -48,6 +48,7 @@ namespace KNS3 { ...@@ -48,6 +48,7 @@ namespace KNS3 {
} }
class BackgroundListModel; class BackgroundListModel;
class SlideModel;
class Image : public QObject, public QQmlParserStatus class Image : public QObject, public QQmlParserStatus
{ {
...@@ -57,6 +58,7 @@ class Image : public QObject, public QQmlParserStatus ...@@ -57,6 +58,7 @@ class Image : public QObject, public QQmlParserStatus
Q_PROPERTY(RenderingMode renderingMode READ renderingMode WRITE setRenderingMode NOTIFY renderingModeChanged) Q_PROPERTY(RenderingMode renderingMode READ renderingMode WRITE setRenderingMode NOTIFY renderingModeChanged)
Q_PROPERTY(QUrl wallpaperPath READ wallpaperPath NOTIFY wallpaperPathChanged) Q_PROPERTY(QUrl wallpaperPath READ wallpaperPath NOTIFY wallpaperPathChanged)
Q_PROPERTY(QAbstractItemModel *wallpaperModel READ wallpaperModel CONSTANT) Q_PROPERTY(QAbstractItemModel *wallpaperModel READ wallpaperModel CONSTANT)
Q_PROPERTY(QAbstractItemModel *slideshowModel READ slideshowModel CONSTANT)
Q_PROPERTY(int slideTimer READ slideTimer WRITE setSlideTimer NOTIFY slideTimerChanged) Q_PROPERTY(int slideTimer READ slideTimer WRITE setSlideTimer NOTIFY slideTimerChanged)
Q_PROPERTY(QStringList usersWallpapers READ usersWallpapers WRITE setUsersWallpapers NOTIFY usersWallpapersChanged) Q_PROPERTY(QStringList usersWallpapers READ usersWallpapers WRITE setUsersWallpapers NOTIFY usersWallpapersChanged)
Q_PROPERTY(QStringList slidePaths READ slidePaths WRITE setSlidePaths NOTIFY slidePathsChanged) Q_PROPERTY(QStringList slidePaths READ slidePaths WRITE setSlidePaths NOTIFY slidePathsChanged)
...@@ -82,6 +84,7 @@ class Image : public QObject, public QQmlParserStatus ...@@ -82,6 +84,7 @@ class Image : public QObject, public QQmlParserStatus
Q_INVOKABLE void addSlidePath(const QString &path); Q_INVOKABLE void addSlidePath(const QString &path);
Q_INVOKABLE void removeSlidePath(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 getNewWallpaper(QQuickItem *ctx = nullptr);
Q_INVOKABLE void showFileDialog(); Q_INVOKABLE void showFileDialog();
...@@ -98,6 +101,7 @@ class Image : public QObject, public QQmlParserStatus ...@@ -98,6 +101,7 @@ class Image : public QObject, public QQmlParserStatus
KPackage::Package *package(); KPackage::Package *package();
QAbstractItemModel* wallpaperModel(); QAbstractItemModel* wallpaperModel();
QAbstractItemModel* slideshowModel();
int slideTimer() const; int slideTimer() const;
void setSlideTimer(int time); void setSlideTimer(int time);
...@@ -116,7 +120,7 @@ class Image : public QObject, public QQmlParserStatus ...@@ -116,7 +120,7 @@ class Image : public QObject, public QQmlParserStatus
QString photosPath() const; QString photosPath() const;
public Q_SLOTS: public Q_SLOTS:
void nextSlide(); void nextSlide();
void removeWallpaper(QString name); void removeWallpaper(QString name);
...@@ -178,6 +182,7 @@ class Image : public QObject, public QQmlParserStatus ...@@ -178,6 +182,7 @@ class Image : public QObject, public QQmlParserStatus
QTimer m_timer; QTimer m_timer;
int m_currentSlide; int m_currentSlide;
BackgroundListModel *m_model; BackgroundListModel *m_model;
SlideModel* m_slideshowModel;
QFileDialog *m_dialog; QFileDialog *m_dialog;
QString m_img; QString m_img;
QDateTime m_previousModified; QDateTime m_previousModified;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Controls.Private 1.0 import QtQuick.Controls.Private 1.0
import QtQuick.Controls 2.3 as QtControls2
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import org.kde.kquickcontrolsaddons 2.0 import org.kde.kquickcontrolsaddons 2.0
import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 2.0 as PlasmaComponents
...@@ -28,7 +29,6 @@ import org.kde.kcm 1.1 as KCM ...@@ -28,7 +29,6 @@ import org.kde.kcm 1.1 as KCM
KCM.GridDelegate { KCM.GridDelegate {
id: wallpaperDelegate id: wallpaperDelegate
property alias color: backgroundRect.color property alias color: backgroundRect.color
property bool selected: (wallpapersGrid.currentIndex === index) property bool selected: (wallpapersGrid.currentIndex === index)
opacity: model.pendingDeletion ? 0.5 : 1 opacity: model.pendingDeletion ? 0.5 : 1
...@@ -43,20 +43,20 @@ KCM.GridDelegate { ...@@ -43,20 +43,20 @@ KCM.GridDelegate {
Kirigami.Action { Kirigami.Action {
icon.name: "document-open-folder" icon.name: "document-open-folder"
tooltip: i18nd("plasma_wallpaper_org.kde.image", "Open Containing Folder") tooltip: i18nd("plasma_wallpaper_org.kde.image", "Open Containing Folder")
onTriggered: imageWallpaper.wallpaperModel.openContainingFolder(index) onTriggered: imageModel.openContainingFolder(index)
}, },
Kirigami.Action { Kirigami.Action {
icon.name: "edit-undo" icon.name: "edit-undo"
visible: model.pendingDeletion visible: model.pendingDeletion
tooltip: i18nd("plasma_wallpaper_org.kde.image", "Restore wallpaper") tooltip: i18nd("plasma_wallpaper_org.kde.image", "Restore wallpaper")
onTriggered: imageWallpaper.wallpaperModel.setPendingDeletion(index, !model.pendingDeletion) onTriggered: imageModel.setPendingDeletion(index, !model.pendingDeletion)
}, },
Kirigami.Action { Kirigami.Action {
icon.name: "edit-delete" icon.name: "edit-delete"
tooltip: i18nd("plasma_wallpaper_org.kde.image", "Remove Wallpaper") tooltip: i18nd("plasma_wallpaper_org.kde.image", "Remove Wallpaper")
visible: model.removable && !model.pendingDeletion visible: model.removable && !model.pendingDeletion && configDialog.currentWallpaper == "org.kde.image"
onTriggered: { onTriggered: {
imageWallpaper.wallpaperModel.setPendingDeletion(index, true); imageModel.setPendingDeletion(index, true);
if (wallpapersGrid.currentIndex === index) { if (wallpapersGrid.currentIndex === index) {
wallpapersGrid.currentIndex = (index + 1) % wallpapersGrid.count; wallpapersGrid.currentIndex = (index + 1) % wallpapersGrid.count;
} }
......
...@@ -238,30 +238,70 @@ ColumnLayout { ...@@ -238,30 +238,70 @@ ColumnLayout {
text: i18nd("plasma_wallpaper_org.kde.image","Seconds") text: i18nd("plasma_wallpaper_org.kde.image","Seconds")
} }
} }
QtControls2.ScrollView { Kirigami.Heading {
id: foldersScroll text: "Folders"
Layout.fillHeight: true; level: 2
}
GridLayout {
columns: 2
Layout.fillWidth: true Layout.fillWidth: true
Component.onCompleted: foldersScroll.background.visible = true; Layout.fillHeight: true
ListView { columnSpacing: Kirigami.Units.largeSpacing
id: slidePathsView QtControls2.ScrollView {
anchors.margins: 4 id: foldersScroll
model: imageWallpaper.slidePaths Layout.fillHeight: true
delegate: QtControls2.Label { Layout.preferredWidth: 0.25 * parent.width
text: modelData Component.onCompleted: foldersScroll.background.visible = true;
width: slidePathsView.width ListView {
height: Math.max(paintedHeight, removeButton.height); id: slidePathsView
QtControls2.ToolButton { anchors.margins: 4
id: removeButton model: imageWallpaper.slidePaths
anchors { delegate: Kirigami.SwipeListItem {
verticalCenter: parent.verticalCenter id: folderDelegate
right: parent.right 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
} }
icon.name: "list-remove" width: slidePathsView.width
onClicked: imageWallpaper.removeSlidePath(modelData); 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);
}
} }
} }
} }
...@@ -271,12 +311,12 @@ ColumnLayout { ...@@ -271,12 +311,12 @@ ColumnLayout {
KCM.GridView { KCM.GridView {
id: wallpapersGrid id: wallpapersGrid
anchors.fill: parent anchors.fill: parent
property var imageModel: (configDialog.currentWallpaper == "org.kde.image")? imageWallpaper.wallpaperModel : imageWallpaper.slideshowModel
//that min is needed as the module will be populated in an async way //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 //and only on demand so we can't ensure it already exists
view.currentIndex: Math.min(imageWallpaper.wallpaperModel.indexOf(cfg_Image), imageWallpaper.wallpaperModel.count-1) view.currentIndex: Math.min(imageModel.indexOf(cfg_Image), imageModel.count-1)
//kill the space for label under thumbnails //kill the space for label under thumbnails
view.model: imageWallpaper.wallpaperModel view.model: imageModel
view.delegate: WallpaperDelegate { view.delegate: WallpaperDelegate {
color: cfg_Color color: cfg_Color
} }
...@@ -307,21 +347,16 @@ ColumnLayout { ...@@ -307,21 +347,16 @@ ColumnLayout {
Loader { Loader {
anchors.fill: parent anchors.fill: parent
sourceComponent: (configDialog.currentWallpaper == "org.kde.image") ? thumbnailsComponent : foldersComponent sourceComponent: (configDialog.currentWallpaper == "org.kde.image") ? thumbnailsComponent :
((configDialog.currentWallpaper == "org.kde.slideshow") ? foldersComponent : undefined)
} }
} }
RowLayout { RowLayout {
id: buttonsRow id: buttonsRow
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
visible: configDialog.currentWallpaper == "org.kde.image"
QtControls2.Button { QtControls2.Button {
visible: (configDialog.currentWallpaper == "org.kde.slideshow")
icon.name: "list-add"
text: i18nd("plasma_wallpaper_org.kde.image","Add Folder...")
onClicked: imageWallpaper.showAddSlidePathsDialog()
}
QtControls2.Button {
visible: (configDialog.currentWallpaper == "org.kde.image")
icon.name: "list-add" icon.name: "list-add"
text: i18nd("plasma_wallpaper_org.kde.image","Add Image...") text: i18nd("plasma_wallpaper_org.kde.image","Add Image...")
onClicked: imageWallpaper.showFileDialog(); onClicked: imageWallpaper.showFileDialog();
......
#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);
}
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);
}
}
#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);
private Q_SLOTS:
void removeBackgrounds(const QStringList &paths, const QString &token);
void backgroundsFound(const QStringList &paths, const QString &token);
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment