seasidecache.h 19.5 KB
Newer Older
mvogt's avatar
mvogt committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 * Copyright (C) 2013 Jolla Mobile <andrew.den.exter@jollamobile.com>
 *
 * 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"
36
#include "cacheconfiguration.h"
mvogt's avatar
mvogt committed
37 38

#include <qtcontacts-extensions.h>
39
#include <QContactStatusFlags>
mvogt's avatar
mvogt committed
40 41 42 43 44 45 46 47 48 49 50 51

#include <QContact>
#include <QContactManager>
#include <QContactFetchRequest>
#include <QContactFetchByIdRequest>
#include <QContactRemoveRequest>
#include <QContactSaveRequest>
#include <QContactRelationshipFetchRequest>
#include <QContactRelationshipSaveRequest>
#include <QContactRelationshipRemoveRequest>
#include <QContactIdFilter>
#include <QContactIdFetchRequest>
52
#include <QContactName>
mvogt's avatar
mvogt committed
53

54
#include <QTranslator>
mvogt's avatar
mvogt committed
55
#include <QBasicTimer>
56
#include <QHash>
mvogt's avatar
mvogt committed
57 58 59 60 61
#include <QSet>

#include <QElapsedTimer>
#include <QAbstractListModel>

62 63
QTCONTACTS_USE_NAMESPACE

64
class CONTACTCACHE_EXPORT SeasideDisplayLabelGroupChangeListener
mvogt's avatar
mvogt committed
65 66
{
public:
67 68
    SeasideDisplayLabelGroupChangeListener() {}
    ~SeasideDisplayLabelGroupChangeListener() {}
mvogt's avatar
mvogt committed
69

70
    virtual void displayLabelGroupsUpdated(const QHash<QString, QSet<quint32> > &groups) = 0;
mvogt's avatar
mvogt committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84
};

class CONTACTCACHE_EXPORT SeasideCache : public QObject
{
    Q_OBJECT
public:
    enum FilterType {
        FilterNone,
        FilterAll,
        FilterFavorites,
        FilterOnline,
        FilterTypesCount
    };

85 86 87 88
    enum FetchDataType {
        FetchNone = 0,
        FetchAccountUri = (1 << 0),
        FetchPhoneNumber = (1 << 1),
89
        FetchEmailAddress = (1 << 2),
90 91 92 93 94
        FetchOrganization = (1 << 3),
        FetchTypesMask = (FetchAccountUri |
                          FetchPhoneNumber |
                          FetchEmailAddress |
                          FetchOrganization)
95 96
    };

mvogt's avatar
mvogt committed
97
    enum DisplayLabelOrder {
98 99
        FirstNameFirst = CacheConfiguration::FirstNameFirst,
        LastNameFirst = CacheConfiguration::LastNameFirst
mvogt's avatar
mvogt committed
100 101 102 103
    };

    enum ContactState {
        ContactAbsent,
104
        ContactPartial,
mvogt's avatar
mvogt committed
105
        ContactRequested,
106
        ContactComplete
mvogt's avatar
mvogt committed
107 108
    };

109 110 111 112 113
    enum {
        // Must be after the highest bit used in QContactStatusFlags::Flag
        HasValidOnlineAccount = (QContactStatusFlags::IsOnline << 1)
    };

mvogt's avatar
mvogt committed
114 115 116 117 118 119
    struct ItemData
    {
        virtual ~ItemData() {}

        virtual void displayLabelOrderChanged(DisplayLabelOrder order) = 0;

120
        virtual void updateContact(const QContact &newContact, QContact *oldContact, ContactState state) = 0;
mvogt's avatar
mvogt committed
121 122 123 124 125 126 127 128

        virtual void constituentsFetched(const QList<int> &ids) = 0;
        virtual void mergeCandidatesFetched(const QList<int> &ids) = 0;
        virtual void aggregationOperationCompleted() = 0;

        virtual QList<int> constituents() const = 0;
    };

129 130
    struct CacheItem;
    struct ItemListener
mvogt's avatar
mvogt committed
131
    {
132 133
        ItemListener() : next(0), key(0) {}
        virtual ~ItemListener() {}
mvogt's avatar
mvogt committed
134

135 136 137 138 139
        virtual void itemUpdated(CacheItem *item) = 0;
        virtual void itemAboutToBeRemoved(CacheItem *item) = 0;

        ItemListener *next;
        void *key;
mvogt's avatar
mvogt committed
140 141 142 143
    };

