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