File indexing completed on 2025-01-19 03:50:47

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2013-02-11
0007  * Description : Table view
0008  *
0009  * SPDX-FileCopyrightText: 2013      by Michael G. Hansen <mike at mghansen dot de>
0010  * SPDX-FileCopyrightText: 2017      by Simon Frei <freisim93 at gmail dot com>
0011  * SPDX-FileCopyrightText: 2017-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "tableview.h"
0018 
0019 // Qt includes
0020 
0021 #include <QContextMenuEvent>
0022 #include <QHeaderView>
0023 #include <QItemSelectionModel>
0024 #include <QVBoxLayout>
0025 #include <QMenu>
0026 #include <QAction>
0027 #include <QIcon>
0028 #include <QApplication>
0029 #include <QPointer>
0030 
0031 // KDE includes
0032 
0033 #include <kconfiggroup.h>
0034 #include <klocalizedstring.h>
0035 
0036 // Local includes
0037 
0038 #include "advancedrenamedialog.h"
0039 #include "advancedrenameprocessdialog.h"
0040 #include "contextmenuhelper.h"
0041 #include "digikam_debug.h"
0042 #include "fileactionmngr.h"
0043 #include "album.h"
0044 #include "tableview_columnfactory.h"
0045 #include "tableview_model.h"
0046 #include "tableview_selection_model_syncer.h"
0047 #include "tableview_shared.h"
0048 #include "tableview_treeview.h"
0049 
0050 namespace Digikam
0051 {
0052 
0053 class ItemAlbumModel;
0054 class ItemFilterModel;
0055 
0056 class Q_DECL_HIDDEN TableView::Private
0057 {
0058 public:
0059 
0060     explicit Private()
0061       : columnProfiles    (),
0062         thumbnailSize     (),
0063         imageViewUtilities(nullptr)
0064     {
0065     }
0066 
0067     QList<TableViewColumnProfile> columnProfiles;
0068     ThumbnailSize                 thumbnailSize;
0069     ItemViewUtilities*            imageViewUtilities;
0070 };
0071 
0072 TableView::TableView(QItemSelectionModel* const selectionModel,
0073                      DCategorizedSortFilterProxyModel* const imageFilterModel,
0074                      QWidget* const parent)
0075     : QWidget(parent),
0076       StateSavingObject(this),
0077       d                (new Private()),
0078       s                (new TableViewShared())
0079 {
0080     s->isActive                      = false;
0081     s->tableView                     = this;
0082     s->thumbnailLoadThread           = new ThumbnailLoadThread(this);
0083     s->imageFilterModel              = dynamic_cast<ItemFilterModel*>(imageFilterModel);
0084     s->imageModel                    = dynamic_cast<ItemModel*>(imageFilterModel->sourceModel());
0085     s->imageFilterSelectionModel     = selectionModel;
0086     s->columnFactory                 = new TableViewColumnFactory(s.data(), this);
0087 
0088     QVBoxLayout* const vbox1         = new QVBoxLayout();
0089     s->tableViewModel                = new TableViewModel(s.data(), this);
0090     s->tableViewSelectionModel       = new QItemSelectionModel(s->tableViewModel);
0091     s->tableViewSelectionModelSyncer = new TableViewSelectionModelSyncer(s.data(), this);
0092     s->treeView                      = new TableViewTreeView(s.data(), this);
0093     s->treeView->installEventFilter(this);
0094 
0095     d->imageViewUtilities            = new ItemViewUtilities(this);
0096 
0097     connect(s->treeView, SIGNAL(activated(QModelIndex)),
0098             this, SLOT(slotItemActivated(QModelIndex)));
0099 
0100     connect(s->treeView, SIGNAL(signalZoomInStep()),
0101             this, SIGNAL(signalZoomInStep()));
0102 
0103     connect(s->treeView, SIGNAL(signalZoomOutStep()),
0104             this, SIGNAL(signalZoomOutStep()));
0105 
0106     connect(s->tableViewSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
0107             this, SIGNAL(signalItemsChanged()));
0108 
0109     connect(s->treeView, SIGNAL(collapsed(QModelIndex)),
0110             this, SIGNAL(signalItemsChanged()));
0111 
0112     connect(s->treeView, SIGNAL(expanded(QModelIndex)),
0113             this, SIGNAL(signalItemsChanged()));
0114 
0115     connect(s->tableViewModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
0116             this, SIGNAL(signalItemsChanged()));
0117 
0118     connect(s->tableViewModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
0119             this, SIGNAL(signalItemsChanged()));
0120 
0121     connect(s->tableViewModel, SIGNAL(layoutChanged()),
0122             this, SIGNAL(signalItemsChanged()));
0123 
0124     connect(s->tableViewModel, SIGNAL(modelReset()),
0125             this, SIGNAL(signalItemsChanged()));
0126 
0127     vbox1->addWidget(s->treeView);
0128     vbox1->setContentsMargins(QMargins());
0129 
0130     setLayout(vbox1);
0131 }
0132 
0133 TableView::~TableView()
0134 {
0135 }
0136 
0137 void TableView::doLoadState()
0138 {
0139     const KConfigGroup group                        = getConfigGroup();
0140 
0141     TableViewColumnProfile profile;
0142     const KConfigGroup groupCurrentProfile          = group.group(QLatin1String("Current Profile"));
0143     profile.loadSettings(groupCurrentProfile);
0144     s->tableViewModel->loadColumnProfile(profile);
0145 
0146     const TableViewModel::GroupingMode groupingMode = TableViewModel::GroupingMode(group.readEntry<int>("Grouping mode",
0147                                                       int(TableViewModel::GroupingShowSubItems)));
0148     s->tableViewModel->setGroupingMode(groupingMode);
0149 
0150     if (!profile.headerState.isEmpty())
0151     {
0152         s->treeView->header()->restoreState(profile.headerState);
0153     }
0154 }
0155 
0156 void TableView::doSaveState()
0157 {
0158     KConfigGroup group = getConfigGroup();
0159 
0160     TableViewColumnProfile profile   = s->tableViewModel->getColumnProfile();
0161     profile.headerState              = s->treeView->header()->saveState();
0162     KConfigGroup groupCurrentProfile = group.group(QLatin1String("Current Profile"));
0163     profile.saveSettings(groupCurrentProfile);
0164     group.writeEntry("Grouping mode", int(s->tableViewModel->groupingMode()));
0165 }
0166 
0167 void TableView::slotItemActivated(const QModelIndex& tableViewIndex)
0168 {
0169     const ItemInfo info = s->tableViewModel->imageInfo(tableViewIndex);
0170 
0171     if (info.isNull())
0172     {
0173         return;
0174     }
0175 
0176     Qt::KeyboardModifiers modifiers = qApp->queryKeyboardModifiers();
0177 
0178     if      (modifiers == Qt::NoModifier)
0179     {
0180         int leftClickAction = ApplicationSettings::instance()->getItemLeftClickAction();
0181 
0182         if      (leftClickAction == ApplicationSettings::ShowPreview)
0183         {
0184             Q_EMIT signalPreviewRequested(info);
0185         }
0186         else if (leftClickAction == ApplicationSettings::StartEditor)
0187         {
0188             d->imageViewUtilities->openInfos(info, allItemInfos(), currentAlbum());
0189         }
0190         else if (leftClickAction == ApplicationSettings::ShowOnTable)
0191         {
0192             d->imageViewUtilities->insertToLightTable(allItemInfos(), info, false);
0193         }
0194         else
0195         {
0196             d->imageViewUtilities->openInfosWithDefaultApplication(QList<ItemInfo>() << info);
0197         }
0198     }
0199     else if (modifiers == Qt::AltModifier)
0200     {
0201         d->imageViewUtilities->openInfosWithDefaultApplication(QList<ItemInfo>() << info);
0202     }
0203 }
0204 
0205 bool TableView::eventFilter(QObject* watched, QEvent* event)
0206 {
0207     // we are looking for context menu events for the table view
0208 
0209     if ((watched == s->treeView) && (event->type() == QEvent::ContextMenu))
0210     {
0211         QContextMenuEvent* const e = static_cast<QContextMenuEvent*>(event);
0212         e->accept();
0213 
0214         const QModelIndex contextMenuIndex = s->treeView->indexAt(e->pos());
0215 
0216         if (contextMenuIndex.isValid())
0217         {
0218             Q_EMIT signalShowContextMenuOnInfo(e,
0219                                              s->tableViewModel->imageInfo(contextMenuIndex),
0220                                              getExtraGroupingActions());
0221         }
0222         else
0223         {
0224             Q_EMIT signalShowContextMenu(e, getExtraGroupingActions());
0225         }
0226 
0227         // event has been filtered by us
0228 
0229         return true;
0230     }
0231 
0232     return QObject::eventFilter(watched, event);
0233 }
0234 
0235 void TableView::setThumbnailSize(const ThumbnailSize& size)
0236 {
0237     d->thumbnailSize                            = size;
0238     const QList<TableViewColumn*> columnObjects = s->tableViewModel->getColumnObjects();
0239 
0240     Q_FOREACH (TableViewColumn* const iColumn, columnObjects)
0241     {
0242         iColumn->updateThumbnailSize();
0243     }
0244 }
0245 
0246 ThumbnailSize TableView::getThumbnailSize() const
0247 {
0248     return d->thumbnailSize;
0249 }
0250 
0251 Album* TableView::currentAlbum() const
0252 {
0253     ItemAlbumModel* const albumModel = qobject_cast<ItemAlbumModel*>(s->imageModel);
0254 
0255     if (!albumModel)
0256     {
0257         return nullptr;
0258     }
0259 
0260     if (albumModel->currentAlbums().isEmpty())
0261     {
0262         return nullptr;
0263     }
0264 
0265     return albumModel->currentAlbums().constFirst();
0266 }
0267 
0268 void TableView::slotPaste()
0269 {
0270     DragDropViewImplementation* const dragDropViewImplementation = s->treeView;
0271     dragDropViewImplementation->paste();
0272 }
0273 
0274 ItemInfo TableView::currentInfo() const
0275 {
0276     return s->tableViewModel->imageInfo(s->tableViewSelectionModel->currentIndex());
0277 }
0278 
0279 ItemInfoList TableView::allItemInfos(bool grouping) const
0280 {
0281     if (grouping)
0282     {
0283         return s->treeView->resolveGrouping(ItemInfoList(s->tableViewModel->allItemInfo()));
0284     }
0285 
0286     return ItemInfoList(s->tableViewModel->allItemInfo());
0287 }
0288 
0289 bool TableView::allNeedGroupResolving(const ApplicationSettings::OperationType type) const
0290 {
0291     return s->treeView->needGroupResolving(type, allItemInfos());
0292 }
0293 
0294 bool TableView::selectedNeedGroupResolving(const ApplicationSettings::OperationType type) const
0295 {
0296     return s->treeView->needGroupResolving(type, selectedItemInfos());
0297 }
0298 
0299 void TableView::slotDeleteSelected(const ItemViewUtilities::DeleteMode deleteMode)
0300 {
0301     const bool allGroupsOpen     = ApplicationSettings::instance()->getAllGroupsOpen();
0302     const ItemInfoList& infoList = selectedItemInfos(!allGroupsOpen);
0303 
0304     /// @todo Update parameter naming for deleteImages
0305 
0306     if (d->imageViewUtilities->deleteImages(infoList, deleteMode))
0307     {
0308         slotAwayFromSelection();
0309     }
0310 }
0311 
0312 void TableView::slotDeleteSelectedWithoutConfirmation(const ItemViewUtilities::DeleteMode deleteMode)
0313 {
0314     const bool allGroupsOpen     = ApplicationSettings::instance()->getAllGroupsOpen();
0315     const ItemInfoList& infoList = selectedItemInfos(!allGroupsOpen);
0316 
0317     d->imageViewUtilities->deleteImagesDirectly(infoList, deleteMode);
0318     slotAwayFromSelection();
0319 }
0320 
0321 QList<QAction*> TableView::getExtraGroupingActions()
0322 {
0323     QList<QAction*> actionList;
0324 
0325     const TableViewModel::GroupingMode currentGroupingMode = s->tableViewModel->groupingMode();
0326 
0327     QAction* const actionHideGrouped = new QAction(i18n("Hide grouped items"), this);
0328     actionHideGrouped->setCheckable(true);
0329     actionHideGrouped->setChecked(currentGroupingMode == TableViewModel::GroupingHideGrouped);
0330     actionHideGrouped->setData(QVariant::fromValue<TableViewModel::GroupingMode>(TableViewModel::GroupingHideGrouped));
0331 
0332     connect(actionHideGrouped, SIGNAL(triggered(bool)),
0333             this, SLOT(slotGroupingModeActionTriggered()));
0334 
0335     actionList << actionHideGrouped;
0336 
0337     QAction* const actionIgnoreGrouping = new QAction(i18n("Ignore grouping"), this);
0338     actionIgnoreGrouping->setCheckable(true);
0339     actionIgnoreGrouping->setChecked(currentGroupingMode == TableViewModel::GroupingIgnoreGrouping);
0340     actionIgnoreGrouping->setData(QVariant::fromValue<TableViewModel::GroupingMode>(TableViewModel::GroupingIgnoreGrouping));
0341 
0342     connect(actionIgnoreGrouping, SIGNAL(triggered(bool)),
0343             this, SLOT(slotGroupingModeActionTriggered()));
0344 
0345     actionList << actionIgnoreGrouping;
0346 
0347     QAction* const actionShowSubItems = new QAction(i18n("Show grouping in tree"), this);
0348     actionShowSubItems->setCheckable(true);
0349     actionShowSubItems->setChecked(currentGroupingMode == TableViewModel::GroupingShowSubItems);
0350     actionShowSubItems->setData(QVariant::fromValue<TableViewModel::GroupingMode>(TableViewModel::GroupingShowSubItems));
0351 
0352     connect(actionShowSubItems, SIGNAL(triggered(bool)),
0353             this, SLOT(slotGroupingModeActionTriggered()));
0354 
0355     actionList << actionShowSubItems;
0356 
0357     return actionList;
0358 }
0359 
0360 void TableView::slotGroupingModeActionTriggered()
0361 {
0362     const QAction* const senderAction = qobject_cast<QAction*>(sender());
0363 
0364     if (!senderAction)
0365     {
0366         return;
0367     }
0368 
0369     const TableViewModel::GroupingMode newGroupingMode = senderAction->data().value<TableViewModel::GroupingMode>();
0370     s->tableViewModel->setGroupingMode(newGroupingMode);
0371 }
0372 
0373 int TableView::numberOfSelectedItems() const
0374 {
0375     return s->tableViewSelectionModel->selectedRows().count();
0376 }
0377 
0378 void TableView::slotGoToRow(const int rowNumber, const bool relativeMove)
0379 {
0380     int nextDeepRowNumber = rowNumber;
0381 
0382     if (relativeMove)
0383     {
0384         const QModelIndex currentTableViewIndex = s->tableViewSelectionModel->currentIndex();
0385         const int currentDeepRowNumber          = s->tableViewModel->indexToDeepRowNumber(currentTableViewIndex);
0386         nextDeepRowNumber                      += currentDeepRowNumber;
0387     }
0388 
0389     const QModelIndex nextIndex = s->tableViewModel->deepRowIndex(nextDeepRowNumber);
0390 
0391     if (nextIndex.isValid())
0392     {
0393         const QItemSelection rowSelection = s->tableViewSelectionModelSyncer->targetIndexToRowItemSelection(nextIndex);
0394         s->tableViewSelectionModel->select(rowSelection, QItemSelectionModel::ClearAndSelect);
0395         s->tableViewSelectionModel->setCurrentIndex(nextIndex, QItemSelectionModel::Select);
0396     }
0397 }
0398 
0399 ItemInfo TableView::deepRowItemInfo(const int rowNumber, const bool relative) const
0400 {
0401     int targetRowNumber = rowNumber;
0402 
0403     if (relative)
0404     {
0405         const QModelIndex& currentTableViewIndex = s->tableViewSelectionModel->currentIndex();
0406 
0407         if (!currentTableViewIndex.isValid())
0408         {
0409             return ItemInfo();
0410         }
0411 
0412         const int currentDeepRowNumber           = s->tableViewModel->indexToDeepRowNumber(currentTableViewIndex);
0413         targetRowNumber                         += currentDeepRowNumber;
0414     }
0415 
0416     const QModelIndex targetIndex = s->tableViewModel->deepRowIndex(targetRowNumber);
0417 
0418     return s->tableViewModel->imageInfo(targetIndex);
0419 }
0420 
0421 ItemInfo TableView::nextInfo() const
0422 {
0423     const QModelIndex cIndex       = s->tableViewSelectionModel->currentIndex();
0424     const int currentDeepRowNumber = s->tableViewModel->indexToDeepRowNumber(cIndex);
0425     const int nextDeepRowNumber    = currentDeepRowNumber + 1;
0426 
0427     if (nextDeepRowNumber>=s->tableViewModel->deepRowCount())
0428     {
0429         return ItemInfo();
0430     }
0431 
0432     const QModelIndex nextDeepRowIndex = s->tableViewModel->deepRowIndex(nextDeepRowNumber);
0433 
0434     return s->tableViewModel->imageInfo(nextDeepRowIndex);
0435 }
0436 
0437 ItemInfo TableView::previousInfo() const
0438 {
0439     const QModelIndex cIndex        = s->tableViewSelectionModel->currentIndex();
0440     const int currentDeepRowNumber  = s->tableViewModel->indexToDeepRowNumber(cIndex);
0441     const int previousDeepRowNumber = currentDeepRowNumber - 1;
0442 
0443     if (previousDeepRowNumber < 0)
0444     {
0445         return ItemInfo();
0446     }
0447 
0448     const QModelIndex previousDeepRowIndex = s->tableViewModel->deepRowIndex(previousDeepRowNumber);
0449 
0450     return s->tableViewModel->imageInfo(previousDeepRowIndex);
0451 }
0452 
0453 void TableView::slotSetCurrentUrlWhenAvailable(const QUrl& url)
0454 {
0455     Q_FOREACH (const ItemInfo& info, allItemInfos())
0456     {
0457         if (info.fileUrl() == url)
0458         {    // cppcheck-suppress useStlAlgorithm
0459             slotSetCurrentWhenAvailable(info.id());
0460             break;
0461         }
0462     }
0463 }
0464 
0465 void TableView::slotSetCurrentWhenAvailable(const qlonglong id)
0466 {
0467     const QModelIndex idx = s->tableViewModel->indexFromImageId(id, 0);
0468 
0469     if (!idx.isValid())
0470     {
0471         /// @todo Actually buffer this request until the model is fully populated
0472 
0473         return;
0474     }
0475 
0476     s->tableViewSelectionModel->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
0477 }
0478 
0479 /**
0480  * @brief Unselects the current selection and changes the current item
0481  *
0482  * @todo This may not work correctly if grouped items are deleted, but are not selected
0483  */
0484 void TableView::slotAwayFromSelection()
0485 {
0486     QModelIndexList selection = s->tableViewSelectionModel->selectedRows(0);
0487 
0488     if (selection.isEmpty())
0489     {
0490         return;
0491     }
0492 
0493     const QModelIndex firstIndex = s->tableViewModel->deepRowIndex(0);
0494     const QModelIndex lastIndex  = s->tableViewModel->deepRowIndex(-1);
0495 
0496     if      (selection.contains(firstIndex) && selection.contains(lastIndex))
0497     {
0498         // both the first and the last index are selected, we have to
0499         // select an index inbetween
0500 
0501         const int nextFreeDeepRow = s->tableViewModel->firstDeepRowNotInList(selection);
0502 
0503         if (nextFreeDeepRow < 0)
0504         {
0505             s->tableViewSelectionModel->clearSelection();
0506             s->tableViewSelectionModel->setCurrentIndex(QModelIndex(), QItemSelectionModel::ClearAndSelect);
0507         }
0508         else
0509         {
0510             const QModelIndex nextFreeIndex         = s->tableViewModel->deepRowIndex(nextFreeDeepRow);
0511             s->tableViewSelectionModel->setCurrentIndex(nextFreeIndex, QItemSelectionModel::ClearAndSelect);
0512             const QItemSelection nextFreeIndexAsRow = s->tableViewSelectionModelSyncer->targetIndexToRowItemSelection(nextFreeIndex);
0513             s->tableViewSelectionModel->select(nextFreeIndexAsRow, QItemSelectionModel::ClearAndSelect);
0514         }
0515     }
0516     else if (selection.contains(lastIndex))
0517     {
0518         const int firstSelectedRowNumber   = s->tableViewModel->indexToDeepRowNumber(selection.first());
0519         const QModelIndex newIndex         = s->tableViewModel->deepRowIndex(firstSelectedRowNumber-1);
0520         s->tableViewSelectionModel->setCurrentIndex(newIndex, QItemSelectionModel::ClearAndSelect);
0521         const QItemSelection newIndexAsRow = s->tableViewSelectionModelSyncer->targetIndexToRowItemSelection(newIndex);
0522         s->tableViewSelectionModel->select(newIndexAsRow, QItemSelectionModel::ClearAndSelect);
0523     }
0524     else
0525     {
0526         const int lastSelectedRowNumber    = s->tableViewModel->indexToDeepRowNumber(selection.last());
0527         const QModelIndex newIndex         = s->tableViewModel->deepRowIndex(lastSelectedRowNumber+1);
0528         s->tableViewSelectionModel->setCurrentIndex(newIndex, QItemSelectionModel::ClearAndSelect);
0529         const QItemSelection newIndexAsRow = s->tableViewSelectionModelSyncer->targetIndexToRowItemSelection(newIndex);
0530         s->tableViewSelectionModel->select(newIndexAsRow, QItemSelectionModel::ClearAndSelect);
0531     }
0532 }
0533 
0534 void TableView::clearSelection()
0535 {
0536     s->tableViewSelectionModel->clearSelection();
0537 }
0538 
0539 void TableView::invertSelection()
0540 {
0541     const int deepRowCount = s->tableViewModel->deepRowCount();
0542     QList<int> rowsToSelect;
0543     int lastSelectedRow    = -1;
0544 
0545     /// @todo Create a DeepRowIterator because there is a lot of overhead here
0546 
0547     for (int i = 0 ; i < deepRowCount ; ++i)
0548     {
0549         const QModelIndex iIndex = s->tableViewModel->deepRowIndex(i);
0550 
0551         if (s->tableViewSelectionModel->isSelected(iIndex))
0552         {
0553             if ((i - 1) > lastSelectedRow)
0554             {
0555                 for (int j = lastSelectedRow + 1 ; j < i ; ++j)
0556                 {
0557                     rowsToSelect << j;
0558                 }
0559             }
0560 
0561             lastSelectedRow = i;
0562         }
0563     }
0564 
0565     if (lastSelectedRow + 1 < deepRowCount)
0566     {
0567         for (int j = lastSelectedRow + 1 ; j < deepRowCount ; ++j)
0568         {
0569             rowsToSelect << j;
0570         }
0571     }
0572 
0573     s->tableViewSelectionModel->clearSelection();
0574 
0575     Q_FOREACH (const int i, rowsToSelect)
0576     {
0577         const QModelIndex iIndex = s->tableViewModel->deepRowIndex(i);
0578         const QItemSelection is  = s->tableViewSelectionModelSyncer->targetIndexToRowItemSelection(iIndex);
0579         s->tableViewSelectionModel->select(is, QItemSelectionModel::Select);
0580     }
0581 }
0582 
0583 void TableView::selectAll()
0584 {
0585     /// @todo This only selects expanded items.
0586 
0587     s->treeView->selectAll();
0588 }
0589 
0590 void TableView::slotSetActive(const bool isActive)
0591 {
0592     if (s->isActive != isActive)
0593     {
0594         s->isActive = isActive;
0595         s->tableViewModel->slotSetActive(isActive);
0596         s->tableViewSelectionModelSyncer->slotSetActive(isActive);
0597     }
0598 }
0599 
0600 ItemInfoList TableView::selectedItemInfos(bool grouping) const
0601 {
0602     ItemInfoList infos = ItemInfoList(s->tableViewModel->imageInfos(s->tableViewSelectionModel->selectedRows()));
0603 
0604     if (grouping)
0605     {
0606         return s->treeView->resolveGrouping(infos);
0607     }
0608 
0609     return infos;
0610 }
0611 
0612 ItemInfoList TableView::selectedItemInfosCurrentFirst(bool grouping) const
0613 {
0614     QModelIndexList indexes   = s->tableViewSelectionModel->selectedRows();
0615     const QModelIndex current = s->tableViewModel->toCol0(s->tableViewSelectionModel->currentIndex());
0616 
0617     if (!indexes.isEmpty())
0618     {
0619         if (indexes.first() != current)
0620         {
0621             if (indexes.removeOne(current))
0622             {
0623                 indexes.prepend(current);
0624             }
0625         }
0626     }
0627 
0628     if (grouping)
0629     {
0630         return s->treeView->resolveGrouping(ItemInfoList(s->tableViewModel->imageInfos(indexes)));
0631     }
0632 
0633     return ItemInfoList(s->tableViewModel->imageInfos(indexes));
0634 }
0635 
0636 void TableView::rename()
0637 {
0638     ItemInfoList infos = selectedItemInfos();
0639 
0640     if (s->treeView->needGroupResolving(ApplicationSettings::Rename, infos))
0641     {
0642         infos = s->treeView->resolveGrouping(infos);
0643     }
0644 
0645     QList<QUrl> urls = infos.toImageUrlList();
0646     bool loop        = false;
0647     NewNamesList newNamesList;
0648 
0649     do
0650     {
0651         qCDebug(DIGIKAM_GENERAL_LOG) << "Selected URLs to rename: " << urls;
0652 
0653         QPointer<AdvancedRenameDialog> dlg = new AdvancedRenameDialog(this);
0654         dlg->slotAddImages(urls);
0655 
0656         if (dlg->exec() != QDialog::Accepted)
0657         {
0658             delete dlg;
0659             break;
0660         }
0661 
0662         if (!loop)
0663         {
0664             slotAwayFromSelection();
0665             loop = true;
0666         }
0667 
0668         newNamesList = dlg->newNames();
0669         delete dlg;
0670 
0671         setFocus();
0672         qApp->processEvents();
0673 
0674         if (!newNamesList.isEmpty())
0675         {
0676             QPointer<AdvancedRenameProcessDialog> dlg2 = new AdvancedRenameProcessDialog(newNamesList, this);
0677             dlg2->exec();
0678 
0679             s->tableViewModel->scheduleResort();
0680             urls = dlg2->failedUrls();
0681             delete dlg2;
0682         }
0683     }
0684     while (!urls.isEmpty() && !newNamesList.isEmpty());
0685 }
0686 
0687 } // namespace Digikam
0688 
0689 #include "moc_tableview.cpp"