File indexing completed on 2024-04-28 04:21:22

0001 // SPDX-FileCopyrightText: 2003-2020 The KPhotoAlbum Development Team
0002 // SPDX-FileCopyrightText: 2022-2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0003 //
0004 // SPDX-License-Identifier: GPL-2.0-or-later
0005 
0006 #include "ThumbnailDND.h"
0007 
0008 #include "ThumbnailModel.h"
0009 #include "ThumbnailWidget.h"
0010 
0011 #include <Browser/BrowserWidget.h>
0012 #include <DB/ImageDB.h>
0013 
0014 #include <KLocalizedString>
0015 #include <KMessageBox>
0016 #include <QMimeData>
0017 #include <QTimer>
0018 #include <kwidgetsaddons_version.h>
0019 
0020 ThumbnailView::ThumbnailDND::ThumbnailDND(ThumbnailFactory *factory)
0021     : ThumbnailComponent(factory)
0022 {
0023 }
0024 
0025 void ThumbnailView::ThumbnailDND::contentsDragMoveEvent(QDragMoveEvent *event)
0026 {
0027     if (event->mimeData()->hasUrls() && widget()->m_selectionInteraction.isDragging())
0028         event->accept();
0029     else {
0030         event->ignore();
0031         return;
0032     }
0033 
0034     removeDropIndications();
0035 
0036     const DB::FileName fileName = widget()->mediaIdUnderCursor();
0037     if (fileName.isNull()) {
0038         // cursor not in drop zone (e.g. empty space right/below of the thumbnails)
0039         return;
0040     }
0041 
0042     const QRect rect = widget()->visualRect(widget()->indexUnderCursor());
0043 
0044     if ((event->pos().y() < 10))
0045         widget()->scrollTo(widget()->indexUnderCursor(), QAbstractItemView::PositionAtCenter);
0046     if ((event->pos().y() > widget()->viewport()->visibleRegion().cbegin()->height() - 10))
0047         widget()->scrollTo(widget()->indexUnderCursor(), QAbstractItemView::PositionAtCenter);
0048     const bool isLeftHalfOfItem = (event->pos().x() - rect.x() < rect.width() / 2);
0049     if (isLeftHalfOfItem) {
0050         model()->setLeftDropItem(fileName);
0051         const int index = model()->indexOf(fileName) - 1;
0052         if (index != -1)
0053             model()->setRightDropItem(model()->imageAt(index));
0054     }
0055 
0056     else {
0057         model()->setRightDropItem(fileName);
0058         const int index = model()->indexOf(fileName) + 1;
0059         if (index != model()->imageCount())
0060             model()->setLeftDropItem(model()->imageAt(index));
0061     }
0062 
0063     model()->updateCell(model()->leftDropItem());
0064     model()->updateCell(model()->rightDropItem());
0065 }
0066 
0067 void ThumbnailView::ThumbnailDND::contentsDragLeaveEvent(QDragLeaveEvent *)
0068 {
0069     removeDropIndications();
0070 }
0071 
0072 void ThumbnailView::ThumbnailDND::contentsDropEvent(QDropEvent *event)
0073 {
0074     if (model()->leftDropItem().isNull() && model()->rightDropItem().isNull()) {
0075         // drop outside drop zone
0076         removeDropIndications();
0077         event->ignore();
0078     } else {
0079         QTimer::singleShot(0, this, SLOT(realDropEvent()));
0080     }
0081 }
0082 
0083 /**
0084  * Do the real work for the drop event.
0085  * We can't bring up the dialog in the contentsDropEvent, as Qt is still in drag and drop mode with a different cursor etc.
0086  * That's why we use a QTimer to get this call back executed.
0087  */
0088 void ThumbnailView::ThumbnailDND::realDropEvent()
0089 {
0090     const QString question = i18n("<p><b>Really reorder thumbnails?</b></p>"
0091                                   "<p>By dragging images around in the thumbnail viewer, you actually reorder them. "
0092                                   "This is very useful where you do not know the exact date for the images. On the other hand, "
0093                                   "if the images have valid timestamps, you should use "
0094                                   "<b>Maintenance -&gt; Sort All By Date and Time</b> or "
0095                                   "<b>View -&gt; Sort Selected By Date and Time</b>.</p>");
0096 
0097     const QString title = i18nc("@title", "Reorder Thumbnails");
0098     const QString dontAskAgainName = QString::fromLatin1("reorder_images");
0099 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0)
0100     const auto answer = KMessageBox::questionTwoActions(widget(),
0101                                                         question,
0102                                                         title,
0103                                                         KStandardGuiItem::ok(),
0104                                                         KStandardGuiItem::cancel(), dontAskAgainName);
0105     if (answer == KMessageBox::ButtonCode::PrimaryAction) {
0106 #else
0107     const auto answer = KMessageBox::questionYesNo(widget(), question, title, KStandardGuiItem::yes(), KStandardGuiItem::no(), dontAskAgainName);
0108     if (answer == KMessageBox::Yes) {
0109 #endif
0110         // expand selection so that stacks are always selected as a whole:
0111         const DB::FileNameList selected = widget()->selection(IncludeAllStacks);
0112 
0113         // protect against self drop
0114         if (selected.indexOf(model()->leftDropItem()) == -1 && selected.indexOf(model()->rightDropItem()) == -1) {
0115             if (model()->rightDropItem().isNull()) {
0116                 // We dropped onto the first image.
0117                 DB::ImageDB::instance()->reorder(model()->leftDropItem(), selected, false);
0118             } else
0119                 DB::ImageDB::instance()->reorder(model()->rightDropItem(), selected, true);
0120 
0121             Browser::BrowserWidget::instance()->reload();
0122         }
0123     }
0124     removeDropIndications();
0125 }
0126 
0127 void ThumbnailView::ThumbnailDND::removeDropIndications()
0128 {
0129     const DB::FileName left = model()->leftDropItem();
0130     const DB::FileName right = model()->rightDropItem();
0131     model()->setLeftDropItem(DB::FileName());
0132     model()->setRightDropItem(DB::FileName());
0133 
0134     model()->updateCell(left);
0135     model()->updateCell(right);
0136 }
0137 
0138 void ThumbnailView::ThumbnailDND::contentsDragEnterEvent(QDragEnterEvent *event)
0139 {
0140     if (event->mimeData()->hasUrls() && widget()->m_selectionInteraction.isDragging())
0141         event->accept();
0142     else
0143         event->ignore();
0144 }
0145 
0146 // vi:expandtab:tabstop=4 shiftwidth=4:
0147 
0148 #include "moc_ThumbnailDND.cpp"