]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistview.h
Provide basic rubberband functionality
[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 * @return Controller of the item-list. The controller gets
94 * initialized by KItemListController::setView() and will
95 * result in calling KItemListController::onControllerChanged().
96 */
97 KItemListController* controller() const;
98
99 /**
100 * @return Model of the item-list. The model gets
101 * initialized by KItemListController::setView() and will
102 * result in calling KItemListController::onModelChanged().
103 */
104 KItemModelBase* model() const;
105
106 /**
107 * Sets the creator that creates a widget showing the
108 * content of one model-item. Usually it is sufficient
109 * to implement a custom widget X derived from KItemListWidget and
110 * set the creator by:
111 * <code>
112 * itemListView->setWidgetCreator(new KItemListWidgetCreator<X>());
113 * </code>
114 * Note that the ownership of the widget creator is not transferred to
115 * the item-list view: One instance of a widget creator might get shared
116 * by several item-list view instances.
117 **/
118 void setWidgetCreator(KItemListWidgetCreatorBase* widgetCreator);
119 KItemListWidgetCreatorBase* widgetCreator() const;
120
121 void setGroupHeaderCreator(KItemListGroupHeaderCreatorBase* groupHeaderCreator);
122 KItemListGroupHeaderCreatorBase* groupHeaderCreator() const;
123
124 void setStyleOption(const KItemListStyleOption& option);
125 const KItemListStyleOption& styleOption() const;
126
127 virtual void setGeometry(const QRectF& rect);
128
129 int itemAt(const QPointF& pos) const;
130 bool isAboveSelectionToggle(int index, const QPointF& pos) const;
131 bool isAboveExpansionToggle(int index, const QPointF& pos) const;
132
133 int firstVisibleIndex() const;
134 int lastVisibleIndex() const;
135
136 virtual QSizeF itemSizeHint(int index) const;
137 virtual QHash<QByteArray, QSizeF> visibleRoleSizes() const;
138
139 QRectF itemBoundingRect(int index) const;
140 int itemsPerOffset() const;
141
142 void beginTransaction();
143 void endTransaction();
144 bool isTransactionActive() const;
145
146 /**
147 * @reimp
148 */
149 virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0);
150
151 signals:
152 void offsetChanged(qreal current, qreal previous);
153 void maximumOffsetChanged(qreal current, qreal previous);
154 void scrollTo(qreal newOffset);
155
156 protected:
157 virtual void initializeItemListWidget(KItemListWidget* item);
158
159 virtual void onControllerChanged(KItemListController* current, KItemListController* previous);
160 virtual void onModelChanged(KItemModelBase* current, KItemModelBase* previous);
161
162 virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous);
163 virtual void onItemSizeChanged(const QSizeF& current, const QSizeF& previous);
164 virtual void onOffsetChanged(qreal current, qreal previous);
165 virtual void onVisibleRolesChanged(const QHash<QByteArray, int>& current, const QHash<QByteArray, int>& previous);
166 virtual void onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous);
167
168 virtual void onTransactionBegin();
169 virtual void onTransactionEnd();
170
171 virtual bool event(QEvent* event);
172 virtual void mousePressEvent(QGraphicsSceneMouseEvent* event);
173 virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
174
175 QList<KItemListWidget*> visibleItemListWidgets() const;
176
177 protected slots:
178 virtual void slotItemsInserted(const KItemRangeList& itemRanges);
179 virtual void slotItemsRemoved(const KItemRangeList& itemRanges);
180 virtual void slotItemsChanged(const KItemRangeList& itemRanges,
181 const QSet<QByteArray>& roles);
182
183 private slots:
184 void slotCurrentChanged(int current, int previous);
185 void slotSelectionChanged(const QSet<int>& current, const QSet<int>& previous);
186 void slotAnimationFinished(QGraphicsWidget* widget,
187 KItemListViewAnimation::AnimationType type);
188 void slotLayoutTimerFinished();
189
190 void slotRubberBandStartPosChanged();
191 void slotRubberBandEndPosChanged();
192 void slotRubberBandActivationChanged(bool active);
193
194 private:
195 enum LayoutAnimationHint
196 {
197 NoAnimation,
198 Animation
199 };
200
201 enum SizeType
202 {
203 LayouterSize,
204 ItemSize
205 };
206
207 void setController(KItemListController* controller);
208 void setModel(KItemModelBase* model);
209
210 KItemListRubberBand* rubberBand() const;
211
212 void updateLayout();
213 void doLayout(LayoutAnimationHint hint, int changedIndex, int changedCount);
214 void doGroupHeadersLayout(LayoutAnimationHint hint, int changedIndex, int changedCount);
215 void emitOffsetChanges();
216
217 KItemListWidget* createWidget(int index);
218 void recycleWidget(KItemListWidget* widget);
219 void setWidgetIndex(KItemListWidget* widget, int index);
220
221 /**
222 * Helper method for setGeometry() and setItemSize(): Calling both methods might result
223 * in a changed number of visible items. To assure that currently invisible items can
224 * get animated from the old position to the new position prepareLayoutForIncreasedItemCount()
225 * takes care to create all item widgets that are visible with the old or the new size.
226 * @param size Size of the layouter or the item dependent on \p sizeType.
227 * @param sizeType LayouterSize: KItemListLayouter::setSize() is used.
228 * ItemSize: KItemListLayouter::setItemSize() is used.
229 */
230 void prepareLayoutForIncreasedItemCount(const QSizeF& size, SizeType sizeType);
231
232 /**
233 * Helper method for prepareLayoutForIncreasedItemCount().
234 */
235 void setLayouterSize(const QSizeF& size, SizeType sizeType);
236
237 /**
238 * Marks the visible roles as dirty so that they will get updated when doing the next
239 * layout. The visible roles will only get marked as dirty if an empty item-size is
240 * given.
241 * @return True if the visible roles have been marked as dirty.
242 */
243 bool markVisibleRolesSizesAsDirty();
244
245 /**
246 * Updates the m_visibleRoleSizes property and applies the dynamic
247 * size to the layouter.
248 */
249 void applyDynamicItemSize();
250
251 /**
252 * Helper method for createWidget() and setWidgetIndex() to update the properties
253 * of the itemlist widget.
254 */
255 void updateWidgetProperties(KItemListWidget* widget, int index);
256
257 /**
258 * Emits the signal scrollTo() with the corresponding target offset if the current
259 * mouse position is above the autoscroll-margin.
260 */
261 void triggerAutoScrolling();
262
263 /**
264 * Helper function for triggerAutoScrolling(). Returns the scroll increment
265 * that should be added to the offset() based on the available size \a size
266 * and the current mouse position \a pos. As soon as \a pos is inside
267 * the autoscroll-margin a value != 0 will be returned.
268 */
269 static int calculateAutoScrollingIncrement(int pos, int size);
270
271 private:
272 bool m_autoScrollMarginEnabled;
273 bool m_grouped;
274 int m_activeTransactions; // Counter for beginTransaction()/endTransaction()
275
276 QSizeF m_itemSize;
277 KItemListController* m_controller;
278 KItemModelBase* m_model;
279 QHash<QByteArray, int> m_visibleRoles;
280 QHash<QByteArray, QSizeF> m_visibleRolesSizes;
281 KItemListWidgetCreatorBase* m_widgetCreator;
282 KItemListGroupHeaderCreatorBase* m_groupHeaderCreator;
283 KItemListStyleOption m_styleOption;
284
285 QHash<int, KItemListWidget*> m_visibleItems;
286 QHash<KItemListWidget*, KItemListGroupHeader*> m_visibleGroups;
287
288 int m_scrollBarExtent;
289 KItemListSizeHintResolver* m_sizeHintResolver;
290 KItemListViewLayouter* m_layouter;
291 KItemListViewAnimation* m_animation;
292
293 QTimer* m_layoutTimer; // Triggers an asynchronous doLayout() call.
294 qreal m_oldOffset;
295 qreal m_oldMaximumOffset;
296
297 KItemListRubberBand* m_rubberBand;
298
299 QPointF m_mousePos;
300
301 friend class KItemListController;
302 };
303
304 /**
305 * Allows to do a fast logical creation and deletion of QGraphicsWidgets
306 * by recycling existing QGraphicsWidgets instances. Is used by
307 * KItemListWidgetCreatorBase and KItemListGroupHeaderCreatorBase.
308 * @internal
309 */
310 class LIBDOLPHINPRIVATE_EXPORT KItemListCreatorBase
311 {
312 public:
313 virtual ~KItemListCreatorBase();
314
315 protected:
316 void addCreatedWidget(QGraphicsWidget* widget);
317 void pushRecycleableWidget(QGraphicsWidget* widget);
318 QGraphicsWidget* popRecycleableWidget();
319
320 private:
321 QSet<QGraphicsWidget*> m_createdWidgets;
322 QList<QGraphicsWidget*> m_recycleableWidgets;
323 };
324
325 /**
326 * @brief Base class for creating KItemListWidgets.
327 *
328 * It is recommended that applications simply use the KItemListWidgetCreator-template class.
329 * For a custom implementation the methods create() and recyle() must be reimplemented.
330 * The intention of the widget creator is to prevent repetitive and expensive instantiations and
331 * deletions of KItemListWidgets by recycling existing widget instances.
332 */
333 class LIBDOLPHINPRIVATE_EXPORT KItemListWidgetCreatorBase : public KItemListCreatorBase
334 {
335 public:
336 virtual ~KItemListWidgetCreatorBase();
337 virtual KItemListWidget* create(KItemListView* view) = 0;
338 virtual void recycle(KItemListWidget* widget);
339 };
340
341 template <class T>
342 class LIBDOLPHINPRIVATE_EXPORT KItemListWidgetCreator : public KItemListWidgetCreatorBase
343 {
344 public:
345 virtual ~KItemListWidgetCreator();
346 virtual KItemListWidget* create(KItemListView* view);
347 };
348
349 template <class T>
350 KItemListWidgetCreator<T>::~KItemListWidgetCreator()
351 {
352 }
353
354 template <class T>
355 KItemListWidget* KItemListWidgetCreator<T>::create(KItemListView* view)
356 {
357 KItemListWidget* widget = static_cast<KItemListWidget*>(popRecycleableWidget());
358 if (!widget) {
359 widget = new T(view);
360 addCreatedWidget(widget);
361 }
362 return widget;
363 }
364
365 /**
366 * @brief Base class for creating KItemListGroupHeaders.
367 *
368 * It is recommended that applications simply use the KItemListGroupHeaderCreator-template class.
369 * For a custom implementation the methods create() and recyle() must be reimplemented.
370 * The intention of the group-header creator is to prevent repetitive and expensive instantiations and
371 * deletions of KItemListGroupHeaders by recycling existing header instances.
372 */
373 class LIBDOLPHINPRIVATE_EXPORT KItemListGroupHeaderCreatorBase : public KItemListCreatorBase
374 {
375 public:
376 virtual ~KItemListGroupHeaderCreatorBase();
377 virtual KItemListGroupHeader* create(QGraphicsWidget* parent) = 0;
378 virtual void recycle(KItemListGroupHeader* header);
379 };
380
381 template <class T>
382 class LIBDOLPHINPRIVATE_EXPORT KItemListGroupHeaderCreator : public KItemListGroupHeaderCreatorBase
383 {
384 public:
385 virtual ~KItemListGroupHeaderCreator();
386 virtual KItemListGroupHeader* create(QGraphicsWidget* parent);
387 };
388
389 template <class T>
390 KItemListGroupHeaderCreator<T>::~KItemListGroupHeaderCreator()
391 {
392 }
393
394 template <class T>
395 KItemListGroupHeader* KItemListGroupHeaderCreator<T>::create(QGraphicsWidget* parent)
396 {
397 KItemListGroupHeader* widget = static_cast<KItemListGroupHeader*>(popRecycleableWidget());
398 if (!widget) {
399 widget = new T(parent);
400 addCreatedWidget(widget);
401 }
402 return widget;
403 }
404
405 #endif