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