| /**************************************************************************** |
| ** |
| ** 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$ |
| ** GNU Lesser General Public License Usage |
| ** 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. |
| ** |
| ** 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. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qhelpcollectionhandler_p.h" |
| #include "qhelp_global.h" |
| #include "qhelpdbreader_p.h" |
| |
| #include <QtCore/QFile> |
| #include <QtCore/QDir> |
| #include <QtCore/QFileInfo> |
| #include <QtCore/QDebug> |
| |
| #include <QtSql/QSqlError> |
| #include <QtSql/QSqlDriver> |
| |
| QT_BEGIN_NAMESPACE |
| |
| QHelpCollectionHandler::QHelpCollectionHandler(const QString &collectionFile, QObject *parent) |
| : QObject(parent) |
| , m_dbOpened(false) |
| , m_collectionFile(collectionFile) |
| , m_connectionName(QString()) |
| { |
| QFileInfo fi(m_collectionFile); |
| if (!fi.isAbsolute()) |
| m_collectionFile = fi.absoluteFilePath(); |
| m_query.clear(); |
| } |
| |
| QHelpCollectionHandler::~QHelpCollectionHandler() |
| { |
| m_query.clear(); |
| if (m_dbOpened) |
| QSqlDatabase::removeDatabase(m_connectionName); |
| } |
| |
| bool QHelpCollectionHandler::isDBOpened() |
| { |
| if (m_dbOpened) |
| return true; |
| emit error(tr("The collection file '%1' is not set up yet!"). |
| arg(m_collectionFile)); |
| return false; |
| } |
| |
| QString QHelpCollectionHandler::collectionFile() const |
| { |
| return m_collectionFile; |
| } |
| |
| bool QHelpCollectionHandler::openCollectionFile() |
| { |
| if (m_dbOpened) |
| return m_dbOpened; |
| |
| m_connectionName = QHelpGlobal::uniquifyConnectionName( |
| QLatin1String("QHelpCollectionHandler"), this); |
| bool openingOk = true; |
| { |
| QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), |
| m_connectionName); |
| if (db.driver() |
| && db.driver()->lastError().type() == QSqlError::ConnectionError) { |
| emit error(tr("Cannot load sqlite database driver!")); |
| return false; |
| } |
| |
| db.setDatabaseName(collectionFile()); |
| openingOk = db.open(); |
| if (openingOk) |
| m_query = QSqlQuery(db); |
| } |
| if (!openingOk) { |
| QSqlDatabase::removeDatabase(m_connectionName); |
| emit error(tr("Cannot open collection file: %1").arg(collectionFile())); |
| return false; |
| } |
| |
| m_query.exec(QLatin1String("PRAGMA synchronous=OFF")); |
| m_query.exec(QLatin1String("PRAGMA cache_size=3000")); |
| |
| m_query.exec(QLatin1String("SELECT COUNT(*) FROM sqlite_master WHERE TYPE=\'table\'" |
| "AND Name=\'NamespaceTable\'")); |
| m_query.next(); |
| if (m_query.value(0).toInt() < 1) { |
| if (!createTables(&m_query)) { |
| emit error(tr("Cannot create tables in file %1!").arg(collectionFile())); |
| return false; |
| } |
| } |
| |
| m_dbOpened = true; |
| return m_dbOpened; |
| } |
| |
| bool QHelpCollectionHandler::copyCollectionFile(const QString &fileName) |
| { |
| if (!m_dbOpened) |
| return false; |
| |
| QFileInfo fi(fileName); |
| if (fi.exists()) { |
| emit error(tr("The collection file '%1' already exists!"). |
| arg(fileName)); |
| return false; |
| } |
| |
| if (!fi.absoluteDir().exists() && !QDir().mkpath(fi.absolutePath())) { |
| emit error(tr("Cannot create directory: %1").arg(fi.absolutePath())); |
| return false; |
| } |
| |
| QString colFile = fi.absoluteFilePath(); |
| QString connectionName = QHelpGlobal::uniquifyConnectionName( |
| QLatin1String("QHelpCollectionHandlerCopy"), this); |
| QSqlQuery *copyQuery = 0; |
| bool openingOk = true; |
| { |
| QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), connectionName); |
| db.setDatabaseName(colFile); |
| openingOk = db.open(); |
| if (openingOk) |
| copyQuery = new QSqlQuery(db); |
| } |
| |
| if (!openingOk) { |
| emit error(tr("Cannot open collection file: %1").arg(colFile)); |
| return false; |
| } |
| |
| copyQuery->exec(QLatin1String("PRAGMA synchronous=OFF")); |
| copyQuery->exec(QLatin1String("PRAGMA cache_size=3000")); |
| |
| if (!createTables(copyQuery)) { |
| emit error(tr("Cannot copy collection file: %1").arg(colFile)); |
| return false; |
| } |
| |
| QString oldBaseDir = QFileInfo(collectionFile()).absolutePath(); |
| QString oldFilePath; |
| QFileInfo newColFi(colFile); |
| m_query.exec(QLatin1String("SELECT Name, FilePath FROM NamespaceTable")); |
| while (m_query.next()) { |
| copyQuery->prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)")); |
| copyQuery->bindValue(0, m_query.value(0).toString()); |
| oldFilePath = m_query.value(1).toString(); |
| if (!QDir::isAbsolutePath(oldFilePath)) |
| oldFilePath = oldBaseDir + QDir::separator() + oldFilePath; |
| copyQuery->bindValue(1, newColFi.absoluteDir().relativeFilePath(oldFilePath)); |
| copyQuery->exec(); |
| } |
| |
| m_query.exec(QLatin1String("SELECT NamespaceId, Name FROM FolderTable")); |
| while (m_query.next()) { |
| copyQuery->prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)")); |
| copyQuery->bindValue(0, m_query.value(0).toString()); |
| copyQuery->bindValue(1, m_query.value(1).toString()); |
| copyQuery->exec(); |
| } |
| |
| m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); |
| while (m_query.next()) { |
| copyQuery->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); |
| copyQuery->bindValue(0, m_query.value(0).toString()); |
| copyQuery->exec(); |
| } |
| |
| m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable")); |
| while (m_query.next()) { |
| copyQuery->prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); |
| copyQuery->bindValue(0, m_query.value(0).toString()); |
| copyQuery->exec(); |
| } |
| |
| m_query.exec(QLatin1String("SELECT NameId, FilterAttributeId FROM FilterTable")); |
| while (m_query.next()) { |
| copyQuery->prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); |
| copyQuery->bindValue(0, m_query.value(0).toInt()); |
| copyQuery->bindValue(1, m_query.value(1).toInt()); |
| copyQuery->exec(); |
| } |
| |
| m_query.exec(QLatin1String("SELECT Key, Value FROM SettingsTable")); |
| while (m_query.next()) { |
| if (m_query.value(0).toString() == QLatin1String("CluceneSearchNamespaces")) |
| continue; |
| copyQuery->prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)")); |
| copyQuery->bindValue(0, m_query.value(0).toString()); |
| copyQuery->bindValue(1, m_query.value(1)); |
| copyQuery->exec(); |
| } |
| |
| copyQuery->clear(); |
| delete copyQuery; |
| QSqlDatabase::removeDatabase(connectionName); |
| return true; |
| } |
| |
| bool QHelpCollectionHandler::createTables(QSqlQuery *query) |
| { |
| QStringList tables; |
| tables << QLatin1String("CREATE TABLE NamespaceTable (" |
| "Id INTEGER PRIMARY KEY, " |
| "Name TEXT, " |
| "FilePath TEXT )") |
| << QLatin1String("CREATE TABLE FolderTable (" |
| "Id INTEGER PRIMARY KEY, " |
| "NamespaceId INTEGER, " |
| "Name TEXT )") |
| << QLatin1String("CREATE TABLE FilterAttributeTable (" |
| "Id INTEGER PRIMARY KEY, " |
| "Name TEXT )") |
| << QLatin1String("CREATE TABLE FilterNameTable (" |
| "Id INTEGER PRIMARY KEY, " |
| "Name TEXT )") |
| << QLatin1String("CREATE TABLE FilterTable (" |
| "NameId INTEGER, " |
| "FilterAttributeId INTEGER )") |
| << QLatin1String("CREATE TABLE SettingsTable (" |
| "Key TEXT PRIMARY KEY, " |
| "Value BLOB )"); |
| |
| foreach (const QString &q, tables) { |
| if (!query->exec(q)) |
| return false; |
| } |
| return true; |
| } |
| |
| QStringList QHelpCollectionHandler::customFilters() const |
| { |
| QStringList list; |
| if (m_dbOpened) { |
| m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable")); |
| while (m_query.next()) |
| list.append(m_query.value(0).toString()); |
| } |
| return list; |
| } |
| |
| bool QHelpCollectionHandler::removeCustomFilter(const QString &filterName) |
| { |
| if (!isDBOpened() || filterName.isEmpty()) |
| return false; |
| |
| int filterNameId = -1; |
| m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); |
| m_query.bindValue(0, filterName); |
| m_query.exec(); |
| if (m_query.next()) |
| filterNameId = m_query.value(0).toInt(); |
| |
| if (filterNameId < 0) { |
| emit error(tr("Unknown filter '%1'!").arg(filterName)); |
| return false; |
| } |
| |
| m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); |
| m_query.bindValue(0, filterNameId); |
| m_query.exec(); |
| |
| m_query.prepare(QLatin1String("DELETE FROM FilterNameTable WHERE Id=?")); |
| m_query.bindValue(0, filterNameId); |
| m_query.exec(); |
| |
| return true; |
| } |
| |
| bool QHelpCollectionHandler::addCustomFilter(const QString &filterName, |
| const QStringList &attributes) |
| { |
| if (!isDBOpened() || filterName.isEmpty()) |
| return false; |
| |
| int nameId = -1; |
| m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); |
| m_query.bindValue(0, filterName); |
| m_query.exec(); |
| if (m_query.next()) |
| nameId = m_query.value(0).toInt(); |
| |
| m_query.exec(QLatin1String("SELECT Id, Name FROM FilterAttributeTable")); |
| QStringList idsToInsert = attributes; |
| QMap<QString, int> attributeMap; |
| while (m_query.next()) { |
| attributeMap.insert(m_query.value(1).toString(), |
| m_query.value(0).toInt()); |
| if (idsToInsert.contains(m_query.value(1).toString())) |
| idsToInsert.removeAll(m_query.value(1).toString()); |
| } |
| |
| foreach (const QString &id, idsToInsert) { |
| m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); |
| m_query.bindValue(0, id); |
| m_query.exec(); |
| attributeMap.insert(id, m_query.lastInsertId().toInt()); |
| } |
| |
| if (nameId < 0) { |
| m_query.prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); |
| m_query.bindValue(0, filterName); |
| if (m_query.exec()) |
| nameId = m_query.lastInsertId().toInt(); |
| } |
| |
| if (nameId < 0) { |
| emit error(tr("Cannot register filter %1!").arg(filterName)); |
| return false; |
| } |
| |
| m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); |
| m_query.bindValue(0, nameId); |
| m_query.exec(); |
| |
| foreach (const QString &att, attributes) { |
| m_query.prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); |
| m_query.bindValue(0, nameId); |
| m_query.bindValue(1, attributeMap[att]); |
| if (!m_query.exec()) |
| return false; |
| } |
| return true; |
| } |
| |
| QHelpCollectionHandler::DocInfoList QHelpCollectionHandler::registeredDocumentations() const |
| { |
| DocInfoList list; |
| if (m_dbOpened) { |
| m_query.exec(QLatin1String("SELECT a.Name, a.FilePath, b.Name " |
| "FROM NamespaceTable a, FolderTable b WHERE a.Id=b.NamespaceId")); |
| |
| while (m_query.next()) { |
| DocInfo info; |
| info.fileName = m_query.value(1).toString(); |
| info.folderName = m_query.value(2).toString(); |
| info.namespaceName = m_query.value(0).toString(); |
| list.append(info); |
| } |
| } |
| return list; |
| } |
| |
| bool QHelpCollectionHandler::registerDocumentation(const QString &fileName) |
| { |
| if (!isDBOpened()) |
| return false; |
| |
| QHelpDBReader reader(fileName, QHelpGlobal::uniquifyConnectionName( |
| QLatin1String("QHelpCollectionHandler"), this), 0); |
| if (!reader.init()) { |
| emit error(tr("Cannot open documentation file %1!").arg(fileName)); |
| return false; |
| } |
| |
| QString ns = reader.namespaceName(); |
| if (ns.isEmpty()) { |
| emit error(tr("Invalid documentation file '%1'!").arg(fileName)); |
| return false; |
| } |
| |
| int nsId = registerNamespace(ns, fileName); |
| if (nsId < 1) |
| return false; |
| |
| if (!registerVirtualFolder(reader.virtualFolder(), nsId)) |
| return false; |
| |
| addFilterAttributes(reader.filterAttributes()); |
| foreach (const QString &filterName, reader.customFilters()) |
| addCustomFilter(filterName, reader.filterAttributes(filterName)); |
| |
| optimizeDatabase(fileName); |
| |
| return true; |
| } |
| |
| bool QHelpCollectionHandler::unregisterDocumentation(const QString &namespaceName) |
| { |
| if (!isDBOpened()) |
| return false; |
| |
| m_query.prepare(QLatin1String("SELECT Id FROM NamespaceTable WHERE Name=?")); |
| m_query.bindValue(0, namespaceName); |
| m_query.exec(); |
| |
| int nsId = -1; |
| if (m_query.next()) |
| nsId = m_query.value(0).toInt(); |
| |
| if (nsId < 0) { |
| emit error(tr("The namespace %1 was not registered!").arg(namespaceName)); |
| return false; |
| } |
| |
| m_query.prepare(QLatin1String("DELETE FROM NamespaceTable WHERE Id=?")); |
| m_query.bindValue(0, nsId); |
| m_query.exec(); |
| |
| m_query.prepare(QLatin1String("DELETE FROM FolderTable WHERE NamespaceId=?")); |
| m_query.bindValue(0, nsId); |
| return m_query.exec(); |
| } |
| |
| bool QHelpCollectionHandler::removeCustomValue(const QString &key) |
| { |
| if (!isDBOpened()) |
| return false; |
| |
| m_query.prepare(QLatin1String("DELETE FROM SettingsTable WHERE Key=?")); |
| m_query.bindValue(0, key); |
| return m_query.exec(); |
| } |
| |
| QVariant QHelpCollectionHandler::customValue(const QString &key, |
| const QVariant &defaultValue) const |
| { |
| QVariant value = defaultValue; |
| if (m_dbOpened) { |
| m_query.prepare(QLatin1String("SELECT COUNT(Key) FROM SettingsTable WHERE Key=?")); |
| m_query.bindValue(0, key); |
| if (!m_query.exec() || !m_query.next() || !m_query.value(0).toInt()) { |
| m_query.clear(); |
| return defaultValue; |
| } |
| |
| m_query.clear(); |
| m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?")); |
| m_query.bindValue(0, key); |
| if (m_query.exec() && m_query.next()) |
| value = m_query.value(0); |
| m_query.clear(); |
| } |
| return value; |
| } |
| |
| bool QHelpCollectionHandler::setCustomValue(const QString &key, |
| const QVariant &value) |
| { |
| if (!isDBOpened()) |
| return false; |
| |
| m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?")); |
| m_query.bindValue(0, key); |
| m_query.exec(); |
| if (m_query.next()) { |
| m_query.prepare(QLatin1String("UPDATE SettingsTable SET Value=? where Key=?")); |
| m_query.bindValue(0, value); |
| m_query.bindValue(1, key); |
| } |
| else { |
| m_query.prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)")); |
| m_query.bindValue(0, key); |
| m_query.bindValue(1, value); |
| } |
| return m_query.exec(); |
| } |
| |
| bool QHelpCollectionHandler::addFilterAttributes(const QStringList &attributes) |
| { |
| if (!isDBOpened()) |
| return false; |
| |
| m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); |
| QSet<QString> atts; |
| while (m_query.next()) |
| atts.insert(m_query.value(0).toString()); |
| |
| foreach (const QString &s, attributes) { |
| if (!atts.contains(s)) { |
| m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); |
| m_query.bindValue(0, s); |
| m_query.exec(); |
| } |
| } |
| return true; |
| } |
| |
| QStringList QHelpCollectionHandler::filterAttributes() const |
| { |
| QStringList list; |
| if (m_dbOpened) { |
| m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); |
| while (m_query.next()) |
| list.append(m_query.value(0).toString()); |
| } |
| return list; |
| } |
| |
| QStringList QHelpCollectionHandler::filterAttributes(const QString &filterName) const |
| { |
| QStringList list; |
| if (m_dbOpened) { |
| m_query.prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, " |
| "FilterTable b, FilterNameTable c WHERE a.Id=b.FilterAttributeId " |
| "AND b.NameId=c.Id AND c.Name=?")); |
| m_query.bindValue(0, filterName); |
| m_query.exec(); |
| while (m_query.next()) |
| list.append(m_query.value(0).toString()); |
| } |
| return list; |
| } |
| |
| int QHelpCollectionHandler::registerNamespace(const QString &nspace, const QString &fileName) |
| { |
| m_query.prepare(QLatin1String("SELECT COUNT(Id) FROM NamespaceTable WHERE Name=?")); |
| m_query.bindValue(0, nspace); |
| m_query.exec(); |
| while (m_query.next()) { |
| if (m_query.value(0).toInt() > 0) { |
| emit error(tr("Namespace %1 already exists!").arg(nspace)); |
| return -1; |
| } |
| } |
| |
| QFileInfo fi(m_collectionFile); |
| m_query.prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)")); |
| m_query.bindValue(0, nspace); |
| m_query.bindValue(1, fi.absoluteDir().relativeFilePath(fileName)); |
| int namespaceId = -1; |
| if (m_query.exec()) |
| namespaceId = m_query.lastInsertId().toInt(); |
| if (namespaceId < 1) { |
| emit error(tr("Cannot register namespace '%1'!").arg(nspace)); |
| return -1; |
| } |
| return namespaceId; |
| } |
| |
| bool QHelpCollectionHandler::registerVirtualFolder(const QString &folderName, int namespaceId) |
| { |
| m_query.prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)")); |
| m_query.bindValue(0, namespaceId); |
| m_query.bindValue(1, folderName); |
| return m_query.exec(); |
| } |
| |
| void QHelpCollectionHandler::optimizeDatabase(const QString &fileName) |
| { |
| if (!QFile::exists(fileName)) |
| return; |
| |
| { // according to removeDatabase() documentation |
| QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), QLatin1String("optimize")); |
| db.setDatabaseName(fileName); |
| if (!db.open()) { |
| QSqlDatabase::removeDatabase(QLatin1String("optimize")); |
| emit error(tr("Cannot open database '%1' to optimize!").arg(fileName)); |
| return; |
| } |
| |
| QSqlQuery query(db); |
| db.exec(QLatin1String("PRAGMA synchronous=OFF")); |
| db.exec(QLatin1String("PRAGMA cache_size=3000")); |
| db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS NameIndex ON IndexTable(Name)")); |
| db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileNameIndex ON FileNameTable(Name)")); |
| db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileIdIndex ON FileNameTable(FileId)")); |
| |
| db.close(); |
| } |
| |
| QSqlDatabase::removeDatabase(QLatin1String("optimize")); |
| } |
| |
| QT_END_NAMESPACE |