    struct CacheItem
    {
144
        CacheItem() : itemData(0), iid(0), statusFlags(0), contactState(ContactAbsent), listeners(0), filterMatchRole(-1) {}
145
        CacheItem(const QContact &contact)
146
            : contact(contact), itemData(0), iid(internalId(contact)),
147 148
              statusFlags(contact.detail<QContactStatusFlags>().flagsValue()), contactState(ContactAbsent), listeners(0),
              filterMatchRole(-1) {}
mvogt's avatar
mvogt committed
149

150
        QContactId apiId() const { return SeasideCache::apiId(contact); }
mvogt's avatar
mvogt committed
151

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
        ItemListener *appendListener(ItemListener *listener, void *key)
        {
            if (listeners) {
                ItemListener *existing(listeners);
                while (existing->next) {
                    existing = existing->next;
                }
                existing->next = listener;
            } else {
                listeners = listener;
            }

            listener->next = 0;
            listener->key = key;
            return listener;
        }

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
        bool removeListener(ItemListener *listener)
        {
            if (listeners) {
                ItemListener *existing(listeners);
                ItemListener **previous = &listeners;

                while (existing) {
                    if (existing == listener) {
                        *previous = listener->next;
                        return true;
                    }
                    previous = &existing->next;
                    existing = existing->next;
                }
            }

            return false;
        }

188 189
        ItemListener *listener(void *key)
        {
190 191 192
            ItemListener *existing(listeners);
            while (existing && (existing->key != key) && (existing->next)) {
                existing = existing->next;
193
            }
194
            return (existing && (existing->key == key)) ? existing : 0;
195 196
        }

mvogt's avatar
mvogt committed
197 198
        QContact contact;
        ItemData *itemData;
199
        quint32 iid;
200
        quint64 statusFlags;
mvogt's avatar
mvogt committed
201
        ContactState contactState;
202
        ItemListener *listeners;
203
        QString displayLabelGroup;
204
        QString displayLabel;
205
        int filterMatchRole;
mvogt's avatar
mvogt committed
206 207 208 209
    };

    struct ContactLinkRequest
    {
210
        ContactLinkRequest(const QContactId &id) : contactId(id), constituentsFetched(false) {}
mvogt's avatar
mvogt committed
211 212
        ContactLinkRequest(const ContactLinkRequest &req) : contactId(req.contactId), constituentsFetched(req.constituentsFetched) {}

213
        QContactId contactId;
mvogt's avatar
mvogt committed
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
        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;

231 232
        virtual void sourceItemsChanged() = 0;

mvogt's avatar
mvogt committed
233 234
        virtual void makePopulated() = 0;
        virtual void updateDisplayLabelOrder() = 0;
235
        virtual void updateSortProperty() = 0;
236
        virtual void updateGroupProperty() = 0;
237 238

        virtual void updateSectionBucketIndexCache() = 0;
239 240

        virtual void saveContactComplete(int localId, int aggregateId) = 0;
mvogt's avatar
mvogt committed
241 242
    };

243 244 245 246
    struct ResolveListener
    {
        virtual ~ResolveListener() {}

247 248 249 250 251 252 253 254 255
        virtual void addressResolved(const QString &first, const QString &second, CacheItem *item) = 0;
    };

    struct ChangeListener
    {
        virtual ~ChangeListener() {}

        virtual void itemUpdated(CacheItem *item) = 0;
        virtual void itemAboutToBeRemoved(CacheItem *item) = 0;
256 257
    };

mvogt's avatar
mvogt committed
258
    static SeasideCache *instance();
259
    static QContactManager *manager();
mvogt's avatar
mvogt committed
260

261 262
    static QContactId apiId(const QContact &contact);
    static QContactId apiId(quint32 iid);
mvogt's avatar
mvogt committed
263

264
    static bool validId(const QContactId &id);
mvogt's avatar
mvogt committed
265 266 267 268

    static quint32 internalId(const QContact &contact);
    static quint32 internalId(const QContactId &id);

269
    static void registerModel(ListModel *model, FilterType type, FetchDataType requiredTypes = FetchNone, FetchDataType extraTypes = FetchNone);
mvogt's avatar
mvogt committed
270 271 272 273 274
    static void unregisterModel(ListModel *model);

    static void registerUser(QObject *user);
    static void unregisterUser(QObject *user);

275 276
    static void registerDisplayLabelGroupChangeListener(SeasideDisplayLabelGroupChangeListener *listener);
    static void unregisterDisplayLabelGroupChangeListener(SeasideDisplayLabelGroupChangeListener *listener);
mvogt's avatar
mvogt committed
277

278 279 280 281 282
    static void registerChangeListener(ChangeListener *listener);
    static void unregisterChangeListener(ChangeListener *listener);

