1 // vim: set tabstop=4 shiftwidth=4 expandtab:
2 /*
3 Gwenview: an image viewer
4 Copyright 2008 Aurélien Gâteau <agateau@kde.org>
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
19 
20 */
21 // Self
22 #include "browsemainpage.h"
23 
24 // Qt
25 #include <QDropEvent>
26 #include <QMenu>
27 #include <QVBoxLayout>
28 
29 // KF
30 #include <KActionCategory>
31 #include <KActionCollection>
32 #include <KActionMenu>
33 #include <KDirModel>
34 #include <KFileItem>
35 #include <KFilePlacesModel>
36 #include <KFormat>
37 #include <KIconLoader>
38 #include <KLocalizedString>
39 #include <KUrlMimeData>
40 #include <KUrlNavigator>
41 
42 // Local
43 #include <fileoperations.h>
44 #include <filtercontroller.h>
45 #include <gvcore.h>
46 #include <lib/archiveutils.h>
47 #include <lib/document/documentfactory.h>
48 #include <lib/gvdebug.h>
49 #include <lib/gwenviewconfig.h>
50 #include <lib/semanticinfo/abstractsemanticinfobackend.h>
51 #include <lib/semanticinfo/sorteddirmodel.h>
52 #include <lib/semanticinfo/tagmodel.h>
53 #include <lib/sorting.h>
54 #include <lib/thumbnailview/previewitemdelegate.h>
55 #include <lib/thumbnailview/thumbnailview.h>
56 #include <mimetypeutils.h>
57 #include <ui_browsemainpage.h>
58 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
59 #include "lib/semanticinfo/semanticinfodirmodel.h"
60 #endif
61 
62 namespace Gwenview
63 {
sortingFromSortAction(const QAction * action)64 inline Sorting::Enum sortingFromSortAction(const QAction *action)
65 {
66     Q_ASSERT(action);
67     return Sorting::Enum(action->data().toInt());
68 }
69 
70 struct BrowseMainPagePrivate : public Ui_BrowseMainPage {
71     BrowseMainPage *q;
72     GvCore *mGvCore;
73     KFilePlacesModel *mFilePlacesModel;
74     KUrlNavigator *mUrlNavigator;
75     SortedDirModel *mDirModel;
76     int mDocumentCountImages;
77     int mDocumentCountVideos;
78     KFileItemList *mSelectedMediaItems;
79     KActionCollection *mActionCollection;
80     FilterController *mFilterController;
81     QActionGroup *mSortAction;
82     KToggleAction *mSortDescendingAction;
83     QActionGroup *mThumbnailDetailsActionGroup;
84     PreviewItemDelegate *mDelegate;
85 
setupWidgetsGwenview::BrowseMainPagePrivate86     void setupWidgets()
87     {
88         setupUi(q);
89         q->layout()->setContentsMargins(0, 0, 0, 0);
90 
91         int margins = q->style()->pixelMetric(QStyle::PM_ToolBarItemMargin) + q->style()->pixelMetric(QStyle::PM_ToolBarFrameWidth);
92         mStatusBarContainer->layout()->setContentsMargins(margins, margins, margins, margins);
93         mStatusBarContainer->layout()->setSpacing(q->style()->pixelMetric(QStyle::PM_ToolBarItemSpacing));
94 
95         // mThumbnailView
96         mThumbnailView->setModel(mDirModel);
97 
98         mDelegate = new PreviewItemDelegate(mThumbnailView);
99         mThumbnailView->setItemDelegate(mDelegate);
100         mThumbnailView->setSelectionMode(QAbstractItemView::ExtendedSelection);
101 
102         // mUrlNavigator (use stupid layouting code because KUrlNavigator ctor
103         // can't be used directly from Designer)
104         mFilePlacesModel = new KFilePlacesModel(q);
105         mUrlNavigator = new KUrlNavigator(mFilePlacesModel, QUrl(), mUrlNavigatorContainer);
106         mUrlNavigatorContainer->setAutoFillBackground(true);
107         mUrlNavigatorContainer->setBackgroundRole(QPalette::Mid);
108         auto *layout = new QVBoxLayout(mUrlNavigatorContainer);
109         layout->setContentsMargins(0, 0, 0, 0);
110         layout->addWidget(mUrlNavigator);
111         QObject::connect(mUrlNavigator, SIGNAL(urlsDropped(QUrl, QDropEvent *)), q, SLOT(slotUrlsDropped(QUrl, QDropEvent *)));
112 
113         // FullScreen Toolbar
114         mFullScreenToolBar->setVisible(false);
115         mFullScreenToolBar2->setVisible(false);
116         mFullScreenToolBar->setAutoFillBackground(true);
117         mFullScreenToolBar2->setAutoFillBackground(true);
118         mFullScreenToolBar->setBackgroundRole(QPalette::Mid);
119         mFullScreenToolBar2->setBackgroundRole(QPalette::Mid);
120 
121         // Thumbnail slider
122         QObject::connect(mThumbnailSlider, &ZoomSlider::valueChanged, mThumbnailView, &ThumbnailView::setThumbnailWidth);
123         QObject::connect(mThumbnailView, &ThumbnailView::thumbnailWidthChanged, mThumbnailSlider, &ZoomSlider::setValue);
124 
125         // Document count label
126         QMargins labelMargins = mDocumentCountLabel->contentsMargins();
127         labelMargins.setLeft(15);
128         labelMargins.setRight(15);
129         mDocumentCountLabel->setContentsMargins(labelMargins);
130     }
131 
thumbnailDetailActionGwenview::BrowseMainPagePrivate132     QAction *thumbnailDetailAction(const QString &text, PreviewItemDelegate::ThumbnailDetail detail)
133     {
134         auto *action = new QAction(q);
135         action->setText(text);
136         action->setCheckable(true);
137         action->setChecked(GwenviewConfig::thumbnailDetails() & detail);
138         action->setData(QVariant(detail));
139         mThumbnailDetailsActionGroup->addAction(action);
140         QObject::connect(action, SIGNAL(triggered(bool)), q, SLOT(updateThumbnailDetails()));
141         return action;
142     }
143 
setupActionsGwenview::BrowseMainPagePrivate144     void setupActions(KActionCollection *actionCollection)
145     {
146         auto *view = new KActionCategory(i18nc("@title actions category - means actions changing smth in interface", "View"), actionCollection);
147         QAction *action = view->addAction("edit_location", q, SLOT(editLocation()));
148         action->setText(i18nc("@action:inmenu Navigation Bar", "Edit Location"));
149         actionCollection->setDefaultShortcut(action, Qt::Key_F6);
150 
151         auto *sortActionMenu = view->add<KActionMenu>("sort_by");
152         sortActionMenu->setText(i18nc("@action:inmenu", "Sort By"));
153         sortActionMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-sort")));
154         sortActionMenu->setPopupMode(QToolButton::InstantPopup);
155 
156         mSortAction = new QActionGroup(actionCollection);
157         action = new QAction(i18nc("@addAction:inmenu", "Name"), mSortAction);
158         action->setCheckable(true);
159         action->setData(QVariant(Sorting::Name));
160         action = new QAction(i18nc("@addAction:inmenu", "Date"), mSortAction);
161         action->setCheckable(true);
162         action->setData(QVariant(Sorting::Date));
163         action = new QAction(i18nc("@addAction:inmenu", "Size"), mSortAction);
164         action->setCheckable(true);
165         action->setData(QVariant(Sorting::Size));
166 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
167         action = new QAction(i18nc("@addAction:inmenu", "Rating"), mSortAction);
168         action->setCheckable(true);
169         action->setData(QVariant(Sorting::Rating));
170 #endif
171         QObject::connect(mSortAction, SIGNAL(triggered(QAction *)), q, SLOT(updateSortOrder()));
172 
173         mSortDescendingAction = view->add<KToggleAction>("sort_desc");
174         mSortDescendingAction->setText(i18nc("@action:inmenu Sort", "Descending"));
175         QObject::connect(mSortDescendingAction, SIGNAL(toggled(bool)), q, SLOT(updateSortOrder()));
176 
177         for (auto action : mSortAction->actions()) {
178             sortActionMenu->addAction(action);
179         }
180         sortActionMenu->addSeparator();
181         sortActionMenu->addAction(mSortDescendingAction);
182 
183         mThumbnailDetailsActionGroup = new QActionGroup(q);
184         mThumbnailDetailsActionGroup->setExclusive(false);
185         auto *thumbnailDetailsAction = view->add<KActionMenu>("thumbnail_details");
186         thumbnailDetailsAction->setText(i18nc("@action:inmenu", "Thumbnail Details"));
187         thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "Filename"), PreviewItemDelegate::FileNameDetail));
188         thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "Date"), PreviewItemDelegate::DateDetail));
189         thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "Image Size"), PreviewItemDelegate::ImageSizeDetail));
190         thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "File Size"), PreviewItemDelegate::FileSizeDetail));
191 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
192         thumbnailDetailsAction->addAction(thumbnailDetailAction(i18nc("@action:inmenu", "Rating"), PreviewItemDelegate::RatingDetail));
193 #endif
194 
195         auto *file = new KActionCategory(i18nc("@title actions category", "File"), actionCollection);
196         action = file->addAction(QStringLiteral("add_folder_to_places"), q, SLOT(addFolderToPlaces()));
197         action->setText(i18nc("@action:inmenu", "Add Folder to Places"));
198         action->setIcon(QIcon::fromTheme(QStringLiteral("bookmark-new")));
199     }
200 
setupFilterControllerGwenview::BrowseMainPagePrivate201     void setupFilterController()
202     {
203         auto *menu = new QMenu(mAddFilterButton);
204         mFilterController = new FilterController(mFilterFrame, mDirModel);
205         const auto actionList = mFilterController->actionList();
206         for (QAction *action : actionList) {
207             menu->addAction(action);
208         }
209         mAddFilterButton->setMenu(menu);
210     }
211 
setupFullScreenToolBarGwenview::BrowseMainPagePrivate212     void setupFullScreenToolBar()
213     {
214         mFullScreenToolBar->setIconDimensions(KIconLoader::SizeMedium);
215         mFullScreenToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
216         mFullScreenToolBar->addAction(mActionCollection->action(QStringLiteral("browse")));
217         mFullScreenToolBar->addAction(mActionCollection->action(QStringLiteral("view")));
218 
219         mFullScreenToolBar2->setIconDimensions(KIconLoader::SizeMedium);
220         mFullScreenToolBar2->setToolButtonStyle(Qt::ToolButtonIconOnly);
221         mFullScreenToolBar2->addAction(mActionCollection->action(QStringLiteral("leave_fullscreen")));
222     }
223 
updateSelectedMediaItemsGwenview::BrowseMainPagePrivate224     void updateSelectedMediaItems(const QItemSelection &selected, const QItemSelection &deselected)
225     {
226         for (auto index : selected.indexes()) {
227             KFileItem item = mDirModel->itemForIndex(index);
228             if (!ArchiveUtils::fileItemIsDirOrArchive(item)) {
229                 mSelectedMediaItems->append(item);
230             }
231         }
232         for (auto index : deselected.indexes()) {
233             KFileItem item = mDirModel->itemForIndex(index);
234             mSelectedMediaItems->removeOne(item);
235         }
236     }
237 
updateDocumentCountLabelGwenview::BrowseMainPagePrivate238     void updateDocumentCountLabel()
239     {
240         if (mSelectedMediaItems->count() > 1) {
241             KIO::filesize_t totalSize = 0;
242             for (const auto &item : *mSelectedMediaItems) {
243                 totalSize += item.size();
244             }
245             const QString text = i18nc("@info:status %1 number of selected documents, %2 total number of documents, %3 total filesize of selected documents",
246                                        "Selected %1 of %2 (%3)",
247                                        mSelectedMediaItems->count(),
248                                        mDocumentCountImages + mDocumentCountVideos,
249                                        KFormat().formatByteSize(totalSize));
250             mDocumentCountLabel->setText(text);
251         } else {
252             const QString imageText = i18ncp("@info:status Image files", "%1 image", "%1 images", mDocumentCountImages);
253             const QString videoText = i18ncp("@info:status Video files", "%1 video", "%1 videos", mDocumentCountVideos);
254             QString labelText;
255             if (mDocumentCountImages > 0 && mDocumentCountVideos == 0) {
256                 labelText = imageText;
257             } else if (mDocumentCountImages == 0 && mDocumentCountVideos > 0) {
258                 labelText = videoText;
259             } else {
260                 labelText = i18nc("@info:status images, videos", "%1, %2", imageText, videoText);
261             }
262             mDocumentCountLabel->setText(labelText);
263         }
264     }
265 
documentCountsForIndexRangeGwenview::BrowseMainPagePrivate266     void documentCountsForIndexRange(const QModelIndex &parent, int start, int end, int &imageCountOut, int &videoCountOut)
267     {
268         imageCountOut = 0;
269         videoCountOut = 0;
270         for (int row = start; row <= end; ++row) {
271             QModelIndex index = mDirModel->index(row, 0, parent);
272             KFileItem item = mDirModel->itemForIndex(index);
273             if (!ArchiveUtils::fileItemIsDirOrArchive(item)) {
274                 MimeTypeUtils::Kind kind = MimeTypeUtils::mimeTypeKind(item.mimetype());
275                 if (kind == MimeTypeUtils::KIND_RASTER_IMAGE || kind == MimeTypeUtils::KIND_SVG_IMAGE) {
276                     imageCountOut++;
277                 } else if (kind == MimeTypeUtils::KIND_VIDEO) {
278                     videoCountOut++;
279                 }
280             }
281         }
282     }
283 
updateContextBarActionsGwenview::BrowseMainPagePrivate284     void updateContextBarActions()
285     {
286         PreviewItemDelegate::ContextBarActions actions;
287         switch (GwenviewConfig::thumbnailActions()) {
288         case ThumbnailActions::None:
289             actions = PreviewItemDelegate::NoAction;
290             break;
291         case ThumbnailActions::ShowSelectionButtonOnly:
292             actions = PreviewItemDelegate::SelectionAction;
293             break;
294         case ThumbnailActions::AllButtons:
295         default:
296             actions = PreviewItemDelegate::SelectionAction | PreviewItemDelegate::RotateAction;
297             if (!q->window()->isFullScreen()) {
298                 actions |= PreviewItemDelegate::FullScreenAction;
299             }
300             break;
301         }
302         mDelegate->setContextBarActions(actions);
303     }
304 
applyPaletteGwenview::BrowseMainPagePrivate305     void applyPalette(bool fullScreenmode)
306     {
307         q->setPalette(mGvCore->palette(fullScreenmode ? GvCore::FullScreenPalette : GvCore::NormalPalette));
308         mThumbnailView->setPalette(mGvCore->palette(fullScreenmode ? GvCore::FullScreenViewPalette : GvCore::NormalViewPalette));
309     }
310 };
311 
BrowseMainPage(QWidget * parent,KActionCollection * actionCollection,GvCore * gvCore)312 BrowseMainPage::BrowseMainPage(QWidget *parent, KActionCollection *actionCollection, GvCore *gvCore)
313     : QWidget(parent)
314     , d(new BrowseMainPagePrivate)
315 {
316     d->q = this;
317     d->mGvCore = gvCore;
318     d->mDirModel = gvCore->sortedDirModel();
319     d->mDocumentCountImages = 0;
320     d->mDocumentCountVideos = 0;
321     d->mSelectedMediaItems = new KFileItemList;
322     d->mActionCollection = actionCollection;
323     d->setupWidgets();
324     d->setupActions(actionCollection);
325     d->setupFilterController();
326     loadConfig();
327     updateSortOrder();
328     updateThumbnailDetails();
329 
330     // Set up connections for document count
331     connect(d->mDirModel, &SortedDirModel::rowsInserted, this, &BrowseMainPage::slotDirModelRowsInserted);
332     connect(d->mDirModel, &SortedDirModel::rowsAboutToBeRemoved, this, &BrowseMainPage::slotDirModelRowsAboutToBeRemoved);
333     connect(d->mDirModel, &SortedDirModel::modelReset, this, &BrowseMainPage::slotDirModelReset);
334     connect(thumbnailView(), &ThumbnailView::selectionChangedSignal, this, &BrowseMainPage::slotSelectionChanged);
335 
336     connect(qApp, &QApplication::paletteChanged, this, [this]() {
337         d->applyPalette(window()->isFullScreen());
338     });
339 
340     installEventFilter(this);
341 }
342 
~BrowseMainPage()343 BrowseMainPage::~BrowseMainPage()
344 {
345     d->mSelectedMediaItems->clear();
346     delete d->mSelectedMediaItems;
347     delete d;
348 }
349 
loadConfig()350 void BrowseMainPage::loadConfig()
351 {
352     d->applyPalette(window()->isFullScreen());
353     d->mUrlNavigator->setUrlEditable(GwenviewConfig::urlNavigatorIsEditable());
354     d->mUrlNavigator->setShowFullPath(GwenviewConfig::urlNavigatorShowFullPath());
355 
356     d->mThumbnailSlider->setValue(GwenviewConfig::thumbnailSize());
357     d->mThumbnailSlider->updateToolTip();
358     // If GwenviewConfig::thumbnailSize() returns the current value of
359     // mThumbnailSlider, it won't emit valueChanged() and the thumbnail view
360     // won't be updated. That's why we do it ourself.
361     d->mThumbnailView->setThumbnailAspectRatio(GwenviewConfig::thumbnailAspectRatio());
362     d->mThumbnailView->setThumbnailWidth(GwenviewConfig::thumbnailSize());
363 
364     const auto actionsList = d->mSortAction->actions();
365     for (QAction *action : actionsList) {
366         if (sortingFromSortAction(action) == GwenviewConfig::sorting()) {
367             action->setChecked(true);
368             break;
369         }
370     }
371     d->mSortDescendingAction->setChecked(GwenviewConfig::sortDescending());
372 
373     d->updateContextBarActions();
374 }
375 
saveConfig() const376 void BrowseMainPage::saveConfig() const
377 {
378     GwenviewConfig::setUrlNavigatorIsEditable(d->mUrlNavigator->isUrlEditable());
379     GwenviewConfig::setUrlNavigatorShowFullPath(d->mUrlNavigator->showFullPath());
380     GwenviewConfig::setThumbnailSize(d->mThumbnailSlider->value());
381     GwenviewConfig::setSorting(sortingFromSortAction(d->mSortAction->checkedAction()));
382     GwenviewConfig::setSortDescending(d->mSortDescendingAction->isChecked());
383     GwenviewConfig::setThumbnailDetails(d->mDelegate->thumbnailDetails());
384 }
385 
eventFilter(QObject * watched,QEvent * event)386 bool BrowseMainPage::eventFilter(QObject *watched, QEvent *event)
387 {
388     // Leave fullscreen when not viewing an image
389     if (window()->isFullScreen() && event->type() == QEvent::ShortcutOverride) {
390         const QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
391         if (keyEvent->key() == Qt::Key_Escape) {
392             d->mActionCollection->action(QStringLiteral("leave_fullscreen"))->trigger();
393             event->accept();
394         }
395     }
396     return QWidget::eventFilter(watched, event);
397 }
398 
mousePressEvent(QMouseEvent * event)399 void BrowseMainPage::mousePressEvent(QMouseEvent *event)
400 {
401     switch (event->button()) {
402     case Qt::ForwardButton:
403     case Qt::BackButton:
404         return;
405     default:
406         QWidget::mousePressEvent(event);
407     }
408 }
409 
thumbnailView() const410 ThumbnailView *BrowseMainPage::thumbnailView() const
411 {
412     return d->mThumbnailView;
413 }
414 
urlNavigator() const415 KUrlNavigator *BrowseMainPage::urlNavigator() const
416 {
417     return d->mUrlNavigator;
418 }
419 
reload()420 void BrowseMainPage::reload()
421 {
422     const QModelIndexList list = d->mThumbnailView->selectionModel()->selectedIndexes();
423     for (const QModelIndex &index : list) {
424         d->mThumbnailView->reloadThumbnail(index);
425     }
426     d->mDirModel->reload();
427 }
428 
editLocation()429 void BrowseMainPage::editLocation()
430 {
431     d->mUrlNavigator->setUrlEditable(true);
432     d->mUrlNavigator->setFocus();
433 }
434 
addFolderToPlaces()435 void BrowseMainPage::addFolderToPlaces()
436 {
437     QUrl url = d->mUrlNavigator->locationUrl();
438     QString text = url.adjusted(QUrl::StripTrailingSlash).fileName();
439     if (text.isEmpty()) {
440         text = url.toDisplayString();
441     }
442     d->mFilePlacesModel->addPlace(text, url);
443 }
444 
slotDirModelRowsInserted(const QModelIndex & parent,int start,int end)445 void BrowseMainPage::slotDirModelRowsInserted(const QModelIndex &parent, int start, int end)
446 {
447     int imageCount;
448     int videoCount;
449     d->documentCountsForIndexRange(parent, start, end, imageCount, videoCount);
450     if (imageCount > 0 || videoCount > 0) {
451         d->mDocumentCountImages += imageCount;
452         d->mDocumentCountVideos += videoCount;
453         d->updateDocumentCountLabel();
454     }
455 }
456 
slotDirModelRowsAboutToBeRemoved(const QModelIndex & parent,int start,int end)457 void BrowseMainPage::slotDirModelRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
458 {
459     int imageCount;
460     int videoCount;
461     d->documentCountsForIndexRange(parent, start, end, imageCount, videoCount);
462     if (imageCount > 0 || videoCount > 0) {
463         d->mDocumentCountImages -= imageCount;
464         d->mDocumentCountVideos -= videoCount;
465         d->updateDocumentCountLabel();
466     }
467 }
468 
slotDirModelReset()469 void BrowseMainPage::slotDirModelReset()
470 {
471     d->mDocumentCountImages = 0;
472     d->mDocumentCountVideos = 0;
473     d->mSelectedMediaItems->clear();
474     d->updateDocumentCountLabel();
475 }
476 
slotSelectionChanged(const QItemSelection & selected,const QItemSelection & deselected)477 void BrowseMainPage::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
478 {
479     d->updateSelectedMediaItems(selected, deselected);
480     d->updateDocumentCountLabel();
481 }
482 
updateSortOrder()483 void BrowseMainPage::updateSortOrder()
484 {
485     const QAction *action = d->mSortAction->checkedAction();
486     GV_RETURN_IF_FAIL(action);
487 
488     const Qt::SortOrder order = d->mSortDescendingAction->isChecked() ? Qt::DescendingOrder : Qt::AscendingOrder;
489     KDirModel::ModelColumns column = KDirModel::Name;
490     int sortRole = Qt::DisplayRole;
491 
492     // Map Sorting::Enum to model columns and sorting roles
493     switch (sortingFromSortAction(action)) {
494     case Sorting::Name:
495         column = KDirModel::Name;
496         break;
497     case Sorting::Size:
498         column = KDirModel::Size;
499         break;
500     case Sorting::Date:
501         column = KDirModel::ModifiedTime;
502         break;
503 #ifndef GWENVIEW_SEMANTICINFO_BACKEND_NONE
504     case Sorting::Rating:
505         column = KDirModel::Name;
506         sortRole = SemanticInfoDirModel::RatingRole;
507         break;
508 #endif
509     }
510 
511     d->mDirModel->setSortRole(sortRole);
512     d->mDirModel->sort(column, order);
513 }
514 
updateThumbnailDetails()515 void BrowseMainPage::updateThumbnailDetails()
516 {
517     PreviewItemDelegate::ThumbnailDetails details = {};
518     const auto actionList = d->mThumbnailDetailsActionGroup->actions();
519     for (const QAction *action : actionList) {
520         if (action->isChecked()) {
521             details |= PreviewItemDelegate::ThumbnailDetail(action->data().toInt());
522         }
523     }
524     d->mDelegate->setThumbnailDetails(details);
525 }
526 
setFullScreenMode(bool fullScreen)527 void BrowseMainPage::setFullScreenMode(bool fullScreen)
528 {
529     d->applyPalette(fullScreen);
530     d->mUrlNavigatorContainer->setContentsMargins(fullScreen ? 6 : 0, 0, 0, 0);
531     d->updateContextBarActions();
532 
533     d->mFullScreenToolBar->setVisible(fullScreen);
534     d->mFullScreenToolBar2->setVisible(fullScreen);
535     if (fullScreen && d->mFullScreenToolBar->actions().isEmpty()) {
536         d->setupFullScreenToolBar();
537     }
538 }
539 
setStatusBarVisible(bool visible)540 void BrowseMainPage::setStatusBarVisible(bool visible)
541 {
542     d->mStatusBarContainer->setVisible(visible);
543 }
544 
slotUrlsDropped(const QUrl & destUrl,QDropEvent * event)545 void BrowseMainPage::slotUrlsDropped(const QUrl &destUrl, QDropEvent *event)
546 {
547     const QList<QUrl> urlList = KUrlMimeData::urlsFromMimeData(event->mimeData());
548     if (urlList.isEmpty()) {
549         return;
550     }
551     event->acceptProposedAction();
552 
553     // We can't call FileOperations::showMenuForDroppedUrls() directly because
554     // we need the slot to return so that the drop event is accepted. Otherwise
555     // the drop cursor is still visible when the menu is shown.
556     QMetaObject::invokeMethod(
557         this,
558         [this, urlList, destUrl]() {
559             showMenuForDroppedUrls(urlList, destUrl);
560         },
561         Qt::QueuedConnection);
562 }
563 
showMenuForDroppedUrls(const QList<QUrl> & urlList,const QUrl & destUrl)564 void BrowseMainPage::showMenuForDroppedUrls(const QList<QUrl> &urlList, const QUrl &destUrl)
565 {
566     FileOperations::showMenuForDroppedUrls(d->mUrlNavigator, urlList, destUrl);
567 }
568 
toggleSideBarButton() const569 QToolButton *BrowseMainPage::toggleSideBarButton() const
570 {
571     return d->mToggleSideBarButton;
572 }
573 
574 } // namespace
575