diff --git a/src/collectioneditor.cpp b/src/collectioneditor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30c05fbb9cf6f16bedbcc69e4b3d2fa4d2f989ee --- /dev/null +++ b/src/collectioneditor.cpp @@ -0,0 +1,26 @@ +/**************************************************************************** + * Copyright (C) 2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#include "itembackendeditor.h" + +CollectionEditorBase::CollectionEditorBase(QAbstractItemModel* m) : m_pModel(m) +{} + +QAbstractItemModel* CollectionEditorBase::model() const +{ + return m_pModel; +} \ No newline at end of file diff --git a/src/collectioneditor.h b/src/collectioneditor.h new file mode 100644 index 0000000000000000000000000000000000000000..82488ced43c63d7391ec579be09935dc322e874e --- /dev/null +++ b/src/collectioneditor.h @@ -0,0 +1,93 @@ +/**************************************************************************** + * Copyright (C) 2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifndef ITEMBACKENDEDITOR_H +#define ITEMBACKENDEDITOR_H +#include <QtCore/QAbstractItemModel> + +#include <typedefs.h> + +//Ring +class PhoneNumber; + +class LIB_EXPORT CollectionEditorBase { +public: + CollectionEditorBase(QAbstractItemModel* m); + QAbstractItemModel* model() const; + +protected: + QAbstractItemModel* m_pModel; +}; + +/** + * This is the class that does the actual work. This class + * represent a delegate of CollectionInterface. It is usually + * recommanded to implement this as a private class in the .cpp + * that implement the CollectionInterface. + * + * The rational behind this inversion of responsability layer + * is to avoid using a template class for CollectionInterface. + * This would add obstable when implementing objects using it due + * to C++11 lack of generic template polymorphism. A base class + * extended by the template call also doesn't solve those issues. + */ +template<typename T> +class LIB_EXPORT CollectionEditor : public CollectionEditorBase { + friend class CollectionInterface; +public: + CollectionEditor(CollectionMediator<T>* m); + virtual ~CollectionEditor(); + + CollectionMediator<T>* mediator() const; + + virtual bool save(const T* item) =0; + virtual bool append(const T* item) =0; + virtual bool batchSave(const QList<T*> contacts); + virtual bool remove(T* item); + + ///Edit 'item', the implementation may be a GUI or something else + virtual bool edit ( T* item ) = 0; + ///Add a new item to the backend + virtual bool addNew ( T* item ) = 0; + + ///Add a new phone number to an existing item + virtual bool addPhoneNumber( T* item , PhoneNumber* number ); + +private: + /** + * Return the items generated by this backend. This overloaded + * version also make sure that the type is compatible. + */ + QVector<T*> items() const; + + /** + * Return the metatype of this editor + */ + QMetaObject metaObject(); + + /** + * Return the items generated by this backend + */ + virtual QVector<T*> items() const = 0; + + //Attributes + CollectionMediator<T>* m_pMediator; +}; + +#include "itembackendeditor.hpp" + +#endif \ No newline at end of file diff --git a/src/collectioneditor.hpp b/src/collectioneditor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3d1f43b394e158c8ba3f8651b3903b502b480f60 --- /dev/null +++ b/src/collectioneditor.hpp @@ -0,0 +1,76 @@ +/**************************************************************************** + * Copyright (C) 2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <QtCore/QMetaObject> + + +template<typename T> +CollectionEditor<T>::CollectionEditor(CollectionMediator<T>* m) : CollectionEditorBase(m->model()), m_pMediator(m) +{ + +} + +template<typename T> +CollectionEditor<T>::~CollectionEditor() +{ + +} + +template<typename T> +CollectionMediator<T>* CollectionEditor<T>::mediator() const +{ + return m_pMediator; +} + +template<typename T> +QVector<T*> CollectionEditor<T>::items() const +{ +// Q_ASSERT(T::staticMetaObject().className() == T2::staticMetaObject().className()); + return items(); +} + +template<typename T> +QMetaObject metaObject() +{ + return T::staticMetaObject(); +} + +///Default batch saving implementation, some backends have better APIs +template <class T> bool CollectionEditor<T>::batchSave(const QList<T*> contacts) +{ + bool ret = true; + foreach(const T* c, contacts) { + ret &= save(c); + } + return ret; +} + +template <class T> +bool CollectionEditor<T>::addPhoneNumber( T* item , PhoneNumber* number ) +{ + Q_UNUSED(item) + Q_UNUSED(number) + return false; +} + +template <class T> +bool CollectionEditor<T>::remove(T* item) +{ + Q_UNUSED(item) + return false; +} \ No newline at end of file diff --git a/src/collectioninterface.cpp b/src/collectioninterface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d50b851b2ad12683f64a5bd7cda390b918c64c8 --- /dev/null +++ b/src/collectioninterface.cpp @@ -0,0 +1,100 @@ +/************************************************************************************ + * Copyright (C) 2014-2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + ***********************************************************************************/ + +//Parent +#include "itembackendinterface.h" + +//Ring library +#include "contact.h" +#include "call.h" +#include "phonenumber.h" +#include "itembackendeditor.h" +#include "itembase.h" + +//Libstdc++ +#include <functional> + +//Qt +#include <QtCore/QHash> +#include <QtCore/QDebug> +#include <QtCore/QCoreApplication> + + + +///Destructor +CollectionInterface::~CollectionInterface() +{ + delete d_ptr; +} + +CollectionInterface* CollectionInterface::parent () const +{ + return d_ptr->m_pParent; +} + +QVector<CollectionInterface*> CollectionInterface::children() const +{ + return d_ptr->m_lChildren; +} + + +bool CollectionInterface::clear() +{ + return false; +} + +bool CollectionInterface::reload() +{ + return false; +} + +bool CollectionInterface::enable(bool) +{ + return false; +} + +QAbstractItemModel* CollectionInterface::model() const +{ + return static_cast<CollectionEditorBase*>(d_ptr->m_pEditor)->model(); +} + +void CollectionInterface::addChildren(CollectionInterface* c) +{ + d_ptr->m_lChildren << c; +} + +bool CollectionInterface::save(ItemBase<QObject>* base) +{ + return d_ptr->m_pSave(base); +} + +bool CollectionInterface::edit(ItemBase<QObject>* base) +{ + return d_ptr->m_pEdit(base); +} + +bool CollectionInterface::remove(ItemBase<QObject>* base) +{ + return d_ptr->m_pRemove(base); +} + +QMetaObject CollectionInterface::metaObject() +{ + return d_ptr->m_pEditorType; +} diff --git a/src/collectioninterface.h b/src/collectioninterface.h new file mode 100644 index 0000000000000000000000000000000000000000..d9540234c7d4528cdc5c4db450ff8ac0dacd8a7f --- /dev/null +++ b/src/collectioninterface.h @@ -0,0 +1,209 @@ +/**************************************************************************** + * Copyright (C) 2014-2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifndef ITEMBACKENDINTERFACE_H +#define ITEMBACKENDINTERFACE_H + +#include <QObject> +#include <QHash> +#include <QStringList> +#include <QVariant> +#include <QtCore/QAbstractItemModel> + +#include "typedefs.h" + +//Ring +class CollectionInterfacePrivate; +class CollectionEditorBase; +template<typename T> class CollectionEditor; +template<typename T> class CollectionMediator; +template<typename T> class ItemBase; + +/** + * This is the iterface that must be implemented by each item backends to + * be used by a CollectionManager. + * + * The class need to be extended with a template constructor: + * + * MyBackend::MyBackend<Contact>(CollectionMediator<Contact>* mediator, CollectionInterface* parent = nullptr) : + * CollectionMediator<Contact*>(mediator,parent) {} + * + * Each backends also need to implement that constructor or they wont load. + */ +class LIB_EXPORT CollectionInterface +{ + template<typename T> friend class CollectionMediator; + friend class ItemBase<QObject>; +public: + + /** + * Each backend can have a serie of feaures that are expected to work. While most editor mutators + * are implemented anyway, each backend should list what is officially supposed to work and what is + * not. + */ + enum SupportedFeatures { + NONE = 0x0 , + LOAD = 0x1 << 0, /*!< Load this backend, DO NOT load anything before "load" is called */ + SAVE = 0x1 << 1, /*!< Save an item */ + EDIT = 0x1 << 2, /*!< Edit, but **DOT NOT**, save an item) */ + PROBE = 0x1 << 3, /*!< Check if the backend has new items (some backends do this automagically)*/ + ADD = 0x1 << 4, /*!< Add (and save) a new item to the backend */ + SAVE_ALL = 0x1 << 5, /*!< Save all items at once, this may or may not be faster than "add" */ + CLEAR = 0x1 << 6, /*!< Clear all items from this backend */ + REMOVE = 0x1 << 7, /*!< Remove a single item */ + EXPORT = 0x1 << 8, /*!< Export all items, format and output need to be defined by each backends */ + IMPORT = 0x1 << 9, /*!< Import items from an external source, details defined by each backends */ + ENABLEABLE = 0x1 << 10, /*!< Can be enabled, I know, it is not a word, but Java use it too */ + DISABLEABLE = 0x1 << 11, /*!< Can be disabled, I know, it is not a word, but Java use it too */ + MANAGEABLE = 0x1 << 12, /*!< Can be managed the config GUI */ + }; + + //Constructor + template<typename T> + explicit CollectionInterface(CollectionMediator<T>* mediator, CollectionEditor<T>* editor, CollectionInterface* parent = nullptr); + virtual ~CollectionInterface(); + + //Generic information getters + + /** + * This method must return an human readable, translatable string. + * This will be used to display the backend in the backend manager + * is SupportedFeatures::MANAGEABLE is set. + */ + virtual QString name () const = 0; + + /** + * Each MANAGEABLE backends can be part of a meta category. This category + * will be the top level element of the BackendManagerModel. This name + * must never change once it is set. + */ + virtual QString category () const = 0; + + /** + * This method must return an optinal icon to be used in the + * backend manager is SupportedFeatures::MANAGEABLE is set. + */ + virtual QVariant icon () const = 0; + + /** + * Return if the backend is currently enabled. An enabled backend + * is one where items are loaded and operations such as save() + * work (when supported) + */ + virtual bool isEnabled() const = 0; + + /** + * This is the identifier for this backend. This id will not + * be displayed to the user, so it doesn't have to be human + * readable. It is usually useful when linking to remote + * data sources. + */ + virtual QByteArray id () const = 0; + + /** + * Return the features supported by this backend. + * + * This method mush always return the same set of flags. + * + * @see SupportedFeatures + */ + virtual SupportedFeatures supportedFeatures() const = 0; + + //Management methods + + /** + * Enable this backend, this may or may not imply load() + */ + virtual bool enable (bool); + + /** + * Load a backend. This is used to fetch the elements to + * be added to the model. This function can (and should) + * start external workers to fetch the elements and add + * them asynchroniously. + * + * @see BackendManagerInterface::addItemCallback + * @see BackendManagerInterface::removeItemCallback + */ + virtual bool load ( ) = 0; + + /** + * Reload this backend. In the best case, this should + * update the existing elements instead of deleting them, + * as this will cause a (massive) memory leak. Reloaded + * can be necessary when a file change on disk or by user + * actions. + */ + virtual bool reload ( ); + + /** + * Clear this backend. Please note that the elements themselves + * should *NOT* be deleted as the pointer has been shared with + * upstream. Unless reference counting is implemented everywhere, + * will will cause a crash. + */ + virtual bool clear ( ); + + /** + * Return a pointer to the model implementing the CollectionManager. + */ + QAbstractItemModel* model() const; + + /** + * Return the items stored in the backend for a given type. The type + * usually is the one managed the the CollectionManager. + */ + template<typename T> + QVector<T*> items() const; + + /** + * Some backends can be hierarchical, for example, a email backend + * can have multiple "folders" where mails are stored, a contact backend + * can have multiple contact groups and an history one can have an archived + * section for previous years. This method return the parent when applicable. + */ + CollectionInterface* parent () const; + + /** + * As explained in the "parent()" method, this method return the backend children + * backends. This can be used by a client to implement different behaviour depending + * on the backend at a finer level. + */ + QVector<CollectionInterface*> children() const; + + /** Get the concrete editor associated with this backend. The template arguments + * must match the one used by the model. + */ + template<typename T> + CollectionEditor<T>* editor() const; + + +protected: + void addChildren(CollectionInterface* c); + + bool save (ItemBase<QObject>* base); + bool edit (ItemBase<QObject>* base); + bool remove(ItemBase<QObject>* base); + QMetaObject metaObject(); + +private: + CollectionInterfacePrivate* d_ptr; +}; + +#include <collectioninterface.hpp> + +#endif diff --git a/src/collectioninterface.hpp b/src/collectioninterface.hpp new file mode 100644 index 0000000000000000000000000000000000000000..073caaf6bdeb36a03f1d70285a5e95d3ad7cfbf6 --- /dev/null +++ b/src/collectioninterface.hpp @@ -0,0 +1,76 @@ +/**************************************************************************** + * Copyright (C) 2014-2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + + +//TODO don't do this +#include <functional> +template<typename T> class ItemBase; + +class CollectionInterfacePrivate { +public: + + ///The backend parent of nullptr + CollectionInterface* m_pParent ; + + ///Keep track of all backend childrens + QVector<CollectionInterface*> m_lChildren ; + + ///This need to be casted to a CollectionMediator<T> + void* m_pEditor ; + + ///Use Qt introspection to make sure casting is valid + QMetaObject m_pEditorType; + + std::function<bool(ItemBase<QObject>*)> m_pSave ; + std::function<bool(ItemBase<QObject>*)> m_pEdit ; + std::function<bool(ItemBase<QObject>*)> m_pRemove ; +}; + +template<typename T> +CollectionInterface::CollectionInterface(CollectionMediator<T>* mediator, CollectionEditor<T>* editor, CollectionInterface* parent) : +d_ptr(new CollectionInterfacePrivate()) +{ + //Ensure the type is based on QObject (required) + d_ptr->m_pParent = parent; +// d_ptr->m_pEditorType = T::staticMetaObject(); + d_ptr->m_pEditor = (void*) editor; + + //The cast is safe because the metatype is checked earlier + d_ptr->m_pSave = [editor](ItemBase<QObject>* item)->bool { + return editor->edit(static_cast<T*>(item)); + }; + d_ptr->m_pEdit = [editor](ItemBase<QObject>* item)->bool { + return editor->edit(static_cast<T*>(item)); + }; + d_ptr->m_pRemove = [editor](ItemBase<QObject>* item)->bool { + return editor->remove(static_cast<T*>(item)); + }; +} + +template<typename T> +QVector<T*> CollectionInterface::items() const +{ + return editor<T>()->items<T>(); +} + +template<typename T> +CollectionEditor<T>* CollectionInterface::editor() const +{ +// Q_ASSERT(T::staticMetaObject() == d_ptr->m_pEditorType); + return static_cast<CollectionEditor<T>*>(d_ptr->m_pEditor); +} \ No newline at end of file diff --git a/src/collectionmanagerinterface.h b/src/collectionmanagerinterface.h new file mode 100644 index 0000000000000000000000000000000000000000..7a9887027b67600b6f80022bf3d61470acd04941 --- /dev/null +++ b/src/collectionmanagerinterface.h @@ -0,0 +1,143 @@ +/**************************************************************************** + * Copyright (C) 2014-2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifndef BACKENDMANAGERINTERFACE_H +#define BACKENDMANAGERINTERFACE_H + +#include "typedefs.h" + +//Qt +#include <QtCore/QString> + +//libstdc++ +#include <type_traits> + +//Ring +#include <itembackendinterface.h> +#include <itembackendmediator.h> + +class CommonCollectionModel; + +enum LoadOptions { + NONE = 0x0 , + FORCE_ENABLED = 0x1 << 0, + FORCE_DISABLED = 0x1 << 1, +}; + +template <class T> +class CollectionManagerInterfacePrivate; + +/** + * This is the base for all models based on the itembackend framework. + * + * This interface has to be implemented by each models. The abstract + * private methods will be called when the managed backends need + * to interact with the model. + * + * All implementation should define their item backend type in the + * class declaration like: + * + * template <typename T > using CollectionMediator = CollectionMediator<Contact>; + * + * And individual backends should extend that alias. For example: + * + * class MyContactSourceBackend : public CollectionInterface { + * public: + * MyContactSourceBackend(CollectionInterfaceMediator* mediator) + * }; + * + * The mediator is used to bridge the model and the item backends. The mediator + * implement the common logic that should otherwise have been copy pasted in each + * backends. + */ +template <class T> class LIB_EXPORT CollectionManagerInterface { + friend class CollectionMediator<T>; + +public: + CollectionManagerInterface(); + virtual ~CollectionManagerInterface() {}; + + /** + * This method is used to add a backend to a model. The LoadOptions + * can be used to enforce some parameters. Please note this function is + * a variadic template. If the backend require some arguments to be passed + * to its constructor, they can be added as extra parameters. + * + * Please note that each backend need to take a CollectionMediator as first + * argument. + * + * @return The newly created backend + */ + template <class T2, typename ...Ts> + T2* addBackend(Ts... args, const LoadOptions options = LoadOptions::NONE); + + /// Do this manager have active backends + virtual bool hasEnabledBackends () const final; + virtual bool hasBackends () const final; + + /// List all backends + virtual const QVector< CollectionInterface* > backends () const final; + virtual const QVector< CollectionInterface* > enabledBackends() const final; + + ///Enable / disable a backend + virtual bool enableBackend( CollectionInterface* backend, bool enabled) final; + + virtual bool clearAllBackends() const; + + /** + * Delete the item from the model and from its backend. This + * is permanent and cannot be undone. + * + * Please note that certain type of items, while removed from the view + * will continue to exist after being removed. This include items part + * of multiple backends or items generated from runtime data. + * + * @return true if successful, false is the backend doesn't support removing items or the operation failed. + */ + bool deleteItem(T* item); + +private: + /** + * This method is called when a new backend is added. Some models + * may need to act on such action, other don't. + */ + virtual void backendAddedCallback(CollectionInterface* backend); + + /** + * This method implement the logic necessary to add the item to + * the model. + * + * This method can be called with items already part of the model. + * All implementation must handle that. + */ + virtual bool addItemCallback (T* item) = 0; + + /** + * Remove an item from the model. Subclasses must implement the logic + * necessary to remove an item from the QAbstractCollection. + * + * This function can be called with nullptr or with items not part + * of the model. All implementations must handle that. + */ + virtual bool removeItemCallback(T* item) = 0; + + CollectionManagerInterfacePrivate<T>* d_ptr; +}; + +#include "itembackendmanagerinterface.hpp" + +#endif diff --git a/src/collectionmanagerinterface.hpp b/src/collectionmanagerinterface.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b82ca28fe021310938346a2722fe55b131bb8a7f --- /dev/null +++ b/src/collectionmanagerinterface.hpp @@ -0,0 +1,138 @@ +/**************************************************************************** + * Copyright (C) 2014-2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +template <class T> +class CollectionManagerInterfacePrivate +{ +public: + CollectionManagerInterfacePrivate(CollectionManagerInterface<T>* p) : m_pMediator(nullptr),q_ptr(p) + {} + ~CollectionManagerInterfacePrivate(); + + QVector< CollectionInterface* > m_lBackends; + QVector< CollectionInterface* > m_lEnabledBackends; + mutable CollectionMediator<T>* m_pMediator; + CollectionManagerInterface<T>* q_ptr; + + CollectionMediator<T>* itemMediator() const; +}; + +template<class T> +CollectionMediator<T>* CollectionManagerInterfacePrivate<T>::itemMediator() const +{ + if (!m_pMediator) { + m_pMediator = new CollectionMediator<T>(q_ptr,nullptr); + } + return m_pMediator; +} + +template<class T> +CollectionManagerInterfacePrivate<T>::~CollectionManagerInterfacePrivate() +{ + if (m_pMediator) + delete m_pMediator; +} + +template<class T> +template <class T2, typename ...Ts> +T2* CollectionManagerInterface<T>::addBackend(Ts... args, const LoadOptions options) +{ + T2* backend = new T2(d_ptr->itemMediator(),args...); + + //This will force the T2 to be a CollectionInterface subclass + CollectionInterface* b = backend; + d_ptr->m_lBackends << b; + + if (options & LoadOptions::FORCE_ENABLED) { //TODO check is the backend is checked + + //Some backends can fail to load directly + //eventually it will necessary to add an async version of this + //to load the backend only when it is loaded + if (backend->load()) + d_ptr->m_lEnabledBackends << backend; + } + + return backend; +} + +template<class T> +CollectionManagerInterface<T>::CollectionManagerInterface() : d_ptr(new CollectionManagerInterfacePrivate<T>(this)) +{ + +} + +template<class T> +const QVector< CollectionInterface* > CollectionManagerInterface<T>::backends() const +{ + return d_ptr->m_lBackends; +} + +template<class T> +const QVector< CollectionInterface* > CollectionManagerInterface<T>::enabledBackends() const +{ + return d_ptr->m_lEnabledBackends; +} + +/// Do this manager have active backends +template<class T> +bool CollectionManagerInterface<T>::hasEnabledBackends() const +{ + return d_ptr->m_lEnabledBackends.size(); +} + +template<class T> +bool CollectionManagerInterface<T>::hasBackends() const +{ + return d_ptr->m_lBackends.size(); +} + +template<class T> +bool CollectionManagerInterface<T>::clearAllBackends() const +{ + return false; +} + +template<class T> +void CollectionManagerInterface<T>::backendAddedCallback(CollectionInterface* backend) +{ + Q_UNUSED(backend) +} + +template<class T> +bool CollectionManagerInterface<T>::deleteItem(T* item) +{ + if (item->backend()->model() == (QAbstractItemModel*) this) { + if (item->backend()->supportedFeatures() & CollectionInterface::SupportedFeatures::REMOVE) { + static_cast<CollectionInterface*>(item->backend())->editor<T>()->remove(item); + return true; + } + else + qDebug() << item << "cannot be deleted, the backend doesn't support removing items"; + } + else + qDebug() << item << "cannot be deleted, it is not managed by" << this; + return false; +} + +template<class T> +bool CollectionManagerInterface<T>::enableBackend( CollectionInterface* backend, bool enabled) +{ + Q_UNUSED(enabled) //TODO implement it + backend->load(); + return true; +} diff --git a/src/collectionmediator.h b/src/collectionmediator.h new file mode 100644 index 0000000000000000000000000000000000000000..cca8b0f385b7e79a749fda0442d38b73ceef89d4 --- /dev/null +++ b/src/collectionmediator.h @@ -0,0 +1,54 @@ +/**************************************************************************** + * Copyright (C) 2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifndef ITEM_BACKEND_MEDIATOR_H +#define ITEM_BACKEND_MEDIATOR_H + +#include <typedefs.h> + +template<class T> +class CollectionManagerInterface; + +template<class T> +class CollectionMediatorPrivate; + +/** + * This is the base class for each BackendMediator. A backend mediator + * is a intermediary object between the backend and the model responsible + * to manage the backends objects. The purpose of this layer are: + * + * * Isolate the item gestion away from the manager public API + * * Work around the lack of polymorphic generics for template objects + * + * The later objective make it easier to later implement the decorator pattern. + */ +template<typename T> +class LIB_EXPORT CollectionMediator { +public: + CollectionMediator(CollectionManagerInterface<T>* parentManager, QAbstractItemModel* m); + bool addItem (T* item); + bool removeItem(T* item); + + QAbstractItemModel* model() const; + +private: + CollectionMediatorPrivate<T>* d_ptr; +}; + +#include <itembackendmediator.hpp> + +#endif \ No newline at end of file diff --git a/src/collectionmediator.hpp b/src/collectionmediator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6349de194f3d408c7b124df50e7812d51e2d7f00 --- /dev/null +++ b/src/collectionmediator.hpp @@ -0,0 +1,51 @@ +/**************************************************************************** + * Copyright (C) 2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +template<class T> +class CollectionMediatorPrivate +{ +public: + CollectionManagerInterface<T>* m_pParent; + QAbstractItemModel* m_pModel; +}; + +template<typename T> +CollectionMediator<T>::CollectionMediator(CollectionManagerInterface<T>* parentManager, QAbstractItemModel* m) : + d_ptr(new CollectionMediatorPrivate<T>()) +{ + d_ptr->m_pParent = parentManager; + d_ptr->m_pModel = m; +} + +template<typename T> +bool CollectionMediator<T>::addItem(T* item) +{ + return d_ptr->m_pParent->addItemCallback(item); +} + +template<typename T> +bool CollectionMediator<T>::removeItem(T* item) +{ + return d_ptr->m_pParent->removeItemCallback(item); +} + +template<typename T> +QAbstractItemModel* CollectionMediator<T>::model() const +{ + return d_ptr->m_pModel; +} \ No newline at end of file diff --git a/src/collectionmodel.cpp b/src/collectionmodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d1d2a0068cf04b9ecd33db18b8e70f505928cc7c --- /dev/null +++ b/src/collectionmodel.cpp @@ -0,0 +1,297 @@ +/**************************************************************************** + * Copyright (C) 2014-2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#include "collectionmodel.h" + +#include "itembackendmanagerinterface.h" +#include "visitors/itemmodelstateserializationvisitor.h" +#include "abstractitembackendmodelextension.h" + +class CollectionModelPrivate : public QObject +{ + Q_OBJECT +public: + CollectionModelPrivate(CollectionModel* parent); + + /* + * This is not very efficient, it doesn't really have to be given the low + * volume. If it ever have to scale, a better mapToSource using persistent + * index have to be implemented. + */ + struct ProxyItem { + ProxyItem() : parent(nullptr),col(1),row(0),backend(nullptr){} + int row; + int col; + CollectionInterface* backend; + ProxyItem* parent; + QVector<ProxyItem*> m_Children; + }; + QHash<CollectionInterface**,ProxyItem*> m_hBackendsNodes; + QVector<ProxyItem*> m_lTopLevelBackends; + QVector<AbstractCollectionModelExtension*> m_lExtensions; + +private: + CollectionModel* q_ptr; + +private Q_SLOTS: + void slotUpdate(); + void slotExtensionDataChanged(const QModelIndex& idx); +}; + +CollectionModelPrivate::CollectionModelPrivate(CollectionModel* parent) : QObject(parent),q_ptr(parent) +{} + +CollectionModel::CollectionModel(QObject* parent) : QAbstractTableModel(parent), d_ptr(new CollectionModelPrivate(this)) +{ + connect(ContactModel::instance(),SIGNAL(newBackendAdded(CollectionInterface*)),d_ptr.data(),SLOT(slotUpdate())); + load(); +} + +CollectionModel::~CollectionModel() +{ + while (d_ptr->m_lTopLevelBackends.size()) { + CollectionModelPrivate::ProxyItem* item = d_ptr->m_lTopLevelBackends[0]; + d_ptr->m_lTopLevelBackends.remove(0); + while (item->m_Children.size()) { + //FIXME I don't think it can currently happen, but there may be + //more than 2 levels. + CollectionModelPrivate::ProxyItem* item2 = item->m_Children[0]; + item->m_Children.remove(0); + delete item2; + } + delete item; + } +} + +QVariant CollectionModel::data (const QModelIndex& idx, int role) const +{ + if (idx.isValid()) { + CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); + + if (idx.column() > 0) + return d_ptr->m_lExtensions[idx.column()-1]->data(item->backend,idx,role); + + switch(role) { + case Qt::DisplayRole: + return item->backend->name(); + break; + case Qt::DecorationRole: + return item->backend->icon(); + break; +// case Qt::CheckStateRole: +// return item->backend->isEnabled()?Qt::Checked:Qt::Unchecked; + case Qt::CheckStateRole: { + if (ItemModelStateSerializationVisitor::instance()) + return ItemModelStateSerializationVisitor::instance()->isChecked(item->backend)?Qt::Checked:Qt::Unchecked; + } + }; + } + //else { +// CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); +// return item->model->data(item->model->index(item->row,item->col)); + //} + return QVariant(); +} + +int CollectionModel::rowCount (const QModelIndex& parent) const +{ + if (!parent.isValid()) { + static bool init = false; //FIXME this doesn't allow dynamic backends + static int result = 0; + if (!init) { + for(int i=0;i<ContactModel::instance()->backends().size();i++) + result += ContactModel::instance()->backends()[i]->parent()==nullptr?1:0; + init = true; + } + return result; + } + else { + CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(parent.internalPointer()); + return item->backend->children().size(); + } +} + +int CollectionModel::columnCount (const QModelIndex& parent) const +{ + Q_UNUSED(parent) + return 1+d_ptr->m_lExtensions.size(); +} + +Qt::ItemFlags CollectionModel::flags(const QModelIndex& idx) const +{ + if (!idx.isValid()) + return 0; + CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); + if (idx.column() > 0) { + //Make sure the cell is disabled if the row is + Qt::ItemFlags f = d_ptr->m_lExtensions[idx.column()-1]->flags(item->backend,idx); + return (((f&Qt::ItemIsEnabled)&&(!item->backend->isEnabled()))?f^Qt::ItemIsEnabled:f); + } + const bool checkable = item->backend->supportedFeatures() & (CollectionInterface::SupportedFeatures::ENABLEABLE | + CollectionInterface::SupportedFeatures::DISABLEABLE | CollectionInterface::SupportedFeatures::MANAGEABLE ); + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | (checkable?Qt::ItemIsUserCheckable:Qt::NoItemFlags); +} + +bool CollectionModel::setData (const QModelIndex& idx, const QVariant &value, int role ) +{ + Q_UNUSED(idx) + Q_UNUSED(value) + Q_UNUSED(role) + if (idx.isValid() && idx.column() > 0) { + CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); + return d_ptr->m_lExtensions[idx.column()-1]->setData(item->backend,idx,value,role); + } + + if (role == Qt::CheckStateRole && idx.column() == 0) { + CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); + if (item) { + const bool old = item->backend->isEnabled(); + ItemModelStateSerializationVisitor::instance()->setChecked(item->backend,value==Qt::Checked); + emit dataChanged(index(idx.row(),0),index(idx.row(),columnCount()-1)); + if (old != (value==Qt::Checked)) { + emit checkStateChanged(); + } + return true; + } + } + return false; +} + +QModelIndex CollectionModel::parent( const QModelIndex& idx ) const +{ + if (idx.isValid()) { + CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); + if (!item->parent) + return QModelIndex(); + return createIndex(item->row,item->col,item->parent); + } + return QModelIndex(); +} + +QModelIndex CollectionModel::index( int row, int column, const QModelIndex& parent ) const +{ + if (parent.isValid()) { + CollectionModelPrivate::ProxyItem* parentItem = static_cast<CollectionModelPrivate::ProxyItem*>(parent.internalPointer()); + CollectionModelPrivate::ProxyItem* item = nullptr; + if (row < parentItem->m_Children.size()) + item = parentItem->m_Children[row]; + else { + item = new CollectionModelPrivate::ProxyItem(); + item->parent = parentItem; + item->backend = static_cast<CollectionInterface*>(parentItem->backend->children()[row]); + parentItem->m_Children << item; + } + item->row = row; + item->col = column; + return createIndex(row,column,item); + } + else { //Top level + CollectionModelPrivate::ProxyItem* item = nullptr; + if (row < d_ptr->m_lTopLevelBackends.size()) + item = d_ptr->m_lTopLevelBackends[row]; + else { + + if (row >= ContactModel::instance()->backends().size()) + return QModelIndex(); + + item = new CollectionModelPrivate::ProxyItem(); + item->backend = ContactModel::instance()->backends()[row]; + d_ptr->m_lTopLevelBackends << item; + } + item->row = row; + item->col = column; + return createIndex(item->row,item->col,item); + } +} + +void CollectionModelPrivate::slotUpdate() +{ + emit q_ptr->layoutChanged(); +} + +QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + Q_UNUSED(section) + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + if (section > 0) + return d_ptr->m_lExtensions[section-1]->headerName(); + return QVariant(tr("Name")); + } + return QVariant(); +} + +bool CollectionModel::save() +{ + if (ItemModelStateSerializationVisitor::instance()) { + + //Load newly enabled backends + foreach(CollectionModelPrivate::ProxyItem* top, d_ptr->m_lTopLevelBackends) { + CollectionInterface* current = top->backend; + bool check = ItemModelStateSerializationVisitor::instance()->isChecked(current); + bool wasChecked = current->isEnabled(); + if (check && !wasChecked) + current->enable(true); + else if ((!check) && wasChecked) + current->enable(false); + + //TODO implement real tree digging + foreach(CollectionModelPrivate::ProxyItem* leaf ,top->m_Children) { + current = leaf->backend; + check = ItemModelStateSerializationVisitor::instance()->isChecked(current); + wasChecked = current->isEnabled(); + if (check && !wasChecked) + current->enable(true); + else if ((!check) && wasChecked) + current->enable(false); + //else: do nothing + } + } + return ItemModelStateSerializationVisitor::instance()->save(); + } + return false; +} + +bool CollectionModel::load() +{ + if (ItemModelStateSerializationVisitor::instance()) { + return ItemModelStateSerializationVisitor::instance()->load(); + } + return false; +} + +///Return the backend at a given index +CollectionInterface* CollectionModel::backendAt(const QModelIndex& index) +{ + if (!index.isValid()) + return nullptr; + return static_cast<CollectionModelPrivate::ProxyItem*>(index.internalPointer())->backend; +} + +void CollectionModel::addExtension(AbstractCollectionModelExtension* extension) +{ + emit layoutAboutToBeChanged(); + d_ptr->m_lExtensions << extension; + connect(extension,SIGNAL(dataChanged(QModelIndex)),d_ptr.data(),SLOT(slotExtensionDataChanged(QModelIndex))); + emit layoutChanged(); +} + +void CollectionModelPrivate::slotExtensionDataChanged(const QModelIndex& idx) +{ + emit q_ptr->dataChanged(idx,idx); +} + +#include <itembackendmodel.moc> diff --git a/src/collectionmodel.h b/src/collectionmodel.h new file mode 100644 index 0000000000000000000000000000000000000000..d67df426bd52c74b484151962f1bd62c9db24f9e --- /dev/null +++ b/src/collectionmodel.h @@ -0,0 +1,67 @@ +/**************************************************************************** + * Copyright (C) 2014-2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifndef COLLECTION_MODEL_H +#define COLLECTION_MODEL_H + +#include "typedefs.h" +#include "contact.h" + +#include <QtCore/QAbstractItemModel> + +#include "itembackendmanagerinterface.h" +#include "contactmodel.h" +#include "itembackendinterface.h" + +//Ring +class AbstractItemBackendModelExtension; + +class CollectionModelPrivate; + +class LIB_EXPORT CollectionModel : public QAbstractTableModel +{ + Q_OBJECT +public: + explicit CollectionModel(QObject* parent = nullptr); + virtual ~CollectionModel(); + + virtual QVariant data (const QModelIndex& index, int role = Qt::DisplayRole ) const override; + virtual int rowCount (const QModelIndex& parent = QModelIndex() ) const override; + virtual int columnCount (const QModelIndex& parent = QModelIndex() ) const override; + virtual Qt::ItemFlags flags (const QModelIndex& index ) const override; + virtual QVariant headerData (int section, Qt::Orientation orientation, int role ) const override; + virtual bool setData (const QModelIndex& index, const QVariant &value, int role ) override; + virtual QModelIndex parent ( const QModelIndex& index ) const override; + virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override; + + ItemBackendInterface* backendAt(const QModelIndex& index); + + void addExtension(AbstractItemBackendModelExtension* extension); + + bool save(); + bool load(); + +Q_SIGNALS: + void checkStateChanged(); + +private: + QScopedPointer<CollectionModelPrivate> d_ptr; + Q_DECLARE_PRIVATE(CollectionModel) + +}; + +#endif diff --git a/src/itembase.h b/src/itembase.h new file mode 100644 index 0000000000000000000000000000000000000000..f36bec78f42d63df7345fedc57a9780bb9c18265 --- /dev/null +++ b/src/itembase.h @@ -0,0 +1,53 @@ +/**************************************************************************** + * Copyright (C) 2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#ifndef ITEMBASE2_H +#define ITEMBASE2_H + +#include <typedefs.h> + +#include <itembackendinterface.h> + +class ItemBasePrivate; + +/** + * Base class for all items to be managed in ItemBackendInterface + */ +template<typename T> +class LIB_EXPORT ItemBase : public T { + friend class ItemBackendInterface; +public: + //Constructor + explicit ItemBase(T* parent = nullptr); + virtual ItemBackendInterface* backend() final; + + //Mutator methods + bool save() const; + bool edit() ; + bool remove() ; + + //Setter + void setBackend(ItemBackendInterface* backend); + +protected: +private: + ItemBasePrivate* d_ptr; +}; + +#include <itembase.hpp> + +#endif \ No newline at end of file diff --git a/src/itembase.hpp b/src/itembase.hpp new file mode 100644 index 0000000000000000000000000000000000000000..76699f3bc5c004d39eb6b3c809b80b7682e974f0 --- /dev/null +++ b/src/itembase.hpp @@ -0,0 +1,77 @@ +/**************************************************************************** + * Copyright (C) 2015 by Savoir-Faire Linux * + * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#include "itembackendinterface.h" +#include "itembackendeditor.h" +#include <QtCore/QObject> +#include <QtCore/QMetaObject> + +class ItemBasePrivate +{ +public: + ItemBackendInterface* m_pBackend; +}; + +template<typename Base> +ItemBase<Base>::ItemBase(Base* parent) : Base(parent), d_ptr(new ItemBasePrivate()) +{ +} + +template<typename Base> +ItemBackendInterface* ItemBase<Base>::backend() +{ + return d_ptr->m_pBackend; +} + +template<typename Base> +void ItemBase<Base>::setBackend(ItemBackendInterface* backend) +{ + d_ptr->m_pBackend = backend; +} + +///Save the contact +template<typename Base> +bool ItemBase<Base>::save() const +{ +// if (((QObject*) this)->staticMetaObject() == d_ptr->m_pBackend->metaObject()){ + return d_ptr->m_pBackend->save(this); +// } +// else +// qDebug() << "Cannot save, invalid item type"; +} + +///Show an implementation dependant dialog to edit the contact +template<typename Base> +bool ItemBase<Base>::edit() +{ +// if (((QObject*) this)->staticMetaObject() == d_ptr->m_pBackend->metaObject()){ + return d_ptr->m_pBackend->edit(this); +// } +// else +// qDebug() << "Cannot save, invalid item type"; +} + +///Remove the contact from the backend +template<typename Base> +bool ItemBase<Base>::remove() +{ +// if (((QObject*) this)->staticMetaObject() == d_ptr->m_pBackend->metaObject()){ + return d_ptr->m_pBackend->remove(this); +// } +// else +// qDebug() << "Cannot save, invalid item type"; +} \ No newline at end of file