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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2012-22-07
0007  * Description : Icon view for import tool items
0008  *
0009  * SPDX-FileCopyrightText: 2012      by Islam Wazery <wazery at ubuntu dot com>
0010  * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "importiconview_p.h"
0017 
0018 // Qt includes
0019 
0020 #include <QDesktopServices>
0021 #include <QPointer>
0022 #include <QAction>
0023 #include <QMenu>
0024 
0025 // Local includes
0026 
0027 #include "importoverlays.h"
0028 #include "importsettings.h"
0029 #include "camitemsortsettings.h"
0030 #include "fileactionmngr.h"
0031 #include "importdelegate.h"
0032 #include "advancedrenamedialog.h"
0033 #include "advancedrenameprocessdialog.h"
0034 #include "itemviewutilities.h"
0035 #include "importcontextmenu.h"
0036 #include "importdragdrop.h"
0037 
0038 namespace Digikam
0039 {
0040 
0041 ImportIconView::ImportIconView(QWidget* const parent)
0042     : ImportCategorizedView(parent),
0043       d(new Private(this))
0044 {
0045     ImportThumbnailModel* const model    = new ImportThumbnailModel(this);
0046     ImportFilterModel* const filterModel = new ImportFilterModel(this);
0047 
0048     filterModel->setSourceImportModel(model);
0049     filterModel->sort(0); // an initial sorting is necessary
0050 
0051     setModels(model, filterModel);
0052 
0053     d->normalDelegate              = new ImportNormalDelegate(this);
0054 
0055     setItemDelegate(d->normalDelegate);
0056     setSpacing(10);
0057 
0058     ImportSettings* const settings = ImportSettings::instance();
0059 
0060     // Virtual method: use Dynamic binding.
0061     this->setThumbnailSize(ThumbnailSize(settings->getDefaultIconSize()));
0062 
0063     importItemModel()->setDragDropHandler(new ImportDragDropHandler(importItemModel()));
0064     setDragEnabled(true);
0065     setAcceptDrops(true);
0066     setDropIndicatorShown(false);
0067 
0068     setToolTipEnabled(settings->showToolTipsIsValid());
0069 
0070     // selection overlay
0071 
0072     addSelectionOverlay(d->normalDelegate);
0073 
0074 /*  TODO
0075     addSelectionOverlay(d->faceDelegate);
0076 */
0077     // rotation overlays
0078 
0079     d->rotateLeftOverlay  = ImportRotateOverlay::left(this);
0080     d->rotateRightOverlay = ImportRotateOverlay::right(this);
0081 
0082     addOverlay(new ImportDownloadOverlay(this));
0083     addOverlay(new ImportLockOverlay(this));
0084     addOverlay(new ImportCoordinatesOverlay(this));
0085 
0086     d->updateOverlays();
0087 
0088     // rating overlay
0089 
0090     ImportRatingOverlay* const ratingOverlay = new ImportRatingOverlay(this);
0091     addOverlay(ratingOverlay);
0092 
0093 /*  TODO
0094     GroupIndicatorOverlay* groupOverlay = new GroupIndicatorOverlay(this);
0095     addOverlay(groupOverlay);
0096 */
0097     connect(ratingOverlay, SIGNAL(ratingEdited(QList<QModelIndex>,int)),
0098             this, SLOT(assignRating(QList<QModelIndex>,int)));
0099 
0100 /*  TODO
0101 
0102     connect(groupOverlay, SIGNAL(toggleGroupOpen(QModelIndex)),
0103             this, SLOT(groupIndicatorClicked(QModelIndex)));
0104 
0105     connect(groupOverlay, SIGNAL(showButtonContextMenu(QModelIndex,QContextMenuEvent*)),
0106             this, SLOT(showGroupContextMenu(QModelIndex,QContextMenuEvent*)));
0107 
0108     connect(importItemModel()->dragDropHandler(), SIGNAL(assignTags(QList<CamItemInfo>,QList<int>)),
0109             FileActionMngr::instance(), SLOT(assignTags(QList<CamItemInfo>,QList<int>)));
0110 
0111     connect(importItemModel()->dragDropHandler(), SIGNAL(addToGroup(CamItemInfo,QList<CamItemInfo>)),
0112             FileActionMngr::instance(), SLOT(addToGroup(CamItemInfo,QList<CamItemInfo>)));
0113 */
0114     // --- NOTE: use dynamic binding as slotSetupChanged() is a virtual method which can be re-implemented in derived classes.
0115 
0116     connect(settings, &ImportSettings::setupChanged,
0117             this, &ImportIconView::slotSetupChanged);
0118 
0119     this->slotSetupChanged();
0120 }
0121 
0122 ImportIconView::~ImportIconView()
0123 {
0124     delete d;
0125 }
0126 
0127 ItemViewUtilities* ImportIconView::utilities() const
0128 {
0129     return d->utilities;
0130 }
0131 
0132 void ImportIconView::setThumbnailSize(const ThumbnailSize& size)
0133 {
0134     ImportCategorizedView::setThumbnailSize(size);
0135 }
0136 
0137 int ImportIconView::fitToWidthIcons()
0138 {
0139     return delegate()->calculatethumbSizeToFit(viewport()->size().width());
0140 }
0141 
0142 CamItemInfo ImportIconView::camItemInfo(const QString& folder, const QString& file)
0143 {
0144     QUrl url = QUrl::fromLocalFile(folder);
0145     url      = url.adjusted(QUrl::StripTrailingSlash);
0146     url.setPath(url.path() + QLatin1Char('/') + file);
0147     QModelIndex indexForCamItemInfo = importFilterModel()->indexForPath(url.toLocalFile());
0148 
0149     if (indexForCamItemInfo.isValid())
0150     {
0151         return importFilterModel()->camItemInfo(indexForCamItemInfo);
0152     }
0153 
0154     return CamItemInfo();
0155 }
0156 
0157 CamItemInfo& ImportIconView::camItemInfoRef(const QString& folder, const QString& file)
0158 {
0159     QUrl url = QUrl::fromLocalFile(folder);
0160     url      = url.adjusted(QUrl::StripTrailingSlash);
0161     url.setPath(url.path() + QLatin1Char('/') + file);
0162     QModelIndex indexForCamItemInfo = importFilterModel()->indexForPath(url.toLocalFile());
0163     QModelIndex mappedIndex         = importFilterModel()->mapToSource(indexForCamItemInfo);
0164 
0165     return importItemModel()->camItemInfoRef(mappedIndex);
0166 }
0167 
0168 void ImportIconView::slotSetupChanged()
0169 {
0170     setToolTipEnabled(ImportSettings::instance()->showToolTipsIsValid());
0171     setFont(ImportSettings::instance()->getIconViewFont());
0172 
0173     d->updateOverlays();
0174 
0175     ImportCategorizedView::slotSetupChanged();
0176 }
0177 
0178 void ImportIconView::rename()
0179 {
0180     QList<QUrl>  urls                  = selectedUrls();
0181     NewNamesList newNamesList;
0182 
0183     QPointer<AdvancedRenameDialog> dlg = new AdvancedRenameDialog(this);
0184     dlg->slotAddImages(urls);
0185 
0186     if (dlg->exec() == QDialog::Accepted)
0187     {
0188         newNamesList = dlg->newNames();
0189     }
0190 
0191     delete dlg;
0192 
0193     if (!newNamesList.isEmpty())
0194     {
0195         QPointer<AdvancedRenameProcessDialog> dlg2 = new AdvancedRenameProcessDialog(newNamesList);
0196         dlg2->exec();
0197         delete dlg2;
0198     }
0199 }
0200 
0201 void ImportIconView::deleteSelected(bool /*permanently*/)
0202 {
0203     CamItemInfoList camItemInfoList = selectedCamItemInfos();
0204 
0205     // FIXME: This way of deletion may not working with camera items.
0206 /*
0207     if (d->utilities->deleteImages(camItemInfoList, permanently))
0208     {
0209        awayFromSelection();
0210     }
0211 */
0212 }
0213 
0214 void ImportIconView::deleteSelectedDirectly(bool /*permanently*/)
0215 {
0216     CamItemInfoList camItemInfoList = selectedCamItemInfos();
0217 
0218     // FIXME: This way of deletion may not working with camera items.
0219 /*
0220     d->utilities->deleteImagesDirectly(camItemInfoList, permanently);
0221 */
0222     awayFromSelection();
0223 }
0224 
0225 void ImportIconView::createGroupFromSelection()
0226 {
0227     // TODO: Implement grouping in import tool.
0228 /*
0229     QList<CamItemInfo> selectedInfos = selectedCamItemInfosCurrentFirst();
0230     CamItemInfo groupLeader          = selectedInfos.takeFirst();
0231     FileActionMngr::instance()->addToGroup(groupLeader, selectedInfos);
0232 */
0233 }
0234 
0235 void ImportIconView::createGroupByTimeFromSelection()
0236 {
0237     // TODO: Implement grouping in import tool.
0238 /*
0239     QList<CamItemInfo> selectedInfos = selectedCamItemInfosCurrentFirst();
0240 
0241     while (selectedInfos.size() > 0)
0242     {
0243         QList<CamItemInfo> group;
0244         CamItemInfo groupLeader = selectedInfos.takeFirst();
0245         QDateTime dateTime    = groupLeader.dateTime();
0246 
0247         while (selectedInfos.size() > 0 && abs(dateTime.secsTo(selectedInfos.first().dateTime())) < 2)
0248         {
0249            group.push_back(selectedInfos.takeFirst());
0250         }
0251 
0252         FileActionMngr::instance()->addToGroup(groupLeader, group);
0253     }
0254 */
0255 }
0256 
0257 void ImportIconView::ungroupSelected()
0258 {
0259     // TODO: Implement grouping in import tool.
0260 /*
0261     FileActionMngr::instance()->ungroup(selectedCamItemInfos());
0262 */
0263 }
0264 
0265 void ImportIconView::removeSelectedFromGroup()
0266 {
0267     // TODO: Implement grouping in import tool.
0268 /*
0269     FileActionMngr::instance()->removeFromGroup(selectedCamItemInfos());
0270 */
0271 }
0272 
0273 void ImportIconView::slotRotateLeft(const QList<QModelIndex>& /*indexes*/)
0274 {
0275 /*
0276     QList<ItemInfo> imageInfos;
0277 
0278     Q_FOREACH (const QModelIndex& index, indexes)
0279     {
0280         ItemInfo imageInfo(importFilterModel()->camItemInfo(index).url());
0281         imageInfos << imageInfo;
0282     }
0283 
0284     FileActionMngr::instance()->transform(imageInfos, MetaEngineRotation::Rotate270);
0285 */
0286 }
0287 
0288 void ImportIconView::slotRotateRight(const QList<QModelIndex>& /*indexes*/)
0289 {
0290 /*
0291     QList<ItemInfo> imageInfos;
0292 
0293     Q_FOREACH (const QModelIndex& index, indexes)
0294     {
0295         ItemInfo imageInfo(importFilterModel()->camItemInfo(index).url());
0296         imageInfos << imageInfo;
0297     }
0298 
0299     FileActionMngr::instance()->transform(imageInfos, MetaEngineRotation::Rotate90);
0300 */
0301 }
0302 
0303 void ImportIconView::activated(const CamItemInfo& info, Qt::KeyboardModifiers)
0304 {
0305     if (info.isNull())
0306     {
0307         return;
0308     }
0309 
0310     int leftClickAction = ImportSettings::instance()->getItemLeftClickAction();
0311 
0312     if      (leftClickAction == ImportSettings::ShowPreview)
0313     {
0314         Q_EMIT previewRequested(info, false);
0315     }
0316     else if (leftClickAction == ImportSettings::StartEditor)
0317     {
0318 /*      TODO
0319         openFile(info);
0320 */
0321     }
0322     else
0323     {
0324         QDesktopServices::openUrl(info.url());
0325     }
0326 }
0327 
0328 void ImportIconView::showContextMenuOnInfo(QContextMenuEvent* event, const CamItemInfo& /*info*/)
0329 {
0330     QList<CamItemInfo> selectedInfos = selectedCamItemInfosCurrentFirst();
0331     QList<qlonglong>   selectedItemIDs;
0332 
0333     Q_FOREACH (const CamItemInfo& info, selectedInfos)
0334     {
0335         selectedItemIDs << info.id;
0336     }
0337 
0338     // --------------------------------------------------------
0339 
0340     QMenu popmenu(this);
0341     ImportContextMenuHelper cmhelper(&popmenu);
0342 
0343     cmhelper.addAction(QLatin1String("importui_fullscreen"));
0344     cmhelper.addAction(QLatin1String("options_show_menubar"));
0345     cmhelper.addAction(QLatin1String("import_zoomfit2window"));
0346     cmhelper.addSeparator();
0347 
0348     // --------------------------------------------------------
0349 
0350     cmhelper.addAction(QLatin1String("importui_imagedownload"));
0351     cmhelper.addAction(QLatin1String("importui_imagemarkasdownloaded"));
0352     cmhelper.addAction(QLatin1String("importui_imagelock"));
0353     cmhelper.addAction(QLatin1String("importui_delete"));
0354     cmhelper.addSeparator();
0355     cmhelper.addAction(QLatin1String("importui_item_view"));
0356     cmhelper.addServicesMenu(selectedUrls());
0357 
0358 /*  TODO
0359     cmhelper.addRotateMenu(selectedItemIDs);
0360 */
0361 
0362     cmhelper.addSeparator();
0363 
0364     // --------------------------------------------------------
0365 
0366     cmhelper.addAction(QLatin1String("importui_selectall"));
0367     cmhelper.addAction(QLatin1String("importui_selectnone"));
0368     cmhelper.addAction(QLatin1String("importui_selectinvert"));
0369     cmhelper.addSeparator();
0370 
0371     // --------------------------------------------------------
0372 /*
0373     cmhelper.addAssignTagsMenu(selectedItemIDs);
0374     cmhelper.addRemoveTagsMenu(selectedItemIDs);
0375     cmhelper.addSeparator();
0376 */
0377     // --------------------------------------------------------
0378 
0379     cmhelper.addLabelsAction();
0380 /*
0381     if (!d->faceMode)
0382     {
0383         cmhelper.addGroupMenu(selectedItemIDs);
0384     }
0385 
0386     // special action handling --------------------------------
0387 
0388     connect(&cmhelper, SIGNAL(signalAssignTag(int)),
0389             this, SLOT(assignTagToSelected(int)));
0390 
0391     TODO: Implement tag view for import tool.
0392 
0393     connect(&cmhelper, SIGNAL(signalPopupTagsView()),
0394             this, SIGNAL(signalPopupTagsView()));
0395 
0396     connect(&cmhelper, SIGNAL(signalRemoveTag(int)),
0397             this, SLOT(removeTagFromSelected(int)));
0398 
0399     connect(&cmhelper, SIGNAL(signalGotoTag(int)),
0400             this, SIGNAL(gotoTagAndImageRequested(int)));
0401 */
0402     connect(&cmhelper, SIGNAL(signalAssignPickLabel(int)),
0403             this, SLOT(assignPickLabelToSelected(int)));
0404 
0405     connect(&cmhelper, SIGNAL(signalAssignColorLabel(int)),
0406             this, SLOT(assignColorLabelToSelected(int)));
0407 
0408     connect(&cmhelper, SIGNAL(signalAssignRating(int)),
0409             this, SLOT(assignRatingToSelected(int)));
0410 /*
0411     connect(&cmhelper, SIGNAL(signalAddToExistingQueue(int)),
0412             this, SLOT(insertSelectedToExistingQueue(int)));
0413 
0414     connect(&cmhelper, SIGNAL(signalCreateGroup()),
0415             this, SLOT(createGroupFromSelection()));
0416 
0417     connect(&cmhelper, SIGNAL(signalUngroup()),
0418             this, SLOT(ungroupSelected()));
0419 
0420     connect(&cmhelper, SIGNAL(signalRemoveFromGroup()),
0421             this, SLOT(removeSelectedFromGroup()));
0422 */
0423     // --------------------------------------------------------
0424 
0425     cmhelper.exec(event->globalPos());
0426 }
0427 
0428 void ImportIconView::showContextMenu(QContextMenuEvent* event)
0429 {
0430     QMenu popmenu(this);
0431     ImportContextMenuHelper cmhelper(&popmenu);
0432 
0433     cmhelper.addAction(QLatin1String("importui_fullscreen"));
0434     cmhelper.addAction(QLatin1String("options_show_menubar"));
0435     cmhelper.addSeparator();
0436     cmhelper.addAction(QLatin1String("importui_close"));
0437 
0438     // --------------------------------------------------------
0439 
0440     cmhelper.exec(event->globalPos());
0441 }
0442 
0443 void ImportIconView::assignTagToSelected(int tagID)
0444 {
0445     CamItemInfoList infos = selectedCamItemInfos();
0446 
0447     Q_FOREACH (const CamItemInfo& info, infos)
0448     {
0449         importItemModel()->camItemInfoRef(importItemModel()->indexForCamItemInfo(info)).tagIds.append(tagID);
0450     }
0451 }
0452 
0453 void ImportIconView::removeTagFromSelected(int tagID)
0454 {
0455     CamItemInfoList infos = selectedCamItemInfos();
0456 
0457     Q_FOREACH (const CamItemInfo& info, infos)
0458     {
0459         importItemModel()->camItemInfoRef(importItemModel()->indexForCamItemInfo(info)).tagIds.removeAll(tagID);
0460     }
0461 }
0462 
0463 void ImportIconView::assignPickLabel(const QModelIndex& index, int pickId)
0464 {
0465     importItemModel()->camItemInfoRef(index).pickLabel = pickId;
0466 }
0467 
0468 void ImportIconView::assignPickLabelToSelected(int pickId)
0469 {
0470     CamItemInfoList infos = selectedCamItemInfos();
0471 
0472     Q_FOREACH (const CamItemInfo& info, infos)
0473     {
0474         importItemModel()->camItemInfoRef(importItemModel()->indexForCamItemInfo(info)).pickLabel = pickId;
0475     }
0476 }
0477 
0478 void ImportIconView::assignColorLabel(const QModelIndex& index, int colorId)
0479 {
0480     importItemModel()->camItemInfoRef(index).colorLabel = colorId;
0481 }
0482 
0483 void ImportIconView::assignColorLabelToSelected(int colorId)
0484 {
0485     CamItemInfoList infos = selectedCamItemInfos();
0486 
0487     Q_FOREACH (const CamItemInfo& info, infos)
0488     {
0489         importItemModel()->camItemInfoRef(importItemModel()->indexForCamItemInfo(info)).colorLabel = colorId;
0490     }
0491 }
0492 
0493 void ImportIconView::assignRating(const QList<QModelIndex>& indexes, int rating)
0494 {
0495     Q_FOREACH (const QModelIndex& index, indexes)
0496     {
0497         if (index.isValid())
0498         {
0499             importItemModel()->camItemInfoRef(index).rating = rating;
0500         }
0501     }
0502 }
0503 
0504 void ImportIconView::assignRatingToSelected(int rating)
0505 {
0506     CamItemInfoList infos = selectedCamItemInfos();
0507 
0508     Q_FOREACH (const CamItemInfo& info, infos)
0509     {
0510         importItemModel()->camItemInfoRef(importItemModel()->indexForCamItemInfo(info)).rating = rating;
0511     }
0512 }
0513 
0514 } // namespace Digikam
0515 
0516 #include "moc_importiconview.cpp"