    static void unregisterResolveListener(ResolveListener *listener);

mvogt's avatar
mvogt committed
283
    static DisplayLabelOrder displayLabelOrder();
284
    static QString sortProperty();
285
    static QString groupProperty();
mvogt's avatar
mvogt committed
286 287 288

    static int contactId(const QContact &contact);

289
    static CacheItem *existingItem(const QContactId &id);
290
    static CacheItem *existingItem(quint32 iid);
291
    static CacheItem *itemById(const QContactId &id, bool requireComplete = true);
292
    static CacheItem *itemById(int id, bool requireComplete = true);
293 294
    static QContactId selfContactId();
    static QContact contactById(const QContactId &id);
295 296

    static void ensureCompletion(CacheItem *cacheItem);
297
    static void refreshContact(CacheItem *cacheItem);
298

299 300 301
    static QString displayLabelGroup(const CacheItem *cacheItem);
    static QStringList allDisplayLabelGroups();
    static QHash<QString, QSet<quint32> > displayLabelGroupMembers();
mvogt's avatar
mvogt committed
302

303 304 305 306 307 308 309 310
    static CacheItem *itemByPhoneNumber(const QString &number, bool requireComplete = true);
    static CacheItem *itemByEmailAddress(const QString &address, bool requireComplete = true);
    static CacheItem *itemByOnlineAccount(const QString &localUid, const QString &remoteUid, bool requireComplete = true);

    static CacheItem *resolvePhoneNumber(ResolveListener *listener, const QString &number, bool requireComplete = true);
    static CacheItem *resolveEmailAddress(ResolveListener *listener, const QString &address, bool requireComplete = true);
    static CacheItem *resolveOnlineAccount(ResolveListener *listener, const QString &localUid, const QString &remoteUid, bool requireComplete = true);

mvogt's avatar
mvogt committed
311
    static bool saveContact(const QContact &contact);
312
    static bool removeContact(const QContact &contact);
313
    static bool removeContacts(const QList<QContact> &contacts);
mvogt's avatar
mvogt committed
314 315 316 317

    static void aggregateContacts(const QContact &contact1, const QContact &contact2);
    static void disaggregateContacts(const QContact &contact1, const QContact &contact2);

318 319
    static bool fetchConstituents(const QContact &contact);
    static bool fetchMergeCandidates(const QContact &contact);
mvogt's avatar
mvogt committed
320 321 322 323

    static int importContacts(const QString &path);
    static QString exportContacts();

324
    static const QList<quint32> *contacts(FilterType filterType);
mvogt's avatar
mvogt committed
325 326
    static bool isPopulated(FilterType filterType);

327 328 329
    static QString primaryName(const QString &firstName, const QString &lastName);
    static QString secondaryName(const QString &firstName, const QString &lastName);

330
    static void decomposeDisplayLabel(const QString &formattedDisplayLabel, QContactName *nameDetail);
mvogt's avatar
mvogt committed
331 332
    static QString generateDisplayLabel(const QContact &contact, DisplayLabelOrder order = FirstNameFirst);
    static QString generateDisplayLabelFromNonNameDetails(const QContact &contact);
333
    static QUrl filteredAvatarUrl(const QContact &contact, const QStringList &metadataFragments = QStringList());
mvogt's avatar
mvogt committed
334

335 336
    static QString normalizePhoneNumber(const QString &input, bool validate = false);
    static QString minimizePhoneNumber(const QString &input, bool validate = false);
337

mvogt's avatar
mvogt committed
338 339 340
    bool event(QEvent *event);

    // For synchronizeLists()
341
    int insertRange(int index, int count, const QList<quint32> &source, int sourceIndex) { return insertRange(m_syncFilter, index, count, source, sourceIndex); }
342
    int removeRange(int index, int count) { removeRange(m_syncFilter, index, count); return 0; }
mvogt's avatar
mvogt committed
343 344 345

protected:
    void timerEvent(QTimerEvent *event);
346
    void setSortOrder(const QString &property);
347
    void startRequest(bool *idleProcessing);
mvogt's avatar
mvogt committed
348 349 350 351 352 353

private slots:
    void contactsAvailable();
    void contactIdsAvailable();
    void relationshipsAvailable();
    void requestStateChanged(QContactAbstractRequest::State state);
354
    void addressRequestStateChanged(QContactAbstractRequest::State state);
355
    void dataChanged();
mvogt's avatar
mvogt committed
356 357
    void contactsAdded(const QList<QContactId> &contactIds);
    void contactsChanged(const QList<QContactId> &contactIds);
358
    void contactsPresenceChanged(const QList<QContactId> &contactIds);
mvogt's avatar
mvogt committed
359
    void contactsRemoved(const QList<QContactId> &contactIds);
360
    void displayLabelGroupsChanged(const QStringList &groups);
361 362
    void displayLabelOrderChanged(CacheConfiguration::DisplayLabelOrder order);
    void sortPropertyChanged(const QString &sortProperty);
363
    void displayStatusChanged(const QString &);
mvogt's avatar
mvogt committed
364 365

private:
366 367 368 369 370
    enum PopulateProgress {
        Unpopulated,
        FetchFavorites,
        FetchMetadata,
        FetchOnline,
371
        Populated
372 373
    };

mvogt's avatar
mvogt committed
374 375 376 377 378
    SeasideCache();
    ~SeasideCache();

