diff options
Diffstat (limited to 'src/assistant/tools/assistant/main.cpp')
-rw-r--r-- | src/assistant/tools/assistant/main.cpp | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/src/assistant/tools/assistant/main.cpp b/src/assistant/tools/assistant/main.cpp new file mode 100644 index 000000000..84972c546 --- /dev/null +++ b/src/assistant/tools/assistant/main.cpp @@ -0,0 +1,440 @@ +/**************************************************************************** +** +** 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 "tracer.h" + +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QLibraryInfo> +#include <QtCore/QLocale> +#include <QtCore/QScopedPointer> +#include <QtCore/QStringList> +#include <QtCore/QTranslator> +#include <QtCore/QUrl> + +#include <QtGui/QApplication> +#include <QtGui/QDesktopServices> + +#include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpSearchEngine> + +#include <QtNetwork/QLocalSocket> + +#include <QtSql/QSqlDatabase> + +#include "../shared/collectionconfiguration.h" +#include "helpenginewrapper.h" +#include "mainwindow.h" +#include "cmdlineparser.h" + +// #define TRACING_REQUESTED + +QT_USE_NAMESPACE + +#if defined(USE_STATIC_SQLITE_PLUGIN) + #include <QtPlugin> + Q_IMPORT_PLUGIN(qsqlite) +#endif + +namespace { + +void +updateLastPagesOnUnregister(QHelpEngineCore& helpEngine, const QString& nsName) +{ + TRACE_OBJ + int lastPage = CollectionConfiguration::lastTabPage(helpEngine); + QStringList currentPages = CollectionConfiguration::lastShownPages(helpEngine); + if (!currentPages.isEmpty()) { + QStringList zoomList = CollectionConfiguration::lastZoomFactors(helpEngine); + while (zoomList.count() < currentPages.count()) + zoomList.append(CollectionConfiguration::DefaultZoomFactor); + + for (int i = currentPages.count(); --i >= 0;) { + if (QUrl(currentPages.at(i)).host() == nsName) { + zoomList.removeAt(i); + currentPages.removeAt(i); + lastPage = (lastPage == (i + 1)) ? 1 : lastPage; + } + } + + CollectionConfiguration::setLastShownPages(helpEngine, currentPages); + CollectionConfiguration::setLastTabPage(helpEngine, lastPage); + CollectionConfiguration::setLastZoomFactors(helpEngine, zoomList); + } +} + +bool +updateUserCollection(QHelpEngineCore& user, const QHelpEngineCore& caller) +{ + TRACE_OBJ + if (!CollectionConfiguration::isNewer(caller, user)) + return false; + CollectionConfiguration::copyConfiguration(caller, user); + return true; +} + +void stripNonexistingDocs(QHelpEngineCore& collection) +{ + TRACE_OBJ + const QStringList &namespaces = collection.registeredDocumentations(); + foreach (const QString &ns, namespaces) { + QFileInfo fi(collection.documentationFileName(ns)); + if (!fi.exists() || !fi.isFile()) + collection.unregisterDocumentation(ns); + } +} + +QString indexFilesFolder(const QString &collectionFile) +{ + TRACE_OBJ + QString indexFilesFolder = QLatin1String(".fulltextsearch"); + if (!collectionFile.isEmpty()) { + QFileInfo fi(collectionFile); + indexFilesFolder = QLatin1Char('.') + + fi.fileName().left(fi.fileName().lastIndexOf(QLatin1String(".qhc"))); + } + return indexFilesFolder; +} + +/* + * Returns the expected absolute file path of the cached collection file + * correspondinging to the given collection's file. + * It may or may not exist yet. + */ +QString constructCachedCollectionFilePath(const QHelpEngineCore &collection) +{ + TRACE_OBJ + const QString &filePath = collection.collectionFile(); + const QString &fileName = QFileInfo(filePath).fileName(); + const QString &cacheDir = CollectionConfiguration::cacheDir(collection); + const QString &dir = !cacheDir.isEmpty() + && CollectionConfiguration::cacheDirIsRelativeToCollection(collection) + ? QFileInfo(filePath).dir().absolutePath() + + QDir::separator() + cacheDir + : MainWindow::collectionFileDirectory(false, cacheDir); + return dir + QDir::separator() + fileName; +} + +bool synchronizeDocs(QHelpEngineCore &collection, + QHelpEngineCore &cachedCollection, + CmdLineParser &cmd) +{ + TRACE_OBJ + const QDateTime &lastCollectionRegisterTime = + CollectionConfiguration::lastRegisterTime(collection); + if (!lastCollectionRegisterTime.isValid() || lastCollectionRegisterTime + < CollectionConfiguration::lastRegisterTime(cachedCollection)) + return true; + + const QStringList &docs = collection.registeredDocumentations(); + const QStringList &cachedDocs = cachedCollection.registeredDocumentations(); + + /* + * Ensure that the cached collection contains all docs that + * the collection contains. + */ + foreach (const QString &doc, docs) { + if (!cachedDocs.contains(doc)) { + const QString &docFile = collection.documentationFileName(doc); + if (!cachedCollection.registerDocumentation(docFile)) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error registering documentation file '%1': %2"). + arg(docFile).arg(cachedCollection.error()), true); + return false; + } + } + } + + CollectionConfiguration::updateLastRegisterTime(cachedCollection); + + return true; +} + +bool removeSearchIndex(const QString &collectionFile) +{ + TRACE_OBJ + QString path = QFileInfo(collectionFile).path(); + path += QLatin1Char('/') + indexFilesFolder(collectionFile); + + QLocalSocket localSocket; + localSocket.connectToServer(QString(QLatin1String("QtAssistant%1")) + .arg(QLatin1String(QT_VERSION_STR))); + + QDir dir(path); // check if there is no other instance ruinning + if (!dir.exists() || localSocket.waitForConnected()) + return false; + + QStringList lst = dir.entryList(QDir::Files | QDir::Hidden); + foreach (const QString &item, lst) + dir.remove(item); + return true; +} + +bool rebuildSearchIndex(QCoreApplication &app, const QString &collectionFile, + CmdLineParser &cmd) +{ + TRACE_OBJ + QHelpEngine engine(collectionFile); + if (!engine.setupData()) { + cmd.showMessage(QCoreApplication::translate("Assistant", "Error: %1") + .arg(engine.error()), true); + return false; + } + + QHelpSearchEngine * const searchEngine = engine.searchEngine(); + QObject::connect(searchEngine, SIGNAL(indexingFinished()), &app, + SLOT(quit())); + searchEngine->reindexDocumentation(); + return app.exec() == 0; +} + +bool useGui(int argc, char *argv[]) +{ + TRACE_OBJ + bool gui = true; +#ifndef Q_OS_WIN + // Look for arguments that imply command-line mode. + const char * cmdModeArgs[] = { + "-help", "-register", "-unregister", "-remove-search-index", + "-rebuild-search-index" + }; + for (int i = 1; i < argc; ++i) { + for (size_t j = 0; j < sizeof cmdModeArgs/sizeof *cmdModeArgs; ++j) { + if(strcmp(argv[i], cmdModeArgs[j]) == 0) { + gui = false; + break; + } + } + } +#else + Q_UNUSED(argc) + Q_UNUSED(argv) +#endif + return gui; +} + +bool registerDocumentation(QHelpEngineCore &collection, CmdLineParser &cmd, + bool printSuccess) +{ + TRACE_OBJ + if (!collection.registerDocumentation(cmd.helpFile())) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Could not register documentation file\n%1\n\nReason:\n%2") + .arg(cmd.helpFile()).arg(collection.error()), true); + return false; + } + if (printSuccess) + cmd.showMessage(QCoreApplication::translate("Assistant", + "Documentation successfully registered."), + false); + CollectionConfiguration::updateLastRegisterTime(collection); + return true; +} + +bool unregisterDocumentation(QHelpEngineCore &collection, + const QString &namespaceName, CmdLineParser &cmd, bool printSuccess) +{ + TRACE_OBJ + if (!collection.unregisterDocumentation(namespaceName)) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Could not unregister documentation" + " file\n%1\n\nReason:\n%2"). + arg(cmd.helpFile()).arg(collection.error()), true); + return false; + } + updateLastPagesOnUnregister(collection, namespaceName); + if (printSuccess) + cmd.showMessage(QCoreApplication::translate("Assistant", + "Documentation successfully unregistered."), + false); + return true; +} + +void setupTranslation(const QString &fileName, const QString &dir) +{ + QTranslator *translator = new QTranslator(QCoreApplication::instance()); + if (translator->load(fileName, dir)) { + QCoreApplication::installTranslator(translator); + } else if (!fileName.endsWith(QLatin1String("en_US")) + && !fileName.endsWith(QLatin1String("_C"))) { + qWarning("Could not load translation file %s in directory %s.", + qPrintable(fileName), qPrintable(dir)); + } +} + +void setupTranslations() +{ + TRACE_OBJ + const QString& locale = QLocale::system().name(); + const QString &resourceDir + = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + setupTranslation(QLatin1String("assistant_") + locale, resourceDir); + setupTranslation(QLatin1String("qt_") + locale, resourceDir); + setupTranslation(QLatin1String("qt_help_") + locale, resourceDir); +} + +} // Anonymous namespace. + +int main(int argc, char *argv[]) +{ + TRACE_OBJ + QApplication a(argc, argv, useGui(argc, argv)); + a.addLibraryPath(a.applicationDirPath() + QLatin1String("/plugins")); + setupTranslations(); + + // Parse arguments. + CmdLineParser cmd(a.arguments()); + CmdLineParser::Result res = cmd.parse(); + if (res == CmdLineParser::Help) + return 0; + else if (res == CmdLineParser::Error) + return -1; + + /* + * Create the collection objects that we need. We always have the + * cached collection file. Depending on whether the user specified + * one, we also may have an input collection file. + */ + const QString collectionFile = cmd.collectionFile(); + const bool collectionFileGiven = !collectionFile.isEmpty(); + QScopedPointer<QHelpEngineCore> collection; + if (collectionFileGiven) { + collection.reset(new QHelpEngineCore(collectionFile)); + if (!collection->setupData()) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error reading collection file '%1': %2."). + arg(collectionFile).arg(collection->error()), true); + return EXIT_FAILURE; + } + } + const QString &cachedCollectionFile = collectionFileGiven + ? constructCachedCollectionFilePath(*collection) + : MainWindow::defaultHelpCollectionFileName(); + if (collectionFileGiven && !QFileInfo(cachedCollectionFile).exists() + && !collection->copyCollectionFile(cachedCollectionFile)) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error creating collection file '%1': %2."). + arg(cachedCollectionFile).arg(collection->error()), true); + return EXIT_FAILURE; + } + QHelpEngineCore cachedCollection(cachedCollectionFile); + if (!cachedCollection.setupData()) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error reading collection file '%1': %2."). + arg(cachedCollectionFile). + arg(cachedCollection.error()), true); + return EXIT_FAILURE; + } + + stripNonexistingDocs(cachedCollection); + if (collectionFileGiven) { + if (CollectionConfiguration::isNewer(*collection, cachedCollection)) + CollectionConfiguration::copyConfiguration(*collection, + cachedCollection); + if (!synchronizeDocs(*collection, cachedCollection, cmd)) + return EXIT_FAILURE; + } + + if (cmd.registerRequest() != CmdLineParser::None) { + const QStringList &cachedDocs = + cachedCollection.registeredDocumentations(); + const QString &namespaceName = + QHelpEngineCore::namespaceName(cmd.helpFile()); + if (cmd.registerRequest() == CmdLineParser::Register) { + if (collectionFileGiven + && !registerDocumentation(*collection, cmd, true)) + return EXIT_FAILURE; + if (!cachedDocs.contains(namespaceName) + && !registerDocumentation(cachedCollection, cmd, !collectionFileGiven)) + return EXIT_FAILURE; + return EXIT_SUCCESS; + } + if (cmd.registerRequest() == CmdLineParser::Unregister) { + if (collectionFileGiven + && !unregisterDocumentation(*collection, namespaceName, cmd, true)) + return EXIT_FAILURE; + if (cachedDocs.contains(namespaceName) + && !unregisterDocumentation(cachedCollection, namespaceName, + cmd, !collectionFileGiven)) + return EXIT_FAILURE; + return EXIT_SUCCESS; + } + } + + if (cmd.removeSearchIndex()) { + return removeSearchIndex(cachedCollectionFile) + ? EXIT_SUCCESS : EXIT_FAILURE; + } + + if (cmd.rebuildSearchIndex()) { + return rebuildSearchIndex(a, cachedCollectionFile, cmd) + ? EXIT_SUCCESS : EXIT_FAILURE; + } + + if (!QSqlDatabase::isDriverAvailable(QLatin1String("QSQLITE"))) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Cannot load sqlite database driver!"), + true); + return EXIT_FAILURE; + } + + if (!cmd.currentFilter().isEmpty()) { + if (collectionFileGiven) + collection->setCurrentFilter(cmd.currentFilter()); + cachedCollection.setCurrentFilter(cmd.currentFilter()); + } + + if (collectionFileGiven) + cmd.setCollectionFile(cachedCollectionFile); + + MainWindow *w = new MainWindow(&cmd); + w->show(); + a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); + + /* + * We need to be careful here: The main window has to be deleted before + * the help engine wrapper, which has to be deleted before the + * QApplication. + */ + const int retval = a.exec(); + delete w; + HelpEngineWrapper::removeInstance(); + return retval; +} |