/* * Copyright (C) 2013 Jolla Mobile * * You may use this file under the terms of the BSD license as follows: * * "Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Nemo Mobile nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." */ #ifndef SEASIDECACHE_H #define SEASIDECACHE_H #include "contactcacheexport.h" #include #include #include #include #include #include #include #include #include #include #ifdef USING_QTPIM #include #include #else #include #include #endif #include #include #include #include #include #ifdef HAS_MLITE #include #endif USE_CONTACTS_NAMESPACE class CONTACTCACHE_EXPORT SeasideNameGroupChangeListener { public: SeasideNameGroupChangeListener() {} ~SeasideNameGroupChangeListener() {} virtual void nameGroupsUpdated(const QHash &groups) = 0; }; class CONTACTCACHE_EXPORT SeasideCache : public QObject { Q_OBJECT public: typedef QtContactsSqliteExtensions::ApiContactIdType ContactIdType; enum FilterType { FilterNone, FilterAll, FilterFavorites, FilterOnline, FilterTypesCount }; enum DisplayLabelOrder { FirstNameFirst, LastNameFirst }; enum ContactState { ContactAbsent, ContactRequested, ContactFetched }; struct ItemData { virtual ~ItemData() {} virtual QString getDisplayLabel() const = 0; virtual void displayLabelOrderChanged(DisplayLabelOrder order) = 0; virtual void updateContact(const QContact &newContact, QContact *oldContact) = 0; virtual void constituentsFetched(const QList &ids) = 0; virtual void mergeCandidatesFetched(const QList &ids) = 0; virtual void aggregationOperationCompleted() = 0; virtual QList constituents() const = 0; }; struct ModelData { virtual ~ModelData() {} virtual void contactChanged(const QContact &newContact) = 0; }; struct CacheItem { CacheItem() : itemData(0), modelData(0), contactState(ContactAbsent) {} CacheItem(const QContact &contact) : contact(contact), itemData(0), modelData(0), contactState(ContactAbsent) {} ContactIdType apiId() const { return SeasideCache::apiId(contact); } QContact contact; ItemData *itemData; ModelData *modelData; ContactState contactState; }; struct ContactLinkRequest { ContactLinkRequest(const SeasideCache::ContactIdType &id) : contactId(id), constituentsFetched(false) {} ContactLinkRequest(const ContactLinkRequest &req) : contactId(req.contactId), constituentsFetched(req.constituentsFetched) {} SeasideCache::ContactIdType contactId; bool constituentsFetched; }; class ListModel : public QAbstractListModel { public: ListModel(QObject *parent = 0) : QAbstractListModel(parent) {} virtual ~ListModel() {} virtual void sourceAboutToRemoveItems(int begin, int end) = 0; virtual void sourceItemsRemoved() = 0; virtual void sourceAboutToInsertItems(int begin, int end) = 0; virtual void sourceItemsInserted(int begin, int end) = 0; virtual void sourceDataChanged(int begin, int end) = 0; virtual void makePopulated() = 0; virtual void updateDisplayLabelOrder() = 0; }; static SeasideCache *instance(); static ContactIdType apiId(const QContact &contact); static ContactIdType apiId(quint32 iid); static bool validId(const ContactIdType &id); static quint32 internalId(const QContact &contact); static quint32 internalId(const QContactId &id); #ifndef USING_QTPIM static quint32 internalId(QContactLocalId id); #endif static void registerModel(ListModel *model, FilterType type); static void unregisterModel(ListModel *model); static void registerUser(QObject *user); static void unregisterUser(QObject *user); static void registerNameGroupChangeListener(SeasideNameGroupChangeListener *listener); static void unregisterNameGroupChangeListener(SeasideNameGroupChangeListener *listener); static DisplayLabelOrder displayLabelOrder(); static int contactId(const QContact &contact); static CacheItem *existingItem(const ContactIdType &id); static CacheItem *itemById(const ContactIdType &id); #ifdef USING_QTPIM static CacheItem *itemById(int id); #endif static ContactIdType selfContactId(); static QContact contactById(const ContactIdType &id); static QChar nameGroupForCacheItem(CacheItem *cacheItem); static QList allNameGroups(); static QHash nameGroupCounts(); static CacheItem *itemByPhoneNumber(const QString &msisdn); static CacheItem *itemByEmailAddress(const QString &email); static bool saveContact(const QContact &contact); static void removeContact(const QContact &contact); static void aggregateContacts(const QContact &contact1, const QContact &contact2); static void disaggregateContacts(const QContact &contact1, const QContact &contact2); static void fetchConstituents(const QContact &contact); static void fetchMergeCandidates(const QContact &contact); static int importContacts(const QString &path); static QString exportContacts(); static const QVector *contacts(FilterType filterType); static bool isPopulated(FilterType filterType); static QString generateDisplayLabel(const QContact &contact, DisplayLabelOrder order = FirstNameFirst); static QString generateDisplayLabelFromNonNameDetails(const QContact &contact); bool event(QEvent *event); // For synchronizeLists() int insertRange(int index, int count, const QList &source, int sourceIndex) { return insertRange(m_fetchFilter, index, count, source, sourceIndex); } int removeRange(int index, int count) { removeRange(m_fetchFilter, index, count); return 0; } protected: void timerEvent(QTimerEvent *event); void setSortOrder(DisplayLabelOrder order); private slots: void contactsAvailable(); void contactIdsAvailable(); void relationshipsAvailable(); void requestStateChanged(QContactAbstractRequest::State state); void updateContacts(); #ifdef USING_QTPIM void contactsAdded(const QList &contactIds); void contactsChanged(const QList &contactIds); void contactsRemoved(const QList &contactIds); #else void contactsAdded(const QList &contactIds); void contactsChanged(const QList &contactIds); void contactsRemoved(const QList &contactIds); #endif void displayLabelOrderChanged(); private: SeasideCache(); ~SeasideCache(); static void checkForExpiry(); void keepPopulated(); void requestUpdate(); void appendContacts(const QList &contacts); void fetchContacts(); void updateContacts(const QList &contactIds); void finalizeUpdate(FilterType filter); void removeRange(FilterType filter, int index, int count); int insertRange( FilterType filter, int index, int count, const QList &queryIds, int queryIndex); void updateContactData(const ContactIdType &contactId, FilterType filter); void removeContactData(const ContactIdType &contactId, FilterType filter); void makePopulated(FilterType filter); void addToContactNameGroup(const QChar &group, QList *modifiedGroups = 0); void removeFromContactNameGroup(const QChar &group, QList *modifiedGroups = 0); void notifyNameGroupsChanged(const QList &groups); void updateConstituentAggregations(const ContactIdType &contactId); void completeContactAggregation(const ContactIdType &contact1Id, const ContactIdType &contact2Id); static QContactRelationship makeRelationship(const QString &type, const QContact &contact1, const QContact &contact2); QBasicTimer m_expiryTimer; QBasicTimer m_fetchTimer; QHash m_people; QHash m_phoneNumberIds; QHash m_emailAddressIds; QHash m_contactsToSave; QHash m_contactNameGroups; QList m_contactsToCreate; QList m_contactsToRemove; QList m_changedContacts; QList m_contactsToFetchConstituents; QList m_contactsToFetchCandidates; QList > m_contactPairsToLink; QList m_relationshipsToSave; QList m_relationshipsToRemove; QList m_nameGroupChangeListeners; QVector m_contacts[FilterTypesCount]; QList m_models[FilterTypesCount]; QSet m_users; QHash m_expiredContacts; QContactManager m_manager; QContactFetchRequest m_fetchRequest; QContactFetchByIdRequest m_fetchByIdRequest; #ifdef USING_QTPIM QContactIdFetchRequest m_contactIdRequest; #else QContactLocalIdFetchRequest m_contactIdRequest; #endif QContactRelationshipFetchRequest m_relationshipsFetchRequest; QContactRemoveRequest m_removeRequest; QContactSaveRequest m_saveRequest; QContactRelationshipSaveRequest m_relationshipSaveRequest; QContactRelationshipRemoveRequest m_relationshipRemoveRequest; #ifdef HAS_MLITE MGConfItem m_displayLabelOrderConf; #endif int m_resultsRead; int m_populated; int m_cacheIndex; int m_queryIndex; int m_appendIndex; FilterType m_fetchFilter; DisplayLabelOrder m_displayLabelOrder; bool m_keepPopulated; bool m_updatesPending; bool m_fetchActive; bool m_refreshRequired; bool m_contactsUpdated; QList m_constituentIds; QList m_candidateIds; QElapsedTimer m_timer; QElapsedTimer m_fetchPostponed; static SeasideCache *instancePtr; static QList allContactNameGroups; }; #endif