/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Mobility Components. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QGALLERYTRACKERITEMLIST_P_P_H #define QGALLERYTRACKERITEMLIST_P_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include "qgallerytrackerresultset_p.h" #include "qgalleryresultset_p.h" #include "qgallerytrackerlistcolumn_p.h" #include "qgallerytrackermetadataedit_p.h" #include "qgallerytrackerschema_p.h" #include #include #include #include #include #include #include #include #include QTM_BEGIN_NAMESPACE class QGalleryTrackerResultSetThread : public QThread { public: QGalleryTrackerResultSetThread(QRunnable *runnable) : runnable(runnable) {} void run() { runnable->run(); } private: QRunnable *runnable; }; class QGalleryTrackerResultSetPrivate : public QGalleryResultSetPrivate, public QRunnable { Q_DECLARE_PUBLIC(QGalleryTrackerResultSet) public: struct SyncEvent { enum Type { Update, Replace, Finish }; const Type type; const int rIndex; const int rCount; const int iIndex; const int iCount; static SyncEvent *updateEvent(int aIndex, int iIndex, int count) { return new SyncEvent(Update, aIndex, count, iIndex, count); } static SyncEvent *replaceEvent(int aIndex, int aCount, int iIndex, int iCount) { return new SyncEvent(Replace, aIndex, aCount, iIndex, iCount); } static SyncEvent *finishEvent(int aIndex, int iIndex) { return new SyncEvent(Finish, aIndex, 0, iIndex, 0); } private: SyncEvent(Type type, int rIndex, int rCount, int iIndex, int iCount) : type(type), rIndex(rIndex), rCount(rCount), iIndex(iIndex), iCount(iCount) {} }; class SyncEventQueue { public: SyncEventQueue() {} ~SyncEventQueue() { qDeleteAll(m_queue); } bool enqueue(SyncEvent *event) { QMutexLocker locker(&m_mutex); m_queue.enqueue(event); m_wait.wakeOne(); return m_queue.count() == 1; } SyncEvent *dequeue() { QMutexLocker locker(&m_mutex); return !m_queue.isEmpty() ? m_queue.dequeue() : 0; } bool waitForEvent(int msecs) { QMutexLocker locker(&m_mutex); if (!m_queue.isEmpty()) return true; return m_wait.wait(&m_mutex, msecs); } private: QQueue m_queue; QMutex m_mutex; QWaitCondition m_wait; }; struct Row { Row() {} Row(QVector::iterator begin, QVector::iterator end) : begin(begin), end(end) {} QVector::iterator begin; QVector::iterator end; }; struct row_iterator { row_iterator() {} row_iterator(QVector::iterator begin, int width) : begin(begin), width(width) {} bool operator != (const row_iterator &other) const { return begin != other.begin; } bool operator <(const row_iterator &other) const { return begin < other.begin; } row_iterator &operator ++() { begin += width; return *this; } row_iterator &operator --() { begin -= width; return *this; } row_iterator operator ++(int) { row_iterator n(*this); begin += width; return n; } row_iterator operator --(int) { row_iterator n(*this); begin -= width; return n; } int operator -(const row_iterator &other) const { return (begin - other.begin) / width; } int operator -(const QVector::const_iterator &iterator) const { return (begin - iterator) / width; } row_iterator operator +(int span) const { return row_iterator(begin + (span * width), width); } row_iterator &operator +=(int span) { begin += span * width; return *this; } Row &operator *() { return row = Row(begin, begin + width); } const Row &operator *() const { return row = Row(begin, begin + width); } bool isEqual(const row_iterator &other, int count) const { return qEqual(begin, begin + count, other.begin); } bool isEqual(const row_iterator &other, int index, int count) { return qEqual(begin + index, begin + count, other.begin + index); } const QVariant &operator[] (int column) const { return *(begin + column); } QVector::iterator begin; int width; mutable Row row; }; struct const_row_iterator { const_row_iterator() {} const_row_iterator(QVector::const_iterator begin, int width) : begin(begin), width(width) {} bool operator != (const const_row_iterator &other) const { return begin != other.begin; } bool operator <(const const_row_iterator &other) const { return begin < other.begin; } const_row_iterator &operator ++() { begin += width; return *this; } const_row_iterator operator --(int) { const_row_iterator n(*this); begin -= width; return n; } int operator -(const const_row_iterator &other) const { return (begin - other.begin) / width; } int operator -(const QVector::const_iterator &iterator) const { return (begin - iterator) / width; } const_row_iterator operator +(int span) const { return const_row_iterator(begin + (span * width), width); } const_row_iterator &operator +=(int span) { begin += span * width; return *this; } bool isEqual(const const_row_iterator &other, int count) const { return qEqual(begin, begin + count, other.begin); } bool isEqual(const const_row_iterator &other, int index, int count) { return qEqual(begin + index, begin + count, other.begin + index); } QVector::const_iterator begin; int width; }; struct Cache { Cache() : count(0), cutoff(0) {} int count; union { int offset; int cutoff; }; QVector values; }; typedef QVector::const_iterator sort_iterator; enum Flag { Canceled = 0x01, Live = 0x02, Refresh = 0x04, Reset = 0x08, UpdateRequested = 0x10, Active = 0x20, SyncFinished = 0x40 }; Q_DECLARE_FLAGS(Flags, Flag) QGalleryTrackerResultSetPrivate( QGalleryTrackerResultSetArguments *arguments, bool autoUpdate, int offset, int limit) : idColumn(arguments->idColumn.take()) , urlColumn(arguments->urlColumn.take()) , typeColumn(arguments->typeColumn.take()) , updateMask(arguments->updateMask) , identityWidth(arguments->identityWidth) , tableWidth(arguments->tableWidth) , valueOffset(arguments->valueOffset) , compositeOffset(arguments->compositeOffset) , aliasOffset(compositeOffset + arguments->compositeColumns.count()) , columnCount(aliasOffset + arguments->aliasColumns.count()) , queryOffset(offset) , queryLimit(limit) , currentRow(0) , currentIndex(-1) , rowCount(0) , progressMaximum(0) , parserLimit(0) , parserReset(false) , queryInterface(arguments->queryInterface) , queryMethod(arguments->queryMethod) , queryArguments(arguments->queryArguments) , propertyNames(arguments->propertyNames) , propertyAttributes(arguments->propertyAttributes) , propertyTypes(arguments->propertyTypes) , valueColumns(arguments->valueColumns) , compositeColumns(arguments->compositeColumns) , aliasColumns(arguments->aliasColumns) , sortCriteria(arguments->sortCriteria) , resourceKeys(arguments->resourceKeys) , parserThread(this) { arguments->clear(); if (autoUpdate) flags |= Live; } ~QGalleryTrackerResultSetPrivate() { qDeleteAll(valueColumns); qDeleteAll(compositeColumns); } Flags flags; const QScopedPointer idColumn; const QScopedPointer urlColumn; const QScopedPointer typeColumn; const int updateMask; const int identityWidth; const int tableWidth; const int valueOffset; const int compositeOffset; const int aliasOffset; const int columnCount; const int queryOffset; const int queryLimit; QVector::const_iterator currentRow; int currentIndex; int rowCount; int progressMaximum; int parserLimit; bool parserReset; const QGalleryDBusInterfacePointer queryInterface; const QString queryMethod; const QVariantList queryArguments; const QStringList propertyNames; const QList propertyKeys; const QVector propertyAttributes; const QVector propertyTypes; const QVector valueColumns; const QVector compositeColumns; const QVector aliasColumns; const QVector sortCriteria; const QVector resourceKeys; Cache rCache; // Remove cache. Cache iCache; // Insert cache. QScopedPointer queryWatcher; QDBusArgument queryReply; QGalleryTrackerResultSetThread parserThread; QList edits; QBasicTimer updateTimer; SyncEventQueue syncEvents; inline int rCacheIndex(const const_row_iterator &iterator) const { return iterator - rCache.values.begin(); } inline int iCacheIndex(const const_row_iterator &iterator) const { return iterator - iCache.values.begin(); } void update(); void requestUpdate() { if (!(flags & UpdateRequested)) { flags |= UpdateRequested; QCoreApplication::postEvent(q_func(), new QEvent(QEvent::UpdateRequest)); } } void query(); void queryFinished(const QDBusPendingCall &call); void run(); void correctRows( row_iterator begin, row_iterator end, const sort_iterator sortBegin, const sort_iterator sortEnd, bool reversed = false) const; void synchronize(); void postSyncEvent(SyncEvent *event) { if (syncEvents.enqueue(event)) QCoreApplication::postEvent(q_func(), new QEvent(QEvent::UpdateLater)); } void processSyncEvents(); void removeItems(const int rIndex, const int iIndex, const int count); void insertItems(const int rIndex, const int iIndex, const int count); void syncUpdate(const int aIndex, const int aCount, const int iIndex, const int iCount); void syncReplace(const int aIndex, const int aCount, const int iIndex, const int iCount); void syncFinish(const int aIndex, const int iIndex); bool waitForSyncFinish(int msecs); void _q_queryFinished(QDBusPendingCallWatcher *watcher); void _q_parseFinished(); void _q_editFinished(QGalleryTrackerMetaDataEdit *edit); }; QTM_END_NAMESPACE template <> inline void qSwap( QTM_PREPEND_NAMESPACE(QGalleryTrackerResultSetPrivate::Row) &row1, QTM_PREPEND_NAMESPACE(QGalleryTrackerResultSetPrivate::Row) &row2) { typedef QVector::iterator iterator; for (iterator it1 = row1.begin, it2 = row2.begin; it1 != row1.end; ++it1, ++it2) qSwap(*it1, *it2); } #endif Q_DECLARE_OPERATORS_FOR_FLAGS(QTM_PREPEND_NAMESPACE(QGalleryTrackerResultSetPrivate::Flags))