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/kstandarditemlistgroupheader.h> |
29 | #include <kitemviews/kitemliststyleoption.h> |
30 | #include <kitemviews/kitemlistwidget.h> |
31 | #include <kitemviews/kitemmodelbase.h> |
32 | #include <kitemviews/private/kitemlistviewanimation.h> |
33 | #include <QGraphicsWidget> |
34 | #include <QSet> |
35 | |
36 | class KItemListController; |
37 | class KItemListGroupHeaderCreatorBase; |
38 | class ; |
39 | class ; |
40 | class KItemListSizeHintResolver; |
41 | class KItemListRubberBand; |
42 | class KItemListViewAnimation; |
43 | class KItemListViewLayouter; |
44 | class KItemListWidget; |
45 | class KItemListWidgetInformant; |
46 | class KItemListWidgetCreatorBase; |
47 | class KItemListViewCreatorBase; |
48 | class QTimer; |
49 | |
50 | /** |
51 | * @brief Represents the view of an item-list. |
52 | * |
53 | * The view is responsible for showing the items of the model within |
54 | * a GraphicsItem. Each visible item is represented by a KItemListWidget. |
55 | * |
56 | * The created view must be applied to the KItemListController with |
57 | * KItemListController::setView() or with the constructor of |
58 | * KItemListController. |
59 | * |
60 | * @see KItemListWidget |
61 | * @see KItemModelBase |
62 | */ |
63 | class LIBDOLPHINPRIVATE_EXPORT KItemListView : public QGraphicsWidget |
64 | { |
65 | Q_OBJECT |
66 | |
67 | Q_PROPERTY(qreal scrollOffset READ scrollOffset WRITE setScrollOffset) |
68 | Q_PROPERTY(qreal itemOffset READ itemOffset WRITE setItemOffset) |
69 | |
70 | public: |
71 | KItemListView(QGraphicsWidget* parent = 0); |
72 | virtual ~KItemListView(); |
73 | |
74 | /** |
75 | * Offset of the scrollbar that represents the scroll-orientation |
76 | * (see setScrollOrientation()). |
77 | */ |
78 | void setScrollOffset(qreal offset); |
79 | qreal scrollOffset() const; |
80 | |
81 | qreal maximumScrollOffset() const; |
82 | |
83 | /** |
84 | * Offset related to an item, that does not fit into the available |
85 | * size of the listview. If the scroll-orientation is vertical |
86 | * the item-offset describes the offset of the horizontal axe, if |
87 | * the scroll-orientation is horizontal the item-offset describes |
88 | * the offset of the vertical axe. |
89 | */ |
90 | void setItemOffset(qreal scrollOffset); |
91 | qreal itemOffset() const; |
92 | |
93 | qreal maximumItemOffset() const; |
94 | |
95 | int maximumVisibleItems() const; |
96 | |
97 | void setVisibleRoles(const QList<QByteArray>& roles); |
98 | QList<QByteArray> visibleRoles() const; |
99 | |
100 | /** |
101 | * If set to true an automatic scrolling is done as soon as the |
102 | * mouse is moved near the borders of the view. Per default |
103 | * the automatic scrolling is turned off. |
104 | */ |
105 | void setAutoScroll(bool enabled); |
106 | bool autoScroll() const; |
107 | |
108 | /** |
109 | * If set to true selection-toggles will be shown when hovering |
110 | * an item. Per default the selection-toggles are disabled. |
111 | */ |
112 | void setEnabledSelectionToggles(bool enabled); |
113 | bool enabledSelectionToggles() const; |
114 | |
115 | /** |
116 | * @return Controller of the item-list. The controller gets |
117 | * initialized by KItemListController::setView() and will |
118 | * result in calling KItemListController::onControllerChanged(). |
119 | */ |
120 | KItemListController* controller() const; |
121 | |
122 | /** |
123 | * @return Model of the item-list. The model gets |
124 | * initialized by KItemListController::setModel() and will |
125 | * result in calling KItemListController::onModelChanged(). |
126 | */ |
127 | KItemModelBase* model() const; |
128 | |
129 | /** |
130 | * Sets the creator that creates a widget showing the |
131 | * content of one model-item. Usually it is sufficient |
132 | * to implement a custom widget X derived from KItemListWidget and |
133 | * set the creator by: |
134 | * <code> |
135 | * itemListView->setWidgetCreator(new KItemListWidgetCreator<X>()); |
136 | * </code> |
137 | * The ownership of the widget creator is transferred to |
138 | * the item-list view. |
139 | **/ |
140 | void setWidgetCreator(KItemListWidgetCreatorBase* widgetCreator); |
141 | KItemListWidgetCreatorBase* widgetCreator() const; |
142 | |
143 | /** |
144 | * Sets the creator that creates a group header. Usually it is sufficient |
145 | * to implement a custom header widget X derived from KItemListGroupHeader and |
146 | * set the creator by: |
147 | * <code> |
148 | * itemListView->setGroupHeaderCreator(new KItemListGroupHeaderCreator<X>()); |
149 | * </code> |
150 | * The ownership of the gropup header creator is transferred to |
151 | * the item-list view. |
152 | **/ |
153 | void (KItemListGroupHeaderCreatorBase* ); |
154 | KItemListGroupHeaderCreatorBase* () const; |
155 | |
156 | /** |
157 | * @return The basic size of all items. The size of an item may be larger than |
158 | * the basic size (see KItemListView::itemSizeHint() and KItemListView::itemRect()). |
159 | */ |
160 | QSizeF itemSize() const; |
161 | |
162 | const KItemListStyleOption& styleOption() const; |
163 | |
164 | /** @reimp */ |
165 | virtual void setGeometry(const QRectF& rect); |
166 | |
167 | /** |
168 | * @return The page step which should be used by the vertical scroll bar. |
169 | * This is the height of the view except for the header widget. |
170 | */ |
171 | qreal verticalPageStep() const; |
172 | |
173 | /** |
174 | * @return Index of the item that is below the point \a pos. |
175 | * The position is relative to the upper right of |
176 | * the visible area. Only (at least partly) visible |
177 | * items are considered. -1 is returned if no item is |
178 | * below the position. |
179 | */ |
180 | int itemAt(const QPointF& pos) const; |
181 | bool isAboveSelectionToggle(int index, const QPointF& pos) const; |
182 | bool isAboveExpansionToggle(int index, const QPointF& pos) const; |
183 | |
184 | /** |
185 | * @return Index of the first item that is at least partly visible. |
186 | * -1 is returned if the model contains no items. |
187 | */ |
188 | int firstVisibleIndex() const; |
189 | |
190 | /** |
191 | * @return Index of the last item that is at least partly visible. |
192 | * -1 is returned if the model contains no items. |
193 | */ |
194 | int lastVisibleIndex() const; |
195 | |
196 | /** |
197 | * @return Calculates the required size for all items in the model. |
198 | * It might be larger than KItemListView::itemSize(). |
199 | * In this case the layout grid will be stretched to assure an |
200 | * unclipped item. |
201 | * NOTE: the logical height (width) is actually the |
202 | * width (height) if the scroll orientation is Qt::Vertical! |
203 | */ |
204 | void calculateItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint) const; |
205 | |
206 | /** |
207 | * If set to true, items having child-items can be expanded to show the child-items as |
208 | * part of the view. Per default the expanding of items is is disabled. If expanding of |
209 | * items is enabled, the methods KItemModelBase::setExpanded(), KItemModelBase::isExpanded(), |
210 | * KItemModelBase::isExpandable() and KItemModelBase::expandedParentsCount() |
211 | * must be reimplemented. The view-implementation |
212 | * has to take care itself how to visually represent the expanded items provided |
213 | * by the model. |
214 | */ |
215 | void setSupportsItemExpanding(bool supportsExpanding); |
216 | bool supportsItemExpanding() const; |
217 | |
218 | /** |
219 | * @return The rectangle of the item relative to the top/left of |
220 | * the currently visible area (see KItemListView::offset()). |
221 | */ |
222 | QRectF itemRect(int index) const; |
223 | |
224 | /** |
225 | * @return The context rectangle of the item relative to the top/left of |
226 | * the currently visible area (see KItemListView::offset()). The |
227 | * context rectangle is defined by by the united rectangle of |
228 | * the icon rectangle and the text rectangle (see KItemListWidget::iconRect() |
229 | * and KItemListWidget::textRect()) and is useful as reference for e.g. aligning |
230 | * a tooltip or a context-menu for an item. Note that a context rectangle will |
231 | * only be returned for (at least partly) visible items. An empty rectangle will |
232 | * be returned for fully invisible items. |
233 | */ |
234 | QRectF itemContextRect(int index) const; |
235 | |
236 | /** |
237 | * Scrolls to the item with the index \a index so that the item |
238 | * will be fully visible. |
239 | */ |
240 | void scrollToItem(int index); |
241 | |
242 | /** |
243 | * If several properties of KItemListView are changed synchronously, it is |
244 | * recommended to encapsulate the calls between beginTransaction() and endTransaction(). |
245 | * This prevents unnecessary and expensive layout-calculations. |
246 | */ |
247 | void beginTransaction(); |
248 | |
249 | /** |
250 | * Counterpart to beginTransaction(). The layout changes will only be animated if |
251 | * all property changes between beginTransaction() and endTransaction() support |
252 | * animations. |
253 | */ |
254 | void endTransaction(); |
255 | |
256 | bool isTransactionActive() const; |
257 | |
258 | /** |
259 | * Turns on the header if \p visible is true. Per default the |
260 | * header is not visible. Usually the header is turned on when |
261 | * showing a classic "table-view" to describe the shown columns. |
262 | */ |
263 | void (bool visible); |
264 | bool () const; |
265 | |
266 | /** |
267 | * @return Header of the list. The header is also available if it is not shown |
268 | * (see KItemListView::setHeaderShown()). |
269 | */ |
270 | KItemListHeader* () const; |
271 | |
272 | /** |
273 | * @return Pixmap that is used for a drag operation based on the |
274 | * items given by \a indexes. |
275 | */ |
276 | virtual QPixmap createDragPixmap(const KItemSet& indexes) const; |
277 | |
278 | /** |
279 | * Lets the user edit the role \a role for item with the index \a index. |
280 | */ |
281 | void editRole(int index, const QByteArray& role); |
282 | |
283 | /** |
284 | * @reimp |
285 | */ |
286 | virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0); |
287 | |
288 | signals: |
289 | void scrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous); |
290 | void scrollOffsetChanged(qreal current, qreal previous); |
291 | void maximumScrollOffsetChanged(qreal current, qreal previous); |
292 | void itemOffsetChanged(qreal current, qreal previous); |
293 | void maximumItemOffsetChanged(qreal current, qreal previous); |
294 | void scrollTo(qreal newOffset); |
295 | |
296 | /** |
297 | * Is emitted if the user has changed the sort order by clicking on a |
298 | * header item (see KItemListView::setHeaderShown()). The sort order |
299 | * of the model has already been adjusted to |
300 | * the current sort order. Note that no signal will be emitted if the |
301 | * sort order of the model has been changed without user interaction. |
302 | */ |
303 | void sortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); |
304 | |
305 | /** |
306 | * Is emitted if the user has changed the sort role by clicking on a |
307 | * header item (see KItemListView::setHeaderShown()). The sort role |
308 | * of the model has already been adjusted to |
309 | * the current sort role. Note that no signal will be emitted if the |
310 | * sort role of the model has been changed without user interaction. |
311 | */ |
312 | void sortRoleChanged(const QByteArray& current, const QByteArray& previous); |
313 | |
314 | /** |
315 | * Is emitted if the user has changed the visible roles by moving a header |
316 | * item (see KItemListView::setHeaderShown()). Note that no signal will be |
317 | * emitted if the roles have been changed without user interaction by |
318 | * KItemListView::setVisibleRoles(). |
319 | */ |
320 | void visibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous); |
321 | |
322 | void roleEditingCanceled(int index, const QByteArray& role, const QVariant& value); |
323 | void roleEditingFinished(int index, const QByteArray& role, const QVariant& value); |
324 | |
325 | protected: |
326 | virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); |
327 | void setItemSize(const QSizeF& size); |
328 | void setStyleOption(const KItemListStyleOption& option); |
329 | |
330 | /** |
331 | * If the scroll-orientation is vertical, the items are ordered |
332 | * from top to bottom (= default setting). If the scroll-orientation |
333 | * is horizontal, the items are ordered from left to right. |
334 | */ |
335 | void setScrollOrientation(Qt::Orientation orientation); |
336 | Qt::Orientation scrollOrientation() const; |
337 | |
338 | /** |
339 | * Factory method for creating a default widget-creator. The method will be used |
340 | * in case if setWidgetCreator() has not been set by the application. |
341 | * @return New instance of the widget-creator that should be used per |
342 | * default. |
343 | */ |
344 | virtual KItemListWidgetCreatorBase* defaultWidgetCreator() const; |
345 | |
346 | /** |
347 | * Factory method for creating a default group-header-creator. The method will be used |
348 | * in case if setGroupHeaderCreator() has not been set by the application. |
349 | * @return New instance of the group-header-creator that should be used per |
350 | * default. |
351 | */ |
352 | virtual KItemListGroupHeaderCreatorBase* () const; |
353 | |
354 | /** |
355 | * Is called when creating a new KItemListWidget instance and allows derived |
356 | * classes to do a custom initialization. |
357 | */ |
358 | virtual void initializeItemListWidget(KItemListWidget* item); |
359 | |
360 | /** |
361 | * @return True if at least one of the changed roles \p changedRoles might result |
362 | * in the need to update the item-size hint (see KItemListView::itemSizeHint()). |
363 | * Per default true is returned which means on each role-change of existing items |
364 | * the item-size hints are recalculated. For performance reasons it is recommended |
365 | * to return false in case if a role-change will not result in a changed |
366 | * item-size hint. |
367 | */ |
368 | virtual bool itemSizeHintUpdateRequired(const QSet<QByteArray>& changedRoles) const; |
369 | |
370 | virtual void onControllerChanged(KItemListController* current, KItemListController* previous); |
371 | virtual void onModelChanged(KItemModelBase* current, KItemModelBase* previous); |
372 | |
373 | virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous); |
374 | virtual void onItemSizeChanged(const QSizeF& current, const QSizeF& previous); |
375 | virtual void onScrollOffsetChanged(qreal current, qreal previous); |
376 | virtual void onVisibleRolesChanged(const QList<QByteArray>& current, const QList<QByteArray>& previous); |
377 | virtual void onStyleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous); |
378 | virtual void onSupportsItemExpandingChanged(bool supportsExpanding); |
379 | |
380 | virtual void onTransactionBegin(); |
381 | virtual void onTransactionEnd(); |
382 | |
383 | virtual bool event(QEvent* event); |
384 | virtual void mousePressEvent(QGraphicsSceneMouseEvent* event); |
385 | virtual void mouseMoveEvent(QGraphicsSceneMouseEvent* event); |
386 | virtual void dragEnterEvent(QGraphicsSceneDragDropEvent* event); |
387 | virtual void dragMoveEvent(QGraphicsSceneDragDropEvent* event); |
388 | virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent* event); |
389 | virtual void dropEvent(QGraphicsSceneDragDropEvent* event); |
390 | |
391 | QList<KItemListWidget*> visibleItemListWidgets() const; |
392 | |
393 | virtual void updateFont(); |
394 | virtual void updatePalette(); |
395 | |
396 | protected slots: |
397 | virtual void slotItemsInserted(const KItemRangeList& itemRanges); |
398 | virtual void slotItemsRemoved(const KItemRangeList& itemRanges); |
399 | virtual void slotItemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes); |
400 | virtual void slotItemsChanged(const KItemRangeList& itemRanges, |
401 | const QSet<QByteArray>& roles); |
402 | virtual void slotGroupsChanged(); |
403 | |
404 | virtual void slotGroupedSortingChanged(bool current); |
405 | virtual void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); |
406 | virtual void slotSortRoleChanged(const QByteArray& current, const QByteArray& previous); |
407 | virtual void slotCurrentChanged(int current, int previous); |
408 | virtual void slotSelectionChanged(const KItemSet& current, const KItemSet& previous); |
409 | |
410 | private slots: |
411 | void slotAnimationFinished(QGraphicsWidget* widget, |
412 | KItemListViewAnimation::AnimationType type); |
413 | void slotLayoutTimerFinished(); |
414 | |
415 | void slotRubberBandPosChanged(); |
416 | void slotRubberBandActivationChanged(bool active); |
417 | |
418 | /** |
419 | * Is invoked if the column-width of one role in the header has |
420 | * been changed by the user. The automatic resizing of columns |
421 | * will be turned off as soon as this method has been called at |
422 | * least once. |
423 | */ |
424 | void slotHeaderColumnWidthChanged(const QByteArray& role, |
425 | qreal currentWidth, |
426 | qreal previousWidth); |
427 | |
428 | /** |
429 | * Is invoked if a column has been moved by the user. Applies |
430 | * the moved role to the view. |
431 | */ |
432 | void slotHeaderColumnMoved(const QByteArray& role, |
433 | int currentIndex, |
434 | int previousIndex); |
435 | |
436 | /** |
437 | * Triggers the autoscrolling if autoScroll() is enabled by checking the |
438 | * current mouse position. If the mouse position is within the autoscroll |
439 | * margins a timer will be started that periodically triggers the autoscrolling. |
440 | */ |
441 | void triggerAutoScrolling(); |
442 | |
443 | /** |
444 | * Is invoked if the geometry of the parent-widget from a group-header has been |
445 | * changed. The x-position and width of the group-header gets adjusted to assure |
446 | * that it always spans the whole width even during temporary transitions of the |
447 | * parent widget. |
448 | */ |
449 | void (); |
450 | |
451 | void slotRoleEditingCanceled(int index, const QByteArray& role, const QVariant& value); |
452 | void slotRoleEditingFinished(int index, const QByteArray& role, const QVariant& value); |
453 | |
454 | private: |
455 | enum LayoutAnimationHint |
456 | { |
457 | NoAnimation, |
458 | Animation |
459 | }; |
460 | |
461 | enum SizeType |
462 | { |
463 | LayouterSize, |
464 | ItemSize |
465 | }; |
466 | |
467 | void setController(KItemListController* controller); |
468 | void setModel(KItemModelBase* model); |
469 | |
470 | KItemListRubberBand* rubberBand() const; |
471 | |
472 | void doLayout(LayoutAnimationHint hint, int changedIndex = 0, int changedCount = 0); |
473 | |
474 | /** |
475 | * Helper method for doLayout: Returns a list of items that can be reused for the visible |
476 | * area. Invisible group headers get recycled. The reusable items are items that are |
477 | * invisible. If the animation hint is 'Animation' then items that are currently animated |
478 | * won't be reused. Reusing items is faster in comparison to deleting invisible |
479 | * items and creating a new instance for visible items. |
480 | */ |
481 | QList<int> recycleInvisibleItems(int firstVisibleIndex, |
482 | int lastVisibleIndex, |
483 | LayoutAnimationHint hint); |
484 | |
485 | /** |
486 | * Helper method for doLayout: Starts a moving-animation for the widget to the given |
487 | * new position. The moving-animation is only started if the new position is within |
488 | * the same row or column, otherwise the create-animation is used instead. |
489 | * @return True if the moving-animation has been applied. |
490 | */ |
491 | bool moveWidget(KItemListWidget* widget, const QPointF& newPos); |
492 | |
493 | void emitOffsetChanges(); |
494 | |
495 | KItemListWidget* createWidget(int index); |
496 | void recycleWidget(KItemListWidget* widget); |
497 | |
498 | /** |
499 | * Changes the index of the widget to \a index and assures a consistent |
500 | * update for m_visibleItems and m_visibleCells. The cell-information |
501 | * for the new index will not be updated and be initialized as empty cell. |
502 | */ |
503 | void setWidgetIndex(KItemListWidget* widget, int index); |
504 | |
505 | /** |
506 | * Changes the index of the widget to \a index. In opposite to |
507 | * setWidgetIndex() the cell-information for the widget gets updated. |
508 | * This update gives doLayout() the chance to animate the moving |
509 | * of the item visually (see moveWidget()). |
510 | */ |
511 | void moveWidgetToIndex(KItemListWidget* widget, int index); |
512 | |
513 | /** |
514 | * Helper method for prepareLayoutForIncreasedItemCount(). |
515 | */ |
516 | void setLayouterSize(const QSizeF& size, SizeType sizeType); |
517 | |
518 | /** |
519 | * Helper method for createWidget() and setWidgetIndex() to update the properties |
520 | * of the itemlist widget. |
521 | */ |
522 | void updateWidgetProperties(KItemListWidget* widget, int index); |
523 | |
524 | /** |
525 | * Helper method for updateWidgetPropertes() to create or update |
526 | * the itemlist group-header. |
527 | */ |
528 | void (KItemListWidget* widget); |
529 | |
530 | /** |
531 | * Updates the position and size of the group-header that belongs |
532 | * to the itemlist widget \a widget. The given widget must represent |
533 | * the first item of a group. |
534 | */ |
535 | void (KItemListWidget* widget); |
536 | |
537 | /** |
538 | * Recycles the group-header for the widget. |
539 | */ |
540 | void (KItemListWidget* widget); |
541 | |
542 | /** |
543 | * Helper method for slotGroupedSortingChanged(), slotSortOrderChanged() |
544 | * and slotSortRoleChanged(): Iterates through all visible items and updates |
545 | * the group-header widgets. |
546 | */ |
547 | void (); |
548 | |
549 | /** |
550 | * @return Index for the item in the list returned by KItemModelBase::groups() |
551 | * that represents the group where the item with the index \a index |
552 | * belongs to. -1 is returned if no groups are available. |
553 | */ |
554 | int groupIndexForItem(int index) const; |
555 | |
556 | /** |
557 | * Updates the alternate background for all visible items. |
558 | * @see updateAlternateBackgroundForWidget() |
559 | */ |
560 | void updateAlternateBackgrounds(); |
561 | |
562 | /** |
563 | * Updates the alternateBackground-property of the widget dependent |
564 | * on the state of useAlternateBackgrounds() and the grouping state. |
565 | */ |
566 | void updateAlternateBackgroundForWidget(KItemListWidget* widget); |
567 | |
568 | /** |
569 | * @return True if alternate backgrounds should be used for the items. |
570 | * This is the case if an empty item-size is given and if there |
571 | * is more than one visible role. |
572 | */ |
573 | bool useAlternateBackgrounds() const; |
574 | |
575 | /** |
576 | * @param itemRanges Items that must be checked for getting the widths of columns. |
577 | * @return The preferred width of the column of each visible role. The width will |
578 | * be respected if the width of the item size is <= 0 (see |
579 | * KItemListView::setItemSize()). Per default an empty hash |
580 | * is returned. |
581 | */ |
582 | QHash<QByteArray, qreal> preferredColumnWidths(const KItemRangeList& itemRanges) const; |
583 | |
584 | /** |
585 | * Applies the column-widths from m_headerWidget to the layout |
586 | * of the view. |
587 | */ |
588 | void applyColumnWidthsFromHeader(); |
589 | |
590 | /** |
591 | * Applies the column-widths from m_headerWidget to \a widget. |
592 | */ |
593 | void updateWidgetColumnWidths(KItemListWidget* widget); |
594 | |
595 | /** |
596 | * Updates the preferred column-widths of m_groupHeaderWidget by |
597 | * invoking KItemListView::columnWidths(). |
598 | */ |
599 | void updatePreferredColumnWidths(const KItemRangeList& itemRanges); |
600 | |
601 | /** |
602 | * Convenience method for |
603 | * updatePreferredColumnWidths(KItemRangeList() << KItemRange(0, m_model->count()). |
604 | */ |
605 | void updatePreferredColumnWidths(); |
606 | |
607 | /** |
608 | * Resizes the column-widths of m_headerWidget based on the preferred widths |
609 | * and the vailable view-size. |
610 | */ |
611 | void applyAutomaticColumnWidths(); |
612 | |
613 | /** |
614 | * @return Sum of the widths of all columns. |
615 | */ |
616 | qreal columnWidthsSum() const; |
617 | |
618 | /** |
619 | * @return Boundaries of the header. An empty rectangle is returned |
620 | * if no header is shown. |
621 | */ |
622 | QRectF () const; |
623 | |
624 | /** |
625 | * @return True if the number of columns or rows will be changed when applying |
626 | * the new grid- and item-size. Used to determine whether an animation |
627 | * should be done when applying the new layout. |
628 | */ |
629 | bool changesItemGridLayout(const QSizeF& newGridSize, |
630 | const QSizeF& newItemSize, |
631 | const QSizeF& newItemMargin) const; |
632 | |
633 | /** |
634 | * @param changedItemCount Number of inserted or removed items. |
635 | * @return True if the inserting or removing of items should be animated. |
636 | * No animation should be done if the number of items is too large |
637 | * to provide a pleasant animation. |
638 | */ |
639 | bool animateChangedItemCount(int changedItemCount) const; |
640 | |
641 | /** |
642 | * @return True if a scrollbar for the given scroll-orientation is required |
643 | * when using a size of \p size for the view. Calling the method is rather |
644 | * expansive as a temporary relayout needs to be done. |
645 | */ |
646 | bool scrollBarRequired(const QSizeF& size) const; |
647 | |
648 | /** |
649 | * Shows a drop-indicator between items dependent on the given |
650 | * cursor position. The cursor position is relative the the upper left |
651 | * edge of the view. |
652 | * @return Index of the item where the dropping is done. An index of -1 |
653 | * indicates that the item has been dropped after the last item. |
654 | */ |
655 | int showDropIndicator(const QPointF& pos); |
656 | void hideDropIndicator(); |
657 | |
658 | /** |
659 | * Applies the height of the group header to the layouter. The height |
660 | * depends on the used scroll orientation. |
661 | */ |
662 | void (); |
663 | |
664 | /** |
665 | * Updates the siblings-information for all visible items that are inside |
666 | * the range of \p firstIndex and \p lastIndex. If firstIndex or lastIndex |
667 | * is smaller than 0, the siblings-information for all visible items gets |
668 | * updated. |
669 | * @see KItemListWidget::setSiblingsInformation() |
670 | */ |
671 | void updateSiblingsInformation(int firstIndex = -1, int lastIndex = -1); |
672 | |
673 | /** |
674 | * Helper method for updateExpansionIndicators(). |
675 | * @return True if the item with the index \a index has a sibling successor |
676 | * (= the item is not the last item of the current hierarchy). |
677 | */ |
678 | bool hasSiblingSuccessor(int index) const; |
679 | |
680 | /** |
681 | * Helper method for slotRoleEditingCanceled() and slotRoleEditingFinished(). |
682 | * Disconnects the two Signals "roleEditingCanceled" and |
683 | * "roleEditingFinished" |
684 | */ |
685 | void disconnectRoleEditingSignals(int index); |
686 | |
687 | /** |
688 | * Helper function for triggerAutoScrolling(). |
689 | * @param pos Logical position of the mouse relative to the range. |
690 | * @param range Range of the visible area. |
691 | * @param oldInc Previous increment. Is used to assure that the increment |
692 | * increases only gradually. |
693 | * @return Scroll increment that should be added to the offset(). |
694 | * As soon as \a pos is inside the autoscroll-margin a |
695 | * value != 0 will be returned. |
696 | */ |
697 | static int calculateAutoScrollingIncrement(int pos, int range, int oldInc); |
698 | |
699 | /** |
700 | * Helper functions for changesItemCount(). |
701 | * @return The number of items that fit into the available size by |
702 | * respecting the size of the item and the margin between the items. |
703 | */ |
704 | static int itemsPerSize(qreal size, qreal itemSize, qreal itemMargin); |
705 | |
706 | private: |
707 | bool m_enabledSelectionToggles; |
708 | bool m_grouped; |
709 | bool m_supportsItemExpanding; |
710 | bool m_editingRole; |
711 | int m_activeTransactions; // Counter for beginTransaction()/endTransaction() |
712 | LayoutAnimationHint m_endTransactionAnimationHint; |
713 | |
714 | QSizeF m_itemSize; |
715 | KItemListController* m_controller; |
716 | KItemModelBase* m_model; |
717 | QList<QByteArray> m_visibleRoles; |
718 | mutable KItemListWidgetCreatorBase* m_widgetCreator; |
719 | mutable KItemListGroupHeaderCreatorBase* ; |
720 | KItemListStyleOption m_styleOption; |
721 | |
722 | QHash<int, KItemListWidget*> m_visibleItems; |
723 | QHash<KItemListWidget*, KItemListGroupHeader*> m_visibleGroups; |
724 | |
725 | struct Cell |
726 | { |
727 | Cell() : column(-1), row(-1) {} |
728 | Cell(int c, int r) : column(c), row(r) {} |
729 | int column; |
730 | int row; |
731 | }; |
732 | QHash<int, Cell> m_visibleCells; |
733 | |
734 | int m_scrollBarExtent; |
735 | KItemListSizeHintResolver* m_sizeHintResolver; |
736 | KItemListViewLayouter* m_layouter; |
737 | KItemListViewAnimation* m_animation; |
738 | |
739 | QTimer* m_layoutTimer; // Triggers an asynchronous doLayout() call. |
740 | qreal m_oldScrollOffset; |
741 | qreal m_oldMaximumScrollOffset; |
742 | qreal m_oldItemOffset; |
743 | qreal m_oldMaximumItemOffset; |
744 | |
745 | bool m_skipAutoScrollForRubberBand; |
746 | KItemListRubberBand* m_rubberBand; |
747 | |
748 | QPointF m_mousePos; |
749 | int m_autoScrollIncrement; |
750 | QTimer* m_autoScrollTimer; |
751 | |
752 | KItemListHeader* ; |
753 | KItemListHeaderWidget* ; |
754 | |
755 | // When dragging items into the view where the sort-role of the model |
756 | // is empty, a visual indicator should be shown during dragging where |
757 | // the dropping will happen. This indicator is specified by an index |
758 | // of the item. -1 means that no indicator will be shown at all. |
759 | // The m_dropIndicator is set by the KItemListController |
760 | // by KItemListView::showDropIndicator() and KItemListView::hideDropIndicator(). |
761 | QRectF m_dropIndicator; |
762 | |
763 | friend class KItemListContainer; // Accesses scrollBarRequired() |
764 | friend class KItemListHeader; // Accesses m_headerWidget |
765 | friend class KItemListController; |
766 | friend class KItemListControllerTest; |
767 | friend class KItemListViewAccessible; |
768 | friend class KItemListAccessibleCell; |
769 | }; |
770 | |
771 | /** |
772 | * Allows to do a fast logical creation and deletion of QGraphicsWidgets |
773 | * by recycling existing QGraphicsWidgets instances. Is used by |
774 | * KItemListWidgetCreatorBase and KItemListGroupHeaderCreatorBase. |
775 | * @internal |
776 | */ |
777 | class LIBDOLPHINPRIVATE_EXPORT KItemListCreatorBase |
778 | { |
779 | public: |
780 | virtual ~KItemListCreatorBase(); |
781 | |
782 | protected: |
783 | void addCreatedWidget(QGraphicsWidget* widget); |
784 | void pushRecycleableWidget(QGraphicsWidget* widget); |
785 | QGraphicsWidget* popRecycleableWidget(); |
786 | |
787 | private: |
788 | QSet<QGraphicsWidget*> m_createdWidgets; |
789 | QList<QGraphicsWidget*> m_recycleableWidgets; |
790 | }; |
791 | |
792 | /** |
793 | * @brief Base class for creating KItemListWidgets. |
794 | * |
795 | * It is recommended that applications simply use the KItemListWidgetCreator-template class. |
796 | * For a custom implementation the methods create(), itemSizeHint() and preferredColumnWith() |
797 | * must be reimplemented. The intention of the widget creator is to prevent repetitive and |
798 | * expensive instantiations and deletions of KItemListWidgets by recycling existing widget |
799 | * instances. |
800 | */ |
801 | class LIBDOLPHINPRIVATE_EXPORT KItemListWidgetCreatorBase : public KItemListCreatorBase |
802 | { |
803 | public: |
804 | virtual ~KItemListWidgetCreatorBase(); |
805 | |
806 | virtual KItemListWidget* create(KItemListView* view) = 0; |
807 | |
808 | virtual void recycle(KItemListWidget* widget); |
809 | |
810 | virtual void calculateItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const = 0; |
811 | |
812 | virtual qreal preferredRoleColumnWidth(const QByteArray& role, |
813 | int index, |
814 | const KItemListView* view) const = 0; |
815 | }; |
816 | |
817 | /** |
818 | * @brief Template class for creating KItemListWidgets. |
819 | */ |
820 | template <class T> |
821 | class KItemListWidgetCreator : public KItemListWidgetCreatorBase |
822 | { |
823 | public: |
824 | KItemListWidgetCreator(); |
825 | virtual ~KItemListWidgetCreator(); |
826 | |
827 | virtual KItemListWidget* create(KItemListView* view); |
828 | |
829 | virtual void calculateItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const; |
830 | |
831 | virtual qreal preferredRoleColumnWidth(const QByteArray& role, |
832 | int index, |
833 | const KItemListView* view) const; |
834 | private: |
835 | KItemListWidgetInformant* m_informant; |
836 | }; |
837 | |
838 | template <class T> |
839 | KItemListWidgetCreator<T>::KItemListWidgetCreator() : |
840 | m_informant(T::createInformant()) |
841 | { |
842 | } |
843 | |
844 | template <class T> |
845 | KItemListWidgetCreator<T>::~KItemListWidgetCreator() |
846 | { |
847 | delete m_informant; |
848 | } |
849 | |
850 | template <class T> |
851 | KItemListWidget* KItemListWidgetCreator<T>::create(KItemListView* view) |
852 | { |
853 | KItemListWidget* widget = static_cast<KItemListWidget*>(popRecycleableWidget()); |
854 | if (!widget) { |
855 | widget = new T(m_informant, view); |
856 | addCreatedWidget(widget); |
857 | } |
858 | return widget; |
859 | } |
860 | |
861 | template<class T> |
862 | void KItemListWidgetCreator<T>::calculateItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const |
863 | { |
864 | return m_informant->calculateItemSizeHints(logicalHeightHints, logicalWidthHint, view); |
865 | } |
866 | |
867 | template<class T> |
868 | qreal KItemListWidgetCreator<T>::preferredRoleColumnWidth(const QByteArray& role, |
869 | int index, |
870 | const KItemListView* view) const |
871 | { |
872 | return m_informant->preferredRoleColumnWidth(role, index, view); |
873 | } |
874 | |
875 | /** |
876 | * @brief Base class for creating KItemListGroupHeaders. |
877 | * |
878 | * It is recommended that applications simply use the KItemListGroupHeaderCreator-template class. |
879 | * For a custom implementation the methods create() and recyle() must be reimplemented. |
880 | * The intention of the group-header creator is to prevent repetitive and expensive instantiations and |
881 | * deletions of KItemListGroupHeaders by recycling existing header instances. |
882 | */ |
883 | class LIBDOLPHINPRIVATE_EXPORT : public KItemListCreatorBase |
884 | { |
885 | public: |
886 | virtual (); |
887 | virtual KItemListGroupHeader* (KItemListView* view) = 0; |
888 | virtual void (KItemListGroupHeader* ); |
889 | }; |
890 | |
891 | template <class T> |
892 | class : public KItemListGroupHeaderCreatorBase |
893 | { |
894 | public: |
895 | virtual ~KItemListGroupHeaderCreator(); |
896 | virtual KItemListGroupHeader* create(KItemListView* view); |
897 | }; |
898 | |
899 | template <class T> |
900 | KItemListGroupHeaderCreator<T>::() |
901 | { |
902 | } |
903 | |
904 | template <class T> |
905 | KItemListGroupHeader* KItemListGroupHeaderCreator<T>::(KItemListView* view) |
906 | { |
907 | KItemListGroupHeader* widget = static_cast<KItemListGroupHeader*>(popRecycleableWidget()); |
908 | if (!widget) { |
909 | widget = new T(view); |
910 | addCreatedWidget(widget); |
911 | } |
912 | return widget; |
913 | } |
914 | |
915 | #endif |
916 | |