tools/assistant/lib/qhelpenginecore.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Assistant of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qhelpenginecore.h"
       
    43 #include "qhelpengine_p.h"
       
    44 #include "qhelpdbreader_p.h"
       
    45 #include "qhelpcollectionhandler_p.h"
       
    46 
       
    47 #include <QtCore/QDir>
       
    48 #include <QtCore/QFile>
       
    49 #include <QtCore/QLibrary>
       
    50 #include <QtCore/QPluginLoader>
       
    51 #include <QtCore/QFileInfo>
       
    52 #include <QtCore/QThread>
       
    53 #include <QtGui/QApplication>
       
    54 #include <QtSql/QSqlQuery>
       
    55 
       
    56 QT_BEGIN_NAMESPACE
       
    57 
       
    58 QHelpEngineCorePrivate::QHelpEngineCorePrivate()
       
    59 {
       
    60     QHelpGlobal::uniquifyConnectionName(QString(), this);
       
    61     autoSaveFilter = true;
       
    62 }
       
    63 
       
    64 void QHelpEngineCorePrivate::init(const QString &collectionFile,
       
    65                                   QHelpEngineCore *helpEngineCore)
       
    66 {
       
    67     q = helpEngineCore;
       
    68     collectionHandler = new QHelpCollectionHandler(collectionFile, helpEngineCore);
       
    69     connect(collectionHandler, SIGNAL(error(const QString&)),
       
    70         this, SLOT(errorReceived(const QString&)));
       
    71     needsSetup = true;
       
    72 }
       
    73 
       
    74 QHelpEngineCorePrivate::~QHelpEngineCorePrivate()
       
    75 {
       
    76     delete collectionHandler;
       
    77     clearMaps();
       
    78 }
       
    79 
       
    80 void QHelpEngineCorePrivate::clearMaps()
       
    81 {
       
    82     QMap<QString, QHelpDBReader*>::iterator it = readerMap.begin();
       
    83     while (it != readerMap.end()) {
       
    84         delete it.value();
       
    85         ++it;
       
    86     }
       
    87     readerMap.clear();
       
    88     fileNameReaderMap.clear();
       
    89     virtualFolderMap.clear();
       
    90     orderedFileNameList.clear();
       
    91 }
       
    92 
       
    93 bool QHelpEngineCorePrivate::setup()
       
    94 {
       
    95     error.clear();
       
    96     if (!needsSetup)
       
    97         return true;
       
    98 
       
    99     needsSetup = false;
       
   100     emit q->setupStarted();
       
   101     clearMaps();
       
   102 
       
   103     if (!collectionHandler->openCollectionFile()) {
       
   104         emit q->setupFinished();
       
   105         return false;
       
   106     }
       
   107 
       
   108     const QHelpCollectionHandler::DocInfoList docList =
       
   109         collectionHandler->registeredDocumentations();
       
   110     QFileInfo fi(collectionHandler->collectionFile());
       
   111     QString absFileName;
       
   112     foreach(const QHelpCollectionHandler::DocInfo &info, docList) {
       
   113         if (QDir::isAbsolutePath(info.fileName)) {
       
   114             absFileName = info.fileName;
       
   115         } else {
       
   116             absFileName = QFileInfo(fi.absolutePath() + QDir::separator() + info.fileName)
       
   117                 .absoluteFilePath();
       
   118         }
       
   119         QHelpDBReader *reader = new QHelpDBReader(absFileName,
       
   120             QHelpGlobal::uniquifyConnectionName(info.fileName, this), this);
       
   121         if (!reader->init()) {
       
   122             emit q->warning(tr("Cannot open documentation file %1: %2!")
       
   123                 .arg(absFileName, reader->errorMessage()));
       
   124             continue;
       
   125         }
       
   126 
       
   127         readerMap.insert(info.namespaceName, reader);
       
   128         fileNameReaderMap.insert(absFileName, reader);
       
   129         virtualFolderMap.insert(info.folderName, reader);
       
   130         orderedFileNameList.append(absFileName);
       
   131     }
       
   132     q->currentFilter();
       
   133     emit q->setupFinished();
       
   134     return true;
       
   135 }
       
   136 
       
   137 void QHelpEngineCorePrivate::errorReceived(const QString &msg)
       
   138 {
       
   139     error = msg;
       
   140 }
       
   141 
       
   142 
       
   143 
       
   144 /*!
       
   145     \class QHelpEngineCore
       
   146     \since 4.4
       
   147     \inmodule QtHelp
       
   148     \brief The QHelpEngineCore class provides the core functionality
       
   149     of the help system.
       
   150 
       
   151     Before the help engine can be used, it must be initialized by
       
   152     calling setupData(). At the beginning of the setup process the
       
   153     signal setupStarted() is emitted. From this point on until
       
   154     the signal setupFinished() is emitted, is the help data in an
       
   155     undefined meaning unusable state.
       
   156 
       
   157     The core help engine can be used to perform different tasks.
       
   158     By calling linksForIdentifier() the engine returns
       
   159     urls specifying the file locations inside the help system. The
       
   160     actual file data can then be retrived by calling fileData(). In
       
   161     contrast to all other functions in this class, linksForIdentifier()
       
   162     depends on the currently set custom filter. Depending on the filter,
       
   163     the function may return different hits.
       
   164 
       
   165     Every help engine can contain any number of custom filters. A custom
       
   166     filter is defined by a name and set of filter attributes and can be
       
   167     added to the help engine by calling addCustomFilter(). Analogous,
       
   168     it is removed by calling removeCustomFilter(). customFilters() returns
       
   169     all defined filters.
       
   170 
       
   171     The help engine also offers the possiblity to set and read values
       
   172     in a persistant way comparable to ini files or Windows registry
       
   173     entries. For more information see setValue() or value().
       
   174 
       
   175     This class does not offer any GUI components or functionality for
       
   176     indices or contents. If you need one of those use QHelpEngine
       
   177     instead.
       
   178 
       
   179     When creating a custom help viewer the viewer can be
       
   180 configured by writing a custom collection file which could contain various
       
   181 keywords to be used to configure the help engine. These keywords and values
       
   182 and their meaning can be found in the help information for
       
   183 \l{assistant-custom-help-viewer.html#creating-a-custom-help-collection-file
       
   184 }{creating a custom help collection file} for
       
   185 Assistant.
       
   186 */
       
   187 
       
   188 /*!
       
   189     \fn void QHelpEngineCore::setupStarted()
       
   190 
       
   191     This signal is emitted when setup is started.
       
   192 */
       
   193 
       
   194 /*!
       
   195     \fn void QHelpEngineCore::setupFinished()
       
   196 
       
   197     This signal is emitted when the setup is complete.
       
   198 */
       
   199 
       
   200 /*!
       
   201     \fn void QHelpEngineCore::currentFilterChanged(const QString &newFilter)
       
   202 
       
   203     This signal is emitted when the current filter is changed to
       
   204     \a newFilter.
       
   205 */
       
   206 
       
   207 /*!
       
   208     \fn void QHelpEngineCore::warning(const QString &msg)
       
   209 
       
   210     This signal is emitted when a non critical error occurs.
       
   211     The warning message is stored in \a msg.
       
   212 */
       
   213 
       
   214 /*!
       
   215     Constructs a new core help engine with a \a parent. The help engine
       
   216     uses the information stored in the \a collectionFile to provide help.
       
   217     If the collection file does not exist yet, it'll be created.
       
   218 */
       
   219 QHelpEngineCore::QHelpEngineCore(const QString &collectionFile, QObject *parent)
       
   220     : QObject(parent)
       
   221 {
       
   222     d = new QHelpEngineCorePrivate();
       
   223     d->init(collectionFile, this);
       
   224 }
       
   225 
       
   226 /*!
       
   227     \internal
       
   228 */
       
   229 QHelpEngineCore::QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate,
       
   230                                  QObject *parent)
       
   231     : QObject(parent)
       
   232 {
       
   233     d = helpEngineCorePrivate;
       
   234 }
       
   235 
       
   236 /*!
       
   237     Destructs the help engine.
       
   238 */
       
   239 QHelpEngineCore::~QHelpEngineCore()
       
   240 {
       
   241     delete d;
       
   242 }
       
   243 
       
   244 /*!
       
   245     \property QHelpEngineCore::collectionFile
       
   246     \brief the absolute file name of the collection file currently used.
       
   247     \since 4.5
       
   248 
       
   249     Setting this property leaves the help engine in an invalid state. It is
       
   250     important to invoke setupData() or any getter function in order to setup
       
   251     the help engine again.
       
   252 */
       
   253 QString QHelpEngineCore::collectionFile() const
       
   254 {
       
   255     return d->collectionHandler->collectionFile();
       
   256 }
       
   257 
       
   258 void QHelpEngineCore::setCollectionFile(const QString &fileName)
       
   259 {
       
   260     if (fileName == collectionFile())
       
   261         return;
       
   262 
       
   263     if (d->collectionHandler) {
       
   264         delete d->collectionHandler;
       
   265         d->collectionHandler = 0;
       
   266         d->clearMaps();
       
   267     }
       
   268     d->init(fileName, this);
       
   269     d->needsSetup = true;
       
   270 }
       
   271 
       
   272 /*!
       
   273     Sets up the help engine by processing the information found
       
   274     in the collection file and returns true if successful; otherwise
       
   275     returns false.
       
   276 
       
   277     By calling the function, the help
       
   278     engine is forced to initialize itself immediately. Most of
       
   279     the times, this function does not have to be called
       
   280     explicitly because getter functions which depend on a correctly
       
   281     set up help engine do that themselves.
       
   282 
       
   283     \note \c{qsqlite4.dll} needs to be deployed with the application as the
       
   284     help system uses the sqlite driver when loading help collections.
       
   285 */
       
   286 bool QHelpEngineCore::setupData()
       
   287 {
       
   288     d->needsSetup = true;
       
   289     return d->setup();
       
   290 }
       
   291 
       
   292 /*!
       
   293     Creates the file \a fileName and copies all contents from
       
   294     the current collection file into the newly created file,
       
   295     and returns true if successful; otherwise returns false.
       
   296 
       
   297     The copying process makes sure that file references to Qt
       
   298     Collection files (\c{.qch}) files are updated accordingly.
       
   299 */
       
   300 bool QHelpEngineCore::copyCollectionFile(const QString &fileName)
       
   301 {
       
   302     if (!d->setup())
       
   303         return false;
       
   304     return d->collectionHandler->copyCollectionFile(fileName);
       
   305 }
       
   306 
       
   307 /*!
       
   308     Returns the namespace name defined for the Qt compressed help file (.qch)
       
   309     specified by its \a documentationFileName. If the file is not valid, an
       
   310     empty string is returned.
       
   311 
       
   312     \sa documentationFileName()
       
   313 */
       
   314 QString QHelpEngineCore::namespaceName(const QString &documentationFileName)
       
   315 {
       
   316     QHelpDBReader reader(documentationFileName,
       
   317         QHelpGlobal::uniquifyConnectionName(QLatin1String("GetNamespaceName"),
       
   318         QThread::currentThread()), 0);
       
   319     if (reader.init())
       
   320         return reader.namespaceName();
       
   321     return QString();
       
   322 }
       
   323 
       
   324 /*!
       
   325     Registers the Qt compressed help file (.qch) contained in the file
       
   326     \a documentationFileName. One compressed help file, uniquely
       
   327     identified by its namespace can only be registered once.
       
   328     True is returned if the registration was successful, otherwise
       
   329     false.
       
   330 
       
   331     \sa unregisterDocumentation(), error()
       
   332 */
       
   333 bool QHelpEngineCore::registerDocumentation(const QString &documentationFileName)
       
   334 {
       
   335     d->error.clear();
       
   336     d->needsSetup = true;
       
   337     return d->collectionHandler->registerDocumentation(documentationFileName);
       
   338 }
       
   339 
       
   340 /*!
       
   341     Unregisters the Qt compressed help file (.qch) identified by its
       
   342     \a namespaceName from the help collection. Returns true
       
   343     on success, otherwise false.
       
   344 
       
   345     \sa registerDocumentation(), error()
       
   346 */
       
   347 bool QHelpEngineCore::unregisterDocumentation(const QString &namespaceName)
       
   348 {
       
   349     d->error.clear();
       
   350     d->needsSetup = true;
       
   351     return d->collectionHandler->unregisterDocumentation(namespaceName);
       
   352 }
       
   353 
       
   354 /*!
       
   355     Returns the absolute file name of the Qt compressed help file (.qch)
       
   356     identified by the \a namespaceName. If there is no Qt compressed help file
       
   357     with the specified namespace registered, an empty string is returned.
       
   358 
       
   359     \sa namespaceName()
       
   360 */
       
   361 QString QHelpEngineCore::documentationFileName(const QString &namespaceName)
       
   362 {
       
   363     QString res;
       
   364     if (!d->setup())
       
   365         return res;
       
   366     const QHelpCollectionHandler::DocInfoList docList = d->collectionHandler->registeredDocumentations();
       
   367     foreach(const QHelpCollectionHandler::DocInfo info, docList) {
       
   368         if (info.namespaceName == namespaceName) {
       
   369             QFileInfo fi(d->collectionHandler->collectionFile());
       
   370             fi.setFile(fi.absolutePath() + QDir::separator() + info.fileName);
       
   371             res = QDir::cleanPath(fi.absoluteFilePath());
       
   372             break;
       
   373         }
       
   374     }
       
   375     return res;
       
   376 }
       
   377 
       
   378 /*!
       
   379     Returns a list of all registered Qt compressed help files of the current collection file.
       
   380     The returned names are the namespaces of the registered Qt compressed help files (.qch).
       
   381 */
       
   382 QStringList QHelpEngineCore::registeredDocumentations() const
       
   383 {
       
   384     QStringList list;
       
   385     if (!d->setup())
       
   386         return list;
       
   387     const QHelpCollectionHandler::DocInfoList docList = d->collectionHandler->registeredDocumentations();
       
   388     foreach(const QHelpCollectionHandler::DocInfo info, docList) {
       
   389         list.append(info.namespaceName);
       
   390     }
       
   391     return list;
       
   392 }
       
   393 
       
   394 /*!
       
   395     Returns a list of custom filters.
       
   396 
       
   397     \sa addCustomFilter(), removeCustomFilter()
       
   398 */
       
   399 QStringList QHelpEngineCore::customFilters() const
       
   400 {
       
   401     if (!d->setup())
       
   402         return QStringList();
       
   403     return d->collectionHandler->customFilters();
       
   404 }
       
   405 
       
   406 /*!
       
   407     Adds the new custom filter \a filterName. The filter attributes
       
   408     are specified by \a attributes. The function returns false if
       
   409     the filter can not be added, e.g. when the filter already exists.
       
   410 
       
   411     \sa customFilters(), removeCustomFilter()
       
   412 */
       
   413 bool QHelpEngineCore::addCustomFilter(const QString &filterName,
       
   414                                       const QStringList &attributes)
       
   415 {
       
   416     d->error.clear();
       
   417     d->needsSetup = true;
       
   418     return d->collectionHandler->addCustomFilter(filterName,
       
   419         attributes);
       
   420 }
       
   421 
       
   422 /*!
       
   423     Returns true if the filter \a filterName was removed successfully,
       
   424     otherwise false.
       
   425 
       
   426     \sa addCustomFilter(), customFilters()
       
   427 */
       
   428 bool QHelpEngineCore::removeCustomFilter(const QString &filterName)
       
   429 {
       
   430     d->error.clear();
       
   431     d->needsSetup = true;
       
   432     return d->collectionHandler->removeCustomFilter(filterName);
       
   433 }
       
   434 
       
   435 /*!
       
   436     Returns a list of all defined filter attributes.
       
   437 */
       
   438 QStringList QHelpEngineCore::filterAttributes() const
       
   439 {
       
   440     if (!d->setup())
       
   441         return QStringList();
       
   442     return d->collectionHandler->filterAttributes();
       
   443 }
       
   444 
       
   445 /*!
       
   446     Returns a list of filter attributes used by the custom
       
   447     filter \a filterName.
       
   448 */
       
   449 QStringList QHelpEngineCore::filterAttributes(const QString &filterName) const
       
   450 {
       
   451     if (!d->setup())
       
   452         return QStringList();
       
   453     return d->collectionHandler->filterAttributes(filterName);
       
   454 }
       
   455 
       
   456 /*!
       
   457     \property QHelpEngineCore::currentFilter
       
   458     \brief the name of the custom filter currently applied.
       
   459     \since 4.5
       
   460 
       
   461     Setting this property will save the new custom filter permanently in the
       
   462     help collection file. To set a custom filter without saving it
       
   463     permanently, disable the auto save filter mode.
       
   464 
       
   465     \sa autoSaveFilter()
       
   466 */
       
   467 QString QHelpEngineCore::currentFilter() const
       
   468 {
       
   469     if (!d->setup())
       
   470         return QString();
       
   471 
       
   472     if (d->currentFilter.isEmpty()) {
       
   473         QString filter =
       
   474             d->collectionHandler->customValue(QLatin1String("CurrentFilter"),
       
   475                 QString()).toString();
       
   476         if (!filter.isEmpty()
       
   477             && d->collectionHandler->customFilters().contains(filter))
       
   478             d->currentFilter = filter;
       
   479     }
       
   480     return d->currentFilter;
       
   481 }
       
   482 
       
   483 void QHelpEngineCore::setCurrentFilter(const QString &filterName)
       
   484 {
       
   485     if (!d->setup() || filterName == d->currentFilter)
       
   486         return;
       
   487     d->currentFilter = filterName;
       
   488     if (d->autoSaveFilter) {
       
   489         d->collectionHandler->setCustomValue(QLatin1String("CurrentFilter"),
       
   490             d->currentFilter);
       
   491     }
       
   492     emit currentFilterChanged(d->currentFilter);
       
   493 }
       
   494 
       
   495 /*!
       
   496     Returns a list of filter attributes for the different filter sections
       
   497     defined in the Qt compressed help file with the given namespace
       
   498     \a namespaceName.
       
   499 */
       
   500 QList<QStringList> QHelpEngineCore::filterAttributeSets(const QString &namespaceName) const
       
   501 {
       
   502     if (d->setup()) {
       
   503         QHelpDBReader *reader = d->readerMap.value(namespaceName);
       
   504         if (reader)
       
   505             return reader->filterAttributeSets();
       
   506     }
       
   507     return QList<QStringList>();
       
   508 }
       
   509 
       
   510 /*!
       
   511     Returns a list of files contained in the Qt compressed help file \a
       
   512     namespaceName. The files can be filtered by \a filterAttributes as
       
   513     well as by their extension \a extensionFilter (e.g. 'html').
       
   514 */
       
   515 QList<QUrl> QHelpEngineCore::files(const QString namespaceName,
       
   516                                    const QStringList &filterAttributes,
       
   517                                    const QString &extensionFilter)
       
   518 {
       
   519     QList<QUrl> res;
       
   520     if (!d->setup())
       
   521         return res;
       
   522     QHelpDBReader *reader = d->readerMap.value(namespaceName);
       
   523     if (!reader) {
       
   524         d->error = tr("The specified namespace does not exist!");
       
   525         return res;
       
   526     }
       
   527 
       
   528     QUrl url;
       
   529     url.setScheme(QLatin1String("qthelp"));
       
   530     url.setAuthority(namespaceName);
       
   531 
       
   532     const QStringList files = reader->files(filterAttributes, extensionFilter);
       
   533     foreach (const QString file, files) {
       
   534         url.setPath(QLatin1String("/") + file);
       
   535         res.append(url);
       
   536     }
       
   537     return res;
       
   538 }
       
   539 
       
   540 /*!
       
   541     Returns an invalid URL if the file \a url cannot be found.
       
   542     If the file exists, either the same url is returned or a
       
   543     different url if the file is located in a different namespace
       
   544     which is merged via a common virtual folder.
       
   545 */
       
   546 QUrl QHelpEngineCore::findFile(const QUrl &url) const
       
   547 {
       
   548     QUrl res;
       
   549     if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4
       
   550         || url.scheme() != QLatin1String("qthelp"))
       
   551         return res;
       
   552 
       
   553     QString ns = url.authority();
       
   554     QString filePath = QDir::cleanPath(url.path());
       
   555     if (filePath.startsWith(QLatin1Char('/')))
       
   556         filePath = filePath.mid(1);
       
   557     QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1));
       
   558     filePath = filePath.mid(virtualFolder.length()+1);
       
   559 
       
   560     QHelpDBReader *defaultReader = 0;
       
   561     if (d->readerMap.contains(ns)) {
       
   562         defaultReader = d->readerMap.value(ns);
       
   563         if (defaultReader->fileExists(virtualFolder, filePath))
       
   564             return url;
       
   565     }
       
   566 
       
   567     QStringList filterAtts = filterAttributes(currentFilter());
       
   568     foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) {
       
   569         if (reader == defaultReader)
       
   570             continue;
       
   571         if (reader->fileExists(virtualFolder, filePath, filterAtts)) {
       
   572             res = url;
       
   573             res.setAuthority(reader->namespaceName());
       
   574             return res;
       
   575         }
       
   576     }
       
   577 
       
   578     foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) {
       
   579         if (reader == defaultReader)
       
   580             continue;
       
   581         if (reader->fileExists(virtualFolder, filePath)) {
       
   582             res = url;
       
   583             res.setAuthority(reader->namespaceName());
       
   584             break;
       
   585         }
       
   586     }
       
   587 
       
   588     return res;
       
   589 }
       
   590 
       
   591 /*!
       
   592     Returns the data of the file specified by \a url. If the
       
   593     file does not exist, an empty QByteArray is returned.
       
   594 
       
   595     \sa findFile()
       
   596 */
       
   597 QByteArray QHelpEngineCore::fileData(const QUrl &url) const
       
   598 {
       
   599     if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4
       
   600         || url.scheme() != QLatin1String("qthelp"))
       
   601         return QByteArray();
       
   602 
       
   603     QString ns = url.authority();
       
   604     QString filePath = QDir::cleanPath(url.path());
       
   605     if (filePath.startsWith(QLatin1Char('/')))
       
   606         filePath = filePath.mid(1);
       
   607     QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1));
       
   608     filePath = filePath.mid(virtualFolder.length()+1);
       
   609 
       
   610     QByteArray ba;
       
   611     QHelpDBReader *defaultReader = 0;
       
   612     if (d->readerMap.contains(ns)) {
       
   613         defaultReader = d->readerMap.value(ns);
       
   614         ba = defaultReader->fileData(virtualFolder, filePath);
       
   615     }
       
   616 
       
   617     if (ba.isEmpty()) {
       
   618         foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) {
       
   619             if (reader == defaultReader)
       
   620                 continue;
       
   621             ba = reader->fileData(virtualFolder, filePath);
       
   622             if (!ba.isEmpty())
       
   623                 return ba;
       
   624         }
       
   625     }
       
   626     return ba;
       
   627 }
       
   628 
       
   629 /*!
       
   630     Returns a map of hits found for the \a id. A hit contains the
       
   631     title of the document and the url where the keyword is located.
       
   632     The result depends on the current filter, meaning only the keywords
       
   633     registered for the current filter will be returned.
       
   634 */
       
   635 QMap<QString, QUrl> QHelpEngineCore::linksForIdentifier(const QString &id) const
       
   636 {
       
   637     QMap<QString, QUrl> linkMap;
       
   638     if (!d->setup())
       
   639         return linkMap;
       
   640 
       
   641     QStringList atts = filterAttributes(d->currentFilter);
       
   642     foreach (QHelpDBReader *reader, d->readerMap)
       
   643         reader->linksForIdentifier(id, atts, linkMap);
       
   644 
       
   645     return linkMap;
       
   646 }
       
   647 
       
   648 /*!
       
   649     Removes the \a key from the settings section in the
       
   650     collection file. Returns true if the value was removed
       
   651     successfully, otherwise false.
       
   652 
       
   653     \sa customValue(), setCustomValue()
       
   654 */
       
   655 bool QHelpEngineCore::removeCustomValue(const QString &key)
       
   656 {
       
   657     d->error.clear();
       
   658     return d->collectionHandler->removeCustomValue(key);
       
   659 }
       
   660 
       
   661 /*!
       
   662     Returns the value assigned to the \a key. If the requested
       
   663     key does not exist, the specified \a defaultValue is
       
   664     returned.
       
   665 
       
   666     \sa setCustomValue(), removeCustomValue()
       
   667 */
       
   668 QVariant QHelpEngineCore::customValue(const QString &key, const QVariant &defaultValue) const
       
   669 {
       
   670     if (!d->setup())
       
   671         return QVariant();
       
   672     return d->collectionHandler->customValue(key, defaultValue);
       
   673 }
       
   674 
       
   675 /*!
       
   676     Save the \a value under the \a key. If the key already exist,
       
   677     the value will be overwritten. Returns true if the value was
       
   678     saved successfully, otherwise false.
       
   679 
       
   680     \sa customValue(), removeCustomValue()
       
   681 */
       
   682 bool QHelpEngineCore::setCustomValue(const QString &key, const QVariant &value)
       
   683 {
       
   684     d->error.clear();
       
   685     return d->collectionHandler->setCustomValue(key, value);
       
   686 }
       
   687 
       
   688 /*!
       
   689     Returns the meta data for the Qt compressed help file \a
       
   690     documentationFileName. If there is no data available for
       
   691     \a name, an invalid QVariant() is returned. The meta
       
   692     data is defined when creating the Qt compressed help file and
       
   693     cannot be modified later. Common meta data includes e.g.
       
   694     the author of the documentation.
       
   695 */
       
   696 QVariant QHelpEngineCore::metaData(const QString &documentationFileName,
       
   697                                    const QString &name)
       
   698 {
       
   699     QHelpDBReader reader(documentationFileName, QLatin1String("GetMetaData"), 0);
       
   700 
       
   701     if (reader.init())
       
   702         return reader.metaData(name);
       
   703     return QVariant();
       
   704 }
       
   705 
       
   706 /*!
       
   707     Returns a description of the last error that occured.
       
   708 */
       
   709 QString QHelpEngineCore::error() const
       
   710 {
       
   711     return d->error;
       
   712 }
       
   713 
       
   714 /*!
       
   715     \property QHelpEngineCore::autoSaveFilter
       
   716     \brief whether QHelpEngineCore is in auto save filter mode or not.
       
   717     \since 4.5
       
   718 
       
   719     If QHelpEngineCore is in auto save filter mode, the current filter is
       
   720     automatically saved when it is changed by the setCurrentFilter()
       
   721     function. The filter is saved persistently in the help collection file.
       
   722 
       
   723     By default, this mode is on.
       
   724 */
       
   725 void QHelpEngineCore::setAutoSaveFilter(bool save)
       
   726 {
       
   727     d->autoSaveFilter = save;
       
   728 }
       
   729 
       
   730 bool QHelpEngineCore::autoSaveFilter() const
       
   731 {
       
   732     return d->autoSaveFilter;
       
   733 }
       
   734 
       
   735 QT_END_NAMESPACE