1 2 #ifndef REFRESHDEFERRER_H 3 #define REFRESHDEFERRER_H 4 5 #include <QObject> 6 7 class CutterDockWidget; 8 class RefreshDeferrer; 9 10 using RefreshDeferrerParams = void *; 11 using RefreshDeferrerParamsResult = void *; 12 13 /** 14 * @brief Abstract class for accumulating params in RefreshDeferrer 15 */ 16 class RefreshDeferrerAccumulator 17 { 18 friend class RefreshDeferrer; 19 20 public: 21 virtual ~RefreshDeferrerAccumulator() = default; 22 23 protected: 24 /** 25 * @brief Add a new param to the accumulator 26 */ 27 virtual void accumulate(RefreshDeferrerParams params) =0; 28 29 /** 30 * @brief Ignore the incoming params. Useful for freeing if necessary. 31 */ 32 virtual void ignoreParams(RefreshDeferrerParams params) =0; 33 34 /** 35 * @brief Clear the current accumulator 36 */ 37 virtual void clear() =0; 38 39 /** 40 * @brief Return the final result of the accumulation 41 */ 42 virtual RefreshDeferrerParamsResult result() =0; 43 }; 44 45 46 /** 47 * @brief Accumulator which simply replaces the current value by an incoming new one 48 * @tparam T The type of the param to store 49 * 50 * This accumulator takes the ownership of all params passed to it and deletes them automatically if not needed anymore! 51 */ 52 template<class T> 53 class ReplacingRefreshDeferrerAccumulator: public RefreshDeferrerAccumulator 54 { 55 private: 56 T *value = nullptr; 57 bool replaceIfNull; 58 59 public: 60 /** 61 * \param Determines whether, if nullptr is passed, the current value should be replaced or kept. 62 */ 63 explicit ReplacingRefreshDeferrerAccumulator(bool replaceIfNull = true) replaceIfNull(replaceIfNull)64 : replaceIfNull(replaceIfNull) {} 65 ~ReplacingRefreshDeferrerAccumulator()66 ~ReplacingRefreshDeferrerAccumulator() override 67 { 68 delete value; 69 } 70 71 protected: accumulate(RefreshDeferrerParams params)72 void accumulate(RefreshDeferrerParams params) override 73 { 74 if (!replaceIfNull && !params) { 75 return; 76 } 77 delete value; 78 value = static_cast<T *>(params); 79 } 80 ignoreParams(RefreshDeferrerParams params)81 void ignoreParams(RefreshDeferrerParams params) override 82 { 83 delete static_cast<T *>(params); 84 } 85 clear()86 void clear() override 87 { 88 delete value; 89 value = nullptr; 90 } 91 result()92 virtual RefreshDeferrerParamsResult result() override 93 { 94 return value; 95 } 96 }; 97 98 /** 99 * @brief Helper class for deferred refreshing in Widgets 100 * 101 * This class can handle the logic necessary to defer the refreshing of widgets when they are not visible. 102 * It contains an optional RefreshDeferrerAccumulator, which can be used to accumulate incoming events while 103 * refreshing is deferred. 104 * 105 * Example (don't write it like this in practice, use the convenience methods in CutterDockWidget): 106 * ``` 107 * // in the constructor of a widget 108 * this->refreshDeferrer = new RefreshDeferrer(new ReplacingRefreshDeferrerAccumulator(false), this); 109 * this->refreshDeferrer->registerFor(this); 110 * connect(this->refreshDeferrer, &RefreshDeferrer::refreshNow, this, [this](MyParam *param) { 111 * // We attempted a refresh some time before, but it got deferred. 112 * // Now the RefreshDeferrer tells us to do the refresh and gives us the accumulated param. 113 * this->doRefresh(*param); 114 * } 115 * 116 * // ... 117 * 118 * void MyWidget::doRefresh(MyParam param) 119 * { 120 * if (!this->refreshDeferrer->attemptRefresh(new MyParam(param))) { 121 * // We shouldn't refresh right now. 122 * // The RefreshDeferrer takes over the param we passed it in attemptRefresh() 123 * // and gives it to the ReplacingRefreshDeferrerAccumulator. 124 * return; 125 * } 126 * // do the actual refresh depending on param 127 * } 128 * ``` 129 * 130 */ 131 class RefreshDeferrer : public QObject 132 { 133 Q_OBJECT 134 135 private: 136 CutterDockWidget *dockWidget = nullptr; 137 RefreshDeferrerAccumulator *acc; 138 bool dirty = false; 139 140 public: 141 /** 142 * @param acc The accumulator (can be nullptr). The RefreshDeferrer takes the ownership! 143 */ 144 explicit RefreshDeferrer(RefreshDeferrerAccumulator *acc, QObject *parent = nullptr); 145 ~RefreshDeferrer() override; 146 147 bool attemptRefresh(RefreshDeferrerParams params); 148 void registerFor(CutterDockWidget *dockWidget); 149 150 signals: 151 void refreshNow(const RefreshDeferrerParamsResult paramsResult); 152 }; 153 154 #endif //REFRESHDEFERRER_H 155