qhelpdbreader.cpp 21.36 KiB
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Assistant of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** 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 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** 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.
** $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) {
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
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.setConnectOptions(QLatin1String("QSQLITE_OPEN_READONLY")); 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;
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
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
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
{ 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, "
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
"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'"))
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
.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(QLatin1Char('/') + 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))));
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
} } 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;
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
} 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; }
561562563564565566567568569570571572573574575576577
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