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"