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 &copy);\
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 &copy)\
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&lt;Contact&gt; 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 &copy) :
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