File indexing completed on 2025-03-09 03:58:51

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2008-11-21
0007  * Description : Batch Queue Manager items list.
0008  *
0009  * SPDX-FileCopyrightText: 2008-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 #define ICONSIZE 32
0016 
0017 #include "assignedlist.h"
0018 
0019 // Qt includes
0020 
0021 #include <QDragEnterEvent>
0022 #include <QFileInfo>
0023 #include <QHeaderView>
0024 #include <QPainter>
0025 #include <QUrl>
0026 #include <QMimeData>
0027 #include <QAction>
0028 #include <QMenu>
0029 
0030 // KDE includes
0031 
0032 #if !defined(Q_OS_DARWIN) && defined(Q_CC_GNU)
0033 #   pragma GCC diagnostic push
0034 #   pragma GCC diagnostic ignored "-Wdeprecated-declarations"
0035 #endif
0036 
0037 #if defined(Q_CC_CLANG)
0038 #   pragma clang diagnostic push
0039 #   pragma clang diagnostic ignored "-Wdeprecated-declarations"
0040 #endif
0041 
0042 #include <kactioncollection.h>
0043 #include <klocalizedstring.h>
0044 
0045 // Restore warnings
0046 #if !defined(Q_OS_DARWIN) && defined(Q_CC_GNU)
0047 #   pragma GCC diagnostic pop
0048 #endif
0049 
0050 #if defined(Q_CC_CLANG)
0051 #   pragma clang diagnostic pop
0052 #endif
0053 
0054 // Local includes
0055 
0056 #include "digikam_debug.h"
0057 #include "queuemgrwindow.h"
0058 #include "queuesettingsview.h"
0059 #include "toolslistview.h"
0060 #include "batchtoolsfactory.h"
0061 
0062 namespace Digikam
0063 {
0064 
0065 AssignedListViewItem::AssignedListViewItem(QTreeWidget* const parent)
0066     : QTreeWidgetItem(parent)
0067 {
0068     setFlags(Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | flags());
0069 }
0070 
0071 AssignedListViewItem::AssignedListViewItem(QTreeWidget* const parent, QTreeWidgetItem* const preceding)
0072     : QTreeWidgetItem(parent, preceding)
0073 {
0074     setFlags(Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | flags());
0075 }
0076 
0077 AssignedListViewItem::~AssignedListViewItem()
0078 {
0079 }
0080 
0081 void AssignedListViewItem::setToolSet(const BatchToolSet& set)
0082 {
0083     m_set                 = set;
0084     setIndex(m_set.index);
0085 
0086     BatchTool* const tool = BatchToolsFactory::instance()->findTool(m_set.name, m_set.group);
0087 
0088     if (tool)
0089     {
0090         setIcon(1, tool->toolIcon());
0091         setText(1, tool->toolTitle());
0092     }
0093 }
0094 
0095 BatchToolSet AssignedListViewItem::toolSet()
0096 {
0097     return m_set;
0098 }
0099 
0100 void AssignedListViewItem::setIndex(int index)
0101 {
0102     m_set.index = index;
0103     setText(0, QString::fromUtf8("%1").arg(m_set.index + 1));
0104 }
0105 
0106 // ---------------------------------------------------------------------------
0107 
0108 AssignedListView::AssignedListView(QWidget* const parent)
0109     : QTreeWidget(parent)
0110 {
0111     setSelectionMode(QAbstractItemView::SingleSelection);
0112     setWhatsThis(i18n("This is the list of batch tools assigned."));
0113     setIconSize(QSize(ICONSIZE, ICONSIZE));
0114 
0115     setDragEnabled(true);
0116     setAcceptDrops(true);
0117     viewport()->setAcceptDrops(true);
0118     setDropIndicatorShown(true);
0119 
0120     setContextMenuPolicy(Qt::CustomContextMenu);
0121     setSortingEnabled(false);
0122     setRootIsDecorated(false);
0123     setUniformRowHeights(true);
0124     setAllColumnsShowFocus(true);
0125     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0126     setColumnCount(2);
0127     setHeaderHidden(true);
0128     header()->setSectionResizeMode(QHeaderView::ResizeToContents);
0129 
0130     connect(this, SIGNAL(itemSelectionChanged()),
0131             this, SLOT(slotSelectionChanged()));
0132 
0133     connect(this, SIGNAL(customContextMenuRequested(QPoint)),
0134             this, SLOT(slotContextMenu()));
0135 }
0136 
0137 AssignedListView::~AssignedListView()
0138 {
0139 }
0140 
0141 void AssignedListView::keyPressEvent(QKeyEvent* e)
0142 {
0143     if (e->key() == Qt::Key_Delete)
0144     {
0145         slotRemoveCurrentTool();
0146     }
0147     else
0148     {
0149         QTreeWidget::keyPressEvent(e);
0150     }
0151 }
0152 
0153 void AssignedListView::setBusy(bool b)
0154 {
0155     viewport()->setEnabled(!b);
0156 }
0157 
0158 AssignedBatchTools AssignedListView::assignedList()
0159 {
0160     BatchSetList            list;
0161     QTreeWidgetItemIterator it(this);
0162 
0163     while (*it)
0164     {
0165         AssignedListViewItem* const item = dynamic_cast<AssignedListViewItem*>(*it);
0166 
0167         if (item)
0168         {
0169             list.append(item->toolSet());
0170         }
0171 
0172         ++it;
0173     }
0174 
0175     AssignedBatchTools tools;
0176     tools.m_toolsList = list;
0177 
0178     return tools;
0179 }
0180 
0181 int AssignedListView::assignedCount()
0182 {
0183     return assignedList().m_toolsList.count();
0184 }
0185 
0186 void AssignedListView::slotRemoveCurrentTool()
0187 {
0188     AssignedListViewItem* const item = dynamic_cast<AssignedListViewItem*>(currentItem());
0189 
0190     if (item)
0191     {
0192         delete item;
0193         refreshIndex();
0194         Q_EMIT signalAssignedToolsChanged(assignedList());
0195     }
0196 
0197     if (assignedCount() == 0)
0198     {
0199         Q_EMIT signalToolSelected(BatchToolSet());
0200     }
0201 }
0202 
0203 void AssignedListView::slotClearToolsList()
0204 {
0205     clear();
0206     Q_EMIT signalAssignedToolsChanged(assignedList());
0207     Q_EMIT signalToolSelected(BatchToolSet());
0208 }
0209 
0210 void AssignedListView::slotMoveCurrentToolUp()
0211 {
0212     AssignedListViewItem* const item = dynamic_cast<AssignedListViewItem*>(currentItem());
0213 
0214     if (item)
0215     {
0216         AssignedListViewItem* const iabove = dynamic_cast<AssignedListViewItem*>(itemAbove(item));
0217 
0218         if (iabove)
0219         {
0220             moveTool(item, iabove->toolSet());
0221             setCurrentItem(item);
0222         }
0223     }
0224 }
0225 
0226 void AssignedListView::slotMoveCurrentToolDown()
0227 {
0228     AssignedListViewItem* const item = dynamic_cast<AssignedListViewItem*>(currentItem());
0229 
0230     if (item)
0231     {
0232         AssignedListViewItem* const ibelow = dynamic_cast<AssignedListViewItem*>(itemBelow(item));
0233 
0234         if (ibelow)
0235         {
0236             AssignedListViewItem* const nitem = moveTool(ibelow, item->toolSet());
0237             setCurrentItem(nitem);
0238         }
0239     }
0240 }
0241 
0242 AssignedListViewItem* AssignedListView::moveTool(AssignedListViewItem* const preceding, const BatchToolSet& set)
0243 {
0244     BatchTool* const tool = BatchToolsFactory::instance()->findTool(set.name, set.group);
0245 
0246     if (!tool)
0247     {
0248         return nullptr;
0249     }
0250 
0251     removeTool(set);
0252     AssignedListViewItem* const item = insertTool(preceding, set);
0253     refreshIndex();
0254 
0255     Q_EMIT signalAssignedToolsChanged(assignedList());
0256 
0257     return item;
0258 }
0259 
0260 AssignedListViewItem* AssignedListView::insertTool(AssignedListViewItem* const preceding, const BatchToolSet& set)
0261 {
0262     AssignedListViewItem* item = nullptr;
0263 
0264     if (preceding)
0265     {
0266         item = new AssignedListViewItem(this, preceding);
0267     }
0268     else
0269     {
0270         item = new AssignedListViewItem(this);
0271     }
0272 
0273     BatchTool* const tool = BatchToolsFactory::instance()->findTool(set.name, set.group);
0274 
0275     // NOTE: Only now create the settings widget when needed.
0276 
0277     if (tool && !tool->settingsWidget())
0278     {
0279         tool->registerSettingsWidget();
0280     }
0281 
0282     item->setToolSet(set);
0283     refreshIndex();
0284 
0285     Q_EMIT signalAssignedToolsChanged(assignedList());
0286 
0287     return item;
0288 }
0289 
0290 AssignedListViewItem* AssignedListView::addTool(const BatchToolSet& set)
0291 {
0292     return insertTool(nullptr, set);
0293 }
0294 
0295 bool AssignedListView::removeTool(const BatchToolSet& set)
0296 {
0297     QTreeWidgetItemIterator it(this);
0298 
0299     while (*it)
0300     {
0301         AssignedListViewItem* const item = dynamic_cast<AssignedListViewItem*>(*it);
0302 
0303         if (item && (item->toolSet() == set))
0304         {
0305             delete item;
0306             refreshIndex();
0307             return true;
0308         }
0309 
0310         ++it;
0311     }
0312 
0313     return false;
0314 }
0315 
0316 AssignedListViewItem* AssignedListView::findTool(const BatchToolSet& set)
0317 {
0318     QTreeWidgetItemIterator it(this);
0319 
0320     while (*it)
0321     {
0322         AssignedListViewItem* const item = dynamic_cast<AssignedListViewItem*>(*it);
0323 
0324         if (item && (item->toolSet() == set))
0325         {
0326             return item;
0327         }
0328 
0329         ++it;
0330     }
0331 
0332     return nullptr;
0333 }
0334 
0335 Qt::DropActions AssignedListView::supportedDropActions() const
0336 {
0337     return (Qt::CopyAction | Qt::MoveAction);
0338 }
0339 
0340 QStringList AssignedListView::mimeTypes() const
0341 {
0342     QStringList types;
0343     types << QLatin1String("digikam/assignedbatchtool");
0344 
0345     return types;
0346 }
0347 
0348 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0349 
0350 QMimeData* AssignedListView::mimeData(const QList<QTreeWidgetItem*>& items) const
0351 
0352 #else
0353 
0354 // cppcheck-suppress passedByValue
0355 QMimeData* AssignedListView::mimeData(const QList<QTreeWidgetItem*> items) const    // clazy:exclude=function-args-by-ref
0356 
0357 #endif
0358 
0359 {
0360     QMimeData* const mimeData = new QMimeData();
0361     QByteArray encodedData;
0362 
0363     QDataStream stream(&encodedData, QIODevice::WriteOnly);
0364     stream << items.count();
0365 
0366     Q_FOREACH (QTreeWidgetItem* const itm, items)
0367     {
0368         AssignedListViewItem* const alwi = dynamic_cast<AssignedListViewItem*>(itm);
0369 
0370         if (alwi)
0371         {
0372             stream << (int)(alwi->toolSet().group);
0373             stream << alwi->toolSet().name;
0374             stream << alwi->toolSet().index;
0375             stream << alwi->toolSet().version;
0376             stream << alwi->toolSet().settings;
0377         }
0378     }
0379 
0380     mimeData->setData(QLatin1String("digikam/assignedbatchtool"), encodedData);
0381 
0382     return mimeData;
0383 }
0384 
0385 void AssignedListView::dragEnterEvent(QDragEnterEvent* e)
0386 {
0387     QTreeWidget::dragEnterEvent(e);
0388     e->accept();
0389 }
0390 
0391 void AssignedListView::dragMoveEvent(QDragMoveEvent* e)
0392 {
0393     if (e->mimeData()->formats().contains(QLatin1String("digikam/batchtoolslist")) ||
0394         e->mimeData()->formats().contains(QLatin1String("digikam/assignedbatchtool")))
0395     {
0396         QTreeWidget::dragMoveEvent(e);
0397         e->accept();
0398 
0399         return;
0400     }
0401 
0402     e->ignore();
0403 }
0404 
0405 void AssignedListView::dropEvent(QDropEvent* e)
0406 {
0407     if      (e->mimeData()->formats().contains(QLatin1String("digikam/batchtoolslist")))
0408     {
0409         QByteArray ba = e->mimeData()->data(QLatin1String("digikam/batchtoolslist"));
0410 
0411         if (ba.size())
0412         {
0413             QDataStream ds(ba);
0414             QMultiMap<int, QString> map;
0415             ds >> map;
0416 
0417 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0418 
0419             AssignedListViewItem* const preceding = dynamic_cast<AssignedListViewItem*>(itemAt(e->position().toPoint()));
0420 
0421 #else
0422 
0423             AssignedListViewItem* const preceding = dynamic_cast<AssignedListViewItem*>(itemAt(e->pos()));
0424 
0425 #endif
0426 
0427             assignTools(map, preceding);
0428         }
0429 
0430         e->acceptProposedAction();
0431     }
0432     else if (e->mimeData()->formats().contains(QLatin1String("digikam/assignedbatchtool")))
0433     {
0434         QByteArray ba = e->mimeData()->data(QLatin1String("digikam/assignedbatchtool"));
0435 
0436         if (ba.size())
0437         {
0438             int count;
0439             QDataStream ds(ba);
0440             ds >> count;
0441 
0442             for (int i = 0 ; i < count ; ++i)
0443             {
0444                 int               group, index, version;
0445                 QString           name;
0446                 BatchToolSettings settings;
0447 
0448                 ds >> group;
0449                 ds >> name;
0450                 ds >> index;
0451                 ds >> version;
0452                 ds >> settings;
0453 
0454 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0455 
0456                 AssignedListViewItem* const preceding = dynamic_cast<AssignedListViewItem*>(itemAt(e->position().toPoint()));
0457 
0458 #else
0459 
0460                 AssignedListViewItem* const preceding = dynamic_cast<AssignedListViewItem*>(itemAt(e->pos()));
0461 
0462 #endif
0463 
0464                 BatchToolSet set;
0465                 set.name                              = name;
0466                 set.group                             = (BatchTool::BatchToolGroup)group;
0467                 set.index                             = index;
0468                 set.version                           = version;
0469                 set.settings                          = settings;
0470                 AssignedListViewItem* const item      = moveTool(preceding, set);
0471                 setCurrentItem(item);
0472             }
0473         }
0474 
0475         e->acceptProposedAction();
0476     }
0477     else
0478     {
0479         e->ignore();
0480     }
0481 }
0482 
0483 void AssignedListView::slotSelectionChanged()
0484 {
0485     QList<QTreeWidgetItem*> list = selectedItems();
0486 
0487     if (list.isEmpty())
0488     {
0489         return;
0490     }
0491 
0492     AssignedListViewItem* const item = dynamic_cast<AssignedListViewItem*>(list.first());
0493 
0494     if (item)
0495     {
0496         BatchToolSet set = item->toolSet();
0497         Q_EMIT signalToolSelected(set);
0498     }
0499     else
0500     {
0501         Q_EMIT signalToolSelected(BatchToolSet());
0502     }
0503 }
0504 
0505 void AssignedListView::slotQueueSelected(int, const QueueSettings&, const AssignedBatchTools& tools)
0506 {
0507     // Clear assigned tools list and tool settings view.
0508 
0509     clear();
0510     Q_EMIT signalToolSelected(BatchToolSet());
0511 
0512     if (!tools.m_toolsList.isEmpty())
0513     {
0514         blockSignals(true);
0515 
0516         Q_FOREACH (const BatchToolSet& set, tools.m_toolsList)
0517         {
0518             addTool(set);
0519         }
0520 
0521         blockSignals(false);
0522     }
0523 }
0524 
0525 void AssignedListView::slotSettingsChanged(const BatchToolSet& set)
0526 {
0527     AssignedListViewItem* const item = findTool(set);
0528 
0529     if (item)
0530     {
0531         item->setToolSet(set);
0532         Q_EMIT signalAssignedToolsChanged(assignedList());
0533     }
0534 }
0535 
0536 void AssignedListView::slotAssignTools(const QMultiMap<int, QString>& map)
0537 {
0538     if (map.isEmpty())
0539     {
0540         return;
0541     }
0542 
0543     assignTools(map, nullptr);
0544 }
0545 
0546 void AssignedListView::assignTools(const QMultiMap<int, QString>& map, AssignedListViewItem* const preceding)
0547 {
0548     // We pop all items in reverse order to have same order than selection from Batch Tools list.
0549 
0550 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0551 
0552     QMultiMapIterator<int, QString> it(map);
0553 
0554 #else
0555 
0556     QMapIterator<int, QString> it(map);
0557 
0558 #endif
0559 
0560     it.toBack();
0561 
0562     while (it.hasPrevious())
0563     {
0564         it.previous();
0565         BatchTool::BatchToolGroup group = (BatchTool::BatchToolGroup)(it.key());
0566         QString name                    = it.value();
0567         BatchTool* const tool           = BatchToolsFactory::instance()->findTool(name, group);
0568 
0569         if (tool)
0570         {
0571             // NOTE: Only now create the settings widget when needed.
0572 
0573             if (!tool->settingsWidget())
0574             {
0575                 tool->registerSettingsWidget();
0576             }
0577 
0578             BatchToolSet set;
0579             set.name                         = tool->objectName();
0580             set.group                        = tool->toolGroup();
0581             set.version                      = tool->toolVersion();
0582             set.settings                     = tool->defaultSettings();
0583             AssignedListViewItem* const item = insertTool(preceding, set);
0584             setCurrentItem(item);
0585         }
0586     }
0587 }
0588 
0589 void AssignedListView::slotContextMenu()
0590 {
0591     if (!viewport()->isEnabled())
0592     {
0593         return;
0594     }
0595 
0596     KActionCollection* const acol = QueueMgrWindow::queueManagerWindow()->actionCollection();
0597     QMenu popmenu(this);
0598     popmenu.addAction(acol->action(QLatin1String("queuemgr_toolup")));
0599     popmenu.addAction(acol->action(QLatin1String("queuemgr_tooldown")));
0600     popmenu.addAction(acol->action(QLatin1String("queuemgr_toolremove")));
0601     popmenu.addSeparator();
0602     popmenu.addAction(acol->action(QLatin1String("queuemgr_savequeue")));
0603     popmenu.addAction(acol->action(QLatin1String("queuemgr_toolsclear")));
0604     popmenu.exec(QCursor::pos());
0605 }
0606 
0607 void AssignedListView::refreshIndex()
0608 {
0609     QTreeWidgetItemIterator it(this);
0610 
0611     while (*it)
0612     {
0613         AssignedListViewItem* const item = dynamic_cast<AssignedListViewItem*>(*it);
0614 
0615         if (item)
0616         {
0617             item->setIndex(indexOfTopLevelItem(item));
0618         }
0619 
0620         ++it;
0621     }
0622 }
0623 
0624 } // namespace Digikam
0625 
0626 #include "moc_assignedlist.cpp"