1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 /***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #ifndef OBSERVABLE_H
17 #define OBSERVABLE_H
18
19 #include "scribusapi.h"
20
21 #include <QObject>
22 #include <QSet>
23 #include <QVariant>
24
25 #include "updatemanager.h"
26
27
28 //#include "observable_private.h"
29 struct SCRIBUS_API Private_Signal : public QObject
30 {
31 Q_OBJECT
32
33 public:
emitSignalPrivate_Signal34 void emitSignal(QObject* what)
35 {
36 emit changedObject(what);
37 }
38
emitSignalPrivate_Signal39 void emitSignal(QVariant what)
40 {
41 emit changedData(what);
42 }
43
connectSignalPrivate_Signal44 bool connectSignal(QObject*, QObject* o, const char* slot)
45 {
46 return QObject::connect(this, SIGNAL(changedObject(QObject*)), o, slot);
47 }
48
disconnectSignalPrivate_Signal49 bool disconnectSignal(QObject*, QObject* o, const char* slot)
50 {
51 return QObject::disconnect(this, SIGNAL(changedObject(QObject*)), o, slot);
52 }
53
connectSignalPrivate_Signal54 bool connectSignal(QVariant, QObject* o, const char* slot)
55 {
56 return QObject::connect(this, SIGNAL(changedData(QVariant)), o, slot);
57 }
58
disconnectSignalPrivate_Signal59 bool disconnectSignal(QVariant, QObject* o, const char* slot)
60 {
61 return QObject::disconnect(this, SIGNAL(changedData(QVariant)), o, slot);
62 }
63
64 signals:
65 void changedObject(QObject* what);
66 void changedData(QVariant what);
67 };
68
69
70
71 template<class OBSERVED>
72 struct Private_Memento : public UpdateMemento
73 {
Private_MementoPrivate_Memento74 Private_Memento(OBSERVED data) : m_data(data), m_layout(false) {}
Private_MementoPrivate_Memento75 Private_Memento(OBSERVED data, bool layout) : m_data(data), m_layout(layout) {}
76
77 OBSERVED m_data;
78 bool m_layout;
79 };
80
81
82
83 /**
84 Implement this interface if you want to observe an observable but don't want to derive from QObject
85 */
86 template<class OBSERVED>
87 class SCRIBUS_API Observer {
88 public:
89 virtual void changed(OBSERVED, bool doLayout) = 0;
~Observer()90 virtual ~Observer() {}
91 };
92
93
94
95
96 /**
97 An MassObservable is basically just the source of a changed() signal.
98 Observers can register via the Qt signal/slot mechanism or via the above interface.
99
100 The difference to Observable (below) is that a MassObservable doesn't report changes to
101 itself but to a bunch of SingleObservables.
102 When you call update() on the SingleObservable, it will tell the associated
103 MassObservable to notify all observers with the "changed" signal,
104 providing a pointer to the single Observable.
105
106 The class parameter OBSERVED is usually a pointer to a subclass of SingleObservable.
107
108 MassObservable does not inherit QObject since that makes it difficult to use it as a mixin class.
109 */
110 template<class OBSERVED>
111 class MassObservable : public UpdateManaged
112 {
113 friend class UpdateManager;
114
115 public:
116 MassObservable(UpdateManager* um = nullptr);
117 virtual ~MassObservable();
118 /**
119 Used if the UpdateManager is not available when the constructor is called
120 */
121 void setUpdateManager(UpdateManager* um);
122
123 /**
124 This method will be called by the SingleObservable.
125 If updates are enabled, it calls updateNow() directly, otherwise the undomanager
126 will take care of that.
127 */
128 virtual void update(OBSERVED what);
129
130 /**
131 Same as update, except layout will be update immediately
132 */
133 virtual void updateLayout(OBSERVED what);
134
135 void connectObserver(Observer<OBSERVED>* o);
136 void disconnectObserver(Observer<OBSERVED>* o);
137
138 bool connectObserver(QObject* o, const char* slot);
139 bool disconnectObserver(QObject* o, const char* slot = 0);
140
141 protected:
142 /**
143 This method will be called by the updatemanager or by update()
144 */
145 virtual void updateNow(UpdateMemento* what);
146
147 QSet<Observer<OBSERVED>*> m_observers;
148 Private_Signal* changedSignal;
149 UpdateManager* m_um;
150 };
151
152
153
154
155 /**
156 This mixin class just provides the update() method.
157 */
158 template<class OBSERVED>
159 class SCRIBUS_API SingleObservable
160 {
161 public:
162 /**
163 Connects this SingleObservale to the MassObservable
164 */
SingleObservable(MassObservable<OBSERVED * > * massObservable)165 SingleObservable(MassObservable<OBSERVED*> * massObservable) : m_massObservable(massObservable) {}
166
~SingleObservable()167 virtual ~SingleObservable() {}
168
setMassObservable(MassObservable<OBSERVED * > * massObservable)169 void setMassObservable(MassObservable<OBSERVED*> * massObservable)
170 {
171 m_massObservable = massObservable;
172 }
173
update()174 virtual void update()
175 {
176 m_massObservable->update(dynamic_cast<OBSERVED*>(this));
177 }
178
updateLayout()179 virtual void updateLayout()
180 {
181 m_massObservable->updateLayout(dynamic_cast<OBSERVED*>(this));
182 }
183
184 private:
185 MassObservable<OBSERVED*>* m_massObservable;
186 };
187
188
189
190
191
192 /**
193 An Observable is basically just the source of a changed() signal.
194 Observers can register via the Qt signal/slot mechanism or via the above interface.
195
196 When you call update(), all observers will receive the "changed" signal with a pointer
197 to the Observable (this).
198
199 Observable is implemented as a MassObservable which.
200
201 The class parameter OBSERVED should be the implementing class.
202 */
203 template<class OBSERVED>
204 class SCRIBUS_API Observable : public MassObservable<OBSERVED*>
205 {
206 public:
207 Observable(UpdateManager* um = nullptr) : MassObservable<OBSERVED*>(um) {}
208
update()209 virtual void update()
210 {
211 MassObservable<OBSERVED*>::update(dynamic_cast<OBSERVED*>(this));
212 }
213 private:
214 using MassObservable<OBSERVED*>::update;
215 };
216
217
218
219 // IMPLEMENTATION
220
221
222
223 template<class OBSERVED>
MassObservable(UpdateManager * um)224 inline MassObservable<OBSERVED>::MassObservable(UpdateManager* um) : m_observers(), changedSignal(new Private_Signal()), m_um(um)
225 {
226 }
227
228 template<class OBSERVED>
~MassObservable()229 inline MassObservable<OBSERVED>::~MassObservable()
230 {
231 m_observers.clear();
232 delete changedSignal;
233 }
234
235
236 template<class OBSERVED>
setUpdateManager(UpdateManager * um)237 inline void MassObservable<OBSERVED>::setUpdateManager(UpdateManager* um)
238 {
239 m_um = um;
240 }
241
242
243 template<class OBSERVED>
update(OBSERVED what)244 inline void MassObservable<OBSERVED>::update(OBSERVED what)
245 {
246 Private_Memento<OBSERVED>* memento = new Private_Memento<OBSERVED>(what);
247 if (m_um == nullptr || m_um->requestUpdate(this, memento))
248 {
249 updateNow(memento);
250 }
251 }
252
253 template<class OBSERVED>
updateLayout(OBSERVED what)254 inline void MassObservable<OBSERVED>::updateLayout(OBSERVED what)
255 {
256 Private_Memento<OBSERVED>* memento = new Private_Memento<OBSERVED>(what, true);
257 if (m_um == nullptr || m_um->requestUpdate(this, memento))
258 updateNow(memento);
259 }
260
261 template<class OBSERVED>
updateNow(UpdateMemento * what)262 inline void MassObservable<OBSERVED>::updateNow(UpdateMemento* what)
263 {
264 Private_Memento<OBSERVED>* memento = dynamic_cast<Private_Memento<OBSERVED>*>(what);
265 if (!memento)
266 qFatal("MassObservable<OBSERVED>::updateNow memento nullptr");
267 foreach (Observer<OBSERVED>* obs, m_observers)
268 obs->changed(memento->m_data, memento->m_layout);
269 changedSignal->emitSignal(QVariant::fromValue(memento->m_data));
270 delete memento;
271 }
272
273
274 template<class OBSERVED>
connectObserver(Observer<OBSERVED> * o)275 inline void MassObservable<OBSERVED>::connectObserver(Observer<OBSERVED>* o)
276 {
277 m_observers.insert(o);
278 }
279
280 template<class OBSERVED>
disconnectObserver(Observer<OBSERVED> * o)281 inline void MassObservable<OBSERVED>::disconnectObserver(Observer<OBSERVED>* o)
282 {
283 m_observers.remove(o);
284 }
285
286
287 template <typename T>
Private_Init(T & dummy)288 inline void Private_Init(T& dummy) {}
289
290 template <>
Private_Init(QObject * & dummy)291 inline void Private_Init(QObject*& dummy)
292 {
293 // dummy->die_compiler_die();
294 dummy = 0;
295 }
296
297
298 template<class OBSERVED>
connectObserver(QObject * o,const char * slot)299 inline bool MassObservable<OBSERVED>::connectObserver(QObject* o, const char* slot)
300 {
301 OBSERVED dummy;
302 Private_Init(dummy);
303 return changedSignal->connectSignal(QVariant::fromValue(dummy), o, slot);
304 }
305
306 template<class OBSERVED>
disconnectObserver(QObject * o,const char * slot)307 inline bool MassObservable<OBSERVED>::disconnectObserver(QObject* o, const char* slot)
308 {
309 OBSERVED dummy;
310 Private_Init(dummy);
311 return changedSignal->disconnectSignal(QVariant::fromValue(dummy), o, slot);
312 }
313
314
315 #endif
316