1 /*
2 * %kadu copyright begin%
3 * Copyright 2011 Piotr Galiszewski (piotr.galiszewski@kadu.im)
4 * Copyright 2014 Piotr Dąbrowski (ultr@ultr.pl)
5 * Copyright 2010, 2011, 2014 Bartosz Brachaczek (b.brachaczek@gmail.com)
6 * Copyright 2009, 2010, 2011, 2012, 2013, 2014 Rafał Przemysław Malinowski (rafal.przemyslaw.malinowski@gmail.com)
7 * %kadu copyright end%
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #ifndef SHARED_BASE_H
24 #define SHARED_BASE_H
25
26 #include <QtCore/QExplicitlySharedDataPointer>
27 #include <QtCore/QObject>
28 #include <QtCore/QUuid>
29 #include <QtCore/QVariant>
30
31 #include "storage/custom-properties.h"
32 #include "storage/storable-object.h"
33
34 /**
35 * @addtogroup Storage
36 * @{
37 */
38
39 /**
40 * @author Rafal 'Vogel' Malinowski
41 * @short Declares standard interface for SharedBase class. Use this macro in each SharedBase subclass declaration.
42 * @param className name of defined class
43 *
44 * Declares operators for SharedBase subclass.
45 */
46 #define KaduSharedBaseClass(className)\
47 public:\
48 operator QVariant () const;\
49 \
50 className & operator = (const className ©);\
51 \
52 bool operator == (const className &compare) const\
53 {\
54 return data() == compare.data();\
55 }\
56 \
57 bool operator != (const className &compare) const\
58 {\
59 return data() != compare.data();\
60 }\
61 \
62 bool operator < (const className &compare) const\
63 {\
64 return data() < compare.data();\
65 }\
66 private:
67
68 /**
69 * @author Rafal 'Vogel' Malinowski
70 * @short Defines standard interface for SharedBase class. Use this macro in each SharedBase subclass definition file.
71 * @param className name of defined class
72 *
73 * Defines operators for SharedBase subclass.
74 */
75 #define KaduSharedBaseClassImpl(className)\
76 className::operator QVariant () const\
77 {\
78 return QVariant::fromValue<className>(*this);\
79 }\
80 \
81 className & className::operator = (const className ©)\
82 {\
83 setData(copy.data());\
84 return *this;\
85 }\
86
87
88 /**
89 * @author Rafal 'Vogel' Malinowski
90 * @short Declares getter for given property of SharedBase's Shared class.
91 * @param type type of property
92 * @param name name of getter
93 * @param capitalized_name name of property
94 *
95 * Declares getter for a delegated property of @link Shared @endlink class stored in
96 * @link SharedBase @endlink. Getter is named 'name'.
97 */
98 #define KaduSharedBase_PropertyRead(type, name, capitalized_name) \
99 type name() const;
100
101 /**
102 * @author Rafal 'Vogel' Malinowski
103 * @short Declares setter for given property of StorableObject.
104 * @param type type of property
105 * @param name name of value parameter
106 * @param capitalized_name name of property (setter will be called set##capitalized_name)
107 *
108 * Declares setter for a delegated property of @link Shared @endlink class stored in
109 * @link SharedBase @endlink. Setter is named 'set##capitalized_name'.
110 */
111 #define KaduSharedBase_PropertyWrite(type, name, capitalized_name) \
112 void set##capitalized_name(type name) const;
113
114 /**
115 * @author Rafal 'Vogel' Malinowski
116 * @short Declares getter and setter for given property of SharedBase's Shared class.
117 * @param type type of property
118 * @param name name of getter
119 * @param capitalized_name name of property
120 *
121 * Declares getter and setter for a delegated property of @link Shared @endlink class stored in
122 * @link SharedBase @endlink. Getter is named 'name'. Setter is named 'set##capitalized_name'.
123 */
124 #define KaduSharedBase_Property(type, name, capitalized_name) \
125 KaduSharedBase_PropertyRead(type, name, capitalized_name) \
126 KaduSharedBase_PropertyWrite(type, name, capitalized_name)
127
128 /**
129 * @author Bartosz 'beevvy' Brachaczek
130 * @short Declares getter and setter for given property of SharedBase's Shared class.
131 * @param type type of property
132 * @param name name of getter
133 * @param capitalized_name name of property
134 *
135 * Declares getter and setter for a delegated property of @link Shared @endlink class stored in
136 * @link SharedBase @endlink. Getter is named 'name'. Setter is named 'set##capitalized_name'.
137 * Argument of the setter will be a const reference to 'type'.
138 */
139 #define KaduSharedBase_PropertyCRW(type, name, capitalized_name) \
140 KaduSharedBase_PropertyRead(type, name, capitalized_name) \
141 KaduSharedBase_PropertyWrite(const type &, name, capitalized_name)
142
143 /**
144 * @author Rafal 'Vogel' Malinowski
145 * @short Declares getter for given boolean property of SharedBase's Shared class.
146 * @param capitalized_name name of property
147 *
148 * Declares getter for a boolean delegated property of @link Shared @endlink class stored in
149 * @link SharedBase @endlink. Getter is named 'is##capitalized_name'.
150 */
151 #define KaduSharedBase_PropertyBoolRead(capitalized_name) \
152 bool is##capitalized_name() const;
153
154 /**
155 * @author Rafal 'Vogel' Malinowski
156 * @short Declares setter for given boolean property of StorableObject.
157 * @param capitalized_name name of property (setter will be called set##capitalized_name)
158 *
159 * Declares setter for a delegated boolean property of @link Shared @endlink class stored in
160 * @link SharedBase @endlink. Setter is named 'set##capitalized_name'.
161 */
162 #define KaduSharedBase_PropertyBoolWrite(capitalized_name) \
163 void set##capitalized_name(bool name) const;
164
165 /**
166 * @author Rafal 'Vogel' Malinowski
167 * @short Declares getter and setter for given boolean property of SharedBase's Shared class.
168 * @param capitalized_name name of property
169 *
170 * Declares getter for a boolean delegated property of @link Shared @endlink class stored in
171 * @link SharedBase @endlink. Getter is named 'is##capitalized_name'. Setter is named 'set##capitalized_name'.
172 */
173 #define KaduSharedBase_PropertyBool(capitalized_name) \
174 KaduSharedBase_PropertyBoolRead(capitalized_name) \
175 KaduSharedBase_PropertyBoolWrite(capitalized_name)
176
177 /**
178 * @author Rafal 'Vogel' Malinowski
179 * @short Defines getter for given property of SharedBase's Shared class.
180 * @param type type of property
181 * @param name name of getter
182 * @param capitalized_name name of property
183 * @param default default value
184 *
185 * If @link SharedBase @endlink does not store any @link Shared @endlink the default value
186 * is returned. Else, value of Shared method 'name' is returned.
187 */
188 #define KaduSharedBase_PropertyReadDef(class_name, type, name, capitalized_name, default) \
189 type class_name::name() const\
190 {\
191 return isNull()\
192 ? default\
193 : data()->name();\
194 }
195
196 /**
197 * @author Rafal 'Vogel' Malinowski
198 * @short Defines setter for given property of SharedBase's Shared class.
199 * @param type type of property
200 * @param name name of getter
201 * @param capitalized_name name of property
202 *
203 * If @link SharedBase @endlink does not store any @link Shared @endlink nothing is done.
204 * Else, method 'set##capitalized_name' of Shared object is called, so the property value
205 * is set.
206 */
207 #define KaduSharedBase_PropertyWriteDef(class_name, type, name, capitalized_name) \
208 void class_name::set##capitalized_name(type name) const\
209 {\
210 if (!isNull())\
211 data()->set##capitalized_name(name);\
212 }
213
214 /**
215 * @author Rafal 'Vogel' Malinowski
216 * @short Defines getter and setter for given property of SharedBase's Shared class.
217 * @param type type of property
218 * @param name name of getter
219 * @param capitalized_name name of property
220 * @param default default value
221 *
222 * Defines getter (@link KaduSharedBase_PropertyReadDef @endlink) and setter
223 * (@link KaduSharedBase_PropertyWriteDef @endlink) got given delegated property.
224 */
225 #define KaduSharedBase_PropertyDef(class_name, type, name, capitalized_name, default) \
226 KaduSharedBase_PropertyReadDef(class_name, type, name, capitalized_name, default) \
227 KaduSharedBase_PropertyWriteDef(class_name, type, name, capitalized_name)
228
229 /**
230 * @author Bartosz 'beevvy' Brachaczek
231 * @short Defines getter and setter for given property of SharedBase's Shared class.
232 * @param type type of property
233 * @param name name of getter
234 * @param capitalized_name name of property
235 * @param default default value
236 *
237 * Defines getter (@link KaduSharedBase_PropertyReadDef @endlink) and setter
238 * (@link KaduSharedBase_PropertyWriteDef @endlink) got given delegated property.
239 * Argument of the setter will be a const reference to 'type'.
240 */
241 #define KaduSharedBase_PropertyDefCRW(class_name, type, name, capitalized_name, default) \
242 KaduSharedBase_PropertyReadDef(class_name, type, name, capitalized_name, default) \
243 KaduSharedBase_PropertyWriteDef(class_name, const type &, name, capitalized_name)
244
245 /**
246 * @author Rafal 'Vogel' Malinowski
247 * @short Defines getter for given boolean property of SharedBase's Shared class.
248 * @param name name of getter
249 * @param capitalized_name name of property
250 * @param default default value
251 *
252 * If @link SharedBase @endlink does not store any @link Shared @endlink the default value
253 * is returned. Else, value of Shared method 'is##capitalized_name' is returned.
254 */
255 #define KaduSharedBase_PropertyBoolReadDef(class_name, capitalized_name, default) \
256 bool class_name::is##capitalized_name() const\
257 {\
258 return isNull()\
259 ? default\
260 : data()->is##capitalized_name();\
261 }
262
263 /**
264 * @author Rafal 'Vogel' Malinowski
265 * @short Defines setter for given boolean property of SharedBase's Shared class.
266 * @param name name of getter
267 * @param capitalized_name name of property
268 *
269 * If @link SharedBase @endlink does not store any @link Shared @endlink nothing is done.
270 * Else, method 'set##capitalized_name' of Shared object is called, so the property value
271 * is set.
272 */
273 #define KaduSharedBase_PropertyBoolWriteDef(class_name, capitalized_name) \
274 void class_name::set##capitalized_name(bool value) const\
275 {\
276 if (!isNull())\
277 data()->set##capitalized_name(value);\
278 }
279
280 /**
281 * @author Rafal 'Vogel' Malinowski
282 * @short Defines getter and setter for given boolean property of SharedBase's Shared class.
283 * @param name name of getter
284 * @param capitalized_name name of property
285 * @param default default value
286 *
287 * Defines getter (@link KaduSharedBase_PropertyBoolReadDef @endlink) and setter
288 * (@link KaduSharedBase_PropertyBoolWriteDef @endlink) got given delegated property.
289 */
290 #define KaduSharedBase_PropertyBoolDef(class_name, capitalized_name, default) \
291 KaduSharedBase_PropertyBoolReadDef(class_name, capitalized_name, default) \
292 KaduSharedBase_PropertyBoolWriteDef(class_name, capitalized_name)
293
294 class ChangeNotifier;
295
296 /**
297 * @class SharedBase
298 * @author Rafal 'Vogel' Malinowski
299 * @short Class that can contain instance of Shared class that holds this class' data.
300 * @param T class derivered from Shared type, it holds data for this SharedBase
301 *
302 * This class is contructed to allow copying objects without copying their data. Each object
303 * of SharedBase class contains only pointer (reference-counted) to Shared class that
304 * contains real data. So every copied object will have the same data, changes in one object
305 * will be visible in all copied object. This is behavior similar to references and very
306 * similar to Java objects.
307 *
308 * Empty objects are called 'null' objects and can be tested by isNull method.
309 *
310 * If no more objects hold given data object, it will be destroyed and memory will be fred.
311 *
312 * If T class is QObject then SharedBase inherits all of its signals and slots, so this
313 * is possible:
314 *
315 * <pre>
316 * ContactShared *contactData = ...
317 * SharedBase<Contact> contact(contactData);
318 * connect(contactData, SIGNAL(...), this, SLOT(...));
319 * connect(contact, SIGNAL(...), this, SLOT(...));
320 * </pre>
321 *
322 * Both connect will connect to exactly the same signal.
323 */
324 template<class T>
325 class SharedBase
326 {
327 QExplicitlySharedDataPointer<T> Data;
328
329 protected:
330 /**
331 * @author Rafal 'Vogel' Malinowski
332 * @short sets new data for object
333 * @param data new data for object
334 *
335 * Sets new data for this object. All reference counters are updated properly.
336 */
setData(T * data)337 void setData(T *data)
338 {
339 Data = data;
340 }
341
342 public:
343 /**
344 * @author Rafal 'Vogel' Malinowski
345 * @short Contructs empty (null) object.
346 *
347 * Contructs empty (null) object. It contains no data.
348 */
SharedBase()349 SharedBase()
350 {
351 }
352
353 /**
354 * @author Rafal 'Vogel' Malinowski
355 * @short Contructs object with given data.
356 * @param data data this object will hold
357 *
358 * Contructs object with given data. Reference counters of data are updated.
359 */
SharedBase(T * data)360 explicit SharedBase(T *data) :
361 Data(data)
362 {
363 }
364
365 /**
366 * @author Rafal 'Vogel' Malinowski
367 * @short Copies object.
368 * @param copy object that will be copied
369 *
370 * Copies copy object. Source and resulting object will have the same data. Udpate
371 * in one will result in update with second.
372 */
SharedBase(const SharedBase & copy)373 SharedBase(const SharedBase ©) :
374 Data(copy.Data)
375 {
376 }
377
378 /**
379 * @author Rafal 'Vogel' Malinowski
380 * @short Destroys object.
381 *
382 * Destroys object. Reference counters of data object will be updated. If this object was
383 * the last one storing given data, the data object will be destroyed as well.
384 */
~SharedBase()385 virtual ~SharedBase()
386 {
387 }
388
389 /**
390 * @author Rafal 'Vogel' Malinowski
391 * @short Cast object to T * variable.
392 * @return this object as T * variable
393 *
394 * Returns data object. Allows for use SharedBase as T * variables.
395 */
396 operator T * () const
397 {
398 return Data.data();
399 }
400
401 /**
402 * @author Rafal 'Vogel' Malinowski
403 * @short Cast object to boolean variable.
404 * @return true if object is not null, false, if object is null
405 *
406 * Returns true if object is not null (contains data) and false, if object is null
407 * (does not contains an data).
408 */
409 explicit operator bool () const // for ! and ifs
410 {
411 return Data;
412 }
413
414 /**
415 * @author Rafal 'Vogel' Malinowski
416 * @short Returns stored data object.
417 * @return stored data object
418 *
419 * Returns data object.
420 */
data()421 T * data() const
422 {
423 return Data.data();
424 }
425
426 /**
427 * @author Rafal 'Vogel' Malinowski
428 * @short Check if object contains any data.
429 * @return true if object is null, false, if object is not null
430 *
431 * Returns false if object is not null (contains data) and true, if object is null
432 * (does not contains an data).
433 */
isNull()434 bool isNull() const
435 {
436 return !Data;
437 }
438
439 /**
440 * @author Rafal 'Vogel' Malinowski
441 * @short Delegates ensureStored method to Shared object.
442 *
443 * @see Shared::ensureStored
444 */
ensureStored()445 void ensureStored()
446 {
447 if (!isNull())
448 Data->ensureStored();
449 }
450
451 /**
452 * @author Rafal 'Vogel' Malinowski
453 * @author Bartosz 'beevvy' Brachaczek
454 * @short Informs the object it is about to be removed.
455 *
456 * If object is null, this method does nothing.
457 * This method calls @link<Shared::aboutToBeRemoved @endlink.
458 */
aboutToBeRemoved()459 void aboutToBeRemoved()
460 {
461 if (!isNull())
462 Data->aboutToBeRemoved();
463 }
464
465 /**
466 * @author Rafal 'Vogel' Malinowski
467 * @short Removes object completely.
468 *
469 * If object is null, this method does nothing.
470 * The Data object is removed from storage (it must be StorableObject then).
471 */
remove()472 void remove()
473 {
474 if (!isNull())
475 Data->removeFromStorage();
476 }
477
478 /**
479 * @author Rafal 'Vogel' Malinowski
480 * @short Return true if given property is available.
481 * @param name name of property
482 * @return true if given property is available
483 */
hasProperty(const QString & name)484 bool hasProperty(const QString &name) const
485 {
486 if (!isNull())
487 return Data->customProperties()->hasProperty(name);
488 else
489 return false;
490 }
491
492 /**
493 * @author Rafal 'Vogel' Malinowski
494 * @short Add/update property value.
495 * @param name name of property
496 * @param value value of property
497 * @param storability storability parameter of property
498 *
499 * If storability is set to @link CustomProperties::Storable @endlink then added property will
500 * be stored to persistent storage. If not, it will be removed from it.
501 */
addProperty(const QString & name,const QVariant & value,CustomProperties::Storability storability)502 void addProperty(const QString &name, const QVariant &value, CustomProperties::Storability storability) const
503 {
504 if (!isNull())
505 Data->customProperties()->addProperty(name, value, storability);
506 }
507
508 /**
509 * @author Rafal 'Vogel' Malinowski
510 * @short Remove given property from this object and from persistent storage.
511 * @param name name of property
512 */
removeProperty(const QString & name)513 void removeProperty(const QString &name) const
514 {
515 if (!isNull())
516 Data->customProperties()->removeProperty(name);
517 }
518
519 /**
520 * @author Rafal 'Vogel' Malinowski
521 * @short Read value of property.
522 * @param name name of property
523 * @param defaultValue value returned when property is not available
524 */
property(const QString & name,const QVariant & defaultValue)525 QVariant property(const QString &name, const QVariant &defaultValue) const
526 {
527 if (!isNull())
528 return Data->customProperties()->property(name, defaultValue);
529 else
530 return defaultValue;
531 }
532
533 /**
534 * @author Rafal 'Vogel' Malinowski
535 * @short Return ChangeNotifier instance for this object.
536 * @return ChangeNotifier instance for this object
537 *
538 * Id object is null, this method has undefined behavior.
539 */
changeNotifier()540 ChangeNotifier & changeNotifier() const
541 {
542 return Data->changeNotifier();
543 }
544
545 KaduSharedBase_Property(QUuid, uuid, Uuid)
546
547 };
548
549 template<class T>
KaduSharedBase_PropertyReadDef(SharedBase<T>,QUuid,uuid,Uuid,QUuid ())550 KaduSharedBase_PropertyReadDef(SharedBase<T>, QUuid, uuid, Uuid, QUuid())
551 template<class T>
552 KaduSharedBase_PropertyWriteDef(SharedBase<T>, QUuid, uuid, Uuid)
553
554 /**
555 * @author Rafal 'Vogel' Malinowski
556 * @short Computes hash for given SharedBase object.
557 * @return hash for given SharedBase object
558 *
559 * Hash is computed by the pointer for data object.
560 * Used for QHash objects.
561 */
562 template<class T>
563 uint qHash(const SharedBase<T> &sharedBase)
564 {
565 if (sharedBase.isNull())
566 return 0;
567
568 return qHash(sharedBase.data());
569 }
570
571 /**
572 * @}
573 */
574
575 #endif // SHARED_BASE_H
576