    static void checkForExpiry();

379
    void keepPopulated(quint32 requiredTypes, quint32 extraTypes);
mvogt's avatar
mvogt committed
380 381

    void requestUpdate();
382
    void appendContacts(const QList<QContact> &contacts, FilterType filterType, bool partialFetch, const QSet<QContactDetail::DetailType> &queryDetailTypes);
mvogt's avatar
mvogt committed
383
    void fetchContacts();
384
    void updateContacts(const QList<QContactId> &contactIds, QList<QContactId> *updateList);
385
    void applyPendingContactUpdates();
386
    void applyContactUpdates(const QList<QContact> &contacts, const QSet<QContactDetail::DetailType> &queryDetailTypes);
387
    void updateSectionBucketIndexCaches();
mvogt's avatar
mvogt committed
388

389
    void resolveUnknownAddresses(const QString &first, const QString &second, CacheItem *item);
390
    bool updateContactIndexing(const QContact &oldContact, const QContact &contact, quint32 iid, const QSet<QContactDetail::DetailType> &queryDetailTypes, CacheItem *item);
391
    void updateCache(CacheItem *item, const QContact &contact, bool partialFetch, bool initialInsert);
392
    void reportItemUpdated(CacheItem *item);
393

mvogt's avatar
mvogt committed
394
    void removeRange(FilterType filter, int index, int count);
395
    int insertRange(FilterType filter, int index, int count, const QList<quint32> &queryIds, int queryIndex);
mvogt's avatar
mvogt committed
396

397 398 399
    void contactDataChanged(quint32 iid);
    void contactDataChanged(quint32 iid, FilterType filter);
    void removeContactData(quint32 iid, FilterType filter);
mvogt's avatar
mvogt committed
400 401
    void makePopulated(FilterType filter);

402 403 404
    void addToContactDisplayLabelGroup(quint32 iid, const QString &group, QSet<QString> *modifiedGroups = 0);
    void removeFromContactDisplayLabelGroup(quint32 iid, const QString &group, QSet<QString> *modifiedGroups = 0);
    void notifyDisplayLabelGroupsChanged(const QSet<QString> &groups);
mvogt's avatar
mvogt committed
405

406 407
    void updateConstituentAggregations(const QContactId &contactId);
    void completeContactAggregation(const QContactId &contact1Id, const QContactId &contact2Id);
mvogt's avatar
mvogt committed
408

409 410
    void resolveAddress(ResolveListener *listener, const QString &first, const QString &second, bool requireComplete);

411 412
    CacheItem *itemMatchingPhoneNumber(const QString &number, const QString &normalized, bool requireComplete);

413 414
    int contactIndex(quint32 iid, FilterType filter);

415 416
    void notifySaveContactComplete(int constituentId, int aggregateId);

417
    static QContactRelationship makeRelationship(const QString &type, const QContactId &id1, const QContactId &id2);
mvogt's avatar
mvogt committed
418 419
    static QContactRelationship makeRelationship(const QString &type, const QContact &contact1, const QContact &contact2);

420 421
    QList<quint32> m_contacts[FilterTypesCount];

mvogt's avatar
mvogt committed
422 423 424
    QBasicTimer m_expiryTimer;
    QBasicTimer m_fetchTimer;
    QHash<quint32, CacheItem> m_people;
425
    QMultiHash<QString, quint32> m_phoneNumberIds;
mvogt's avatar
mvogt committed
426
    QHash<QString, quint32> m_emailAddressIds;
427
    QHash<QPair<QString, QString>, quint32> m_onlineAccountIds;
428
    QHash<QContactId, QContact> m_contactsToSave;
429
    QHash<QString, QSet<quint32> > m_contactDisplayLabelGroups;
mvogt's avatar
mvogt committed
430
    QList<QContact> m_contactsToCreate;
431 432 433 434 435 436
    QHash<FilterType, QPair<QSet<QContactDetail::DetailType>, QList<QContact> > > m_contactsToAppend;
    QList<QPair<QSet<QContactDetail::DetailType>, QList<QContact> > > m_contactsToUpdate;
    QList<QContactId> m_contactsToRemove;
    QList<QContactId> m_changedContacts;
    QList<QContactId> m_presenceChangedContacts;
    QSet<QContactId> m_aggregatedContacts;
mvogt's avatar
mvogt committed
437 438
    QList<QContactId> m_contactsToFetchConstituents;
    QList<QContactId> m_contactsToFetchCandidates;
439
    QList<QContactId> m_contactsToLinkTo;
mvogt's avatar
mvogt committed
440 441 442
    QList<QPair<ContactLinkRequest, ContactLinkRequest> > m_contactPairsToLink;
    QList<QContactRelationship> m_relationshipsToSave;
    QList<QContactRelationship> m_relationshipsToRemove;
443
    QList<SeasideDisplayLabelGroupChangeListener*> m_displayLabelGroupChangeListeners;
444
    QList<ChangeListener*> m_changeListeners;
mvogt's avatar
mvogt committed
445 446
    QList<ListModel *> m_models[FilterTypesCount];
    QSet<QObject *> m_users;
447
    QHash<QContactId,int> m_expiredContacts;
mvogt's avatar
mvogt committed
448 449 450 451 452 453 454 455
    QContactFetchRequest m_fetchRequest;
    QContactFetchByIdRequest m_fetchByIdRequest;
    QContactIdFetchRequest m_contactIdRequest;
    QContactRelationshipFetchRequest m_relationshipsFetchRequest;
    QContactRemoveRequest m_removeRequest;
    QContactSaveRequest m_saveRequest;
    QContactRelationshipSaveRequest m_relationshipSaveRequest;
    QContactRelationshipRemoveRequest m_relationshipRemoveRequest;
456 457
    QList<QContactSortOrder> m_sortOrder;
    QList<QContactSortOrder> m_onlineSortOrder;
458
    FilterType m_syncFilter;
mvogt's avatar
mvogt committed
459 460 461
    int m_populated;
    int m_cacheIndex;
    int m_queryIndex;
462 463
    int m_fetchProcessedCount;
    int m_fetchByIdProcessedCount;
mvogt's avatar
mvogt committed
464
    DisplayLabelOrder m_displayLabelOrder;
465
    QString m_sortProperty;
466
    QString m_groupProperty;
mvogt's avatar
mvogt committed
467
    bool m_keepPopulated;
468
    PopulateProgress m_populateProgress;
469
    bool m_populating; // true if current m_fetchRequest makes progress
470
    quint32 m_fetchTypes;
471 472
    quint32 m_extraFetchTypes;
    quint32 m_dataTypesFetched;
mvogt's avatar
mvogt committed
473 474 475
    bool m_updatesPending;
    bool m_refreshRequired;
    bool m_contactsUpdated;
476
    bool m_displayOff;
477 478
    QSet<QContactId> m_constituentIds;
    QSet<QContactId> m_candidateIds;
mvogt's avatar
mvogt committed
479

480 481 482
    struct ResolveData {
        QString first;
        QString second;
483
        QString compare; // only used in m_unknownAddresses
484 485 486
        bool requireComplete;
        ResolveListener *listener;
    };
487
    QHash<QContactFetchRequest *, ResolveData> m_resolveAddresses;
488
    QSet<ResolveData> m_pendingResolve; // these have active requests already
489
    QList<ResolveData> m_unknownResolveAddresses;
490
    QList<ResolveData> m_unknownAddresses;
491
    QSet<QString> m_resolvedPhoneNumbers;
492

mvogt's avatar
mvogt committed
493 494 495 496
    QElapsedTimer m_timer;
    QElapsedTimer m_fetchPostponed;

    static SeasideCache *instancePtr;
497 498
    static int contactDisplayLabelGroupCount;
    static QStringList allContactDisplayLabelGroups;
499 500
    static QTranslator *engEnTranslator;
    static QTranslator *translator;
501 502 503

    friend bool operator==(const SeasideCache::ResolveData &lhs, const SeasideCache::ResolveData &rhs);
    friend uint qHash(const SeasideCache::ResolveData &key, uint seed);
mvogt's avatar
mvogt committed
504 505
};

506 507 508
bool operator==(const SeasideCache::ResolveData &lhs, const SeasideCache::ResolveData &rhs);
uint qHash(const SeasideCache::ResolveData &key, uint seed = 0);

mvogt's avatar
mvogt committed
509
#endif