1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2018-07-30
7 * Description : a plugin to render slideshow.
8 *
9 * Copyright (C) 2018-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 * Copyright (C) 2019-2020 by Minh Nghia Duong <minhnghiaduong997 at gmail dot com>
11 *
12 * This program is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU General
14 * Public License as published by the Free Software Foundation;
15 * either version 2, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "slideshowplugin.h"
25
26 // Qt includes
27
28 #include <QPointer>
29 #include <QMenu>
30 #include <QDebug>
31 #include <QString>
32 #include <QApplication>
33
34 // KDE includes
35
36 #include <klocalizedstring.h>
37 #include <kactioncollection.h>
38 #include <kxmlguiwindow.h>
39
40 // Local includes
41
42 #include "metaenginesettings.h"
43 #include "setupslideshow_dialog.h"
44 #include "slideshowloader.h"
45
46 using namespace Digikam;
47
48 namespace DigikamGenericSlideShowPlugin
49 {
50
SlideShowPlugin(QObject * const parent)51 SlideShowPlugin::SlideShowPlugin(QObject* const parent)
52 : DPluginGeneric(parent)
53 {
54 }
55
~SlideShowPlugin()56 SlideShowPlugin::~SlideShowPlugin()
57 {
58 }
59
name() const60 QString SlideShowPlugin::name() const
61 {
62 return i18n("SlideShow");
63 }
64
iid() const65 QString SlideShowPlugin::iid() const
66 {
67 return QLatin1String(DPLUGIN_IID);
68 }
69
icon() const70 QIcon SlideShowPlugin::icon() const
71 {
72 return QIcon::fromTheme(QLatin1String("view-presentation"));
73 }
74
description() const75 QString SlideShowPlugin::description() const
76 {
77 return i18n("A tool to render slideshow");
78 }
79
details() const80 QString SlideShowPlugin::details() const
81 {
82 return i18n("<p>This tool render a series of items as a simple slide-show.</p>"
83 "<p>Plenty of items properties can be displayed as overlay while running.</p>"
84 "<p>This tool can play album contents in recursive mode with children albums if any.</p>"
85 "<p><u>Usage:</u></p>"
86
87 "<table>"
88
89 "<tr>"
90 "<td colspan=\"2\"><nobr><center>"
91 "<b><h1>Item Access</h1></b>"
92 "</center></nobr></td>"
93 "</tr>"
94
95 "<tr><td>Previous Item:</td>" "<td><i>Up</i> key</td></tr>"
96 "<tr><td></td>" "<td><i>PgUp</i> key</td></tr>"
97 "<tr><td></td>" "<td><i>Left</i> key</td></tr>"
98 "<tr><td></td>" "<td>Mouse wheel up</td></tr>"
99 "<tr><td></td>" "<td>Left mouse button</td></tr>"
100 "<tr><td>Next Item:</td>" "<td><i>Down</i> key</td></tr>"
101 "<tr><td></td>" "<td><i>PgDown</i> key</td></tr>"
102 "<tr><td></td>" "<td><i>Right</i> key</td></tr>"
103 "<tr><td></td>" "<td>Mouse wheel down</td></tr>"
104 "<tr><td></td>" "<td>Right mouse button</td></tr>"
105 "<tr><td>Pause/Start:</td>" "<td><i>Space</i> key</td></tr>"
106 "<tr><td>Slideshow Settings:</td>" "<td><i>F2</i> key</td></tr>"
107 "<tr><td>Hide/Show Properties:</td>" "<td><i>F4</i> key</td></tr>"
108 "<tr><td>Quit:</td>" "<td><i>Esc</i> key</td></tr>"
109
110 "<tr>"
111 "<td colspan=\"2\"><nobr><center>"
112 "<b><h1>Item Properties</h1></b>"
113 "</center></nobr></td>"
114 "</tr>"
115
116 "<tr><td>Change Tags:</td>" "<td>Use Tags keyboard shortcuts</td></tr>"
117 "<tr><td>Change Rating:</td>" "<td>Use Rating keyboard shortcuts</td></tr>"
118 "<tr><td>Change Color Label:</td>" "<td>Use Color label keyboard shortcuts</td></tr>"
119 "<tr><td>Change Pick Label:</td>" "<td>Use Pick label keyboard shortcuts</td></tr>"
120
121 "<tr>"
122 "<td colspan=\"2\"><nobr><center>"
123 "<b><h1>Others</h1></b>"
124 "</center></nobr></td>"
125 "</tr>"
126
127 "<tr><td>Show this help:</td>" "<td><i>F1</i> key</td></tr>"
128
129 "</table>");
130 }
131
authors() const132 QList<DPluginAuthor> SlideShowPlugin::authors() const
133 {
134 return QList<DPluginAuthor>()
135 << DPluginAuthor(QString::fromUtf8("Enrico Ros"),
136 QString::fromUtf8("eros dot kde at email dot it"),
137 QString::fromUtf8("(C) 2004"))
138 << DPluginAuthor(QString::fromUtf8("Renchi Raju"),
139 QString::fromUtf8("renchi dot raju at gmail dot com"),
140 QString::fromUtf8("(C) 2004-2005"))
141 << DPluginAuthor(QString::fromUtf8("Gilles Caulier"),
142 QString::fromUtf8("caulier dot gilles at gmail dot com"),
143 QString::fromUtf8("(C) 2005-2021"))
144 << DPluginAuthor(QString::fromUtf8("Minh Nghia Duong"),
145 QString::fromUtf8("minhnghiaduong997 at gmail dot com"),
146 QString::fromUtf8("(C) 2019-2021"))
147 << DPluginAuthor(QString::fromUtf8("Phuoc Khanh Le"),
148 QString::fromUtf8("phuockhanhnk94 at gmail dot com"),
149 QString::fromUtf8("(C) 2021"))
150 << DPluginAuthor(QString::fromUtf8("Fady Khalaf"),
151 QString::fromUtf8("fadykhalaf01 at gmail dot com"),
152 QString::fromUtf8("(C) 2019"))
153 ;
154 }
setup(QObject * const parent)155 void SlideShowPlugin::setup(QObject* const parent)
156 {
157 DPluginAction* const ac = new DPluginAction(parent);
158 ac->setIcon(icon());
159 ac->setText(i18nc("@action", "Slideshow"));
160 ac->setObjectName(QLatin1String("slideshow_plugin"));
161 ac->setActionCategory(DPluginAction::GenericView);
162
163 DInfoInterface* const iface = infoIface(ac);
164
165 if (iface && (parent->objectName() == QLatin1String("Digikam")))
166 {
167
168 QMenu* const slideShowActions = new QMenu(i18n("Slideshow"));
169 slideShowActions->setIcon(icon());
170 ac->setMenu(slideShowActions);
171
172 // Action show all
173
174 QAction* const slideShowAllAction = new QAction(i18n("Play All"), ac);
175 slideShowAllAction->setObjectName(QLatin1String("slideshow_all"));
176 slideShowActions->addAction(slideShowAllAction);
177
178 connect(slideShowAllAction, SIGNAL(triggered()),
179 this, SLOT(slotMenuSlideShowAll()));
180
181 // Action show selection
182
183 QAction* const slideShowSelectionAction = new QAction(i18n("Play Selection"), ac);
184 slideShowSelectionAction->setObjectName(QLatin1String("slideshow_selected"));
185 slideShowActions->addAction(slideShowSelectionAction);
186
187 connect(slideShowSelectionAction, SIGNAL(triggered()),
188 this, SLOT(slotMenuSlideShowSelection()));
189
190 // Action show recursive
191
192 QAction* const slideShowRecursiveAction = new QAction(i18n("Play With Sub-Albums"), ac);
193 slideShowRecursiveAction->setObjectName(QLatin1String("slideshow_recursive"));
194 slideShowActions->addAction(slideShowRecursiveAction);
195
196 connect(slideShowRecursiveAction, SIGNAL(triggered()),
197 this, SLOT(slotMenuSlideShowRecursive()));
198
199 connect(ac, SIGNAL(triggered(bool)),
200 this, SLOT(slotShowManual()));
201
202 // See bug #425425: register all sub-actions to collection instance to be able to edit keyboard shorcuts
203
204 KXmlGuiWindow* const gui = dynamic_cast<KXmlGuiWindow*>(parent);
205
206 if (gui)
207 {
208 KActionCollection* const collection = gui->actionCollection();
209 collection->setShortcutsConfigurable(slideShowActions->menuAction(), false);
210
211 collection->addAction(slideShowAllAction->objectName(), slideShowAllAction);
212 collection->addAction(slideShowSelectionAction->objectName(), slideShowSelectionAction);
213 collection->addAction(slideShowRecursiveAction->objectName(), slideShowRecursiveAction);
214
215 collection->setDefaultShortcut(slideShowAllAction, Qt::Key_F9);
216 collection->setDefaultShortcut(slideShowSelectionAction, Qt::ALT + Qt::Key_F9);
217 collection->setDefaultShortcut(slideShowRecursiveAction, Qt::SHIFT + Qt::Key_F9);
218 }
219 }
220 else
221 {
222 ac->setShortcut(Qt::Key_F9);
223
224 connect(ac, SIGNAL(triggered(bool)),
225 this, SLOT(slotMenuSlideShow()));
226 }
227
228 addAction(ac);
229 }
230
addConnectionSlideEnd(QObject * const obj)231 void SlideShowPlugin::addConnectionSlideEnd(QObject* const obj)
232 {
233 Q_UNUSED(obj);
234 }
235
slotMenuSlideShow()236 void SlideShowPlugin::slotMenuSlideShow()
237 {
238 QUrl startFrom;
239 DPluginAction* const ac = dynamic_cast<DPluginAction*>(sender());
240
241 if (ac)
242 {
243 startFrom = ac->data().toUrl();
244 ac->setData(QVariant());
245 }
246
247 SlideShowSettings* const settings = new SlideShowSettings();
248 settings->iface = infoIface(ac);
249 settings->readFromConfig();
250 settings->exifRotate = MetaEngineSettings::instance()->settings().exifRotate;
251 settings->fileList = settings->iface->currentAlbumItems();
252
253 slideshow(settings, true, startFrom);
254 }
255
slotMenuSlideShowAll()256 void SlideShowPlugin::slotMenuSlideShowAll()
257 {
258 SlideShowSettings* const settings = new SlideShowSettings();
259 settings->iface = infoIface(sender()->parent());
260 settings->readFromConfig();
261 settings->fileList = settings->iface->currentAlbumItems();
262
263 slideshow(settings);
264 }
265
slotMenuSlideShowSelection()266 void SlideShowPlugin::slotMenuSlideShowSelection()
267 {
268 SlideShowSettings* const settings = new SlideShowSettings();
269 settings->iface = infoIface(sender()->parent());
270 settings->readFromConfig();
271 settings->fileList = settings->iface->currentSelectedItems();
272
273 slideshow(settings);
274 }
275
slotMenuSlideShowRecursive()276 void SlideShowPlugin::slotMenuSlideShowRecursive()
277 {
278 DInfoInterface* const iface = infoIface(sender()->parent());
279
280 connect(iface, SIGNAL(signalAlbumItemsRecursiveCompleted(QList<QUrl>)),
281 this, SLOT(slotShowRecursive(QList<QUrl>)));
282
283 iface->parseAlbumItemsRecursive();
284 }
285
slotShowRecursive(const QList<QUrl> & imageList)286 void SlideShowPlugin::slotShowRecursive(const QList<QUrl>& imageList)
287 {
288 SlideShowSettings* const settings = new SlideShowSettings();
289 settings->iface = dynamic_cast<DInfoInterface*>(sender());
290 settings->readFromConfig();
291 settings->fileList = imageList;
292
293 slideshow(settings);
294 }
295
slotShowManual()296 void SlideShowPlugin::slotShowManual()
297 {
298 DPluginAction* const ac = dynamic_cast<DPluginAction*>(sender());
299
300 if (!ac)
301 {
302 return;
303 }
304
305 QUrl startFrom(ac->data().toUrl());
306 ac->setData(QVariant());
307
308 SlideShowSettings* const settings = new SlideShowSettings();
309 settings->iface = infoIface(ac);
310 settings->readFromConfig();
311 settings->exifRotate = MetaEngineSettings::instance()->settings().exifRotate;
312 settings->fileList = settings->iface->currentAlbumItems();
313
314 slideshow(settings, !startFrom.isValid(), startFrom);
315 }
316
slideshow(SlideShowSettings * const settings,bool autoPlayEnabled,const QUrl & startFrom)317 void SlideShowPlugin::slideshow(SlideShowSettings* const settings, bool autoPlayEnabled, const QUrl& startFrom)
318 {
319 settings->autoPlayEnabled = autoPlayEnabled;
320 settings->plugin = this;
321
322 // TODO: preview settings for digikam
323 //settings.previewSettings = ApplicationSettings::instance()->getPreviewSettings();
324
325 if (startFrom.isValid())
326 {
327 settings->imageUrl = startFrom;
328 }
329
330 SlideShowLoader* const slide = new SlideShowLoader(settings);
331 slide->setShortCutPrefixes(settings->iface->passShortcutActionsToWidget(slide));
332
333 if (settings->imageUrl.isValid())
334 {
335 slide->setCurrentItem(settings->imageUrl);
336 }
337 else if (settings->startWithCurrent)
338 {
339 if (!settings->iface->currentSelectedItems().isEmpty())
340 {
341 slide->setCurrentItem(settings->iface->currentSelectedItems()[0]);
342 }
343 else
344 {
345 // no current selection, do nothing.
346
347 return;
348 }
349 }
350
351 connect(slide, SIGNAL(signalLastItemUrl(QUrl)),
352 settings->iface, SIGNAL(signalLastItemUrl(QUrl)));
353
354 connect(settings->iface, SIGNAL(signalShortcutPressed(QString,int)),
355 slide, SLOT(slotHandleShortcut(QString,int)));
356
357 slide->show();
358 }
359
360 } // namespace DigikamGenericSlideShowPlugin
361