1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2010-02-06
7  * Description : Thumbnail bar for items
8  *
9  * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10  * Copyright (C) 2009-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  *
12  * This program is free software you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation
15  * either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "itemthumbnailbar.h"
26 
27 // Qt includes
28 
29 #include <QEvent>
30 
31 // Local includes
32 
33 #include "digikam_debug.h"
34 #include "applicationsettings.h"
35 #include "itemalbumfiltermodel.h"
36 #include "itemalbummodel.h"
37 #include "itemdragdrop.h"
38 #include "itemratingoverlay.h"
39 #include "itemcoordinatesoverlay.h"
40 #include "itemthumbnaildelegate.h"
41 #include "fileactionmngr.h"
42 
43 namespace Digikam
44 {
45 
46 class Q_DECL_HIDDEN ItemThumbnailBar::Private
47 {
48 public:
49 
Private()50     explicit Private()
51     {
52         scrollPolicy     = Qt::ScrollBarAlwaysOn;
53         duplicatesFilter = nullptr;
54     }
55 
56     Qt::ScrollBarPolicy          scrollPolicy;
57     NoDuplicatesItemFilterModel* duplicatesFilter;
58 };
59 
ItemThumbnailBar(QWidget * const parent)60 ItemThumbnailBar::ItemThumbnailBar(QWidget* const parent)
61     : ItemCategorizedView(parent),
62       d(new Private())
63 {
64     setItemDelegate(new ItemThumbnailDelegate(this));
65     setSpacing(3);
66     setUsePointingHandCursor(false);
67     setScrollStepGranularity(5);
68     setScrollBarPolicy(Qt::ScrollBarAlwaysOn);
69 
70     setDragEnabled(true);
71     setAcceptDrops(true);
72     setDropIndicatorShown(false);
73 
74     setScrollCurrentToCenter(ApplicationSettings::instance()->getScrollItemToCenter());
75     setToolTipEnabled(ApplicationSettings::instance()->showToolTipsIsValid());
76 
77     // --- NOTE: use dynamic binding as slotSetupChanged() is a virtual slot which can be re-implemented in derived classes.
78     connect(ApplicationSettings::instance(), &ApplicationSettings::setupChanged,
79             this, &ItemThumbnailBar::slotSetupChanged);
80 
81     this->slotSetupChanged();
82     // ---
83 
84     setFlow(LeftToRight);
85 }
86 
~ItemThumbnailBar()87 ItemThumbnailBar::~ItemThumbnailBar()
88 {
89     delete d;
90 }
91 
setModelsFiltered(ItemModel * model,ImageSortFilterModel * filterModel)92 void ItemThumbnailBar::setModelsFiltered(ItemModel* model, ImageSortFilterModel* filterModel)
93 {
94     if (!d->duplicatesFilter)
95     {
96         d->duplicatesFilter = new NoDuplicatesItemFilterModel(this);
97     }
98 
99     d->duplicatesFilter->setSourceFilterModel(filterModel);
100     ItemCategorizedView::setModels(model, d->duplicatesFilter);
101 }
102 
installOverlays()103 void ItemThumbnailBar::installOverlays()
104 {
105     ItemRatingOverlay* const ratingOverlay = new ItemRatingOverlay(this);
106     addOverlay(ratingOverlay);
107 
108     connect(ratingOverlay, SIGNAL(ratingEdited(QList<QModelIndex>,int)),
109             this, SLOT(assignRating(QList<QModelIndex>,int)));
110 
111     addOverlay(new ItemCoordinatesOverlay(this));
112 }
113 
slotDockLocationChanged(Qt::DockWidgetArea area)114 void ItemThumbnailBar::slotDockLocationChanged(Qt::DockWidgetArea area)
115 {
116     if (area == Qt::LeftDockWidgetArea || area == Qt::RightDockWidgetArea)
117     {
118         setFlow(TopToBottom);
119     }
120     else
121     {
122         setFlow(LeftToRight);
123     }
124 
125     scrollTo(currentIndex());
126 }
127 
setScrollBarPolicy(Qt::ScrollBarPolicy policy)128 void ItemThumbnailBar::setScrollBarPolicy(Qt::ScrollBarPolicy policy)
129 {
130     if (policy == Qt::ScrollBarAsNeeded)
131     {
132         // Delegate resizing will cause endless relayouting, see bug #228807
133         qCDebug(DIGIKAM_GENERAL_LOG) << "The Qt::ScrollBarAsNeeded policy is not supported by ItemThumbnailBar";
134     }
135 
136     d->scrollPolicy = policy;
137 
138     if (flow() == TopToBottom)
139     {
140         setVerticalScrollBarPolicy(d->scrollPolicy);
141         setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
142     }
143     else
144     {
145         setHorizontalScrollBarPolicy(d->scrollPolicy);
146         setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
147     }
148 }
149 
setFlow(QListView::Flow flow)150 void ItemThumbnailBar::setFlow(QListView::Flow flow)
151 {
152     setWrapping(false);
153 
154     ItemCategorizedView::setFlow(flow);
155 
156     ItemThumbnailDelegate* const del = static_cast<ItemThumbnailDelegate*>(delegate());
157     del->setFlow(flow);
158 
159     // Reset the minimum and maximum sizes.
160     setMinimumSize(QSize(0, 0));
161     setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
162 
163     // Adjust minimum and maximum width to thumbnail sizes.
164     if (flow == TopToBottom)
165     {
166         int viewportFullWidgetOffset = size().width() - viewport()->size().width();
167         setMinimumWidth(del->minimumSize() + viewportFullWidgetOffset);
168         setMaximumWidth(del->maximumSize() + viewportFullWidgetOffset);
169     }
170     else
171     {
172         int viewportFullWidgetOffset = size().height() - viewport()->size().height();
173         setMinimumHeight(del->minimumSize() + viewportFullWidgetOffset);
174         setMaximumHeight(del->maximumSize() + viewportFullWidgetOffset);
175     }
176 
177     setScrollBarPolicy(d->scrollPolicy);
178 }
179 
slotSetupChanged()180 void ItemThumbnailBar::slotSetupChanged()
181 {
182     setScrollCurrentToCenter(ApplicationSettings::instance()->getScrollItemToCenter());
183     setToolTipEnabled(ApplicationSettings::instance()->showToolTipsIsValid());
184     setFont(ApplicationSettings::instance()->getIconViewFont());
185 
186     ItemCategorizedView::slotSetupChanged();
187 }
188 
assignRating(const QList<QModelIndex> & indexes,int rating)189 void ItemThumbnailBar::assignRating(const QList<QModelIndex>& indexes, int rating)
190 {
191     FileActionMngr::instance()->assignRating(imageSortFilterModel()->imageInfos(indexes), rating);
192 }
193 
event(QEvent * e)194 bool ItemThumbnailBar::event(QEvent* e)
195 {
196     // reset widget max/min sizes
197     if (e->type() == QEvent::StyleChange || e->type() == QEvent::Show)
198     {
199         setFlow(flow());
200     }
201 
202     return ItemCategorizedView::event(e);
203 }
204 
nextIndex(const QModelIndex & index) const205 QModelIndex ItemThumbnailBar::nextIndex(const QModelIndex& index) const
206 {
207     return imageFilterModel()->index(index.row() + 1, 0);
208 }
209 
previousIndex(const QModelIndex & index) const210 QModelIndex ItemThumbnailBar::previousIndex(const QModelIndex& index) const
211 {
212     return imageFilterModel()->index(index.row() - 1, 0);
213 }
214 
firstIndex() const215 QModelIndex ItemThumbnailBar::firstIndex() const
216 {
217     return imageFilterModel()->index(0, 0);
218 }
219 
lastIndex() const220 QModelIndex ItemThumbnailBar::lastIndex() const
221 {
222     return imageFilterModel()->index(imageFilterModel()->rowCount() - 1, 0);
223 }
224 
225 } // namespace Digikam
226