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 : 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 * SPDX-FileCopyrightText: 2014 by Mohamed_Anwer <m_dot_anwer at gmx dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "queuelist.h" 0017 0018 // Qt includes 0019 0020 #include <QDragEnterEvent> 0021 #include <QFileInfo> 0022 #include <QHeaderView> 0023 #include <QPainter> 0024 #include <QTimer> 0025 #include <QUrl> 0026 #include <QDrag> 0027 #include <QMenu> 0028 #include <QAction> 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 "coredb.h" 0058 #include "coredbchangesets.h" 0059 #include "coredbwatch.h" 0060 #include "ddragobjects.h" 0061 #include "defaultrenameparser.h" 0062 #include "queuemgrwindow.h" 0063 #include "queuesettings.h" 0064 #include "queuetooltip.h" 0065 #include "thumbnailloadthread.h" 0066 #include "thumbnailsize.h" 0067 #include "workflowmanager.h" 0068 #include "dlayoutbox.h" 0069 #include "dworkingpixmap.h" 0070 0071 namespace Digikam 0072 { 0073 0074 class Q_DECL_HIDDEN QueueListViewItem::Private 0075 { 0076 0077 public: 0078 0079 explicit Private() 0080 : isBusy (false), 0081 done (false), 0082 hasThumb (false), 0083 progressIndex(0), 0084 view (nullptr) 0085 { 0086 } 0087 0088 bool isBusy; 0089 bool done; 0090 bool hasThumb; 0091 0092 int progressIndex; 0093 0094 QString destFileName; 0095 0096 QPixmap preview; 0097 0098 QueueListView* view; 0099 0100 ItemInfo info; 0101 }; 0102 0103 QueueListViewItem::QueueListViewItem(QueueListView* const view, const ItemInfo& info) 0104 : QTreeWidgetItem(view), 0105 d (new Private) 0106 { 0107 d->view = view; 0108 setThumb(QIcon::fromTheme(QLatin1String("view-preview")).pixmap(48, QIcon::Disabled), false); 0109 setInfo(info); 0110 } 0111 0112 QueueListViewItem::~QueueListViewItem() 0113 { 0114 delete d; 0115 } 0116 0117 bool QueueListViewItem::hasValidThumbnail() const 0118 { 0119 return d->hasThumb; 0120 } 0121 0122 void QueueListViewItem::setInfo(const ItemInfo& info) 0123 { 0124 d->info = info; 0125 setText(1, d->info.name()); 0126 } 0127 0128 ItemInfo QueueListViewItem::info() const 0129 { 0130 return d->info; 0131 } 0132 0133 void QueueListViewItem::setPixmap(const QPixmap& pix) 0134 { 0135 QIcon icon = QIcon(pix); 0136 0137 // We make sure the preview icon stays the same regardless of the role 0138 0139 icon.addPixmap(pix, QIcon::Selected, QIcon::On); 0140 icon.addPixmap(pix, QIcon::Selected, QIcon::Off); 0141 icon.addPixmap(pix, QIcon::Active, QIcon::On); 0142 icon.addPixmap(pix, QIcon::Active, QIcon::Off); 0143 icon.addPixmap(pix, QIcon::Normal, QIcon::On); 0144 icon.addPixmap(pix, QIcon::Normal, QIcon::Off); 0145 setIcon(0, icon); 0146 } 0147 0148 void QueueListViewItem::setThumb(const QPixmap& pix, bool hasThumb) 0149 { 0150 QSize iSize = treeWidget()->iconSize(); 0151 QPixmap pixmap(iSize.width() + 2, iSize.height() + 2); 0152 pixmap.fill(Qt::transparent); 0153 QPainter p(&pixmap); 0154 p.drawPixmap((pixmap.width() / 2) - (pix.width() / 2), (pixmap.height() / 2) - (pix.height() / 2), pix); 0155 d->preview = pixmap; 0156 setPixmap(d->preview); 0157 d->hasThumb = hasThumb; 0158 } 0159 0160 void QueueListViewItem::animProgress() 0161 { 0162 QPixmap icon(d->view->progressPixmapForIndex(d->progressIndex)); 0163 d->progressIndex++; 0164 0165 if (d->view->progressPixmapForIndex(d->progressIndex).isNull()) 0166 { 0167 d->progressIndex = 0; 0168 } 0169 0170 QPixmap preview = d->preview; 0171 QPixmap mask(preview.size()); 0172 mask.fill(QColor(128, 128, 128, 192)); 0173 QPainter p(&preview); 0174 p.drawPixmap(0, 0, mask); 0175 p.drawPixmap((preview.width() / 2) - (icon.width() / 2), (preview.height() / 2) - (icon.height() / 2), icon); 0176 setPixmap(preview); 0177 } 0178 0179 void QueueListViewItem::setCanceled() 0180 { 0181 setPixmap(d->preview); 0182 setIcon(1, QIcon::fromTheme(QLatin1String("dialog-cancel"))); 0183 d->done = false; 0184 d->isBusy = false; 0185 d->progressIndex = 0; 0186 } 0187 0188 void QueueListViewItem::setFailed() 0189 { 0190 setPixmap(d->preview); 0191 setIcon(1, QIcon::fromTheme(QLatin1String("dialog-error"))); 0192 d->done = false; 0193 d->isBusy = false; 0194 d->progressIndex = 0; 0195 } 0196 0197 void QueueListViewItem::setDone() 0198 { 0199 setPixmap(d->preview); 0200 setIcon(1, QIcon::fromTheme(QLatin1String("dialog-ok-apply"))); 0201 d->done = true; 0202 d->isBusy = false; 0203 d->progressIndex = 0; 0204 } 0205 0206 bool QueueListViewItem::isDone() const 0207 { 0208 return d->done; 0209 } 0210 0211 void QueueListViewItem::reset() 0212 { 0213 setPixmap(d->preview); 0214 setIcon(1, QIcon()); 0215 d->done = false; 0216 d->isBusy = false; 0217 d->progressIndex = 0; 0218 } 0219 0220 void QueueListViewItem::setBusy() 0221 { 0222 d->isBusy = true; 0223 } 0224 0225 bool QueueListViewItem::isBusy() const 0226 { 0227 return d->isBusy; 0228 } 0229 0230 void QueueListViewItem::setDestFileName(const QString& str) 0231 { 0232 d->destFileName = str; 0233 setText(2, d->destFileName); 0234 } 0235 0236 QString QueueListViewItem::destFileName() const 0237 { 0238 return d->destFileName; 0239 } 0240 0241 QString QueueListViewItem::destBaseName() const 0242 { 0243 QFileInfo fi(d->destFileName); 0244 0245 return fi.completeBaseName(); 0246 } 0247 0248 QString QueueListViewItem::destSuffix() const 0249 { 0250 QFileInfo fi(d->destFileName); 0251 0252 return fi.suffix(); 0253 } 0254 0255 // --------------------------------------------------------------------------- 0256 0257 class Q_DECL_HIDDEN QueueListView::Private 0258 { 0259 0260 public: 0261 0262 enum RemoveItemsType 0263 { 0264 ItemsSelected = 0, 0265 ItemsDone, 0266 ItemsAll 0267 }; 0268 0269 public: 0270 0271 explicit Private() 0272 : showTips (false), 0273 iconSize (64), 0274 toolTipTimer (nullptr), 0275 progressTimer (nullptr), 0276 thumbLoadThread (ThumbnailLoadThread::defaultThread()), 0277 toolTip (nullptr), 0278 toolTipItem (nullptr), 0279 progressPix (nullptr) 0280 { 0281 } 0282 0283 bool showTips; 0284 0285 const int iconSize; 0286 0287 QTimer* toolTipTimer; 0288 QTimer* progressTimer; 0289 0290 ThumbnailLoadThread* thumbLoadThread; 0291 0292 QueueSettings settings; 0293 0294 AssignedBatchTools toolsList; 0295 0296 QueueToolTip* toolTip; 0297 0298 QueueListViewItem* toolTipItem; 0299 0300 DWorkingPixmap* progressPix; 0301 }; 0302 0303 QueueListView::QueueListView(QWidget* const parent) 0304 : QTreeWidget(parent), 0305 d (new Private) 0306 { 0307 setIconSize(QSize(d->iconSize, d->iconSize)); 0308 setSelectionMode(QAbstractItemView::ExtendedSelection); 0309 setWhatsThis(i18nc("@info", "This is the list of images to batch process.")); 0310 0311 setDragEnabled(true); 0312 setAcceptDrops(true); 0313 setDropIndicatorShown(true); 0314 viewport()->setAcceptDrops(true); 0315 viewport()->setMouseTracking(true); 0316 0317 setColumnCount(3); 0318 setSortingEnabled(true); 0319 setRootIsDecorated(false); 0320 setUniformRowHeights(true); 0321 setAllColumnsShowFocus(true); 0322 sortByColumn(1, Qt::AscendingOrder); 0323 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 0324 setContextMenuPolicy(Qt::CustomContextMenu); 0325 0326 QStringList titles; 0327 titles.append(i18nc("@title: preview item", "Thumbnail")); 0328 titles.append(i18nc("@title: original item name", "Original")); 0329 titles.append(i18nc("@title: target item name", "Target")); 0330 setHeaderLabels(titles); 0331 header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); 0332 header()->setSectionResizeMode(1, QHeaderView::Stretch); 0333 header()->setSectionResizeMode(2, QHeaderView::Stretch); 0334 0335 d->toolTip = new QueueToolTip(this); 0336 d->toolTipTimer = new QTimer(this); 0337 d->progressTimer = new QTimer(this); 0338 d->progressPix = new DWorkingPixmap(this); 0339 0340 // ----------------------------------------------------------- 0341 0342 connect(CoreDbAccess::databaseWatch(), SIGNAL(collectionImageChange(CollectionImageChangeset)), 0343 this, SLOT(slotCollectionImageChange(CollectionImageChangeset)), 0344 Qt::QueuedConnection); 0345 0346 connect(d->thumbLoadThread, SIGNAL(signalThumbnailLoaded(LoadingDescription,QPixmap)), 0347 this, SLOT(slotThumbnailLoaded(LoadingDescription,QPixmap))); 0348 0349 connect(this, SIGNAL(customContextMenuRequested(QPoint)), 0350 this, SLOT(slotContextMenu())); 0351 0352 connect(d->toolTipTimer, SIGNAL(timeout()), 0353 this, SLOT(slotToolTip())); 0354 0355 connect(d->progressTimer, SIGNAL(timeout()), 0356 this, SLOT(slotProgressTimerDone())); 0357 } 0358 0359 QueueListView::~QueueListView() 0360 { 0361 delete d->toolTip; 0362 delete d; 0363 } 0364 0365 QPixmap QueueListView::progressPixmapForIndex(int index) const 0366 { 0367 if ((index >= 0) && (index < d->progressPix->frameCount())) 0368 { 0369 return (d->progressPix->frameAt(index)); 0370 } 0371 0372 return QPixmap(); 0373 } 0374 0375 Qt::DropActions QueueListView::supportedDropActions() const 0376 { 0377 return (Qt::CopyAction | Qt::MoveAction); 0378 } 0379 0380 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0381 0382 QMimeData* QueueListView::mimeData(const QList<QTreeWidgetItem*>& items) const 0383 0384 #else 0385 0386 // cppcheck-suppress passedByValue 0387 QMimeData* QueueListView::mimeData(const QList<QTreeWidgetItem*> items) const // clazy:exclude=function-args-by-ref 0388 0389 #endif 0390 0391 { 0392 QList<QUrl> urls; 0393 QList<int> albumIDs; 0394 QList<qlonglong> imageIDs; 0395 0396 Q_FOREACH (QTreeWidgetItem* const itm, items) 0397 { 0398 QueueListViewItem* const vitem = dynamic_cast<QueueListViewItem*>(itm); 0399 0400 if (vitem) 0401 { 0402 urls.append(vitem->info().fileUrl()); 0403 albumIDs.append(vitem->info().albumId()); 0404 imageIDs.append(vitem->info().id()); 0405 } 0406 } 0407 0408 DItemDrag* const mimeData = new DItemDrag(urls, albumIDs, imageIDs); 0409 0410 return mimeData; 0411 } 0412 0413 void QueueListView::startDrag(Qt::DropActions /*supportedActions*/) 0414 { 0415 QList<QTreeWidgetItem*> items = selectedItems(); 0416 0417 if (items.isEmpty()) 0418 { 0419 return; 0420 } 0421 0422 QPixmap icon(QIcon::fromTheme(QLatin1String("image-jpeg")).pixmap(48)); 0423 int w = icon.width(); 0424 int h = icon.height(); 0425 0426 QPixmap pix(w + 4, h + 4); 0427 QString text(QString::number(items.count())); 0428 0429 QPainter p(&pix); 0430 p.fillRect(0, 0, pix.width() - 1, pix.height() - 1, QColor(Qt::white)); 0431 p.setPen(QPen(Qt::black, 1)); 0432 p.drawRect(0, 0, pix.width() - 1, pix.height() - 1); 0433 p.drawPixmap(2, 2, icon); 0434 QRect r = p.boundingRect(2, 2, w, h, Qt::AlignLeft | Qt::AlignTop, text); 0435 r.setWidth(qMax(r.width(), r.height())); 0436 r.setHeight(qMax(r.width(), r.height())); 0437 p.fillRect(r, QColor(0, 80, 0)); 0438 p.setPen(Qt::white); 0439 QFont f(font()); 0440 f.setBold(true); 0441 p.setFont(f); 0442 p.drawText(r, Qt::AlignCenter, text); 0443 p.end(); 0444 0445 QDrag* const drag = new QDrag(this); 0446 drag->setMimeData(mimeData(items)); 0447 drag->setPixmap(pix); 0448 drag->exec(); 0449 } 0450 0451 void QueueListView::dragEnterEvent(QDragEnterEvent* e) 0452 { 0453 QTreeWidget::dragEnterEvent(e); 0454 e->accept(); 0455 } 0456 0457 void QueueListView::dragMoveEvent(QDragMoveEvent* e) 0458 { 0459 int albumID; 0460 QList<int> albumIDs; 0461 QList<qlonglong> imageIDs; 0462 QList<QUrl> urls; 0463 0464 if (DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs) || 0465 DAlbumDrag::decode(e->mimeData(), urls, albumID) || 0466 DTagListDrag::canDecode(e->mimeData())) 0467 { 0468 if (DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs)) 0469 { 0470 ItemInfoList imageInfoList; 0471 0472 for (QList<qlonglong>::const_iterator it = imageIDs.constBegin() ; 0473 it != imageIDs.constEnd() ; ++it) 0474 { 0475 ItemInfo info(*it); 0476 0477 if (!findItemByInfo(info)) 0478 { 0479 imageInfoList.append(info); 0480 } 0481 } 0482 0483 if (!imageInfoList.isEmpty()) 0484 { 0485 QTreeWidget::dragMoveEvent(e); 0486 e->accept(); 0487 return; 0488 } 0489 } 0490 } 0491 else if (e->mimeData()->formats().contains(QLatin1String("digikam/workflow"))) 0492 { 0493 QTreeWidget::dragMoveEvent(e); 0494 e->accept(); 0495 return; 0496 } 0497 0498 e->ignore(); 0499 } 0500 0501 void QueueListView::dropEvent(QDropEvent* e) 0502 { 0503 int albumID; 0504 QList<int> albumIDs; 0505 QList<qlonglong> imageIDs; 0506 QList<QUrl> urls; 0507 0508 if (DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs)) 0509 { 0510 ItemInfoList imageInfoList; 0511 0512 for (QList<qlonglong>::const_iterator it = imageIDs.constBegin() ; 0513 it != imageIDs.constEnd() ; ++it) 0514 { 0515 ItemInfo info(*it); 0516 0517 if (!findItemByInfo(info)) 0518 { 0519 imageInfoList.append(info); 0520 } 0521 } 0522 0523 if (!imageInfoList.isEmpty()) 0524 { 0525 slotAddItems(imageInfoList); 0526 e->acceptProposedAction(); 0527 0528 QueueListView* const vitem = dynamic_cast<QueueListView*>(e->source()); 0529 0530 if (vitem && vitem != this) 0531 { 0532 Q_FOREACH (const ItemInfo& info, imageInfoList) 0533 { 0534 vitem->removeItemByInfo(info); 0535 } 0536 } 0537 } 0538 } 0539 else if (DAlbumDrag::decode(e->mimeData(), urls, albumID)) 0540 { 0541 QList<qlonglong> itemIDs = CoreDbAccess().db()->getItemIDsInAlbum(albumID); 0542 ItemInfoList imageInfoList; 0543 0544 for (QList<qlonglong>::const_iterator it = itemIDs.constBegin() ; 0545 it != itemIDs.constEnd() ; ++it) 0546 { 0547 ItemInfo info(*it); 0548 0549 if (!findItemByInfo(info)) 0550 { 0551 imageInfoList.append(info); 0552 } 0553 } 0554 0555 if (!imageInfoList.isEmpty()) 0556 { 0557 slotAddItems(imageInfoList); 0558 e->acceptProposedAction(); 0559 } 0560 } 0561 else if (DTagListDrag::canDecode(e->mimeData())) 0562 { 0563 QList<int> tagIDs; 0564 0565 if (!DTagListDrag::decode(e->mimeData(), tagIDs)) 0566 { 0567 return; 0568 } 0569 0570 QList<qlonglong> itemIDs = CoreDbAccess().db()->getItemIDsInTag(tagIDs.first(), true); 0571 ItemInfoList imageInfoList; 0572 0573 for (QList<qlonglong>::const_iterator it = itemIDs.constBegin() ; 0574 it != itemIDs.constEnd() ; ++it) 0575 { 0576 ItemInfo info(*it); 0577 0578 if (!findItemByInfo(info)) 0579 { 0580 imageInfoList.append(info); 0581 } 0582 } 0583 0584 if (!imageInfoList.isEmpty()) 0585 { 0586 slotAddItems(imageInfoList); 0587 e->acceptProposedAction(); 0588 } 0589 } 0590 else if (e->mimeData()->formats().contains(QLatin1String("digikam/workflow"))) 0591 { 0592 QByteArray ba = e->mimeData()->data(QLatin1String("digikam/workflow")); 0593 0594 if (ba.size()) 0595 { 0596 QDataStream ds(ba); 0597 QString title; 0598 ds >> title; 0599 QueueMgrWindow::queueManagerWindow()->slotAssignQueueSettings(title); 0600 0601 e->acceptProposedAction(); 0602 } 0603 } 0604 else 0605 { 0606 e->ignore(); 0607 } 0608 0609 Q_EMIT signalQueueContentsChanged(); 0610 } 0611 0612 void QueueListView::setEnableToolTips(bool val) 0613 { 0614 d->showTips = val; 0615 0616 if (!val) 0617 { 0618 hideToolTip(); 0619 } 0620 } 0621 0622 void QueueListView::hideToolTip() 0623 { 0624 d->toolTipItem = nullptr; 0625 d->toolTipTimer->stop(); 0626 slotToolTip(); 0627 } 0628 0629 bool QueueListView::acceptToolTip(const QPoint& pos) const 0630 { 0631 if (columnAt(pos.x()) == 0) 0632 { 0633 return true; 0634 } 0635 0636 return false; 0637 } 0638 0639 void QueueListView::slotToolTip() 0640 { 0641 d->toolTip->setQueueItem(d->toolTipItem); 0642 } 0643 0644 void QueueListView::mouseMoveEvent(QMouseEvent* e) 0645 { 0646 if (e->buttons() == Qt::NoButton) 0647 { 0648 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(itemAt(e->pos())); 0649 0650 if (d->showTips) 0651 { 0652 if (!isActiveWindow()) 0653 { 0654 hideToolTip(); 0655 return; 0656 } 0657 0658 if (item != d->toolTipItem) 0659 { 0660 hideToolTip(); 0661 0662 if (acceptToolTip(e->pos())) 0663 { 0664 d->toolTipItem = item; 0665 d->toolTipTimer->setSingleShot(true); 0666 d->toolTipTimer->start(500); 0667 } 0668 } 0669 0670 if ((item == d->toolTipItem) && !acceptToolTip(e->pos())) 0671 { 0672 hideToolTip(); 0673 } 0674 } 0675 0676 return; 0677 } 0678 0679 hideToolTip(); 0680 QTreeWidget::mouseMoveEvent(e); 0681 } 0682 0683 void QueueListView::wheelEvent(QWheelEvent* e) 0684 { 0685 hideToolTip(); 0686 QTreeWidget::wheelEvent(e); 0687 } 0688 0689 void QueueListView::keyPressEvent(QKeyEvent* e) 0690 { 0691 hideToolTip(); 0692 QTreeWidget::keyPressEvent(e); 0693 } 0694 0695 void QueueListView::focusOutEvent(QFocusEvent* e) 0696 { 0697 hideToolTip(); 0698 QTreeWidget::focusOutEvent(e); 0699 } 0700 0701 void QueueListView::leaveEvent(QEvent* e) 0702 { 0703 hideToolTip(); 0704 QTreeWidget::leaveEvent(e); 0705 } 0706 0707 void QueueListView::slotAddItems(const ItemInfoList& list) 0708 { 0709 if (list.count() == 0) 0710 { 0711 return; 0712 } 0713 0714 for (ItemInfoList::ConstIterator it = list.begin() ; it != list.end() ; ++it) 0715 { 0716 ItemInfo info = *it; 0717 0718 // Check if the new item already exist in the list. 0719 0720 bool find = false; 0721 QueueListViewItem* item = nullptr; 0722 0723 QTreeWidgetItemIterator iter(this); 0724 0725 while (*iter) 0726 { 0727 item = dynamic_cast<QueueListViewItem*>(*iter); 0728 0729 if (item && (item->info() == info)) 0730 { 0731 find = true; 0732 } 0733 0734 ++iter; 0735 } 0736 0737 if (!find) 0738 { 0739 new QueueListViewItem(this, info); 0740 } 0741 } 0742 0743 updateDestFileNames(); 0744 0745 Q_EMIT signalQueueContentsChanged(); 0746 } 0747 0748 void QueueListView::drawRow(QPainter* p, const QStyleOptionViewItem& opt, const QModelIndex& index) const 0749 { 0750 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(itemFromIndex(index)); 0751 0752 if (item && !item->hasValidThumbnail()) 0753 { 0754 ItemInfo info = item->info(); 0755 d->thumbLoadThread->find(ThumbnailIdentifier(info.fileUrl().toLocalFile())); 0756 } 0757 0758 QTreeWidget::drawRow(p, opt, index); 0759 } 0760 0761 void QueueListView::slotThumbnailLoaded(const LoadingDescription& desc, const QPixmap& pix) 0762 { 0763 QTreeWidgetItemIterator it(this); 0764 0765 while (*it) 0766 { 0767 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 0768 0769 if (item && (item->info().fileUrl() == QUrl::fromLocalFile(desc.filePath))) 0770 { 0771 if (pix.isNull()) 0772 { 0773 item->setThumb(QIcon::fromTheme(QLatin1String("view-preview")).pixmap(d->iconSize, QIcon::Disabled)); 0774 } 0775 else 0776 { 0777 item->setThumb(pix.scaled(d->iconSize, d->iconSize, Qt::KeepAspectRatio)); 0778 } 0779 0780 return; 0781 } 0782 0783 ++it; 0784 } 0785 } 0786 0787 void QueueListView::slotClearList() 0788 { 0789 removeItems(Private::ItemsAll); 0790 0791 Q_EMIT signalQueueContentsChanged(); 0792 } 0793 0794 void QueueListView::slotRemoveSelectedItems() 0795 { 0796 removeItems(Private::ItemsSelected); 0797 0798 Q_EMIT signalQueueContentsChanged(); 0799 } 0800 0801 void QueueListView::slotRemoveItemsDone() 0802 { 0803 removeItems(Private::ItemsDone); 0804 0805 Q_EMIT signalQueueContentsChanged(); 0806 } 0807 0808 void QueueListView::removeItems(int removeType) 0809 { 0810 hideToolTip(); 0811 0812 bool find; 0813 0814 do 0815 { 0816 find = false; 0817 QTreeWidgetItemIterator it(this); 0818 0819 while (*it) 0820 { 0821 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 0822 0823 if (item) 0824 { 0825 switch (removeType) 0826 { 0827 case Private::ItemsSelected: 0828 { 0829 if (item->isSelected()) 0830 { 0831 delete item; 0832 find = true; 0833 } 0834 0835 break; 0836 } 0837 0838 case Private::ItemsDone: 0839 { 0840 if (item->isDone()) 0841 { 0842 delete item; 0843 find = true; 0844 } 0845 0846 break; 0847 } 0848 0849 default: // Private::ItemsAll 0850 { 0851 delete item; 0852 find = true; 0853 break; 0854 } 0855 } 0856 } 0857 0858 ++it; 0859 } 0860 } 0861 while (find); 0862 0863 Q_EMIT signalQueueContentsChanged(); 0864 } 0865 0866 void QueueListView::removeItemByInfo(const ItemInfo& info) 0867 { 0868 removeItemById(info.id()); 0869 } 0870 0871 void QueueListView::removeItemById(qlonglong id) 0872 { 0873 hideToolTip(); 0874 0875 bool find; 0876 0877 do 0878 { 0879 find = false; 0880 QTreeWidgetItemIterator it(this); 0881 0882 while (*it) 0883 { 0884 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 0885 0886 if (item && (item->info().id() == id)) 0887 { 0888 delete item; 0889 find = true; 0890 break; 0891 } 0892 0893 ++it; 0894 } 0895 } 0896 while (find); 0897 0898 Q_EMIT signalQueueContentsChanged(); 0899 } 0900 0901 bool QueueListView::findItemByInfo(const ItemInfo& info) 0902 { 0903 return (findItemById(info.id()) ? true : false); 0904 } 0905 0906 QueueListViewItem* QueueListView::findItemById(qlonglong id) 0907 { 0908 QTreeWidgetItemIterator it(this); 0909 0910 while (*it) 0911 { 0912 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 0913 0914 if (item && (item->info().id() == id)) 0915 { 0916 return item; 0917 } 0918 0919 ++it; 0920 } 0921 0922 return nullptr; 0923 } 0924 0925 QueueListViewItem* QueueListView::findItemByUrl(const QUrl& url) 0926 { 0927 QTreeWidgetItemIterator it(this); 0928 0929 while (*it) 0930 { 0931 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 0932 0933 if (item && (item->info().fileUrl() == url)) 0934 { 0935 return item; 0936 } 0937 0938 ++it; 0939 } 0940 0941 return nullptr; 0942 } 0943 0944 int QueueListView::itemsCount() 0945 { 0946 int count = 0; 0947 QTreeWidgetItemIterator it(this); 0948 0949 while (*it) 0950 { 0951 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 0952 0953 if (item) 0954 { 0955 ++count; 0956 } 0957 0958 ++it; 0959 } 0960 0961 return count; 0962 } 0963 0964 void QueueListView::cancelItems() 0965 { 0966 QTreeWidgetItemIterator it(this); 0967 0968 while (*it) 0969 { 0970 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 0971 0972 if (item && item->isBusy()) 0973 { 0974 item->setCanceled(); 0975 } 0976 0977 ++it; 0978 } 0979 } 0980 0981 ItemInfoList QueueListView::pendingItemsList() 0982 { 0983 ItemInfoList list; 0984 QTreeWidgetItemIterator it(this); 0985 0986 while (*it) 0987 { 0988 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 0989 0990 if (item && !item->isDone()) 0991 { 0992 list.append(item->info()); 0993 } 0994 0995 ++it; 0996 } 0997 0998 return list; 0999 } 1000 1001 int QueueListView::pendingItemsCount() 1002 { 1003 return pendingItemsList().count(); 1004 } 1005 1006 int QueueListView::pendingTasksCount() 1007 { 1008 int count = 0; 1009 QTreeWidgetItemIterator it(this); 1010 1011 while (*it) 1012 { 1013 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 1014 1015 if (item && !item->isDone()) 1016 { 1017 count += assignedTools().m_toolsList.count(); 1018 } 1019 1020 ++it; 1021 } 1022 1023 return count; 1024 } 1025 1026 void QueueListView::setSettings(const QueueSettings& settings) 1027 { 1028 d->settings = settings; 1029 resetQueue(); 1030 updateDestFileNames(); 1031 } 1032 1033 QueueSettings QueueListView::settings() const 1034 { 1035 return d->settings; 1036 } 1037 1038 void QueueListView::setAssignedTools(const AssignedBatchTools& tools) 1039 { 1040 d->toolsList = tools; 1041 resetQueue(); 1042 updateDestFileNames(); 1043 } 1044 1045 AssignedBatchTools QueueListView::assignedTools() const 1046 { 1047 return d->toolsList; 1048 } 1049 1050 void QueueListView::slotAssignedToolsChanged(const AssignedBatchTools& tools) 1051 { 1052 setAssignedTools(tools); 1053 } 1054 1055 void QueueListView::resetQueue() 1056 { 1057 //reset all items 1058 1059 QTreeWidgetItemIterator it(this); 1060 1061 while (*it) 1062 { 1063 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 1064 1065 if (item) 1066 { 1067 item->reset(); 1068 } 1069 1070 ++it; 1071 } 1072 } 1073 1074 void QueueListView::updateDestFileNames() 1075 { 1076 QMap<QString, QString> renamingResults; 1077 1078 if (settings().renamingRule == QueueSettings::CUSTOMIZE) 1079 { 1080 AdvancedRenameManager manager; 1081 1082 ParseSettings psettings; 1083 psettings.parseString = settings().renamingParser; 1084 1085 QList<ParseSettings> files; 1086 QTreeWidgetItemIterator it(this); 1087 1088 while (*it) 1089 { 1090 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 1091 1092 if (item) 1093 { 1094 // Update base name using queue renaming rules. 1095 1096 ItemInfo info = item->info(); 1097 QFileInfo fi(info.filePath()); 1098 1099 ParseSettings ps; 1100 ps.fileUrl = QUrl::fromLocalFile(fi.absoluteFilePath()); 1101 files << ps; 1102 } 1103 1104 ++it; 1105 } 1106 1107 manager.addFiles(files); 1108 manager.parseFiles(psettings); 1109 renamingResults = manager.newFileList(true); 1110 } 1111 1112 AssignedBatchTools tools = assignedTools(); 1113 1114 QTreeWidgetItemIterator it(this); 1115 1116 while (*it) 1117 { 1118 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 1119 1120 if (item) 1121 { 1122 // Update base name using queue renaming rules. 1123 1124 ItemInfo info = item->info(); 1125 QFileInfo fi(info.filePath()); 1126 1127 // Update suffix using assigned batch tool rules. 1128 1129 bool extensionSet = false; 1130 tools.m_itemUrl = item->info().fileUrl(); 1131 QString newSuffix = tools.targetSuffix(&extensionSet); 1132 QString newName = QString::fromUtf8("%1.%2").arg(fi.completeBaseName()).arg(newSuffix); 1133 1134 if ((settings().renamingRule == QueueSettings::CUSTOMIZE) && !renamingResults.isEmpty()) 1135 { 1136 QFileInfo fi2(renamingResults[fi.absoluteFilePath()]); 1137 1138 if (extensionSet) 1139 { 1140 newName = QString::fromUtf8("%1.%2").arg(fi2.completeBaseName()) 1141 .arg(newSuffix); 1142 } 1143 else 1144 { 1145 newName = fi2.fileName(); 1146 } 1147 } 1148 1149 item->setDestFileName(newName); 1150 } 1151 1152 ++it; 1153 } 1154 } 1155 1156 void QueueListView::slotContextMenu() 1157 { 1158 if (!viewport()->isEnabled()) 1159 { 1160 return; 1161 } 1162 1163 KActionCollection* const acol = QueueMgrWindow::queueManagerWindow()->actionCollection(); 1164 QMenu popmenu(this); 1165 popmenu.addAction(acol->action(QLatin1String("queuemgr_removeitemssel"))); 1166 popmenu.addSeparator(); 1167 popmenu.addAction(acol->action(QLatin1String("queuemgr_clearlist"))); 1168 popmenu.exec(QCursor::pos()); 1169 } 1170 1171 void QueueListView::slotCollectionImageChange(const CollectionImageChangeset& changeset) 1172 { 1173 if (QueueMgrWindow::queueManagerWindow()->isBusy()) 1174 { 1175 return; 1176 } 1177 1178 switch (changeset.operation()) 1179 { 1180 case CollectionImageChangeset::Deleted: 1181 case CollectionImageChangeset::Removed: 1182 case CollectionImageChangeset::RemovedAll: 1183 { 1184 Q_FOREACH (const qlonglong& id, changeset.ids()) 1185 { 1186 removeItemById(id); 1187 } 1188 1189 break; 1190 } 1191 1192 default: 1193 { 1194 break; 1195 } 1196 } 1197 } 1198 1199 void QueueListView::reloadThumbs(const QUrl& url) 1200 { 1201 d->thumbLoadThread->find(ThumbnailIdentifier(url.toLocalFile())); 1202 } 1203 1204 void QueueListView::setItemBusy(qlonglong id) 1205 { 1206 QueueListViewItem* const item = findItemById(id); 1207 1208 if (item) 1209 { 1210 item->setBusy(); 1211 d->progressTimer->start(300); 1212 } 1213 } 1214 1215 void QueueListView::slotProgressTimerDone() 1216 { 1217 QTreeWidgetItemIterator it(this); 1218 int active = 0; 1219 1220 while (*it) 1221 { 1222 QueueListViewItem* const item = dynamic_cast<QueueListViewItem*>(*it); 1223 1224 if (item && item->isBusy()) 1225 { 1226 item->animProgress(); 1227 active++; 1228 } 1229 1230 ++it; 1231 } 1232 1233 if (!active) 1234 { 1235 d->progressTimer->stop(); 1236 } 1237 } 1238 1239 } // namespace Digikam 1240 1241 #include "moc_queuelist.cpp"