]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistview.h
Improve the autoscrolling for the rubberband selection
[dolphin.git] / src / kitemviews / kitemlistview.h
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * *
4 * Based on the Itemviews NG project from Trolltech Labs: *
5 * http://qt.gitorious.org/qt-labs/itemviews-ng *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
21 ***************************************************************************/
22
23 #ifndef KITEMLISTVIEW_H
24 #define KITEMLISTVIEW_H
25
26 #include <libdolphin_export.h>
27
28 #include <kitemviews/kitemliststyleoption.h>
29 #include <kitemviews/kitemlistviewanimation_p.h>
30 #include <kitemviews/kitemlistwidget.h>
31 #include <kitemviews/kitemmodelbase.h>
32 #include <QGraphicsWidget>
33 #include <QSet>
34
35 class KItemListController;
36 class KItemListWidgetCreatorBase;
37 class KItemListGroupHeader;
38 class KItemListGroupHeaderCreatorBase;
39 class KItemListSizeHintResolver;
40 class KItemListRubberBand;
41 class KItemListViewAnimation;
42 class KItemListViewLayouter;
43 class KItemListWidget;
44 class KItemListViewCreatorBase;
45 class QTimer;
46
47 /**
48 * @brief Represents the view of an item-list.
49 *
50 * The view is responsible for showing the items of the model within
51 * a GraphicsItem. Each visible item is represented by a KItemListWidget.
52 *
53 * The created view must be applied to the KItemListController with
54 * KItemListController::setView(). For showing a custom model it is not
55 * mandatory to derive from KItemListView, all that is necessary is
56 * to set a widget-creator that is capable to create KItemListWidgets
57 * showing the model items. A widget-creator can be set with
58 * KItemListView::setWidgetCreator().
59 *
60 * @see KItemListWidget
61 * @see KItemModelBase
62 */
63 class LIBDOLPHINPRIVATE_EXPORT KItemListView : public QGraphicsWidget
64 {
65 Q_OBJECT
66
67 Q_PROPERTY(qreal offset READ offset WRITE setOffset)
68
69 public:
70 KItemListView(QGraphicsWidget* parent = 0);
71 virtual ~KItemListView();
72
73 void setScrollOrientation(Qt::Orientation orientation);
74 Qt::Orientation scrollOrientation() const;
75
76 void setItemSize(const QSizeF& size);
77 QSizeF itemSize() const;
78
79 // TODO: add note that offset is not checked against maximumOffset, only against 0.
80 void setOffset(qreal offset);
81 qreal offset() const;
82
83 qreal maximumOffset() const;
84
85 /**
86 * Sets the visible roles to \p roles. The integer-value defines
87 * the order of the visible role: Smaller values are ordered first.
88 */
89 void setVisibleRoles(const QHash<QByteArray, int>& roles);
90 QHash<QByteArray, int> visibleRoles() const;
91
92 /**
93 * If set to true an automatic scrolling is done as soon as the
94 * mouse is moved near the borders of the view. Per default
95 * the automatic scrolling is turned off.
96 */
97 void setAutoScroll(bool enabled);
98 bool autoScroll() const;
99
100 /**
101 * @return Controller of the item-list. The controller gets
102 * initialized by KItemListController::setView() and will
103 * result in calling KItemListController::onControllerChanged().
104 */
105 KItemListController* controller() const;
106
107 /**
108 * @return Model of the item-list. The model gets
109 * initialized by KItemListController::setView() and will
110 * result in calling KItemListController::onModelChanged().
111 */
112 KItemModelBase* model() const;
113
114 /**
115 * Sets the creator that creates a widget showing the
116 * content of one model-item. Usually it is sufficient
117 * to implement a custom widget X derived from KItemListWidget and
118 * set the creator by:
119 * <code>
120 * itemListView->setWidgetCreator(new KItemListWidgetCreator<X>());
121 * </code>
122 * Note that the ownership of the widget creator is not transferred to
123 * the item-list view: One instance of a widget creator might get shared
124 * by several item-list view instances.
125 **/
126 void setWidgetCreator(KItemListWidgetCreatorBase* widgetCreator);
127 KItemListWidgetCreatorBase* widgetCreator() const;
128
129 void setGroupHeaderCreator(KItemListGroupHeaderCreatorBase* groupHeaderCreator);
130 KItemListGroupHeaderCreatorBase* groupHeaderCreator() const;
131
132 void setStyleOption(const KItemListStyleOption& option);
133 const KItemListStyleOption& styleOption() const;
134
135 /** @reimp */
136 virtual void setGeometry(const QRectF& rect);
137
138 int itemAt(const QPointF& pos) const;
139 bool isAboveSelectionToggle(int index, const QPointF& pos) const;
140 bool isAboveExpansionToggle(int index, const QPointF& pos) const;
141
142 int firstVisibleIndex() const;
143 int lastVisibleIndex() const;
144
145 virtual QSizeF itemSizeHint(int index) const;
146 virtual QHash<QByteArray, QSizeF> visibleRoleSizes() const;
147
148 /**
149 * @return The bounding rectangle of the item relative to the top/left of
150 * the currently visible area (see KItemListView::offset()).
151 */
152 QRectF itemBoundingRect(int index) const;
153
154 /**
155 * @return The number of items that can be shown in parallel for one offset.
156 * Assuming the scrolldirection is vertical then a value of 4 means
157 * that 4 columns for items are available. Assuming the scrolldirection
158 * is horizontal then a value of 4 means that 4 lines for items are
159 * available.
160 */
161 int itemsPerOffset() const;
162
163 void beginTransaction();
164 void endTransaction();
165 bool isTransactionActive() const;
166
167 /**
168 * @return Pixmap that is used for a drag operation based on the
169 * items given by \a indexes. The default implementation returns
170 * a null-pixmap.
171 */
172 virtual QPixmap createDragPixmap(const QSet<int>& indexes) const;
173
174 /**
175 * @reimp
176 */
177 virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
178
179 signals:
180 void offsetChanged(qreal current, qreal previous);
181 void maximumOffsetChanged(qreal current, qreal previous);
182 void scrollTo(qreal newOffset);
183
184 protected:
185 virtual void initializeItemListWidget(KItemListWidget* item);
186
187 virtual void onControllerChanged(KItemListController* current, KItemListController* previous);
188 virtual void onModelChanged(KItemModelBase* current, KItemModelBase* previous);
189
190 virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous);
191 virtual void onItemSizeChanged(const QSizeF& current, const QSizeF& previous);
192 virtual void onOffsetChanged(qreal current, qreal previous);
193 virtual void onVisibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous);
194 virtual void onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
195
196 virtual void onTransactionBegin();
197 virtual void onTransactionEnd();
198
199 virtual bool event(QEvent* event);
200 virtual void mousePressEvent(QGraphicsSceneMouseEvent* event);
201 virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
202 virtual void dragEnterEvent(QGraphicsSceneDragDropEvent* event);
203
204 QList<KItemListWidget*> visibleItemListWidgets() const;
205
206 protected slots:
207 virtual void slotItemsInserted(const KItemRangeList& itemRanges);
208 virtual void slotItemsRemoved(const KItemRangeList& itemRanges);
209 virtual void slotItemsChanged(const KItemRangeList& itemRanges,
210 const QSet<QByteArray>& roles);
211
212 private slots:
213 void slotCurrentChanged(int current, int previous);
214 void slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous);
215 void slotAnimationFinished(QGraphicsWidget* widget,
216 KItemListViewAnimation::AnimationType type);
217 void slotLayoutTimerFinished();
218
219 void slotRubberBandPosChanged();
220 void slotRubberBandActivationChanged(bool active);
221
222 /**
223 * Triggers the autoscrolling if autoScroll() is enabled by checking the
224 * current mouse position. If the mouse position is within the autoscroll
225 * margins a timer will be started that periodically triggers the autoscrolling.
226 */
227 void triggerAutoScrolling();
228
229 private:
230 enum LayoutAnimationHint
231 {
232 NoAnimation,
233 Animation
234 };
235
236 enum SizeType
237 {
238 LayouterSize,
239 ItemSize
240 };
241
242 void setController(KItemListController* controller);
243 void setModel(KItemModelBase* model);
244
245 KItemListRubberBand* rubberBand() const;
246
247 void updateLayout();
248 void doLayout(LayoutAnimationHint hint, int changedIndex, int changedCount);
249 void doGroupHeadersLayout(LayoutAnimationHint hint, int changedIndex, int changedCount);
250 void emitOffsetChanges();
251
252 KItemListWidget* createWidget(int index);
253 void recycleWidget(KItemListWidget* widget);
254 void setWidgetIndex(KItemListWidget* widget, int index);
255
256 /**
257 * Helper method for setGeometry() and setItemSize(): Calling both methods might result
258 * in a changed number of visible items. To assure that currently invisible items can
259 * get animated from the old position to the new position prepareLayoutForIncreasedItemCount()
260 * takes care to create all item widgets that are visible with the old or the new size.
261 * @param size Size of the layouter or the item dependent on \p sizeType.
262 * @param sizeType LayouterSize: KItemListLayouter::setSize() is used.
263 * ItemSize: KItemListLayouter::setItemSize() is used.
264 */
265 void prepareLayoutForIncreasedItemCount(const QSizeF& size, SizeType sizeType);
266
267 /**
268 * Helper method for prepareLayoutForIncreasedItemCount().
269 */
270 void setLayouterSize(const QSizeF& size, SizeType sizeType);
271
272 /**
273 * Marks the visible roles as dirty so that they will get updated when doing the next
274 * layout. The visible roles will only get marked as dirty if an empty item-size is
275 * given.
276 * @return True if the visible roles have been marked as dirty.
277 */
278 bool markVisibleRolesSizesAsDirty();
279
280 /**
281 * Updates the m_visibleRoleSizes property and applies the dynamic
282 * size to the layouter.
283 */
284 void applyDynamicItemSize();
285
286 /**
287 * Helper method for createWidget() and setWidgetIndex() to update the properties
288 * of the itemlist widget.
289 */
290 void updateWidgetProperties(KItemListWidget* widget, int index);
291
292 /**
293 * Helper function for triggerAutoScrolling(). Returns the scroll increment
294 * that should be added to the offset() based on the available size \a size
295 * and the current mouse position \a pos. As soon as \a pos is inside
296 * the autoscroll-margin a value != 0 will be returned.
297 */
298 static int calculateAutoScrollingIncrement(int pos, int size);
299
300 private:
301 bool m_grouped;
302 int m_activeTransactions; // Counter for beginTransaction()/endTransaction()
303
304 QSizeF m_itemSize;
305 KItemListController* m_controller;
306 KItemModelBase* m_model;
307 QHash<QByteArray, int> m_visibleRoles;
308 QHash<QByteArray, QSizeF> m_visibleRolesSizes;
309 KItemListWidgetCreatorBase* m_widgetCreator;
310 KItemListGroupHeaderCreatorBase* m_groupHeaderCreator;
311 KItemListStyleOption m_styleOption;
312
313 QHash<int, KItemListWidget*> m_visibleItems;
314 QHash<KItemListWidget*, KItemListGroupHeader*> m_visibleGroups;
315
316 int m_scrollBarExtent;
317 KItemListSizeHintResolver* m_sizeHintResolver;
318 KItemListViewLayouter* m_layouter;
319 KItemListViewAnimation* m_animation;
320
321 QTimer* m_layoutTimer; // Triggers an asynchronous doLayout() call.
322 qreal m_oldOffset;
323 qreal m_oldMaximumOffset;
324
325 bool m_skipAutoScrollForRubberBand;
326 KItemListRubberBand* m_rubberBand;
327
328 QPointF m_mousePos;
329 QTimer* m_autoScrollTimer;
330
331 friend class KItemListController;
332 };
333
334 /**
335 * Allows to do a fast logical creation and deletion of QGraphicsWidgets
336 * by recycling existing QGraphicsWidgets instances. Is used by
337 * KItemListWidgetCreatorBase and KItemListGroupHeaderCreatorBase.
338 * @internal
339 */
340 class LIBDOLPHINPRIVATE_EXPORT KItemListCreatorBase
341 {
342 public:
343 virtual ~KItemListCreatorBase();
344
345 protected:
346 void addCreatedWidget(QGraphicsWidget* widget);
347 void pushRecycleableWidget(QGraphicsWidget* widget);
348 QGraphicsWidget* popRecycleableWidget();
349
350 private:
351 QSet<QGraphicsWidget*> m_createdWidgets;
352 QList<QGraphicsWidget*> m_recycleableWidgets;
353 };
354
355 /**
356 * @brief Base class for creating KItemListWidgets.
357 *
358 * It is recommended that applications simply use the KItemListWidgetCreator-template class.
359 * For a custom implementation the methods create() and recyle() must be reimplemented.
360 * The intention of the widget creator is to prevent repetitive and expensive instantiations and
361 * deletions of KItemListWidgets by recycling existing widget instances.
362 */
363 class LIBDOLPHINPRIVATE_EXPORT KItemListWidgetCreatorBase : public KItemListCreatorBase
364 {
365 public:
366 virtual ~KItemListWidgetCreatorBase();
367 virtual KItemListWidget* create(KItemListView* view) = 0;
368 virtual void recycle(KItemListWidget* widget);
369 };
370
371 template <class T>
372 class LIBDOLPHINPRIVATE_EXPORT KItemListWidgetCreator : public KItemListWidgetCreatorBase
373 {
374 public:
375 virtual ~KItemListWidgetCreator();
376 virtual KItemListWidget* create(KItemListView* view);
377 };
378
379 template <class T>
380 KItemListWidgetCreator<T>::~KItemListWidgetCreator()
381 {
382 }
383
384 template <class T>
385 KItemListWidget* KItemListWidgetCreator<T>::create(KItemListView* view)
386 {
387 KItemListWidget* widget = static_cast<KItemListWidget*>(popRecycleableWidget());
388 if (!widget) {
389 widget = new T(view);
390 addCreatedWidget(widget);
391 }
392 return widget;
393 }
394
395 /**
396 * @brief Base class for creating KItemListGroupHeaders.
397 *
398 * It is recommended that applications simply use the KItemListGroupHeaderCreator-template class.
399 * For a custom implementation the methods create() and recyle() must be reimplemented.
400 * The intention of the group-header creator is to prevent repetitive and expensive instantiations and
401 * deletions of KItemListGroupHeaders by recycling existing header instances.
402 */
403 class LIBDOLPHINPRIVATE_EXPORT KItemListGroupHeaderCreatorBase : public KItemListCreatorBase
404 {
405 public:
406 virtual ~KItemListGroupHeaderCreatorBase();
407 virtual KItemListGroupHeader* create(QGraphicsWidget* parent) = 0;
408 virtual void recycle(KItemListGroupHeader* header);
409 };
410
411 template <class T>
412 class LIBDOLPHINPRIVATE_EXPORT KItemListGroupHeaderCreator : public KItemListGroupHeaderCreatorBase
413 {
414 public:
415 virtual ~KItemListGroupHeaderCreator();
416 virtual KItemListGroupHeader* create(QGraphicsWidget* parent);
417 };
418
419 template <class T>
420 KItemListGroupHeaderCreator<T>::~KItemListGroupHeaderCreator()
421 {
422 }
423
424 template <class T>
425 KItemListGroupHeader* KItemListGroupHeaderCreator<T>::create(QGraphicsWidget* parent)
426 {
427 KItemListGroupHeader* widget = static_cast<KItemListGroupHeader*>(popRecycleableWidget());
428 if (!widget) {
429 widget = new T(parent);
430 addCreatedWidget(widget);
431 }
432 return widget;
433 }
434
435 #endif