File indexing completed on 2025-03-09 03:58:52
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-02-13 0007 * Description : tabbed queue items list. 0008 * 0009 * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "queuepool.h" 0016 0017 // Qt includes 0018 0019 #include <QApplication> 0020 #include <QIcon> 0021 0022 // KDE includes 0023 0024 #include <klocalizedstring.h> 0025 0026 // Local includes 0027 0028 #include "digikam_debug.h" 0029 #include "dmessagebox.h" 0030 #include "applicationsettings.h" 0031 #include "iccsettings.h" 0032 #include "metaenginesettings.h" 0033 #include "ddragobjects.h" 0034 #include "queuelist.h" 0035 #include "workflowmanager.h" 0036 #include "workflowdlg.h" 0037 #include "queuesettings.h" 0038 #include "loadingcacheinterface.h" 0039 0040 namespace Digikam 0041 { 0042 0043 QueuePoolBar::QueuePoolBar(QWidget* const parent) 0044 : QTabBar(parent) 0045 { 0046 setAcceptDrops(true); 0047 setMouseTracking(true); 0048 } 0049 0050 QueuePoolBar::~QueuePoolBar() 0051 { 0052 } 0053 0054 void QueuePoolBar::dragEnterEvent(QDragEnterEvent* e) 0055 { 0056 0057 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0058 0059 int tab = tabAt(e->position().toPoint()); 0060 0061 #else 0062 0063 int tab = tabAt(e->pos()); 0064 0065 #endif 0066 0067 if (tab != -1) 0068 { 0069 bool accept = false; 0070 0071 // The receivers of the testCanDecode() signal has to adjust 'accept' accordingly. 0072 0073 Q_EMIT signalTestCanDecode(e, accept); 0074 0075 e->setAccepted(accept); 0076 0077 return; 0078 } 0079 0080 QTabBar::dragEnterEvent(e); 0081 } 0082 0083 void QueuePoolBar::dragMoveEvent(QDragMoveEvent* e) 0084 { 0085 0086 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0087 0088 int tab = tabAt(e->position().toPoint()); 0089 0090 #else 0091 0092 int tab = tabAt(e->pos()); 0093 0094 #endif 0095 0096 if (tab != -1) 0097 { 0098 bool accept = false; 0099 0100 // The receivers of the testCanDecode() signal has to adjust 'accept' accordingly. 0101 0102 Q_EMIT signalTestCanDecode(e, accept); 0103 0104 e->setAccepted(accept); 0105 0106 return; 0107 } 0108 0109 QTabBar::dragMoveEvent(e); 0110 } 0111 0112 // -------------------------------------------------------------------------------------------- 0113 0114 QueuePool::QueuePool(QWidget* const parent) 0115 : QTabWidget(parent) 0116 { 0117 setTabBar(new QueuePoolBar(this)); 0118 setTabsClosable(false); 0119 setAcceptDrops(true); 0120 slotAddQueue(); 0121 0122 connect(this, SIGNAL(currentChanged(int)), 0123 this, SLOT(slotQueueSelected(int))); 0124 0125 connect(this, SIGNAL(tabCloseRequested(int)), 0126 this, SLOT(slotCloseQueueRequest(int))); 0127 0128 connect(tabBar(), SIGNAL(signalTestCanDecode(const QDragMoveEvent*,bool&)), 0129 this, SLOT(slotTestCanDecode(const QDragMoveEvent*,bool&))); 0130 0131 // -- FileWatch connections ------------------------------ 0132 0133 LoadingCacheInterface::connectToSignalFileChanged(this, SLOT(slotFileChanged(QString))); 0134 } 0135 0136 QueuePool::~QueuePool() 0137 { 0138 } 0139 0140 void QueuePool::keyPressEvent(QKeyEvent* event) 0141 { 0142 if (event->key() == Qt::Key_Delete) 0143 { 0144 slotRemoveSelectedItems(); 0145 } 0146 else 0147 { 0148 QTabWidget::keyPressEvent(event); 0149 } 0150 } 0151 0152 void QueuePool::setBusy(bool b) 0153 { 0154 tabBar()->setEnabled(!b); 0155 0156 for (int i = 0 ; i < count() ; ++i) 0157 { 0158 QueueListView* const queue = dynamic_cast<QueueListView*>(widget(i)); 0159 0160 if (queue) 0161 { 0162 queue->viewport()->setEnabled(!b); 0163 } 0164 } 0165 } 0166 0167 QueueListView* QueuePool::currentQueue() const 0168 { 0169 return (dynamic_cast<QueueListView*>(currentWidget())); 0170 } 0171 0172 QString QueuePool::currentTitle() const 0173 { 0174 return queueTitle(currentIndex()); 0175 } 0176 0177 QueueListView* QueuePool::findQueueByItemId(qlonglong id) const 0178 { 0179 for (int i = 0 ; i < count() ; ++i) 0180 { 0181 QueueListView* const queue = dynamic_cast<QueueListView*>(widget(i)); 0182 0183 if (queue && queue->findItemById(id)) 0184 { 0185 return queue; 0186 } 0187 } 0188 0189 return nullptr; 0190 } 0191 0192 void QueuePool::setItemBusy(qlonglong id) 0193 { 0194 QueueListView* const queue = findQueueByItemId(id); 0195 0196 if (queue) 0197 { 0198 queue->setItemBusy(id); 0199 } 0200 } 0201 0202 QueueListView* QueuePool::findQueueByIndex(int index) const 0203 { 0204 return (dynamic_cast<QueueListView*>(widget(index))); 0205 } 0206 0207 QMap<int, QString> QueuePool::queuesMap() const 0208 { 0209 QMap<int, QString> map; 0210 0211 for (int i = 0 ; i < count() ; ++i) 0212 { 0213 map.insert(i, queueTitle(i)); 0214 } 0215 0216 return map; 0217 } 0218 0219 QString QueuePool::queueTitle(int index) const 0220 { 0221 // NOTE: clean up tab title. With QTabWidget, it sound like mistake is added, as '&' and space. 0222 // NOTE update, & is an usability helper to allow keyboard access -teemu 0223 0224 return (tabText(index).remove(QLatin1Char('&')).remove(QLatin1Char(' '))); 0225 } 0226 0227 void QueuePool::slotAddQueue() 0228 { 0229 QueueListView* const queue = new QueueListView(this); 0230 0231 if (!queue) 0232 { 0233 return; 0234 } 0235 0236 int index = addTab(queue, QIcon::fromTheme(QLatin1String("run-build")), QString::fromUtf8("#%1").arg(count() + 1)); 0237 0238 connect(queue, SIGNAL(signalQueueContentsChanged()), 0239 this, SIGNAL(signalQueueContentsChanged())); 0240 0241 connect(queue, SIGNAL(itemSelectionChanged()), 0242 this, SIGNAL(signalItemSelectionChanged())); 0243 0244 Q_EMIT signalQueuePoolChanged(); 0245 0246 setCurrentIndex(index); 0247 } 0248 0249 QueuePoolItemsList QueuePool::queueItemsList(int index) const 0250 { 0251 QueuePoolItemsList qpool; 0252 0253 QueueListView* const queue = dynamic_cast<QueueListView*>(widget(index)); 0254 0255 if (queue) 0256 { 0257 ItemInfoList list = queue->pendingItemsList(); 0258 0259 for (ItemInfoList::const_iterator it = list.constBegin() ; it != list.constEnd() ; ++it) 0260 { 0261 ItemInfo info = *it; 0262 ItemInfoSet set(index, info); 0263 qpool.append(set); 0264 } 0265 } 0266 0267 return qpool; 0268 } 0269 0270 int QueuePool::totalPendingItems() const 0271 { 0272 int items = 0; 0273 0274 for (int i = 0 ; i < count() ; ++i) 0275 { 0276 QueueListView* const queue = dynamic_cast<QueueListView*>(widget(i)); 0277 0278 if (queue) 0279 { 0280 items += queue->pendingItemsCount(); 0281 } 0282 } 0283 0284 return items; 0285 } 0286 0287 int QueuePool::totalPendingTasks() const 0288 { 0289 int tasks = 0; 0290 0291 for (int i = 0 ; i < count() ; ++i) 0292 { 0293 QueueListView* const queue = dynamic_cast<QueueListView*>(widget(i)); 0294 0295 if (queue) 0296 { 0297 tasks += queue->pendingTasksCount(); 0298 } 0299 } 0300 0301 return tasks; 0302 } 0303 0304 void QueuePool::slotRemoveCurrentQueue() 0305 { 0306 QueueListView* const queue = currentQueue(); 0307 0308 if (!queue) 0309 { 0310 return; 0311 } 0312 0313 removeTab(indexOf(queue)); 0314 0315 if (count() == 0) 0316 { 0317 slotAddQueue(); 0318 } 0319 else 0320 { 0321 for (int i = 0; i < count(); ++i) 0322 { 0323 setTabText(i, QString::fromUtf8("#%1").arg(i + 1)); 0324 } 0325 } 0326 0327 Q_EMIT signalQueuePoolChanged(); 0328 } 0329 0330 bool QueuePool::saveWorkflow() const 0331 { 0332 QueueListView* const queue = currentQueue(); 0333 0334 if (queue) 0335 { 0336 WorkflowManager* const mngr = WorkflowManager::instance(); 0337 Workflow wf; 0338 wf.qSettings = queue->settings(); 0339 wf.aTools = queue->assignedTools().m_toolsList; 0340 0341 if (WorkflowDlg::createNew(wf)) 0342 { 0343 mngr->insert(wf); 0344 mngr->save(); 0345 0346 return true; 0347 } 0348 } 0349 0350 return false; 0351 } 0352 0353 void QueuePool::slotClearList() 0354 { 0355 QueueListView* const queue = currentQueue(); 0356 0357 if (queue) 0358 { 0359 queue->slotClearList(); 0360 } 0361 } 0362 0363 void QueuePool::slotRemoveSelectedItems() 0364 { 0365 QueueListView* const queue = currentQueue(); 0366 0367 if (queue) 0368 { 0369 queue->slotRemoveSelectedItems(); 0370 } 0371 } 0372 0373 void QueuePool::slotRemoveItemsDone() 0374 { 0375 QueueListView* const queue = currentQueue(); 0376 0377 if (queue) 0378 { 0379 queue->slotRemoveItemsDone(); 0380 } 0381 } 0382 0383 void QueuePool::slotAddItems(const ItemInfoList& list, int queueId) 0384 { 0385 QueueListView* const queue = findQueueByIndex(queueId); 0386 0387 if (queue) 0388 { 0389 queue->slotAddItems(list); 0390 } 0391 } 0392 0393 void QueuePool::slotAssignedToolsChanged(const AssignedBatchTools& tools4Item) 0394 { 0395 QueueListView* const queue = currentQueue(); 0396 0397 if (queue) 0398 { 0399 queue->slotAssignedToolsChanged(tools4Item); 0400 } 0401 } 0402 0403 void QueuePool::slotQueueSelected(int index) 0404 { 0405 QueueListView* const queue = dynamic_cast<QueueListView*>(widget(index)); 0406 0407 if (queue) 0408 { 0409 Q_EMIT signalItemSelectionChanged(); 0410 Q_EMIT signalQueueSelected(index, queue->settings(), queue->assignedTools()); 0411 } 0412 } 0413 0414 void QueuePool::slotCloseQueueRequest(int index) 0415 { 0416 removeTab(index); 0417 0418 if (count() == 0) 0419 { 0420 slotAddQueue(); 0421 } 0422 0423 Q_EMIT signalQueuePoolChanged(); 0424 } 0425 0426 void QueuePool::removeTab(int index) 0427 { 0428 QueueListView* const queue = dynamic_cast<QueueListView*>(widget(index)); 0429 0430 if (!queue) 0431 { 0432 return; 0433 } 0434 0435 int count = queue->pendingItemsCount(); 0436 0437 if (count > 0) 0438 { 0439 int ret = QMessageBox::question(this, qApp->applicationName(), 0440 i18np("There is still 1 unprocessed item in \"%2\".\nDo you want to close this queue?", 0441 "There are still %1 unprocessed items in \"%2\".\nDo you want to close this queue?", 0442 count, queueTitle(index)), 0443 QMessageBox::Yes | QMessageBox::No); 0444 0445 if (ret == QMessageBox::No) 0446 { 0447 return; 0448 } 0449 } 0450 0451 QTabWidget::removeTab(index); 0452 } 0453 0454 void QueuePool::slotTestCanDecode(const QDragMoveEvent* e, bool& accept) 0455 { 0456 int albumID; 0457 QList<int> albumIDs; 0458 QList<qlonglong> imageIDs; 0459 QList<QUrl> urls; 0460 0461 if (DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs) || 0462 DAlbumDrag::decode(e->mimeData(), urls, albumID) || 0463 DTagListDrag::canDecode(e->mimeData())) 0464 { 0465 accept = true; 0466 0467 return; 0468 } 0469 0470 accept = false; 0471 } 0472 0473 void QueuePool::slotSettingsChanged(const QueueSettings& settings) 0474 { 0475 QueueListView* const queue = currentQueue(); 0476 0477 if (queue) 0478 { 0479 queue->setSettings(settings); 0480 } 0481 } 0482 0483 bool QueuePool::customRenamingRulesAreValid() const 0484 { 0485 QStringList list; 0486 0487 for (int i = 0 ; i < count() ; ++i) 0488 { 0489 QueueListView* const queue = findQueueByIndex(i); 0490 0491 if (queue) 0492 { 0493 if (queue->settings().renamingRule == QueueSettings::CUSTOMIZE && 0494 queue->settings().renamingParser.isEmpty()) 0495 { 0496 list.append(queueTitle(i)); 0497 } 0498 } 0499 } 0500 0501 if (!list.isEmpty()) 0502 { 0503 DMessageBox::showInformationList(QMessageBox::Critical, 0504 qApp->activeWindow(), 0505 qApp->applicationName(), 0506 i18n("Custom renaming rules are invalid for Queues listed below. " 0507 "Please fix them."), 0508 list); 0509 return false; 0510 } 0511 0512 return true; 0513 } 0514 0515 bool QueuePool::assignedBatchToolsListsAreValid() const 0516 { 0517 QStringList list; 0518 0519 for (int i = 0 ; i < count() ; ++i) 0520 { 0521 QueueListView* const queue = findQueueByIndex(i); 0522 0523 if (queue) 0524 { 0525 if (queue->assignedTools().m_toolsList.isEmpty()) 0526 { 0527 list.append(queueTitle(i)); 0528 } 0529 } 0530 } 0531 0532 if (!list.isEmpty()) 0533 { 0534 DMessageBox::showInformationList(QMessageBox::Critical, 0535 qApp->activeWindow(), 0536 qApp->applicationName(), 0537 i18n("Assigned batch tools list is empty for Queues listed below. " 0538 "Please assign tools."), 0539 list); 0540 return false; 0541 } 0542 0543 return true; 0544 } 0545 0546 void QueuePool::slotFileChanged(const QString& filePath) 0547 { 0548 for (int i = 0 ; i < count() ; ++i) 0549 { 0550 QueueListView* const queue = dynamic_cast<QueueListView*>(widget(i)); 0551 0552 if (queue) 0553 { 0554 queue->reloadThumbs(QUrl::fromLocalFile(filePath)); 0555 } 0556 } 0557 } 0558 0559 void QueuePool::applySettings() 0560 { 0561 for (int i = 0 ; i < count() ; ++i) 0562 { 0563 QueueListView* const queue = dynamic_cast<QueueListView*>(widget(i)); 0564 0565 if (queue) 0566 { 0567 // Show/hide tool-tips settings. 0568 0569 queue->setEnableToolTips(ApplicationSettings::instance()->getShowToolTips()); 0570 0571 // Reset Exif Orientation settings. 0572 0573 QueueSettings prm = queue->settings(); 0574 prm.exifSetOrientation = MetaEngineSettings::instance()->settings().exifRotate; 0575 0576 // Apply Color Management rules to RAW images decoding settings 0577 0578 // If digiKam Color Management is enable, no need to correct color of decoded RAW image, 0579 // else, sRGB color workspace will be used. 0580 0581 ICCSettingsContainer ICCSettings = IccSettings::instance()->settings(); 0582 0583 if (ICCSettings.enableCM) 0584 { 0585 if ((ICCSettings.defaultUncalibratedBehavior & ICCSettingsContainer::AskUser) || 0586 (ICCSettings.defaultUncalibratedBehavior & ICCSettingsContainer::AutomaticColors)) 0587 { 0588 prm.rawDecodingSettings.outputColorSpace = DRawDecoderSettings::CUSTOMOUTPUTCS; 0589 prm.rawDecodingSettings.outputProfile = ICCSettings.workspaceProfile; 0590 } 0591 else 0592 { 0593 prm.rawDecodingSettings.outputColorSpace = DRawDecoderSettings::RAWCOLOR; 0594 } 0595 } 0596 else 0597 { 0598 prm.rawDecodingSettings.outputColorSpace = DRawDecoderSettings::SRGB; 0599 } 0600 0601 queue->setSettings(prm); 0602 } 0603 } 0604 } 0605 0606 } // namespace Digikam 0607 0608 #include "moc_queuepool.cpp"