blob: bb06bdc84d4ae137218ff6a5e6d2e48551b71d5c [file] [log] [blame]
/****************************************************************************
**
** 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