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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2012-12-18
0007  * Description : Customized Workflow Settings list.
0008  *
0009  * SPDX-FileCopyrightText: 2012-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 "workflowlist.h"
0016 
0017 // Qt includes
0018 
0019 #include <QApplication>
0020 #include <QDrag>
0021 #include <QHeaderView>
0022 #include <QMimeData>
0023 #include <QPainter>
0024 #include <QMenu>
0025 #include <QAction>
0026 #include <QIcon>
0027 #include <QMessageBox>
0028 
0029 // KDE includes
0030 
0031 #include <klocalizedstring.h>
0032 
0033 // Local includes
0034 
0035 #include "workflowmanager.h"
0036 #include "workflowdlg.h"
0037 #include "dmessagebox.h"
0038 
0039 namespace Digikam
0040 {
0041 
0042 WorkflowItem::WorkflowItem(WorkflowList* const parent, const QString& title)
0043     : QTreeWidgetItem(parent)
0044 {
0045     setDisabled(false);
0046     setSelected(false);
0047 
0048     Workflow q = WorkflowManager::instance()->findByTitle(title);
0049 
0050     setIcon(0, QIcon::fromTheme(QLatin1String("step")));
0051     setItem(title, q.desc, q.aTools.count());
0052 }
0053 
0054 WorkflowItem::~WorkflowItem()
0055 {
0056 }
0057 
0058 QString WorkflowItem::title() const
0059 {
0060     return text(0);
0061 }
0062 
0063 int WorkflowItem::count() const
0064 {
0065     return text(1).toInt();
0066 }
0067 
0068 void WorkflowItem::setItem(const QString& title, const QString& desc, int count)
0069 {
0070     if (!title.isEmpty())
0071     {
0072         setText(0, title);
0073     }
0074 
0075     if (!desc.isEmpty())
0076     {
0077         setText(2, desc);
0078     }
0079 
0080     if (count > 0)
0081     {
0082         setText(1, QString::number(count));
0083     }
0084 }
0085 
0086 // ---------------------------------------------------------------------------
0087 
0088 WorkflowList::WorkflowList(QWidget* const parent)
0089     : QTreeWidget(parent)
0090 {
0091     setContextMenuPolicy(Qt::CustomContextMenu);
0092     setIconSize(QSize(22, 22));
0093     setSelectionMode(QAbstractItemView::SingleSelection);
0094     setSortingEnabled(true);
0095     setRootIsDecorated(false);
0096     setUniformRowHeights(true);
0097     setAllColumnsShowFocus(true);
0098     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0099     setColumnCount(3);
0100     setHeaderHidden(false);
0101     setDragEnabled(true);
0102 
0103     QStringList titles;
0104     titles.append(i18nc("@title: batch workflow name",        "Title"));
0105     titles.append(i18nc("@title: batch workflow tools list",  "Tools"));
0106     titles.append(i18nc("@title: batch workflow description", "Description"));
0107 
0108     setHeaderLabels(titles);
0109     header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
0110     header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
0111     header()->setSectionResizeMode(2, QHeaderView::Stretch);
0112 
0113     connect(this, SIGNAL(customContextMenuRequested(QPoint)),
0114             this, SLOT(slotContextMenu()));
0115 
0116     WorkflowManager* const mngr = WorkflowManager::instance();
0117     QStringList failed;
0118     mngr->load(failed);
0119 
0120     Q_FOREACH (const Workflow& q, mngr->queueSettingsList())
0121     {
0122         slotAddQueueSettings(q.title);
0123     }
0124 
0125     if (!failed.isEmpty())
0126     {
0127         DMessageBox::showInformationList(QMessageBox::Information,
0128                                          qApp->activeWindow(),
0129                                          i18nc("@title:window", "Batch Queue Manager"),
0130                                          i18nc("@info", "Some Workflows cannot be loaded from your config file due to an incompatible "
0131                                                         "version of a tool."),
0132                                          failed);
0133     }
0134 }
0135 
0136 WorkflowList::~WorkflowList()
0137 {
0138 }
0139 
0140 void WorkflowList::slotAddQueueSettings(const QString& title)
0141 {
0142     WorkflowItem* const item = findByTitle(title);
0143 
0144     if (!item)
0145     {
0146         new WorkflowItem(this, title);
0147     }
0148 }
0149 
0150 void WorkflowList::slotRemoveQueueSettings(const QString& title)
0151 {
0152     WorkflowItem* const item = findByTitle(title);
0153 
0154     if (item)
0155     {
0156         delete item;
0157     }
0158 }
0159 
0160 WorkflowItem* WorkflowList::findByTitle(const QString& title)
0161 {
0162     QTreeWidgetItemIterator it(this);
0163 
0164     while (*it)
0165     {
0166         WorkflowItem* const item = dynamic_cast<WorkflowItem*>(*it);
0167 
0168         if (item && (item->title() == title))
0169         {
0170             return item;
0171         }
0172 
0173         ++it;
0174     }
0175 
0176     return nullptr;
0177 }
0178 
0179 void WorkflowList::startDrag(Qt::DropActions /*supportedActions*/)
0180 {
0181     QList<QTreeWidgetItem*> list = selectedItems();
0182 
0183     if (!list.isEmpty())
0184     {
0185         WorkflowItem* const item = dynamic_cast<WorkflowItem*>(list.first());
0186 
0187         if (!item)
0188         {
0189             return;
0190         }
0191 
0192         QPixmap icon(QIcon::fromTheme(QLatin1String("step")).pixmap(48));
0193         int w = icon.width();
0194         int h = icon.height();
0195 
0196         QPixmap pix(w + 4, h + 4);
0197         QString text(QString::number(item->count()));
0198 
0199         QPainter p(&pix);
0200         p.fillRect(0, 0, pix.width() - 1, pix.height() - 1, QColor(Qt::white));
0201         p.setPen(QPen(Qt::black, 1));
0202         p.drawRect(0, 0, pix.width() - 1, pix.height() - 1);
0203         p.drawPixmap(2, 2, icon);
0204         QRect r = p.boundingRect(2, 2, w, h, Qt::AlignLeft | Qt::AlignTop, text);
0205         r.setWidth(qMax(r.width(), r.height()));
0206         r.setHeight(qMax(r.width(), r.height()));
0207         p.fillRect(r, QColor(0, 80, 0));
0208         p.setPen(Qt::white);
0209         QFont f(font());
0210         f.setBold(true);
0211         p.setFont(f);
0212         p.drawText(r, Qt::AlignCenter, text);
0213         p.end();
0214 
0215         QDrag* const drag = new QDrag(this);
0216         drag->setMimeData(mimeData(list));
0217         drag->setPixmap(pix);
0218         drag->exec();
0219 
0220         if (drag->target())
0221         {
0222             m_lastAssignedTitel = item->title();
0223         }
0224     }
0225 }
0226 
0227 QStringList WorkflowList::mimeTypes() const
0228 {
0229     return QStringList() << QLatin1String("digikam/workflow");
0230 }
0231 
0232 void WorkflowList::mouseDoubleClickEvent(QMouseEvent*)
0233 {
0234     if (viewport()->isEnabled())
0235     {
0236         slotAssignQueueSettings();
0237     }
0238 }
0239 
0240 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0241 
0242 QMimeData* WorkflowList::mimeData(const QList<QTreeWidgetItem*>& items) const
0243 
0244 #else
0245 
0246 // cppcheck-suppress passedByValue
0247 QMimeData* WorkflowList::mimeData(const QList<QTreeWidgetItem*> items) const    // clazy:exclude=function-args-by-ref
0248 
0249 #endif
0250 
0251 {
0252     QMimeData* const mimeData = new QMimeData();
0253     QByteArray encodedData;
0254     QDataStream stream(&encodedData, QIODevice::WriteOnly);
0255 
0256     if (!items.isEmpty())
0257     {
0258         WorkflowItem* const item  = dynamic_cast<WorkflowItem*>(items.first());
0259 
0260         if (item)
0261         {
0262             stream << item->title();
0263         }
0264     }
0265 
0266     mimeData->setData(QLatin1String("digikam/workflow"), encodedData);
0267     return mimeData;
0268 }
0269 
0270 void WorkflowList::slotContextMenu()
0271 {
0272     QList<QTreeWidgetItem*> list = selectedItems();
0273 
0274     if (list.isEmpty())
0275     {
0276         return;
0277     }
0278 
0279     WorkflowItem* const item    = dynamic_cast<WorkflowItem*>(list.first());
0280     WorkflowManager* const mngr = WorkflowManager::instance();
0281 
0282     if (!item)
0283     {
0284         return;
0285     }
0286 
0287     QMenu popmenu(this);
0288     QAction* const assignAction = new QAction(QIcon::fromTheme(QLatin1String("list-add")),     i18nc("@action", "Assign Workflow to current queue"), this);
0289     QAction* const propAction   = new QAction(QIcon::fromTheme(QLatin1String("configure")),    i18nc("@action", "Edit Workflow"),                    this);
0290     QAction* const updAction    = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18nc("@action", "Update Workflow"),                  this);
0291     QAction* const delAction    = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")),  i18nc("@action", "Delete Workflow"),                  this);
0292 
0293     popmenu.addAction(assignAction);
0294     popmenu.addAction(propAction);
0295 
0296     if (m_lastAssignedTitel == item->title())
0297     {
0298         popmenu.addAction(updAction);
0299     }
0300 
0301     popmenu.addSeparator();
0302     popmenu.addAction(delAction);
0303 
0304     QAction* const choice = popmenu.exec(QCursor::pos());
0305 
0306     if      (choice == assignAction)
0307     {
0308         slotAssignQueueSettings();
0309     }
0310     else if (choice == propAction)
0311     {
0312         Workflow wfOld = mngr->findByTitle(item->title());
0313         Workflow wfNew = wfOld;
0314 
0315         if (WorkflowDlg::editProps(wfNew))
0316         {
0317             mngr->remove(wfOld);
0318             mngr->insert(wfNew);
0319             mngr->save();
0320 
0321             if (wfOld.title != wfNew.title)
0322             {
0323                 removeItemWidget(item, 0);
0324                 delete item;
0325             }
0326             else
0327             {
0328                 item->setItem(QString(), wfNew.desc);
0329             }
0330         }
0331     }
0332     else if (choice == updAction)
0333     {
0334         Q_EMIT signalUpdateQueueSettings(item->title());
0335 
0336         Workflow q = WorkflowManager::instance()->findByTitle(item->title());
0337         item->setItem(QString(), QString(), q.aTools.count());
0338     }
0339     else if (choice == delAction)
0340     {
0341         int result = QMessageBox::warning(qApp->activeWindow(),
0342                                   i18nc("@title:window", "Delete Workflow?"),
0343                                   i18nc("@info", "Are you sure you want to "
0344                                                  "delete the selected workflow "
0345                                                  "\"%1\"?", item->title()),
0346                                   QMessageBox::Yes | QMessageBox::Cancel);
0347 
0348         if (result == QMessageBox::Yes)
0349         {
0350             Workflow wf = mngr->findByTitle(item->title());
0351             mngr->remove(wf);
0352             mngr->save();
0353             removeItemWidget(item, 0);
0354             delete item;
0355         }
0356     }
0357 }
0358 
0359 void WorkflowList::slotAssignQueueSettings()
0360 {
0361     QList<QTreeWidgetItem*> list = selectedItems();
0362 
0363     if (!list.isEmpty())
0364     {
0365         WorkflowItem* const item = dynamic_cast<WorkflowItem*>(list.first());
0366 
0367         if (item)
0368         {
0369             Q_EMIT signalAssignQueueSettings(item->title());
0370             m_lastAssignedTitel = item->title();
0371         }
0372     }
0373 }
0374 
0375 } // namespace Digikam
0376 
0377 #include "moc_workflowlist.cpp"