File indexing completed on 2025-04-27 03:58:28
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-04-29 0007 * Description : Qt item view for images - delegate additions 0008 * 0009 * SPDX-FileCopyrightText: 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #ifndef DIGIKAM_ITEM_DELEGATE_OVERLAY_H 0016 #define DIGIKAM_ITEM_DELEGATE_OVERLAY_H 0017 0018 // Qt includes 0019 0020 #include <QAbstractItemView> 0021 0022 // Local includes 0023 0024 #include "digikam_export.h" 0025 0026 namespace Digikam 0027 { 0028 0029 class ItemViewHoverButton; 0030 0031 class DIGIKAM_EXPORT ItemDelegateOverlay : public QObject 0032 { 0033 Q_OBJECT 0034 0035 public: 0036 0037 explicit ItemDelegateOverlay(QObject* const parent = nullptr); 0038 ~ItemDelegateOverlay() override; 0039 0040 /** 0041 * Called when the overlay was installed and shall begin working, 0042 * and before it is removed and shall stop. 0043 * Setup your connections to view and delegate here. 0044 * You will be disconnected automatically on removal. 0045 */ 0046 virtual void setActive(bool active); 0047 0048 /** 0049 * Only these two methods are implemented as virtual methods. 0050 * For all other events, connect to the view's signals. 0051 * There are a few signals specifically for overlays and all 0052 * QAbstractItemView standard signals. 0053 */ 0054 virtual void mouseMoved(QMouseEvent* e, const QRect& visualRect, const QModelIndex& index); 0055 virtual void paint(QPainter* p, const QStyleOptionViewItem& option, const QModelIndex& index); 0056 0057 void setView(QAbstractItemView* view); 0058 QAbstractItemView* view() const; 0059 0060 void setDelegate(QAbstractItemDelegate* delegate); 0061 QAbstractItemDelegate* delegate() const; 0062 0063 virtual bool acceptsDelegate(QAbstractItemDelegate*) const { return true; } 0064 0065 Q_SIGNALS: 0066 0067 void update(const QModelIndex& index); 0068 0069 void requestNotification(const QModelIndex& index, const QString& message); 0070 void hideNotification(); 0071 0072 protected Q_SLOTS: 0073 0074 /** 0075 * Called when any change from the delegate occurs - when the overlay is installed, 0076 * when size hints, styles or fonts change 0077 */ 0078 virtual void visualChange(); 0079 0080 protected: 0081 0082 /** 0083 * For the context that an overlay can affect multiple items: 0084 * Assuming the currently overlayed index is given. 0085 * Will an operation affect only the single item, or multiple? 0086 * If multiple, retrieve the affected selection. 0087 */ 0088 bool affectsMultiple(const QModelIndex& index) const; 0089 QList<QModelIndex> affectedIndexes(const QModelIndex& index) const; 0090 int numberOfAffectedIndexes(const QModelIndex& index) const; 0091 0092 /** 0093 * Utility method 0094 */ 0095 bool viewHasMultiSelection() const; 0096 0097 protected: 0098 0099 QAbstractItemView* m_view; 0100 QAbstractItemDelegate* m_delegate; 0101 }; 0102 0103 #define REQUIRE_DELEGATE(Delegate) \ 0104 \ 0105 public: \ 0106 \ 0107 void setDelegate(Delegate* delegate) { ItemDelegateOverlay::setDelegate(delegate); } \ 0108 Delegate* delegate() const { return static_cast<Delegate*>(ItemDelegateOverlay::delegate()); } \ 0109 virtual bool acceptsDelegate(QAbstractItemDelegate*d) const override { return dynamic_cast<Delegate*>(d); } \ 0110 \ 0111 private: 0112 0113 // ------------------------------------------------------------------------------------------- 0114 0115 class DIGIKAM_EXPORT AbstractWidgetDelegateOverlay : public ItemDelegateOverlay 0116 { 0117 Q_OBJECT 0118 0119 public: 0120 0121 /** 0122 * This class provides functionality for using a widget in an overlay. 0123 * You must reimplement at least createWidget to return your widget. 0124 * Per default it will be shown when the cursor enters an index and hidden when left. 0125 * Reimplement slotEntered() and mouseMove() for more fine grained control. 0126 */ 0127 explicit AbstractWidgetDelegateOverlay(QObject* const parent); 0128 0129 /** 0130 * If active is true, this will call createWidget(), initialize the widget for use, 0131 * and setup connections for the virtual slots. 0132 * If active is false, this will delete the widget and 0133 * disconnect all signal from model and view to this object (!) 0134 */ 0135 void setActive(bool active) override; 0136 0137 protected: 0138 0139 /** 0140 * Create your widget here. When creating the object, pass parentWidget() as parent widget. 0141 * Ownership of the object is passed. It will be deleted in setActive(false). 0142 */ 0143 virtual QWidget* createWidget() = 0; 0144 0145 /** 0146 * Called when the widget shall be hidden (mouse cursor left index, viewport, uninstalled etc.). 0147 * Default implementation hide()s m_widget. 0148 */ 0149 virtual void hide(); 0150 0151 /** 0152 * Returns the widget to be used as parent for your widget created in createWidget() 0153 */ 0154 QWidget* parentWidget() const; 0155 0156 /** 0157 * Return true here if you want to show the overlay for the given index. 0158 * The default implementation returns true. 0159 */ 0160 virtual bool checkIndex(const QModelIndex& index) const; 0161 0162 /** 0163 * Called when a QEvent::Leave of the viewport is received. 0164 * The default implementation hide()s. 0165 */ 0166 virtual void viewportLeaveEvent(QObject* obj, QEvent* event); 0167 0168 /** 0169 * Called when a QEvent::Enter resp. QEvent::Leave event for the widget is received. 0170 * The default implementation does nothing. 0171 */ 0172 virtual void widgetEnterEvent(); 0173 virtual void widgetLeaveEvent(); 0174 0175 /** 0176 * A sample implementation for above methods 0177 */ 0178 void widgetEnterNotifyMultiple(const QModelIndex& index); 0179 void widgetLeaveNotifyMultiple(); 0180 virtual QString notifyMultipleMessage(const QModelIndex&, int number); 0181 0182 /** 0183 * Utility method called from slotEntered 0184 */ 0185 bool checkIndexOnEnter(const QModelIndex& index) const; 0186 0187 protected Q_SLOTS: 0188 0189 /** 0190 * Default implementation shows the widget iff the index is valid and checkIndex returns true. 0191 */ 0192 virtual void slotEntered(const QModelIndex& index); 0193 0194 /** 0195 * Default implementations of these three slots call hide() 0196 */ 0197 virtual void slotReset(); 0198 virtual void slotViewportEntered(); 0199 virtual void slotRowsRemoved(const QModelIndex& parent, int start, int end); 0200 virtual void slotLayoutChanged(); 0201 0202 protected: 0203 0204 bool eventFilter(QObject* obj, QEvent* event) override; 0205 0206 protected: 0207 0208 QWidget* m_widget; 0209 0210 bool m_mouseButtonPressedOnWidget; 0211 }; 0212 0213 // ------------------------------------------------------------------------------------------- 0214 0215 class DIGIKAM_EXPORT HoverButtonDelegateOverlay : public AbstractWidgetDelegateOverlay 0216 { 0217 Q_OBJECT 0218 0219 public: 0220 0221 explicit HoverButtonDelegateOverlay(QObject* const parent); 0222 0223 /** 0224 * Will call createButton(). 0225 */ 0226 void setActive(bool active) override; 0227 0228 ItemViewHoverButton* button() const; 0229 0230 protected: 0231 0232 /** 0233 * Create your widget here. Pass view() as parent. 0234 */ 0235 virtual ItemViewHoverButton* createButton() = 0; 0236 0237 /** 0238 * Called when a new index is entered. Reposition your button here, 0239 * adjust and store state. 0240 */ 0241 virtual void updateButton(const QModelIndex& index) = 0; 0242 0243 QWidget* createWidget() override; 0244 void visualChange() override; 0245 0246 protected Q_SLOTS: 0247 0248 void slotEntered(const QModelIndex& index) override; 0249 void slotReset() override; 0250 }; 0251 0252 // ------------------------------------------------------------------------------------------- 0253 0254 class DIGIKAM_EXPORT PersistentWidgetDelegateOverlay : public AbstractWidgetDelegateOverlay 0255 { 0256 Q_OBJECT 0257 0258 /** 0259 * This class offers additional / modified behavior: 0260 * When a "persistent" mode is entered, it will not move 0261 * by mouse hover, but stay and only move on mouse click. 0262 * If the overlay widget had focus, it will be restored on show. 0263 */ 0264 0265 public: 0266 0267 explicit PersistentWidgetDelegateOverlay(QObject* const parent); 0268 ~PersistentWidgetDelegateOverlay() override; 0269 0270 void setActive(bool active) override; 0271 0272 bool isPersistent() const; 0273 0274 public Q_SLOTS: 0275 0276 /** 0277 * Enters persistent mode. 0278 * The overlay is moved because of mouse hover. 0279 */ 0280 void setPersistent(bool persistent); 0281 void enterPersistentMode(); 0282 void leavePersistentMode(); 0283 0284 void storeFocus(); 0285 0286 protected: 0287 0288 QModelIndex index() const; 0289 0290 /** 0291 * Most overlays reimplement this slot to get the starting point 0292 * for repositioning a widget etc. 0293 * This class instead provides showOnIndex() which you shall 0294 * use for this purpose. 0295 */ 0296 void slotEntered(const QModelIndex& index) override; 0297 void slotReset() override; 0298 void slotViewportEntered() override; 0299 void slotRowsRemoved(const QModelIndex& parent, int start, int end) override; 0300 void slotLayoutChanged() override; 0301 void viewportLeaveEvent(QObject* obj, QEvent* event) override; 0302 void hide() override; 0303 0304 /** 0305 * Reimplement to set the focus on the correct subwidget. 0306 * Default implementation sets focus on widget() 0307 */ 0308 virtual void setFocusOnWidget(); 0309 0310 /// see slotEntered() 0311 virtual void showOnIndex(const QModelIndex& index); 0312 0313 void restoreFocus(); 0314 0315 private: 0316 0317 class Private; 0318 Private* const d; 0319 }; 0320 0321 // ------------------------------------------------------------------------------------------- 0322 0323 class DIGIKAM_EXPORT ItemDelegateOverlayContainer 0324 { 0325 public: 0326 0327 /** 0328 * This is a sample implementation for 0329 * delegate management methods, to be inherited by a delegate. 0330 * Does not inherit QObject, the delegate already does. 0331 */ 0332 0333 ItemDelegateOverlayContainer() = default; 0334 virtual ~ItemDelegateOverlayContainer() = default; 0335 0336 QList<ItemDelegateOverlay*> overlays() const; 0337 0338 void installOverlay(ItemDelegateOverlay* overlay); 0339 void removeOverlay(ItemDelegateOverlay* overlay); 0340 void setAllOverlaysActive(bool active); 0341 void setViewOnAllOverlays(QAbstractItemView* view); 0342 void removeAllOverlays(); 0343 void mouseMoved(QMouseEvent* e, const QRect& visualRect, const QModelIndex& index); 0344 0345 /* 0346 /// Provide as signal in the delegate: 0347 void visualChange(); 0348 void requestNotification(const QModelIndex& index, const QString& message); 0349 void hideNotification(); 0350 */ 0351 0352 protected: 0353 0354 virtual void drawOverlays(QPainter* p, const QStyleOptionViewItem& option, const QModelIndex& index) const; 0355 0356 /// Declare as slot in the derived class calling this method 0357 virtual void overlayDestroyed(QObject* o); 0358 0359 /// Returns the delegate, typically, the derived class 0360 virtual QAbstractItemDelegate* asDelegate() = 0; 0361 0362 protected: 0363 0364 QList<ItemDelegateOverlay*> m_overlays; 0365 0366 private: 0367 0368 Q_DISABLE_COPY(ItemDelegateOverlayContainer) 0369 }; 0370 0371 } // namespace Digikam 0372 0373 #endif // DIGIKAM_ITEM_DELEGATE_OVERLAY_H