summaryrefslogtreecommitdiffstats
path: root/src/assistant/lib/qhelpdbreader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/assistant/lib/qhelpdbreader.cpp')
-rw-r--r--src/assistant/lib/qhelpdbreader.cpp583
1 files changed, 583 insertions, 0 deletions
diff --git a/src/assistant/lib/qhelpdbreader.cpp b/src/assistant/lib/qhelpdbreader.cpp
new file mode 100644
index 000000000..c4735f8b8
--- /dev/null
+++ b/src/assistant/lib/qhelpdbreader.cpp
@@ -0,0 +1,583 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhelpdbreader_p.h"
+#include "qhelp_global.h"
+
+#include <QtCore/QVariant>
+#include <QtCore/QFile>
+#include <QtSql/QSqlError>
+#include <QtSql/QSqlQuery>
+
+QT_BEGIN_NAMESPACE
+
+QHelpDBReader::QHelpDBReader(const QString &dbName)
+ : QObject(0)
+{
+ initObject(dbName,
+ QHelpGlobal::uniquifyConnectionName(QLatin1String("QHelpDBReader"),
+ this));
+}
+
+QHelpDBReader::QHelpDBReader(const QString &dbName, const QString &uniqueId,
+ QObject *parent)
+ : QObject(parent)
+{
+ initObject(dbName, uniqueId);
+}
+
+void QHelpDBReader::initObject(const QString &dbName, const QString &uniqueId)
+{
+ m_dbName = dbName;
+ m_uniqueId = uniqueId;
+ m_initDone = false;
+ m_query = 0;
+ m_useAttributesCache = false;
+}
+
+QHelpDBReader::~QHelpDBReader()
+{
+ if (m_initDone) {
+ delete m_query;
+ QSqlDatabase::removeDatabase(m_uniqueId);
+ }
+}
+
+bool QHelpDBReader::init()
+{
+ if (m_initDone)
+ return true;
+
+ if (!QFile::exists(m_dbName))
+ return false;
+
+ QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_uniqueId);
+ db.setDatabaseName(m_dbName);
+ if (!db.open()) {
+ /*: The placeholders are: %1 - The name of the database which cannot be opened
+ %2 - The unique id for the connection
+ %3 - The actual error string */
+ m_error = tr("Cannot open database '%1' '%2': %3").arg(m_dbName, m_uniqueId, db.lastError().text());
+ QSqlDatabase::removeDatabase(m_uniqueId);
+ return false;
+ }
+
+ m_initDone = true;
+ m_query = new QSqlQuery(db);
+
+ return true;
+}
+
+QString QHelpDBReader::databaseName() const
+{
+ return m_dbName;
+}
+
+QString QHelpDBReader::errorMessage() const
+{
+ return m_error;
+}
+
+QString QHelpDBReader::namespaceName() const
+{
+ if (!m_namespace.isEmpty())
+ return m_namespace;
+ if (m_query) {
+ m_query->exec(QLatin1String("SELECT Name FROM NamespaceTable"));
+ if (m_query->next())
+ m_namespace = m_query->value(0).toString();
+ }
+ return m_namespace;
+}
+
+QString QHelpDBReader::virtualFolder() const
+{
+ if (m_query) {
+ m_query->exec(QLatin1String("SELECT Name FROM FolderTable WHERE Id=1"));
+ if (m_query->next())
+ return m_query->value(0).toString();
+ }
+ return QString();
+}
+
+QList<QStringList> QHelpDBReader::filterAttributeSets() const
+{
+ QList<QStringList> result;
+ if (m_query) {
+ m_query->exec(QLatin1String("SELECT a.Id, b.Name FROM FileAttributeSetTable a, "
+ "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id ORDER BY a.Id"));
+ int oldId = -1;
+ while (m_query->next()) {
+ int id = m_query->value(0).toInt();
+ if (id != oldId) {
+ result.append(QStringList());
+ oldId = id;
+ }
+ result.last().append(m_query->value(1).toString());
+ }
+ }
+ return result;
+}
+
+bool QHelpDBReader::fileExists(const QString &virtualFolder,
+ const QString &filePath,
+ const QStringList &filterAttributes) const
+{
+ if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query)
+ return false;
+
+//SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id AND b.Name='qtdoc' AND a.Name='qstring.html' AND a.FileId=c.FileId AND c.FilterAttributeId=d.Id AND d.Name='qtrefdoc'
+
+ QString query;
+ namespaceName();
+ if (filterAttributes.isEmpty()) {
+ query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b "
+ "WHERE a.FolderId=b.Id AND b.Name=\'%1\' AND a.Name=\'%2\'")).arg(quote(virtualFolder)).arg(quote(filePath));
+ } else {
+ query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, "
+ "FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id "
+ "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND "
+ "c.FilterAttributeId=d.Id AND d.Name=\'%3\'"))
+ .arg(quote(virtualFolder)).arg(quote(filePath))
+ .arg(quote(filterAttributes.first()));
+ for (int i=1; i<filterAttributes.count(); ++i) {
+ query.append(QString(QLatin1String(" INTERSECT SELECT COUNT(a.Name) FROM FileNameTable a, "
+ "FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id "
+ "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND "
+ "c.FilterAttributeId=d.Id AND d.Name=\'%3\'"))
+ .arg(quote(virtualFolder)).arg(quote(filePath))
+ .arg(quote(filterAttributes.at(i))));
+ }
+ }
+ m_query->exec(query);
+ if (m_query->next() && m_query->isValid() && m_query->value(0).toInt())
+ return true;
+ return false;
+}
+
+QByteArray QHelpDBReader::fileData(const QString &virtualFolder,
+ const QString &filePath) const
+{
+ QByteArray ba;
+ if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query)
+ return ba;
+
+ namespaceName();
+ m_query->prepare(QLatin1String("SELECT a.Data FROM FileDataTable a, FileNameTable b, FolderTable c, "
+ "NamespaceTable d WHERE a.Id=b.FileId AND (b.Name=? OR b.Name=?) AND b.FolderId=c.Id "
+ "AND c.Name=? AND c.NamespaceId=d.Id AND d.Name=?"));
+ m_query->bindValue(0, filePath);
+ m_query->bindValue(1, QString(QLatin1String("./") + filePath));
+ m_query->bindValue(2, virtualFolder);
+ m_query->bindValue(3, m_namespace);
+ m_query->exec();
+ if (m_query->next() && m_query->isValid())
+ ba = qUncompress(m_query->value(0).toByteArray());
+ return ba;
+}
+
+QStringList QHelpDBReader::customFilters() const
+{
+ QStringList lst;
+ if (m_query) {
+ m_query->exec(QLatin1String("SELECT Name FROM FilterNameTable"));
+ while (m_query->next())
+ lst.append(m_query->value(0).toString());
+ }
+ return lst;
+}
+
+QStringList QHelpDBReader::filterAttributes(const QString &filterName) const
+{
+ QStringList lst;
+ if (m_query) {
+ if (filterName.isEmpty()) {
+ m_query->prepare(QLatin1String("SELECT Name FROM FilterAttributeTable"));
+ } else {
+ m_query->prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, "
+ "FilterTable b, FilterNameTable c WHERE c.Name=? "
+ "AND c.Id=b.NameId AND b.FilterAttributeId=a.Id"));
+ m_query->bindValue(0, filterName);
+ }
+ m_query->exec();
+ while (m_query->next())
+ lst.append(m_query->value(0).toString());
+ }
+ return lst;
+}
+
+QStringList QHelpDBReader::indicesForFilter(const QStringList &filterAttributes) const
+{
+ QStringList indices;
+ if (!m_query)
+ return indices;
+
+ //SELECT DISTINCT a.Name FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId AND b.FilterAttributeId=c.Id AND c.Name in ('4.2.3', 'qt')
+
+ QString query;
+ if (filterAttributes.isEmpty()) {
+ query = QLatin1String("SELECT DISTINCT Name FROM IndexTable");
+ } else {
+ query = QString(QLatin1String("SELECT DISTINCT a.Name FROM IndexTable a, "
+ "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId "
+ "AND b.FilterAttributeId=c.Id AND c.Name='%1'")).arg(quote(filterAttributes.first()));
+ for (int i=1; i<filterAttributes.count(); ++i) {
+ query.append(QString(QLatin1String(" INTERSECT SELECT DISTINCT a.Name FROM IndexTable a, "
+ "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId "
+ "AND b.FilterAttributeId=c.Id AND c.Name='%1'"))
+ .arg(quote(filterAttributes.at(i))));
+ }
+ }
+
+ m_query->exec(query);
+ while (m_query->next()) {
+ if (!m_query->value(0).toString().isEmpty())
+ indices.append(m_query->value(0).toString());
+ }
+ return indices;
+}
+
+void QHelpDBReader::linksForKeyword(const QString &keyword, const QStringList &filterAttributes,
+ QMap<QString, QUrl> &linkMap) const
+{
+ if (!m_query)
+ return;
+
+ QString query;
+ if (filterAttributes.isEmpty()) {
+ query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
+ "FROM IndexTable a, FileNameTable d, "
+ "FolderTable e, NamespaceTable f WHERE "
+ "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id "
+ "AND a.Name='%1'")).arg(quote(keyword));
+ } else if (m_useAttributesCache) {
+ query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id "
+ "FROM IndexTable a, "
+ "FileNameTable d, FolderTable e, NamespaceTable f WHERE "
+ "a.FileId=d.FileId AND d.FolderId=e.Id "
+ "AND a.NamespaceId=f.Id AND a.Name='%1'"))
+ .arg(quote(keyword));
+ m_query->exec(query);
+ while (m_query->next()) {
+ if (m_indicesCache.contains(m_query->value(5).toInt())) {
+ linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(),
+ m_query->value(2).toString(), m_query->value(3).toString(),
+ m_query->value(4).toString()));
+ }
+ }
+ return;
+ } else {
+ query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
+ "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, "
+ "FileNameTable d, FolderTable e, NamespaceTable f "
+ "WHERE a.FileId=d.FileId AND d.FolderId=e.Id "
+ "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id "
+ "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword))
+ .arg(quote(filterAttributes.first()));
+ for (int i=1; i<filterAttributes.count(); ++i) {
+ query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
+ "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, "
+ "FileNameTable d, FolderTable e, NamespaceTable f "
+ "WHERE a.FileId=d.FileId AND d.FolderId=e.Id "
+ "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id "
+ "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword))
+ .arg(quote(filterAttributes.at(i))));
+ }
+ }
+
+ QString title;
+ m_query->exec(query);
+ while (m_query->next()) {
+ title = m_query->value(0).toString();
+ if (title.isEmpty()) // generate a title + corresponding path
+ title = keyword + QLatin1String(" : ") + m_query->value(3).toString();
+ linkMap.insertMulti(title, buildQUrl(m_query->value(1).toString(),
+ m_query->value(2).toString(), m_query->value(3).toString(),
+ m_query->value(4).toString()));
+ }
+}
+
+void QHelpDBReader::linksForIdentifier(const QString &id,
+ const QStringList &filterAttributes,
+ QMap<QString, QUrl> &linkMap) const
+{
+ if (!m_query)
+ return;
+
+ QString query;
+ if (filterAttributes.isEmpty()) {
+ query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
+ "FROM IndexTable a, FileNameTable d, FolderTable e, "
+ "NamespaceTable f WHERE a.FileId=d.FileId AND "
+ "d.FolderId=e.Id AND a.NamespaceId=f.Id AND a.Identifier='%1'"))
+ .arg(quote(id));
+ } else if (m_useAttributesCache) {
+ query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id "
+ "FROM IndexTable a,"
+ "FileNameTable d, FolderTable e, NamespaceTable f WHERE "
+ "a.FileId=d.FileId AND d.FolderId=e.Id "
+ "AND a.NamespaceId=f.Id AND a.Identifier='%1'"))
+ .arg(quote(id));
+ m_query->exec(query);
+ while (m_query->next()) {
+ if (m_indicesCache.contains(m_query->value(5).toInt())) {
+ linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(),
+ m_query->value(2).toString(), m_query->value(3).toString(),
+ m_query->value(4).toString()));
+ }
+ }
+ return;
+ } else {
+ query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor "
+ "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, "
+ "FileNameTable d, FolderTable e, NamespaceTable f "
+ "WHERE a.FileId=d.FileId AND d.FolderId=e.Id "
+ "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id "
+ "AND a.Identifier='%1' AND c.Name='%2'")).arg(quote(id))
+ .arg(quote(filterAttributes.first()));
+ for (int i=0; i<filterAttributes.count(); ++i) {
+ query.append(QString(QLatin1String(" INTERSECT SELECT d.Title, f.Name, e.Name, "
+ "d.Name, a.Anchor FROM IndexTable a, IndexFilterTable b, "
+ "FilterAttributeTable c, FileNameTable d, "
+ "FolderTable e, NamespaceTable f WHERE "
+ "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id "
+ "AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id AND "
+ "a.Identifier='%1' AND c.Name='%2'")).arg(quote(id))
+ .arg(quote(filterAttributes.at(i))));
+ }
+ }
+
+ m_query->exec(query);
+ while (m_query->next()) {
+ linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(),
+ m_query->value(2).toString(), m_query->value(3).toString(),
+ m_query->value(4).toString()));
+ }
+}
+
+QUrl QHelpDBReader::buildQUrl(const QString &ns, const QString &folder,
+ const QString &relFileName, const QString &anchor) const
+{
+ QUrl url;
+ url.setScheme(QLatin1String("qthelp"));
+ url.setAuthority(ns);
+ url.setPath(folder + QLatin1Char('/') + relFileName);
+ url.setFragment(anchor);
+ return url;
+}
+
+QList<QByteArray> QHelpDBReader::contentsForFilter(const QStringList &filterAttributes) const
+{
+ QList<QByteArray> contents;
+ if (!m_query)
+ return contents;
+
+ //SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='qt' INTERSECT SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='3.3.8';
+
+ QString query;
+ if (filterAttributes.isEmpty()) {
+ query = QLatin1String("SELECT Data from ContentsTable");
+ } else {
+ query = QString(QLatin1String("SELECT a.Data FROM ContentsTable a, "
+ "ContentsFilterTable b, FilterAttributeTable c "
+ "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id "
+ "AND c.Name='%1'")).arg(quote(filterAttributes.first()));
+ for (int i=1; i<filterAttributes.count(); ++i) {
+ query.append(QString(QLatin1String(" INTERSECT SELECT a.Data FROM ContentsTable a, "
+ "ContentsFilterTable b, FilterAttributeTable c "
+ "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id "
+ "AND c.Name='%1'")).arg(quote(filterAttributes.at(i))));
+ }
+ }
+
+ m_query->exec(query);
+ while (m_query->next()) {
+ contents.append(m_query->value(0).toByteArray());
+ }
+ return contents;
+}
+
+QUrl QHelpDBReader::urlOfPath(const QString &relativePath) const
+{
+ QUrl url;
+ if (!m_query)
+ return url;
+
+ m_query->exec(QLatin1String("SELECT a.Name, b.Name FROM NamespaceTable a, "
+ "FolderTable b WHERE a.id=b.NamespaceId and a.Id=1"));
+ if (m_query->next()) {
+ QString rp = relativePath;
+ QString anchor;
+ int i = rp.indexOf(QLatin1Char('#'));
+ if (i > -1) {
+ rp = relativePath.left(i);
+ anchor = relativePath.mid(i+1);
+ }
+ url = buildQUrl(m_query->value(0).toString(),
+ m_query->value(1).toString(), rp, anchor);
+ }
+ return url;
+}
+
+QStringList QHelpDBReader::files(const QStringList &filterAttributes,
+ const QString &extensionFilter) const
+{
+ QStringList lst;
+ if (!m_query)
+ return lst;
+
+ QString query;
+ QString extension;
+ if (!extensionFilter.isEmpty())
+ extension = QString(QLatin1String("AND b.Name like \'%.%1\'")).arg(extensionFilter);
+
+ if (filterAttributes.isEmpty()) {
+ query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, "
+ "FileNameTable b WHERE b.FolderId=a.Id %1"))
+ .arg(extension);
+ } else {
+ query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, "
+ "FileNameTable b, FileFilterTable c, FilterAttributeTable d "
+ "WHERE b.FolderId=a.Id AND b.FileId=c.FileId "
+ "AND c.FilterAttributeId=d.Id AND d.Name=\'%1\' %2"))
+ .arg(quote(filterAttributes.first())).arg(extension);
+ for (int i=1; i<filterAttributes.count(); ++i) {
+ query.append(QString(QLatin1String(" INTERSECT SELECT a.Name, b.Name FROM "
+ "FolderTable a, FileNameTable b, FileFilterTable c, "
+ "FilterAttributeTable d WHERE b.FolderId=a.Id AND "
+ "b.FileId=c.FileId AND c.FilterAttributeId=d.Id AND "
+ "d.Name=\'%1\' %2")).arg(quote(filterAttributes.at(i)))
+ .arg(extension));
+ }
+ }
+ m_query->exec(query);
+ while (m_query->next()) {
+ lst.append(m_query->value(0).toString() + QLatin1Char('/')
+ + m_query->value(1).toString());
+ }
+
+ return lst;
+}
+
+QVariant QHelpDBReader::metaData(const QString &name) const
+{
+ QVariant v;
+ if (!m_query)
+ return v;
+
+ m_query->prepare(QLatin1String("SELECT COUNT(Value), Value FROM MetaDataTable "
+ "WHERE Name=?"));
+ m_query->bindValue(0, name);
+ if (m_query->exec() && m_query->next()
+ && m_query->value(0).toInt() == 1)
+ v = m_query->value(1);
+ return v;
+}
+
+QString QHelpDBReader::mergeList(const QStringList &list) const
+{
+ QString str;
+ foreach (const QString &s, list)
+ str.append(QLatin1Char('\'') + quote(s) + QLatin1String("\', "));
+ if (str.endsWith(QLatin1String(", ")))
+ str = str.left(str.length()-2);
+ return str;
+}
+
+QString QHelpDBReader::quote(const QString &string) const
+{
+ QString s = string;
+ s.replace(QLatin1Char('\''), QLatin1String("\'\'"));
+ return s;
+}
+
+QSet<int> QHelpDBReader::indexIds(const QStringList &attributes) const
+{
+ QSet<int> ids;
+
+ if (attributes.isEmpty())
+ return ids;
+
+ QString query = QString(QLatin1String("SELECT a.IndexId FROM IndexFilterTable a, "
+ "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id "
+ "AND b.Name='%1'")).arg(attributes.first());
+ for (int i=0; i<attributes.count(); ++i) {
+ query.append(QString(QLatin1String(" INTERSECT SELECT a.IndexId FROM "
+ "IndexFilterTable a, FilterAttributeTable b WHERE "
+ "a.FilterAttributeId=b.Id AND b.Name='%1'"))
+ .arg(attributes.at(i)));
+ }
+
+ if (!m_query->exec(query))
+ return ids;
+
+ while (m_query->next())
+ ids.insert(m_query->value(0).toInt());
+
+ return ids;
+}
+
+bool QHelpDBReader::createAttributesCache(const QStringList &attributes,
+ const QSet<int> &indexIds)
+{
+ m_useAttributesCache = false;
+
+ if (attributes.count() < 2) {
+ m_viewAttributes.clear();
+ return true;
+ }
+
+ bool needUpdate = !m_viewAttributes.count();
+
+ foreach (const QString &s, attributes)
+ m_viewAttributes.remove(s);
+
+ if (m_viewAttributes.count() || needUpdate) {
+ m_viewAttributes.clear();
+ m_indicesCache = indexIds;
+ }
+ foreach (const QString &s, attributes)
+ m_viewAttributes.insert(s);
+ m_useAttributesCache = true;
+ return true;
+}
+
+QT_END_NAMESPACE