1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2008-11-21
7 * Description : Batch Queue Manager GUI
8 *
9 * Copyright (C) 2008-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option)
15 * 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 "queuemgrwindow_p.h"
25
26 namespace Digikam
27 {
28
29 QueueMgrWindow* QueueMgrWindow::m_instance = nullptr;
30
queueManagerWindow()31 QueueMgrWindow* QueueMgrWindow::queueManagerWindow()
32 {
33 if (!m_instance)
34 {
35 new QueueMgrWindow();
36 }
37
38 return m_instance;
39 }
40
queueManagerWindowCreated()41 bool QueueMgrWindow::queueManagerWindowCreated()
42 {
43 return m_instance;
44 }
45
QueueMgrWindow()46 QueueMgrWindow::QueueMgrWindow()
47 : DXmlGuiWindow(nullptr),
48 d (new Private)
49 {
50 setConfigGroupName(QLatin1String("Batch Queue Manager Settings"));
51 setXMLFile(QLatin1String("queuemgrwindowui5.rc"));
52
53 qRegisterMetaType<BatchToolSettings>("BatchToolSettings");
54 qRegisterMetaType<BatchToolSet>("BatchToolSet");
55
56 m_instance = this;
57 BatchToolsFactory::instance(); // Create first instance here
58 WorkflowManager::instance(); // Create first instance here
59 d->thread = new ActionThread(this);
60
61 setWindowFlags(Qt::Window);
62 setCaption(i18n("Batch Queue Manager"));
63
64 // We don't want to be deleted on close
65
66 setAttribute(Qt::WA_DeleteOnClose, false);
67 setFullScreenOptions(FS_NONE);
68
69 // -- Build the GUI -------------------------------
70
71 setupUserArea();
72 setupStatusBar();
73 setupActions();
74
75 // Make signals/slots connections
76
77 setupConnections();
78
79 //-------------------------------------------------------------
80
81 readSettings();
82 applySettings();
83 setAutoSaveSettings(configGroupName(), true);
84
85 populateToolsList();
86 slotQueueContentsChanged();
87 }
88
~QueueMgrWindow()89 QueueMgrWindow::~QueueMgrWindow()
90 {
91 m_instance = nullptr;
92 delete d;
93 }
94
queuesMap() const95 QMap<int, QString> QueueMgrWindow::queuesMap() const
96 {
97 if (d->queuePool)
98 {
99 return d->queuePool->queuesMap();
100 }
101
102 return QMap<int, QString>();
103 }
104
isBusy() const105 bool QueueMgrWindow::isBusy() const
106 {
107 return d->busy;
108 }
109
closeEvent(QCloseEvent * e)110 void QueueMgrWindow::closeEvent(QCloseEvent* e)
111 {
112 if (!e)
113 {
114 return;
115 }
116
117 writeSettings();
118
119 DXmlGuiWindow::closeEvent(e);
120 }
121
setupUserArea()122 void QueueMgrWindow::setupUserArea()
123 {
124 QWidget* const mainW = new QWidget(this);
125 QVBoxLayout* const mainLayout = new QVBoxLayout(mainW);
126
127 // ------------------------------------------------------------------------------
128
129 QGroupBox* const queuesBox = new QGroupBox(i18n("Queues"), mainW);
130 QVBoxLayout* const vlay1 = new QVBoxLayout(queuesBox);
131 d->queuePool = new QueuePool(queuesBox);
132 vlay1->addWidget(d->queuePool);
133 vlay1->setContentsMargins(QMargins());
134 vlay1->setSpacing(0);
135
136 // ------------------------------------------------------------------------------
137
138 QGroupBox* const queueSettingsBox = new QGroupBox(i18n("Queue Settings"), mainW);
139 QVBoxLayout* const vlay2 = new QVBoxLayout(queueSettingsBox);
140 d->queueSettingsView = new QueueSettingsView(queueSettingsBox);
141 vlay2->addWidget(d->queueSettingsView);
142 vlay2->setContentsMargins(QMargins());
143 vlay2->setSpacing(0);
144
145 // ------------------------------------------------------------------------------
146
147 QGroupBox* const toolsBox = new QGroupBox(i18n("Control Panel"), mainW);
148 QVBoxLayout* const vlay3 = new QVBoxLayout(toolsBox);
149 d->toolsView = new ToolsView(toolsBox);
150 vlay3->addWidget(d->toolsView);
151 vlay3->setContentsMargins(QMargins());
152 vlay3->setSpacing(0);
153
154 // ------------------------------------------------------------------------------
155
156 QGroupBox* const assignBox = new QGroupBox(i18n("Assigned Tools"), mainW);
157 QVBoxLayout* const vlay4 = new QVBoxLayout(assignBox);
158 d->assignedList = new AssignedListView(assignBox);
159 vlay4->addWidget(d->assignedList);
160 vlay4->setContentsMargins(QMargins());
161 vlay4->setSpacing(0);
162
163 // ------------------------------------------------------------------------------
164
165 QGroupBox* const toolSettingsBox = new QGroupBox(i18n("Tool Settings"), mainW);
166 QVBoxLayout* const vlay5 = new QVBoxLayout(toolSettingsBox);
167 d->toolSettings = new ToolSettingsView(toolSettingsBox);
168 vlay5->addWidget(d->toolSettings);
169 vlay5->setContentsMargins(QMargins());
170 vlay5->setSpacing(0);
171
172 // ------------------------------------------------------------------------------
173
174 d->topSplitter = new SidebarSplitter(mainW);
175 d->topSplitter->addWidget(queuesBox);
176 d->topSplitter->addWidget(assignBox);
177 d->topSplitter->addWidget(toolSettingsBox);
178
179 d->bottomSplitter = new SidebarSplitter(mainW);
180 d->bottomSplitter->addWidget(queueSettingsBox);
181 d->bottomSplitter->addWidget(toolsBox);
182
183 d->verticalSplitter = new SidebarSplitter(Qt::Vertical, mainW);
184 d->verticalSplitter->addWidget(d->topSplitter);
185 d->verticalSplitter->addWidget(d->bottomSplitter);
186
187 mainLayout->addWidget(d->verticalSplitter);
188
189 setCentralWidget(mainW);
190 }
191
setupStatusBar()192 void QueueMgrWindow::setupStatusBar()
193 {
194 d->statusProgressBar = new StatusProgressBar(statusBar());
195 d->statusProgressBar->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
196 d->statusProgressBar->setMaximumHeight(fontMetrics().height() + 2);
197 d->statusProgressBar->setNotify(true);
198 d->statusProgressBar->setNotificationTitle(i18n("Batch Queue Manager"), QIcon::fromTheme(QLatin1String("run-build")));
199 statusBar()->addWidget(d->statusProgressBar, 60);
200
201 d->statusLabel = new QLabel(statusBar());
202 d->statusLabel->setAlignment(Qt::AlignCenter);
203 d->statusLabel->setMaximumHeight(fontMetrics().height() + 2);
204 statusBar()->addWidget(d->statusLabel, 40);
205 }
206
setupConnections()207 void QueueMgrWindow::setupConnections()
208 {
209 // -- Assigned tools list connections -----------------------------------
210
211 connect(d->assignedList, SIGNAL(signalToolSelected(BatchToolSet)),
212 d->toolSettings, SLOT(slotToolSelected(BatchToolSet)));
213
214 connect(d->assignedList, SIGNAL(signalAssignedToolsChanged(AssignedBatchTools)),
215 d->queuePool, SLOT(slotAssignedToolsChanged(AssignedBatchTools)));
216
217 connect(d->toolSettings, SIGNAL(signalSettingsChanged(BatchToolSet)),
218 d->assignedList, SLOT(slotSettingsChanged(BatchToolSet)));
219
220 connect(d->assignedList, SIGNAL(signalAssignedToolsChanged(AssignedBatchTools)),
221 this, SLOT(slotAssignedToolsChanged(AssignedBatchTools)));
222
223 connect(d->toolsView, SIGNAL(signalAssignTools(QMultiMap<int,QString>)),
224 d->assignedList, SLOT(slotAssignTools(QMultiMap<int,QString>)));
225
226 // -- Queued Items list connections -------------------------------------
227
228 connect(d->queuePool, SIGNAL(signalQueueSelected(int,QueueSettings,AssignedBatchTools)),
229 d->queueSettingsView, SLOT(slotQueueSelected(int,QueueSettings,AssignedBatchTools)));
230
231 connect(d->queuePool, SIGNAL(signalQueueSelected(int,QueueSettings,AssignedBatchTools)),
232 d->assignedList, SLOT(slotQueueSelected(int,QueueSettings,AssignedBatchTools)));
233
234 connect(d->queueSettingsView, SIGNAL(signalSettingsChanged(QueueSettings)),
235 d->queuePool, SLOT(slotSettingsChanged(QueueSettings)));
236
237 connect(d->queueSettingsView, SIGNAL(signalSettingsChanged(QueueSettings)),
238 this, SLOT(slotQueueContentsChanged()));
239
240 connect(d->queuePool, SIGNAL(signalQueueSelected(int,QueueSettings,AssignedBatchTools)),
241 this, SLOT(slotQueueContentsChanged()));
242
243 connect(d->queuePool, SIGNAL(signalQueuePoolChanged()),
244 this, SLOT(slotQueueContentsChanged()));
245
246 connect(d->queuePool, SIGNAL(signalQueueContentsChanged()),
247 this, SLOT(slotQueueContentsChanged()));
248
249 connect(d->queuePool, SIGNAL(signalItemSelectionChanged()),
250 this, SLOT(slotItemSelectionChanged()));
251
252 // -- Multithreaded interface connections -------------------------------
253
254 connect(d->thread, SIGNAL(signalStarting(Digikam::ActionData)),
255 this, SLOT(slotAction(Digikam::ActionData)));
256
257 connect(d->thread, SIGNAL(signalFinished(Digikam::ActionData)),
258 this, SLOT(slotAction(Digikam::ActionData)));
259
260 connect(d->thread, SIGNAL(signalQueueProcessed()),
261 this, SLOT(slotQueueProcessed()));
262
263 // -- GUI connections ---------------------------------------------------
264
265 connect(d->toolsView, SIGNAL(signalHistoryEntryClicked(int,qlonglong)),
266 this, SLOT(slotHistoryEntryClicked(int,qlonglong)));
267
268 connect(d->toolsView, SIGNAL(signalAssignQueueSettings(QString)),
269 this, SLOT(slotAssignQueueSettings(QString)));
270 }
271
setupActions()272 void QueueMgrWindow::setupActions()
273 {
274 // -- Standard 'File' menu actions ---------------------------------------------
275
276 KActionCollection* const ac = actionCollection();
277
278 d->runAction = new QAction(QIcon::fromTheme(QLatin1String("media-playback-start")),
279 i18n("Run"), this);
280 d->runAction->setEnabled(false);
281 connect(d->runAction, SIGNAL(triggered()), this, SLOT(slotRun()));
282 ac->addAction(QLatin1String("queuemgr_run"), d->runAction);
283 ac->setDefaultShortcut(d->runAction, Qt::CTRL + Qt::Key_P);
284
285 d->runAllAction = new QAction(QIcon::fromTheme(QLatin1String("media-playback-start")),
286 i18n("Run all"), this);
287 d->runAllAction->setEnabled(false);
288 connect(d->runAllAction, SIGNAL(triggered()), this, SLOT(slotRunAll()));
289 ac->addAction(QLatin1String("queuemgr_run_all"), d->runAllAction);
290 ac->setDefaultShortcut(d->runAllAction, Qt::CTRL + Qt::ALT + Qt::Key_P);
291
292 d->stopAction = new QAction(QIcon::fromTheme(QLatin1String("media-playback-stop")), i18n("Stop"), this);
293 d->stopAction->setEnabled(false);
294 connect(d->stopAction, SIGNAL(triggered()), this, SLOT(slotStop()));
295 ac->addAction(QLatin1String("queuemgr_stop"), d->stopAction);
296 ac->setDefaultShortcut(d->stopAction, Qt::CTRL + Qt::Key_S);
297
298 d->newQueueAction = new QAction(QIcon::fromTheme(QLatin1String("list-add")), i18n("New Queue"), this);
299 connect(d->newQueueAction, SIGNAL(triggered()), d->queuePool, SLOT(slotAddQueue()));
300 ac->addAction(QLatin1String("queuemgr_newqueue"), d->newQueueAction);
301
302 d->removeQueueAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Remove Queue"), this);
303 connect(d->removeQueueAction, SIGNAL(triggered()), d->queuePool, SLOT(slotRemoveCurrentQueue()));
304 ac->addAction(QLatin1String("queuemgr_removequeue"), d->removeQueueAction);
305
306 // TODO rename action to saveWorkflowAction to avoid confusion?
307
308 d->saveQueueAction = new QAction(QIcon::fromTheme(QLatin1String("document-save")), i18n("Save Workflow"), this);
309 connect(d->saveQueueAction, SIGNAL(triggered()), this, SLOT(slotSaveWorkflow()));
310 ac->addAction(QLatin1String("queuemgr_savequeue"), d->saveQueueAction);
311
312 d->removeItemsSelAction = new QAction(QIcon::fromTheme(QLatin1String("list-remove")), i18n("Remove items"), this);
313 d->removeItemsSelAction->setEnabled(false);
314 connect(d->removeItemsSelAction, SIGNAL(triggered()), d->queuePool, SLOT(slotRemoveSelectedItems()));
315 ac->addAction(QLatin1String("queuemgr_removeitemssel"), d->removeItemsSelAction);
316 ac->setDefaultShortcut(d->removeItemsSelAction, Qt::CTRL + Qt::Key_K);
317
318 d->removeItemsDoneAction = new QAction(i18n("Remove processed items"), this);
319 d->removeItemsDoneAction->setEnabled(false);
320 connect(d->removeItemsDoneAction, SIGNAL(triggered()), d->queuePool, SLOT(slotRemoveItemsDone()));
321 ac->addAction(QLatin1String("queuemgr_removeitemsdone"), d->removeItemsDoneAction);
322
323 d->clearQueueAction = new QAction(QIcon::fromTheme(QLatin1String("edit-clear")), i18n("Clear Queue"), this);
324 d->clearQueueAction->setEnabled(false);
325 connect(d->clearQueueAction, SIGNAL(triggered()), d->queuePool, SLOT(slotClearList()));
326 ac->addAction(QLatin1String("queuemgr_clearlist"), d->clearQueueAction);
327 ac->setDefaultShortcut(d->clearQueueAction, Qt::CTRL + Qt::SHIFT + Qt::Key_K);
328
329 QAction* const close = buildStdAction(StdCloseAction, this, SLOT(close()), this);
330 ac->addAction(QLatin1String("queuemgr_close"), close);
331
332 // -- 'Tools' menu actions -----------------------------------------------------
333
334 d->moveUpToolAction = new QAction(QIcon::fromTheme(QLatin1String("go-up")), i18n("Move up"), this);
335 connect(d->moveUpToolAction, SIGNAL(triggered()), d->assignedList, SLOT(slotMoveCurrentToolUp()));
336 ac->addAction(QLatin1String("queuemgr_toolup"), d->moveUpToolAction);
337
338 d->moveDownToolAction = new QAction(QIcon::fromTheme(QLatin1String("go-down")), i18n("Move down"), this);
339 connect(d->moveDownToolAction, SIGNAL(triggered()), d->assignedList, SLOT(slotMoveCurrentToolDown()));
340 ac->addAction(QLatin1String("queuemgr_tooldown"), d->moveDownToolAction);
341
342 d->removeToolAction = new QAction(QIcon::fromTheme(QLatin1String("list-remove")), i18n("Remove tool"), this);
343 connect(d->removeToolAction, SIGNAL(triggered()), d->assignedList, SLOT(slotRemoveCurrentTool()));
344 ac->addAction(QLatin1String("queuemgr_toolremove"), d->removeToolAction);
345
346 d->clearToolsAction = new QAction(QIcon::fromTheme(QLatin1String("edit-clear")), i18n("Clear List"), this);
347 connect(d->clearToolsAction, SIGNAL(triggered()), d->assignedList, SLOT(slotClearToolsList()));
348 ac->addAction(QLatin1String("queuemgr_toolsclear"), d->clearToolsAction);
349
350 // -- Standard 'View' menu actions ---------------------------------------------
351
352 createFullScreenAction(QLatin1String("queuemgr_fullscreen"));
353
354 // ---------------------------------------------------------------------------------
355
356 ThemeManager::instance()->registerThemeActions(this);
357
358 // Standard 'Help' menu actions
359
360 createHelpActions();
361
362 // Provides a menu entry that allows showing/hiding the toolbar(s)
363
364 setStandardToolBarMenuEnabled(true);
365
366 // Provides a menu entry that allows showing/hiding the statusbar
367
368 createStandardStatusBarAction();
369
370 // Standard 'Configure' menu actions
371
372 createSettingsActions();
373
374 // ---------------------------------------------------------------------------------
375
376 createGUI(xmlFile());
377 cleanupActions();
378
379 showMenuBarAction()->setChecked(!menuBar()->isHidden()); // NOTE: workaround for bug #171080
380 }
381
refreshView()382 void QueueMgrWindow::refreshView()
383 {
384 // NOTE: method called when something is changed from Database (tags, rating, etc...).
385 // There is nothing to do for the moment.
386 }
387
readSettings()388 void QueueMgrWindow::readSettings()
389 {
390 KSharedConfig::Ptr config = KSharedConfig::openConfig();
391 KConfigGroup group = config->group(configGroupName());
392
393 d->verticalSplitter->restoreState(group, d->VERTICAL_SPLITTER_CONFIG_KEY);
394 d->bottomSplitter->restoreState(group, d->BOTTOM_SPLITTER_CONFIG_KEY);
395 d->topSplitter->restoreState(group, d->TOP_SPLITTER_CONFIG_KEY);
396
397 readFullScreenSettings(group);
398 }
399
writeSettings()400 void QueueMgrWindow::writeSettings()
401 {
402 KSharedConfig::Ptr config = KSharedConfig::openConfig();
403 KConfigGroup group = config->group(configGroupName());
404
405 d->topSplitter->saveState(group, d->TOP_SPLITTER_CONFIG_KEY);
406 d->bottomSplitter->saveState(group, d->BOTTOM_SPLITTER_CONFIG_KEY);
407 d->verticalSplitter->saveState(group, d->VERTICAL_SPLITTER_CONFIG_KEY);
408
409 config->sync();
410 }
411
applySettings()412 void QueueMgrWindow::applySettings()
413 {
414 // Do not apply general settings from config panel if BQM is busy.
415
416 if (d->busy)
417 {
418 return;
419 }
420
421 d->queuePool->applySettings();
422
423 KSharedConfig::Ptr config = KSharedConfig::openConfig();
424 KConfigGroup group = config->group(configGroupName());
425 readFullScreenSettings(group);
426 }
427
refreshStatusBar()428 void QueueMgrWindow::refreshStatusBar()
429 {
430 int items = d->queuePool->currentQueue()->itemsCount();
431 int pendingItems = d->queuePool->currentQueue()->pendingItemsCount();
432 int tasks = d->queuePool->currentQueue()->pendingTasksCount();
433 int totalItems = d->queuePool->totalPendingItems();
434 int totalTasks = d->queuePool->totalPendingTasks();
435 QString message = i18n("Current Queue: ");
436
437 switch (pendingItems)
438 {
439 case 0:
440 message.append(i18n("No items"));
441 break;
442
443 default:
444 message.append(i18np("1 item", "%1 items", pendingItems));
445 break;
446 }
447
448 message.append(QLatin1String(" / "));
449
450 switch (tasks)
451 {
452 case 0:
453 message.append(i18n("No tasks"));
454 break;
455
456 default:
457 message.append(i18np("1 task", "%1 tasks", tasks));
458 break;
459 }
460
461 message.append(QLatin1String(" - ") + i18nc("#info: total number of items to process", "Total: "));
462
463 switch (totalItems)
464 {
465 case 0:
466 message.append(i18n("No items"));
467 break;
468
469 default:
470 message.append(i18np("1 item", "%1 items", totalItems));
471 break;
472 }
473
474 message.append(QLatin1String(" / "));
475
476 switch (totalTasks)
477 {
478 case 0:
479 message.append(i18n("No tasks"));
480 break;
481
482 default:
483 message.append(i18np("1 task", "%1 tasks", totalTasks));
484 break;
485 }
486
487 d->statusLabel->setText(message);
488
489 if (!d->busy)
490 {
491 d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18nc("batch queue manager is ready to use", "Ready"));
492 d->removeItemsSelAction->setEnabled(items > 0);
493 d->removeItemsDoneAction->setEnabled((items - pendingItems) > 0);
494 d->clearQueueAction->setEnabled(items > 0);
495 d->runAction->setEnabled((tasks > 0) && (pendingItems > 0));
496 d->runAllAction->setEnabled((totalTasks > 0) && (totalItems > 0));
497 }
498 }
499
slotSetup()500 void QueueMgrWindow::slotSetup()
501 {
502 setup(Setup::LastPageUsed);
503 }
504
setup(Setup::Page page)505 void QueueMgrWindow::setup(Setup::Page page)
506 {
507 Setup::execDialog(this, page);
508 }
509
slotComponentsInfo()510 void QueueMgrWindow::slotComponentsInfo()
511 {
512 showDigikamComponentsInfo();
513 }
514
slotDBStat()515 void QueueMgrWindow::slotDBStat()
516 {
517 showDigikamDatabaseStat();
518 }
519
slotOnlineVersionCheck()520 void QueueMgrWindow::slotOnlineVersionCheck()
521 {
522 Setup::onlineVersionCheck();
523 }
524
queryClose()525 bool QueueMgrWindow::queryClose()
526 {
527 if (isBusy())
528 {
529 int result = QMessageBox::warning(this, i18n("Processing under progress"),
530 i18n("Batch Queue Manager is running. Do you want to cancel current job?"),
531 QMessageBox::Yes | QMessageBox::No);
532
533 if (result == QMessageBox::Yes)
534 {
535 slotStop();
536 }
537 else if (result == QMessageBox::No)
538 {
539 return false;
540 }
541 }
542
543 return true;
544 }
545
addNewQueue()546 void QueueMgrWindow::addNewQueue()
547 {
548 d->queuePool->slotAddQueue();
549 }
550
currentQueueId() const551 int QueueMgrWindow::currentQueueId() const
552 {
553 return (d->queuePool->currentIndex());
554 }
555
loadItemInfos(const ItemInfoList & list,int queueId)556 void QueueMgrWindow::loadItemInfos(const ItemInfoList& list, int queueId)
557 {
558 QueueListView* const queue = d->queuePool->findQueueByIndex(queueId);
559
560 if (queue)
561 {
562 queue->slotAddItems(list);
563 }
564 }
565
loadItemInfosToCurrentQueue(const ItemInfoList & list)566 void QueueMgrWindow::loadItemInfosToCurrentQueue(const ItemInfoList& list)
567 {
568 if (!d->queuePool->currentQueue())
569 {
570 addNewQueue();
571 }
572
573 d->queuePool->currentQueue()->slotAddItems(list);
574 }
575
loadItemInfosToNewQueue(const ItemInfoList & list)576 void QueueMgrWindow::loadItemInfosToNewQueue(const ItemInfoList& list)
577 {
578 QueueListView* const queue = d->queuePool->currentQueue();
579
580 if (!queue || queue->itemsCount())
581 {
582 addNewQueue();
583 }
584
585 d->queuePool->currentQueue()->slotAddItems(list);
586 }
587
slotQueueContentsChanged()588 void QueueMgrWindow::slotQueueContentsChanged()
589 {
590 if (d->busy)
591 {
592 refreshStatusBar();
593 }
594 else
595 {
596 // refreshStatusBar() and actions in tools view
597
598 slotAssignedToolsChanged(d->assignedList->assignedList());
599 }
600 }
601
slotItemSelectionChanged()602 void QueueMgrWindow::slotItemSelectionChanged()
603 {
604 if (!d->busy)
605 {
606 int count = d->queuePool->currentQueue()->selectedItems().count();
607 d->removeItemsSelAction->setEnabled((count != 0) ? true : false);
608 }
609 }
610
populateToolsList()611 void QueueMgrWindow::populateToolsList()
612 {
613 BatchToolsList list = BatchToolsFactory::instance()->toolsList();
614
615 foreach (BatchTool* const tool, list)
616 {
617 d->toolsView->addTool(tool);
618 }
619 }
620
slotRun()621 void QueueMgrWindow::slotRun()
622 {
623 d->currentQueueToProcess = d->queuePool->currentIndex();
624 QueueListView* const queue = d->queuePool->currentQueue();
625 QString msg;
626
627 if (!queue)
628 {
629 msg = i18n("There is no queue to be run.");
630 }
631 else if (queue->pendingItemsCount() == 0)
632 {
633 msg = i18n("There is no item to process in the current queue (%1).",
634 d->queuePool->currentTitle());
635 }
636 else if ((queue->settings().renamingRule == QueueSettings::CUSTOMIZE) &&
637 queue->settings().renamingParser.isEmpty())
638 {
639 msg = i18n("Custom renaming rule is invalid for current queue (%1). "
640 "Please fix it.", d->queuePool->currentTitle());
641 }
642 else if (queue->assignedTools().m_toolsList.isEmpty())
643 {
644 msg = i18n("Assigned batch tools list is empty for current queue (%1). "
645 "Please assign tools.", d->queuePool->currentTitle());
646 }
647
648 if (!msg.isEmpty())
649 {
650 QMessageBox::critical(this, qApp->applicationName(), msg);
651 processingAborted();
652
653 return;
654 }
655
656 // Take a look if general settings are changed, as we cannot do it when BQM is busy.
657
658 applySettings();
659
660 d->statusProgressBar->setProgressTotalSteps(queue ? queue->pendingTasksCount() : 0);
661 d->statusProgressBar->setProgressValue(0);
662 d->statusProgressBar->setProgressBarMode(StatusProgressBar::ProgressBarMode);
663 d->toolsView->showTab(ToolsView::HISTORY);
664 busy(true);
665
666 d->processingAllQueues = false;
667 processOneQueue();
668 }
669
slotRunAll()670 void QueueMgrWindow::slotRunAll()
671 {
672 d->currentQueueToProcess = 0;
673
674 if (!d->queuePool->totalPendingItems())
675 {
676 QMessageBox::critical(this, qApp->applicationName(), i18n("There are no items to process in the queues."));
677 processingAborted();
678
679 return;
680 }
681
682 if (!d->queuePool->customRenamingRulesAreValid())
683 {
684 processingAborted();
685
686 return;
687 }
688
689 if (!d->queuePool->assignedBatchToolsListsAreValid())
690 {
691 processingAborted();
692
693 return;
694 }
695
696 // Take a look if general settings are changed, as we cannot do it when BQM is busy.
697
698 applySettings();
699
700 d->statusProgressBar->setProgressTotalSteps(d->queuePool->totalPendingTasks());
701 d->statusProgressBar->setProgressValue(0);
702 d->statusProgressBar->setProgressBarMode(StatusProgressBar::ProgressBarMode);
703 d->toolsView->showTab(ToolsView::HISTORY);
704 busy(true);
705
706 d->processingAllQueues = true;
707 processOneQueue();
708 }
709
processingAborted()710 void QueueMgrWindow::processingAborted()
711 {
712 d->statusProgressBar->setProgressValue(0);
713 d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode);
714 busy(false);
715 refreshStatusBar();
716 }
717
processOneQueue()718 void QueueMgrWindow::processOneQueue()
719 {
720 d->assignedList->reset();
721
722 d->queuePool->setCurrentIndex(d->currentQueueToProcess);
723 QueuePoolItemsList itemsList = d->queuePool->queueItemsList(d->currentQueueToProcess);
724 QueueSettings settings = d->queuePool->currentQueue()->settings();
725
726 if (!checkTargetAlbum(d->currentQueueToProcess))
727 {
728 processingAborted();
729 return;
730 }
731
732 QList<AssignedBatchTools> tools4Items;
733
734 foreach (const ItemInfoSet& item, itemsList)
735 {
736 AssignedBatchTools one = d->queuePool->currentQueue()->assignedTools();
737 one.m_itemUrl = item.info.fileUrl();
738 QueueListViewItem* const cItem = d->queuePool->currentQueue()->findItemByUrl(one.m_itemUrl);
739 one.m_destFileName = cItem->destFileName();
740 tools4Items.append(one);
741 }
742
743 d->thread->setSettings(settings);
744 d->thread->processQueueItems(tools4Items);
745
746 if (!d->thread->isRunning())
747 {
748 d->thread->start();
749 }
750 }
751
busy(bool busy)752 void QueueMgrWindow::busy(bool busy)
753 {
754 d->busy = busy;
755 d->runAction->setEnabled(!d->busy);
756 d->runAllAction->setEnabled(!d->busy);
757 d->newQueueAction->setEnabled(!d->busy);
758 d->saveQueueAction->setEnabled(!d->busy);
759 d->removeQueueAction->setEnabled(!d->busy);
760 d->removeItemsSelAction->setEnabled(!d->busy);
761 d->removeItemsDoneAction->setEnabled(!d->busy);
762 d->clearQueueAction->setEnabled(!d->busy);
763 d->stopAction->setEnabled(d->busy);
764
765 d->queuePool->setBusy(d->busy);
766 d->queueSettingsView->setBusy(d->busy);
767 d->toolsView->setBusy(d->busy);
768 d->assignedList->setBusy(d->busy);
769 d->toolSettings->setBusy(d->busy);
770
771 // To update status of Tools actions.
772
773 slotAssignedToolsChanged(d->assignedList->assignedList());
774
775 // To update status of Queue items actions.
776
777 slotItemSelectionChanged();
778
779 d->busy ? d->queuePool->setCursor(Qt::WaitCursor) : d->queuePool->unsetCursor();
780 d->busy ? m_animLogo->start() : m_animLogo->stop();
781
782 emit signalBqmIsBusy(d->busy);
783 }
784
slotAssignedToolsChanged(const AssignedBatchTools & tools)785 void QueueMgrWindow::slotAssignedToolsChanged(const AssignedBatchTools& tools)
786 {
787 if (d->busy)
788 {
789 d->moveUpToolAction->setEnabled(false);
790 d->moveDownToolAction->setEnabled(false);
791 d->removeToolAction->setEnabled(false);
792 d->clearToolsAction->setEnabled(false);
793
794 return;
795 }
796
797 switch (tools.m_toolsList.count())
798 {
799 case 0:
800 {
801 d->moveUpToolAction->setEnabled(false);
802 d->moveDownToolAction->setEnabled(false);
803 d->removeToolAction->setEnabled(false);
804 d->clearToolsAction->setEnabled(false);
805 break;
806 }
807
808 case 1:
809 {
810 d->moveUpToolAction->setEnabled(false);
811 d->moveDownToolAction->setEnabled(false);
812 d->removeToolAction->setEnabled(true);
813 d->clearToolsAction->setEnabled(true);
814 break;
815 }
816
817 default:
818 {
819 d->moveUpToolAction->setEnabled(true);
820 d->moveDownToolAction->setEnabled(true);
821 d->removeToolAction->setEnabled(true);
822 d->clearToolsAction->setEnabled(true);
823 break;
824 }
825 }
826
827 refreshStatusBar();
828 }
829
checkTargetAlbum(int queueId)830 bool QueueMgrWindow::checkTargetAlbum(int queueId)
831 {
832 QueueListView* const queue = d->queuePool->findQueueByIndex(queueId);
833
834 if (!queue)
835 {
836 return false;
837 }
838
839 if (!queue->settings().useOrgAlbum)
840 {
841 QString queueName = d->queuePool->queueTitle(queueId);
842 QUrl processedItemsAlbumUrl = queue->settings().workingUrl;
843 qCDebug(DIGIKAM_GENERAL_LOG) << "Target album for queue " << queueName << " is: " << processedItemsAlbumUrl.toLocalFile();
844
845 if (processedItemsAlbumUrl.isEmpty())
846 {
847 QMessageBox::critical(this, i18n("Processed items album settings"),
848 i18n("Album to host processed items from queue \"%1\" is not set. "
849 "Please select one from Queue Settings panel.", queueName));
850 return false;
851 }
852
853 QFileInfo dir(processedItemsAlbumUrl.toLocalFile());
854
855 if (!dir.exists() || !dir.isWritable())
856 {
857 QMessageBox::critical(this, i18n("Processed items album settings"),
858 i18n("Album to host processed items from queue \"%1\" "
859 "is not available or not writable. "
860 "Please set another one from Queue Settings panel.", queueName));
861 return false;
862 }
863 }
864
865 return true;
866 }
867
moveEvent(QMoveEvent * e)868 void QueueMgrWindow::moveEvent(QMoveEvent* e)
869 {
870 Q_UNUSED(e)
871 emit signalWindowHasMoved();
872 }
873
slotHistoryEntryClicked(int queueId,qlonglong itemId)874 void QueueMgrWindow::slotHistoryEntryClicked(int queueId, qlonglong itemId)
875 {
876 if (d->busy)
877 {
878 return;
879 }
880
881 QueueListView* const view = d->queuePool->findQueueByIndex(queueId);
882
883 if (view)
884 {
885 QueueListViewItem* const item = view->findItemById(itemId);
886
887 if (item)
888 {
889 d->queuePool->setCurrentIndex(queueId);
890 view->scrollToItem(item);
891 view->setCurrentItem(item);
892 item->setSelected(true);
893 }
894 }
895 }
896
slotAction(const ActionData & ad)897 void QueueMgrWindow::slotAction(const ActionData& ad)
898 {
899 QueueListViewItem* const cItem = d->queuePool->currentQueue()->findItemByUrl(ad.fileUrl);
900
901 switch (ad.status)
902 {
903 case ActionData::BatchStarted:
904 {
905 if (cItem)
906 {
907 cItem->reset();
908 d->queuePool->currentQueue()->setCurrentItem(cItem);
909 d->queuePool->currentQueue()->scrollToItem(cItem);
910 d->queuePool->setItemBusy(cItem->info().id());
911 addHistoryMessage(cItem, i18n("Processing..."), DHistoryView::StartingEntry);
912 }
913
914 break;
915 }
916
917 case ActionData::BatchDone:
918 case ActionData::BatchSkipped:
919 {
920 if (cItem)
921 {
922 cItem->setDestFileName(ad.destUrl.fileName());
923 cItem->setDone();
924 addHistoryMessage(cItem, ad.message, DHistoryView::SuccessEntry);
925 d->statusProgressBar->setProgressValue(d->statusProgressBar->progressValue() + 1);
926 }
927
928 break;
929 }
930
931 case ActionData::BatchFailed:
932 {
933 if (cItem)
934 {
935 cItem->setFailed();
936 addHistoryMessage(cItem, i18n("Failed to process item..."), DHistoryView::ErrorEntry);
937 addHistoryMessage(cItem, ad.message, DHistoryView::ErrorEntry);
938 d->statusProgressBar->setProgressValue(d->statusProgressBar->progressValue() + 1);
939 }
940
941 break;
942 }
943
944 case ActionData::BatchCanceled:
945 {
946 if (cItem)
947 {
948 cItem->setCanceled();
949 addHistoryMessage(cItem, i18n("Process Cancelled..."), DHistoryView::CancelEntry);
950 d->statusProgressBar->setProgressValue(d->statusProgressBar->progressValue() + 1);
951 }
952
953 break;
954 }
955
956 default: // NONE
957 {
958 break;
959 }
960 }
961 }
962
addHistoryMessage(QueueListViewItem * const cItem,const QString & msg,DHistoryView::EntryType type)963 void QueueMgrWindow::addHistoryMessage(QueueListViewItem* const cItem, const QString& msg, DHistoryView::EntryType type)
964 {
965 if (cItem)
966 {
967 int itemId = cItem->info().id();
968 int queueId = d->queuePool->currentIndex();
969 QString text = i18n("Item \"%1\" from queue \"%2\": %3", cItem->info().name(),
970 d->queuePool->queueTitle(queueId), msg);
971 d->toolsView->addHistoryEntry(text, type, queueId, itemId);
972 }
973 else
974 {
975 d->toolsView->addHistoryEntry(msg, type);
976 }
977 }
978
slotStop()979 void QueueMgrWindow::slotStop()
980 {
981 d->thread->cancel();
982 d->queuePool->currentQueue()->cancelItems();
983 processingAborted();
984 }
985
slotQueueProcessed()986 void QueueMgrWindow::slotQueueProcessed()
987 {
988 if (!d->busy)
989 {
990 return;
991 }
992
993 d->currentQueueToProcess++;
994 QString msg;
995
996 if (!d->processingAllQueues)
997 {
998 msg = i18n("Batch queue finished");
999 }
1000 else if (d->currentQueueToProcess == d->queuePool->count())
1001 {
1002 msg = i18n("All batch queues finished");
1003 }
1004 else
1005 {
1006 // We will process next queue from the pool.
1007
1008 processOneQueue();
1009
1010 return;
1011 }
1012
1013 DNotificationWrapper(QLatin1String("batchqueuecompleted"), msg, this,
1014 windowTitle());
1015 processingAborted();
1016 }
1017
slotAssignQueueSettings(const QString & title)1018 void QueueMgrWindow::slotAssignQueueSettings(const QString& title)
1019 {
1020 if (!title.isEmpty())
1021 {
1022 Workflow q = WorkflowManager::instance()->findByTitle(title);
1023 QueueListView* const queue = d->queuePool->currentQueue();
1024
1025 if (queue)
1026 {
1027 queue->setSettings(q.qSettings);
1028 AssignedBatchTools tools;
1029 tools.m_toolsList = q.aTools;
1030
1031 //qCDebug(DIGIKAM_GENERAL_LOG) << tools.m_toolsList;
1032
1033 queue->setAssignedTools(tools);
1034 d->queuePool->slotQueueSelected(d->queuePool->currentIndex());
1035 }
1036 }
1037 }
1038
slotSaveWorkflow()1039 void QueueMgrWindow::slotSaveWorkflow()
1040 {
1041 if (d->queuePool->saveWorkflow())
1042 {
1043 d->toolsView->showTab(ToolsView::WORKFLOW);
1044 }
1045 }
1046
customizedFullScreenMode(bool set)1047 void QueueMgrWindow::customizedFullScreenMode(bool set)
1048 {
1049 showStatusBarAction()->setEnabled(!set);
1050 toolBarMenuAction()->setEnabled(!set);
1051 showMenuBarAction()->setEnabled(!set);
1052 }
1053
1054 } // namespace Digikam
1055