/* * SPDX-FileCopyrightText: 2011 Peter Penz * * Based on the Itemviews NG project from Trolltech Labs * * SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef KITEMLISTVIEW_H #define KITEMLISTVIEW_H #include #include "dolphin_export.h" #include "kitemviews/kitemliststyleoption.h" #include "kitemviews/kitemlistwidget.h" #include "kitemviews/kitemmodelbase.h" #include "kitemviews/kstandarditemlistgroupheader.h" #include "kitemviews/private/kitemlistviewanimation.h" #include #include class KItemListContainer; class KItemListContainerAccessible; class KItemListController; class KItemListGroupHeaderCreatorBase; class KItemListHeader; class KItemListHeaderWidget; class KItemListSizeHintResolver; class KItemListRubberBand; class KItemListViewAnimation; class KItemListViewLayouter; class KItemListWidget; class KItemListWidgetInformant; class KItemListWidgetCreatorBase; class QTimer; class QPropertyAnimation; class QVariantAnimation; /** * @brief Represents the view of an item-list. * * The view is responsible for showing the items of the model within * a GraphicsItem. Each visible item is represented by a KItemListWidget. * * The created view must be applied to the KItemListController with * KItemListController::setView() or with the constructor of * KItemListController. * * @see KItemListWidget * @see KItemModelBase */ class DOLPHIN_EXPORT KItemListView : public QGraphicsWidget { Q_OBJECT Q_PROPERTY(qreal scrollOffset READ scrollOffset WRITE setScrollOffset NOTIFY scrollOffsetChanged) Q_PROPERTY(qreal itemOffset READ itemOffset WRITE setItemOffset NOTIFY itemOffsetChanged) public: /** The position in the view to which an item should be scrolled to. */ enum ViewItemPosition { Beginning, Middle, End, Nearest }; explicit KItemListView(QGraphicsWidget *parent = nullptr); ~KItemListView() override; /** * Offset of the scrollbar that represents the scroll-orientation * (see setScrollOrientation()). */ void setScrollOffset(qreal offset); qreal scrollOffset() const; qreal maximumScrollOffset() const; /** * Offset related to an item, that does not fit into the available * size of the listview. If the scroll-orientation is vertical * the item-offset describes the offset of the horizontal axe, if * the scroll-orientation is horizontal the item-offset describes * the offset of the vertical axe. */ void setItemOffset(qreal scrollOffset); qreal itemOffset() const; qreal maximumItemOffset() const; int maximumVisibleItems() const; void setVisibleRoles(const QList &roles); QList visibleRoles() const; /** * If set to true an automatic scrolling is done as soon as the * mouse is moved near the borders of the view. Per default * the automatic scrolling is turned off. */ void setAutoScroll(bool enabled); bool autoScroll() const; /** * If set to true selection-toggles will be shown when hovering * an item. Per default the selection-toggles are disabled. */ void setEnabledSelectionToggles(bool enabled); bool enabledSelectionToggles() const; /** * @return Controller of the item-list. The controller gets * initialized by KItemListController::setView() and will * result in calling KItemListController::onControllerChanged(). */ KItemListController *controller() const; /** * @return Model of the item-list. The model gets * initialized by KItemListController::setModel() and will * result in calling KItemListController::onModelChanged(). */ KItemModelBase *model() const; /** * Sets the creator that creates a widget showing the * content of one model-item. Usually it is sufficient * to implement a custom widget X derived from KItemListWidget and * set the creator by: * * itemListView->setWidgetCreator(new KItemListWidgetCreator()); * * The ownership of the widget creator is transferred to * the item-list view. **/ void setWidgetCreator(KItemListWidgetCreatorBase *widgetCreator); KItemListWidgetCreatorBase *widgetCreator() const; /** * Sets the creator that creates a group header. Usually it is sufficient * to implement a custom header widget X derived from KItemListGroupHeader and * set the creator by: * * itemListView->setGroupHeaderCreator(new KItemListGroupHeaderCreator()); * * The ownership of the gropup header creator is transferred to * the item-list view. **/ void setGroupHeaderCreator(KItemListGroupHeaderCreatorBase *groupHeaderCreator); KItemListGroupHeaderCreatorBase *groupHeaderCreator() const; #ifndef QT_NO_ACCESSIBILITY /** * Uses \a parent to create an accessible object for \a parent. That accessible object will * then be used as the accessible parent of the accessible object for this KItemListView. * Make sure \a parent is the container which contains this specific KItemListView. * This method must be called once before the accessible interface is queried for this class. */ void setAccessibleParentsObject(KItemListContainer *accessibleParentsObject); /** The parent of the QAccessibilityInterface of this class. */ KItemListContainerAccessible *accessibleParent(); #endif /** * @return The basic size of all items. The size of an item may be larger than * the basic size (see KItemListView::itemRect()). */ QSizeF itemSize() const; const KItemListStyleOption &styleOption() const; void setGeometry(const QRectF &rect) override; /** * @return The page step which should be used by the vertical scroll bar. * This is the height of the view except for the header widget. */ qreal verticalPageStep() const; /** * @return Index of the item that is below the point \a pos. * The position is relative to the upper right of * the visible area. Only (at least partly) visible * items are considered. std::nullopt is returned if * no item is below the position. */ std::optional itemAt(const QPointF &pos) const; bool isAboveSelectionToggle(int index, const QPointF &pos) const; bool isAboveExpansionToggle(int index, const QPointF &pos) const; bool isAboveText(int index, const QPointF &pos) const; /** * @return Index of the first item that is at least partly visible. * -1 is returned if the model contains no items. */ int firstVisibleIndex() const; /** * @return Index of the last item that is at least partly visible. * -1 is returned if the model contains no items. */ int lastVisibleIndex() const; /** * Calculates the required size for all items in the model. * It might be larger than KItemListView::itemSize(). * In this case the layout grid will be stretched to assure an * unclipped item. * * @note the logical height (width) is actually the * width (height) if the scroll orientation is Qt::Vertical! */ void calculateItemSizeHints(QVector> &logicalHeightHints, qreal &logicalWidthHint) const; /** * If set to true, items having child-items can be expanded to show the child-items as * part of the view. Per default the expanding of items is disabled. If expanding of * items is enabled, the methods KItemModelBase::setExpanded(), KItemModelBase::isExpanded(), * KItemModelBase::isExpandable() and KItemModelBase::expandedParentsCount() * must be reimplemented. The view-implementation * has to take care itself how to visually represent the expanded items provided * by the model. */ void setSupportsItemExpanding(bool supportsExpanding); bool supportsItemExpanding() const; void setHighlightEntireRow(bool highlightEntireRow); bool highlightEntireRow() const; void setAlternateBackgrounds(bool alternate); bool alternateBackgrounds() const; /** * @return The rectangle of the item relative to the top/left of * the currently visible area (see KItemListView::offset()). */ QRectF itemRect(int index) const; /** * @return The context rectangle of the item relative to the top/left of * the currently visible area (see KItemListView::offset()). The * context rectangle is defined by the united rectangle of * the icon rectangle and the text rectangle (see KItemListWidget::iconRect() * and KItemListWidget::textRect()) and is useful as reference for e.g. aligning * a tooltip or a context-menu for an item. Note that a context rectangle will * only be returned for (at least partly) visible items. An empty rectangle will * be returned for fully invisible items. */ QRectF itemContextRect(int index) const; /** * @return Whether or not the name of the file has been elided. At present this will * only ever be true when in icons view. */ bool isElided(int index) const; /** * Scrolls to the item with the index \a index so that the item * will be fully visible. The item is positioned within the view * as specified by \a viewItemPosition. */ void scrollToItem(int index, ViewItemPosition viewItemPosition = ViewItemPosition::Nearest); /** * If several properties of KItemListView are changed synchronously, it is * recommended to encapsulate the calls between beginTransaction() and endTransaction(). * This prevents unnecessary and expensive layout-calculations. */ void beginTransaction(); /** * Counterpart to beginTransaction(). The layout changes will only be animated if * all property changes between beginTransaction() and endTransaction() support * animations. */ void endTransaction(); bool isTransactionActive() const; /** * Turns on the header if \p visible is true. Per default the * header is not visible. Usually the header is turned on when * showing a classic "table-view" to describe the shown columns. */ void setHeaderVisible(bool visible); bool isHeaderVisible() const; /** * @return Header of the list. The header is also available if it is not shown * (see KItemListView::setHeaderShown()). */ KItemListHeader *header() const; /** * @return Pixmap that is used for a drag operation based on the * items given by \a indexes. */ virtual QPixmap createDragPixmap(const KItemSet &indexes) const; /** * Lets the user edit the role \a role for item with the index \a index. */ void editRole(int index, const QByteArray &role); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; Q_SIGNALS: void scrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous); void scrollOffsetChanged(qreal current, qreal previous); void maximumScrollOffsetChanged(qreal current, qreal previous); void itemOffsetChanged(qreal current, qreal previous); void maximumItemOffsetChanged(qreal current, qreal previous); void scrollTo(qreal newOffset); /** * Is emitted if the user has changed the sort order by clicking on a * header item (see KItemListView::setHeaderShown()). The sort order * of the model has already been adjusted to * the current sort order. Note that no signal will be emitted if the * sort order of the model has been changed without user interaction. */ void sortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); /** * Is emitted if the user has changed the sort role by clicking on a * header item (see KItemListView::setHeaderShown()). The sort role * of the model has already been adjusted to * the current sort role. Note that no signal will be emitted if the * sort role of the model has been changed without user interaction. */ void sortRoleChanged(const QByteArray ¤t, const QByteArray &previous); /** * Is emitted if the user has changed the visible roles by moving a header * item (see KItemListView::setHeaderShown()). Note that no signal will be * emitted if the roles have been changed without user interaction by * KItemListView::setVisibleRoles(). */ void visibleRolesChanged(const QList ¤t, const QList &previous); void roleEditingCanceled(int index, const QByteArray &role, const QVariant &value); void roleEditingFinished(int index, const QByteArray &role, const QVariant &value); /** * Emitted once scrolling has finished, or immediately if no scrolling was necessary * to get item in view in scrollToItem. */ void scrollingStopped(); void columnHovered(int roleIndex); void columnUnHovered(int roleIndex); protected: QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; void setItemSize(const QSizeF &size); void setStyleOption(const KItemListStyleOption &option); /** * If the scroll-orientation is vertical, the items are ordered * from top to bottom (= default setting). If the scroll-orientation * is horizontal, the items are ordered from left to right. */ void setScrollOrientation(Qt::Orientation orientation); Qt::Orientation scrollOrientation() const; /** * Factory method for creating a default widget-creator. The method will be used * in case if setWidgetCreator() has not been set by the application. * @return New instance of the widget-creator that should be used per * default. */ virtual KItemListWidgetCreatorBase *defaultWidgetCreator() const; /** * Factory method for creating a default group-header-creator. The method will be used * in case if setGroupHeaderCreator() has not been set by the application. * @return New instance of the group-header-creator that should be used per * default. */ virtual KItemListGroupHeaderCreatorBase *defaultGroupHeaderCreator() const; /** * Is called when creating a new KItemListWidget instance and allows derived * classes to do a custom initialization. */ virtual void initializeItemListWidget(KItemListWidget *item); /** * @return True if at least one of the changed roles \p changedRoles might result * in the need to update the item-size hint (see KItemListView::itemSizeHint()). * Per default true is returned which means on each role-change of existing items * the item-size hints are recalculated. For performance reasons it is recommended * to return false in case if a role-change will not result in a changed * item-size hint. */ virtual bool itemSizeHintUpdateRequired(const QSet &changedRoles) const; virtual void onControllerChanged(KItemListController *current, KItemListController *previous); virtual void onModelChanged(KItemModelBase *current, KItemModelBase *previous); virtual void onScrollOrientationChanged(Qt::Orientation current, Qt::Orientation previous); virtual void onItemSizeChanged(const QSizeF ¤t, const QSizeF &previous); virtual void onScrollOffsetChanged(qreal current, qreal previous); virtual void onVisibleRolesChanged(const QList ¤t, const QList &previous); virtual void onStyleOptionChanged(const KItemListStyleOption ¤t, const KItemListStyleOption &previous); virtual void onHighlightEntireRowChanged(bool highlightEntireRow); virtual void onSupportsItemExpandingChanged(bool supportsExpanding); virtual void onTransactionBegin(); virtual void onTransactionEnd(); bool event(QEvent *event) override; void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void dragEnterEvent(QGraphicsSceneDragDropEvent *event) override; void dragMoveEvent(QGraphicsSceneDragDropEvent *event) override; void dragLeaveEvent(QGraphicsSceneDragDropEvent *event) override; void dropEvent(QGraphicsSceneDragDropEvent *event) override; QList visibleItemListWidgets() const; virtual void updateFont(); virtual void updatePalette(); protected Q_SLOTS: virtual void slotItemsInserted(const KItemRangeList &itemRanges); virtual void slotItemsRemoved(const KItemRangeList &itemRanges); virtual void slotItemsMoved(const KItemRange &itemRange, const QList &movedToIndexes); virtual void slotItemsChanged(const KItemRangeList &itemRanges, const QSet &roles); virtual void slotGroupsChanged(); virtual void slotGroupedSortingChanged(bool current); virtual void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); virtual void slotSortRoleChanged(const QByteArray ¤t, const QByteArray &previous); virtual void slotCurrentChanged(int current, int previous); virtual void slotSelectionChanged(const KItemSet ¤t, const KItemSet &previous); private Q_SLOTS: void slotAnimationFinished(QGraphicsWidget *widget, KItemListViewAnimation::AnimationType type); void slotRubberBandPosChanged(); void slotRubberBandActivationChanged(bool active); /** * Is invoked if the column-width of one role in the header has * been changed by the user. The automatic resizing of columns * will be turned off as soon as this method has been called at * least once. */ void slotHeaderColumnWidthChanged(const QByteArray &role, qreal currentWidth, qreal previousWidth); void slotSidePaddingChanged(qreal width); /** * Is invoked if a column has been moved by the user. Applies * the moved role to the view. */ void slotHeaderColumnMoved(const QByteArray &role, int currentIndex, int previousIndex); /** * Triggers the autoscrolling if autoScroll() is enabled by checking the * current mouse position. If the mouse position is within the autoscroll * margins a timer will be started that periodically triggers the autoscrolling. */ void triggerAutoScrolling(); /** * Is invoked if the geometry of the parent-widget from a group-header has been * changed. The x-position and width of the group-header gets adjusted to assure * that it always spans the whole width even during temporary transitions of the * parent widget. */ void slotGeometryOfGroupHeaderParentChanged(); void slotRoleEditingCanceled(int index, const QByteArray &role, const QVariant &value); void slotRoleEditingFinished(int index, const QByteArray &role, const QVariant &value); private: enum LayoutAnimationHint { NoAnimation, Animation }; enum SizeType { LayouterSize, ItemSize }; void setController(KItemListController *controller); void setModel(KItemModelBase *model); KItemListRubberBand *rubberBand() const; void doLayout(LayoutAnimationHint hint, int changedIndex = 0, int changedCount = 0); /** * Helper method for doLayout: Returns a list of items that can be reused for the visible * area. Invisible group headers get recycled. The reusable items are items that are * invisible. If the animation hint is 'Animation' then items that are currently animated * won't be reused. Reusing items is faster in comparison to deleting invisible * items and creating a new instance for visible items. */ QList recycleInvisibleItems(int firstVisibleIndex, int lastVisibleIndex, LayoutAnimationHint hint); /** * Helper method for doLayout: Starts a moving-animation for the widget to the given * new position. The moving-animation is only started if the new position is within * the same row or column, otherwise the create-animation is used instead. * @return True if the moving-animation has been applied. */ bool moveWidget(KItemListWidget *widget, const QPointF &newPos); void emitOffsetChanges(); KItemListWidget *createWidget(int index); void recycleWidget(KItemListWidget *widget); /** * Changes the index of the widget to \a index and assures a consistent * update for m_visibleItems and m_visibleCells. The cell-information * for the new index will not be updated and be initialized as empty cell. */ void setWidgetIndex(KItemListWidget *widget, int index); /** * Changes the index of the widget to \a index. In opposite to * setWidgetIndex() the cell-information for the widget gets updated. * This update gives doLayout() the chance to animate the moving * of the item visually (see moveWidget()). */ void moveWidgetToIndex(KItemListWidget *widget, int index); /** * Helper method for prepareLayoutForIncreasedItemCount(). */ void setLayouterSize(const QSizeF &size, SizeType sizeType); /** * Helper method for createWidget() and setWidgetIndex() to update the properties * of the itemlist widget. */ void updateWidgetProperties(KItemListWidget *widget, int index); /** * Helper method for updateWidgetPropertes() to create or update * the itemlist group-header. */ void updateGroupHeaderForWidget(KItemListWidget *widget); /** * Updates the position and size of the group-header that belongs * to the itemlist widget \a widget. The given widget must represent * the first item of a group. */ void updateGroupHeaderLayout(KItemListWidget *widget); /** * Recycles the group-header for the widget. */ void recycleGroupHeaderForWidget(KItemListWidget *widget); /** * Helper method for slotGroupedSortingChanged(), slotSortOrderChanged() * and slotSortRoleChanged(): Iterates through all visible items and updates * the group-header widgets. */ void updateVisibleGroupHeaders(); /** * @return Index for the item in the list returned by KItemModelBase::groups() * that represents the group where the item with the index \a index * belongs to. -1 is returned if no groups are available. */ int groupIndexForItem(int index) const; /** * Updates the alternate background for all visible items. * @see updateAlternateBackgroundForWidget() */ void updateAlternateBackgrounds(); /** * Updates the alternateBackground-property of the widget dependent * on the state of useAlternateBackgrounds() and the grouping state. */ void updateAlternateBackgroundForWidget(KItemListWidget *widget); /** * @return True if alternate backgrounds should be used for the items. * This is the case if an empty item-size is given and if there * is more than one visible role. */ bool useAlternateBackgrounds() const; /** * @param itemRanges Items that must be checked for getting the widths of columns. * @return The preferred width of the column of each visible role. The width will * be respected if the width of the item size is <= 0 (see * KItemListView::setItemSize()). Per default an empty hash * is returned. */ QHash preferredColumnWidths(const KItemRangeList &itemRanges) const; /** * Applies the column-widths from m_headerWidget to the layout * of the view. */ void applyColumnWidthsFromHeader(); /** * Applies the column-widths from m_headerWidget to \a widget. */ void updateWidgetColumnWidths(KItemListWidget *widget); /** * Updates the preferred column-widths of m_groupHeaderWidget by * invoking KItemListView::columnWidths(). */ void updatePreferredColumnWidths(const KItemRangeList &itemRanges); /** * Convenience method for * updatePreferredColumnWidths(KItemRangeList() << KItemRange(0, m_model->count()). */ void updatePreferredColumnWidths(); /** * Resizes the column-widths of m_headerWidget based on the preferred widths * and the available view-size. */ void applyAutomaticColumnWidths(); /** * @return Sum of the widths of all columns. */ qreal columnWidthsSum() const; /** * @return Boundaries of the header. An empty rectangle is returned * if no header is shown. */ QRectF headerBoundaries() const; /** * @return True if the number of columns or rows will be changed when applying * the new grid- and item-size. Used to determine whether an animation * should be done when applying the new layout. */ bool changesItemGridLayout(const QSizeF &newGridSize, const QSizeF &newItemSize, const QSizeF &newItemMargin) const; /** * @param changedItemCount Number of inserted or removed items. * @return True if the inserting or removing of items should be animated. * No animation should be done if the number of items is too large * to provide a pleasant animation. */ bool animateChangedItemCount(int changedItemCount) const; /** * @return True if a scrollbar for the given scroll-orientation is required * when using a size of \p size for the view. Calling the method is rather * expansive as a temporary relayout needs to be done. */ bool scrollBarRequired(const QSizeF &size) const; /** * Shows a drop-indicator between items dependent on the given * cursor position. The cursor position is relative to the upper left * edge of the view. * @return Index of the item where the dropping is done. An index of -1 * indicates that the item has been dropped after the last item. */ int showDropIndicator(const QPointF &pos); void hideDropIndicator(); /** * Applies the height of the group header to the layouter. The height * depends on the used scroll orientation. */ void updateGroupHeaderHeight(); /** * Updates the siblings-information for all visible items that are inside * the range of \p firstIndex and \p lastIndex. If firstIndex or lastIndex * is smaller than 0, the siblings-information for all visible items gets * updated. * @see KItemListWidget::setSiblingsInformation() */ void updateSiblingsInformation(int firstIndex = -1, int lastIndex = -1); /** * Helper method for updateExpansionIndicators(). * @return True if the item with the index \a index has a sibling successor * (= the item is not the last item of the current hierarchy). */ bool hasSiblingSuccessor(int index) const; /** * Helper method for slotRoleEditingCanceled() and slotRoleEditingFinished(). * Disconnects the two Signals "roleEditingCanceled" and * "roleEditingFinished" */ void disconnectRoleEditingSignals(int index); /** * Helper function for triggerAutoScrolling(). * @param pos Logical position of the mouse relative to the range. * @param range Range of the visible area. * @param oldInc Previous increment. Is used to assure that the increment * increases only gradually. * @return Scroll increment that should be added to the offset(). * As soon as \a pos is inside the autoscroll-margin a * value != 0 will be returned. */ static int calculateAutoScrollingIncrement(int pos, int range, int oldInc); /** * Helper functions for changesItemCount(). * @return The number of items that fit into the available size by * respecting the size of the item and the margin between the items. */ static int itemsPerSize(qreal size, qreal itemSize, qreal itemMargin); private: bool m_enabledSelectionToggles; bool m_grouped; bool m_highlightEntireRow; bool m_alternateBackgrounds; bool m_supportsItemExpanding; bool m_editingRole; int m_activeTransactions; // Counter for beginTransaction()/endTransaction() LayoutAnimationHint m_endTransactionAnimationHint; QSizeF m_itemSize; KItemListController *m_controller; KItemModelBase *m_model; QList m_visibleRoles; mutable KItemListWidgetCreatorBase *m_widgetCreator; mutable KItemListGroupHeaderCreatorBase *m_groupHeaderCreator; #ifndef QT_NO_ACCESSIBILITY /** The object that will be the parent of this classes QAccessibleInterface. */ KItemListContainerAccessible *m_accessibleParent = nullptr; #endif KItemListStyleOption m_styleOption; QHash m_visibleItems; QHash m_visibleGroups; struct Cell { Cell() : column(-1) , row(-1) { } Cell(int c, int r) : column(c) , row(r) { } int column; int row; }; QHash m_visibleCells; int m_scrollBarExtent; KItemListViewLayouter *m_layouter; KItemListViewAnimation *m_animation; qreal m_oldScrollOffset; qreal m_oldMaximumScrollOffset; qreal m_oldItemOffset; qreal m_oldMaximumItemOffset; bool m_skipAutoScrollForRubberBand; KItemListRubberBand *m_rubberBand; KItemListRubberBand *m_tapAndHoldIndicator; QPointF m_mousePos; int m_autoScrollIncrement; QTimer *m_autoScrollTimer; KItemListHeader *m_header; KItemListHeaderWidget *m_headerWidget; QPropertyAnimation *m_indicatorAnimation; // When dragging items into the view where the sort-role of the model // is empty, a visual indicator should be shown during dragging where // the dropping will happen. This indicator is specified by an index // of the item. -1 means that no indicator will be shown at all. // The m_dropIndicator is set by the KItemListController // by KItemListView::showDropIndicator() and KItemListView::hideDropIndicator(). QRectF m_dropIndicator; QList m_rubberBandAnimations; KItemListSizeHintResolver *m_sizeHintResolver; friend class KItemListContainer; // Accesses scrollBarRequired() friend class KItemListHeader; // Accesses m_headerWidget friend class KItemListController; friend class KItemListControllerTest; friend class KItemListViewAccessible; friend class KItemListDelegateAccessible; }; /** * Allows to do a fast logical creation and deletion of QGraphicsWidgets * by recycling existing QGraphicsWidgets instances. Is used by * KItemListWidgetCreatorBase and KItemListGroupHeaderCreatorBase. * @internal */ class DOLPHIN_EXPORT KItemListCreatorBase { public: virtual ~KItemListCreatorBase(); protected: void addCreatedWidget(QGraphicsWidget *widget); void pushRecycleableWidget(QGraphicsWidget *widget); QGraphicsWidget *popRecycleableWidget(); private: QSet m_createdWidgets; QList m_recycleableWidgets; }; /** * @brief Base class for creating KItemListWidgets. * * It is recommended that applications simply use the KItemListWidgetCreator-template class. * For a custom implementation the methods create(), itemSizeHint() and preferredColumnWith() * must be reimplemented. The intention of the widget creator is to prevent repetitive and * expensive instantiations and deletions of KItemListWidgets by recycling existing widget * instances. */ class DOLPHIN_EXPORT KItemListWidgetCreatorBase : public KItemListCreatorBase { public: ~KItemListWidgetCreatorBase() override; virtual KItemListWidget *create(KItemListView *view) = 0; virtual void recycle(KItemListWidget *widget); virtual void calculateItemSizeHints(QVector> &logicalHeightHints, qreal &logicalWidthHint, const KItemListView *view) const = 0; virtual qreal preferredRoleColumnWidth(const QByteArray &role, int index, const KItemListView *view) const = 0; }; /** * @brief Template class for creating KItemListWidgets. */ template class KItemListWidgetCreator : public KItemListWidgetCreatorBase { public: KItemListWidgetCreator(); ~KItemListWidgetCreator() override; KItemListWidget *create(KItemListView *view) override; void calculateItemSizeHints(QVector> &logicalHeightHints, qreal &logicalWidthHint, const KItemListView *view) const override; qreal preferredRoleColumnWidth(const QByteArray &role, int index, const KItemListView *view) const override; private: KItemListWidgetInformant *m_informant; }; template KItemListWidgetCreator::KItemListWidgetCreator() : m_informant(T::createInformant()) { } template KItemListWidgetCreator::~KItemListWidgetCreator() { delete m_informant; } template KItemListWidget *KItemListWidgetCreator::create(KItemListView *view) { KItemListWidget *widget = static_cast(popRecycleableWidget()); if (!widget) { widget = new T(m_informant, view); addCreatedWidget(widget); } widget->setParentItem(view); return widget; } template void KItemListWidgetCreator::calculateItemSizeHints(QVector> &logicalHeightHints, qreal &logicalWidthHint, const KItemListView *view) const { return m_informant->calculateItemSizeHints(logicalHeightHints, logicalWidthHint, view); } template qreal KItemListWidgetCreator::preferredRoleColumnWidth(const QByteArray &role, int index, const KItemListView *view) const { return m_informant->preferredRoleColumnWidth(role, index, view); } /** * @brief Base class for creating KItemListGroupHeaders. * * It is recommended that applications simply use the KItemListGroupHeaderCreator-template class. * For a custom implementation the methods create() and recycle() must be reimplemented. * The intention of the group-header creator is to prevent repetitive and expensive instantiations and * deletions of KItemListGroupHeaders by recycling existing header instances. */ class DOLPHIN_EXPORT KItemListGroupHeaderCreatorBase : public KItemListCreatorBase { public: ~KItemListGroupHeaderCreatorBase() override; virtual KItemListGroupHeader *create(KItemListView *view) = 0; virtual void recycle(KItemListGroupHeader *header); }; template class KItemListGroupHeaderCreator : public KItemListGroupHeaderCreatorBase { public: ~KItemListGroupHeaderCreator() override; KItemListGroupHeader *create(KItemListView *view) override; }; template KItemListGroupHeaderCreator::~KItemListGroupHeaderCreator() { } template KItemListGroupHeader *KItemListGroupHeaderCreator::create(KItemListView *view) { KItemListGroupHeader *widget = static_cast(popRecycleableWidget()); if (!widget) { widget = new T(view); addCreatedWidget(widget); } return widget; } #endif