util/tools/assistant/lib/qhelpsearchengine.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 "qhelpsearchengine.h"
       
    44 #include "qhelpsearchquerywidget.h"
       
    45 #include "qhelpsearchresultwidget.h"
       
    46 
       
    47 #include "qhelpsearchindexreader_p.h"
       
    48 #if defined(QT_CLUCENE_SUPPORT)
       
    49 #   include "qhelpsearchindexreader_clucene_p.h"
       
    50 #   include "qhelpsearchindexwriter_clucene_p.h"
       
    51 #else
       
    52 #   include "qhelpsearchindexreader_default_p.h"
       
    53 #   include "qhelpsearchindexwriter_default_p.h"
       
    54 #endif
       
    55 
       
    56 #include <QtCore/QDir>
       
    57 #include <QtCore/QFile>
       
    58 #include <QtCore/QFileInfo>
       
    59 #include <QtCore/QVariant>
       
    60 #include <QtCore/QThread>
       
    61 #include <QtCore/QPointer>
       
    62 
       
    63 QT_BEGIN_NAMESPACE
       
    64 
       
    65 #if defined(QT_CLUCENE_SUPPORT)
       
    66     using namespace fulltextsearch::clucene;
       
    67 #else
       
    68     using namespace fulltextsearch::std;
       
    69 #endif
       
    70 
       
    71 class QHelpSearchEnginePrivate : public QObject
       
    72 {
       
    73     Q_OBJECT
       
    74 
       
    75 signals:
       
    76     void indexingStarted();
       
    77     void indexingFinished();
       
    78 
       
    79     void searchingStarted();
       
    80     void searchingFinished(int hits);
       
    81 
       
    82 private:
       
    83     QHelpSearchEnginePrivate(QHelpEngineCore *helpEngine)
       
    84         : queryWidget(0)
       
    85         , resultWidget(0)
       
    86         , helpEngine(helpEngine)
       
    87     {
       
    88         indexReader = 0;
       
    89         indexWriter = 0;
       
    90     }
       
    91 
       
    92     ~QHelpSearchEnginePrivate()
       
    93     {
       
    94         delete indexReader;
       
    95         delete indexWriter;
       
    96     }
       
    97 
       
    98     int hitCount() const
       
    99     {
       
   100         int count = 0;
       
   101         if (indexReader)
       
   102             count = indexReader->hitCount();
       
   103 
       
   104         return count;
       
   105     }
       
   106 
       
   107     QList<QHelpSearchEngine::SearchHit> hits(int start, int end) const
       
   108     {
       
   109         return indexReader ?
       
   110                 indexReader->hits(start, end) :
       
   111                 QList<QHelpSearchEngine::SearchHit>();
       
   112     }
       
   113 
       
   114     void updateIndex(bool reindex = false)
       
   115     {
       
   116         if (helpEngine.isNull())
       
   117             return;
       
   118 
       
   119         if (!QFile::exists(QFileInfo(helpEngine->collectionFile()).path()))
       
   120             return;
       
   121 
       
   122         if (!indexWriter) {
       
   123             indexWriter = new QHelpSearchIndexWriter();
       
   124 
       
   125             connect(indexWriter, SIGNAL(indexingStarted()), this, SIGNAL(indexingStarted()));
       
   126             connect(indexWriter, SIGNAL(indexingFinished()), this, SIGNAL(indexingFinished()));
       
   127             connect(indexWriter, SIGNAL(indexingFinished()), this, SLOT(optimizeIndex()));
       
   128         }
       
   129 
       
   130         indexWriter->cancelIndexing();
       
   131         indexWriter->updateIndex(helpEngine->collectionFile(),
       
   132                                  indexFilesFolder(), reindex);
       
   133     }
       
   134 
       
   135     void cancelIndexing()
       
   136     {
       
   137         if (indexWriter)
       
   138             indexWriter->cancelIndexing();
       
   139     }
       
   140 
       
   141     void search(const QList<QHelpSearchQuery> &queryList)
       
   142     {
       
   143         if (helpEngine.isNull())
       
   144             return;
       
   145 
       
   146         if (!QFile::exists(QFileInfo(helpEngine->collectionFile()).path()))
       
   147             return;
       
   148 
       
   149         if (!indexReader) {
       
   150 #if defined(QT_CLUCENE_SUPPORT)
       
   151             indexReader = new QHelpSearchIndexReaderClucene();
       
   152 #else
       
   153             indexReader = new QHelpSearchIndexReaderDefault();
       
   154 #endif // QT_CLUCENE_SUPPORT
       
   155             connect(indexReader, SIGNAL(searchingStarted()), this, SIGNAL(searchingStarted()));
       
   156             connect(indexReader, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int)));
       
   157         }
       
   158 
       
   159         m_queryList = queryList;
       
   160         indexReader->cancelSearching();
       
   161         indexReader->search(helpEngine->collectionFile(), indexFilesFolder(), queryList);
       
   162     }
       
   163 
       
   164     void cancelSearching()
       
   165     {
       
   166         if (indexReader)
       
   167             indexReader->cancelSearching();
       
   168     }
       
   169 
       
   170     QString indexFilesFolder() const
       
   171     {
       
   172         QString indexFilesFolder = QLatin1String(".fulltextsearch");
       
   173         if (helpEngine && !helpEngine->collectionFile().isEmpty()) {
       
   174             QFileInfo fi(helpEngine->collectionFile());
       
   175             indexFilesFolder = fi.absolutePath() + QDir::separator()
       
   176                 + QLatin1Char('.')
       
   177                 + fi.fileName().left(fi.fileName().lastIndexOf(QLatin1String(".qhc")));
       
   178         }
       
   179         return indexFilesFolder;
       
   180     }
       
   181 
       
   182 private slots:
       
   183     void optimizeIndex()
       
   184     {
       
   185 #if defined(QT_CLUCENE_SUPPORT)
       
   186         if (indexWriter && !helpEngine.isNull()) {
       
   187             indexWriter->optimizeIndex();
       
   188         }
       
   189 #endif
       
   190     }
       
   191 
       
   192 private:
       
   193     friend class QHelpSearchEngine;
       
   194 
       
   195     QHelpSearchQueryWidget *queryWidget;
       
   196     QHelpSearchResultWidget *resultWidget;
       
   197 
       
   198     fulltextsearch::QHelpSearchIndexReader *indexReader;
       
   199     QHelpSearchIndexWriter *indexWriter;
       
   200 
       
   201     QPointer<QHelpEngineCore> helpEngine;
       
   202 
       
   203     QList<QHelpSearchQuery> m_queryList;
       
   204 };
       
   205 
       
   206 #include "qhelpsearchengine.moc"
       
   207 
       
   208 
       
   209 /*!
       
   210     \class QHelpSearchQuery
       
   211     \since 4.4
       
   212     \inmodule QtHelp
       
   213     \brief The QHelpSearchQuery class contains the field name and the associated
       
   214     search term
       
   215 
       
   216     The QHelpSearchQuery class contains the field name and the associated search
       
   217     term. Depending on the field the search term might get split up into separate
       
   218     terms to be parsed differently by the search engine.
       
   219 
       
   220     \sa QHelpSearchQueryWidget
       
   221 */
       
   222 
       
   223 /*!
       
   224     \fn QHelpSearchQuery::QHelpSearchQuery()
       
   225 
       
   226     Constructs a new empty QHelpSearchQuery.
       
   227 */
       
   228 
       
   229 /*!
       
   230     \fn QHelpSearchQuery::QHelpSearchQuery(FieldName field, const QStringList &wordList)
       
   231 
       
   232     Constructs a new QHelpSearchQuery and initializes it with the given \a field and \a wordList.
       
   233 */
       
   234 
       
   235 /*!
       
   236     \enum QHelpSearchQuery::FieldName
       
   237     This enum type specifies the field names that are handled by the search engine.
       
   238 
       
   239     \value DEFAULT  the default field provided by the search widget, several terms should be
       
   240                     split and stored in the word list except search terms enclosed in quotes.
       
   241     \value FUZZY    a field only provided in use with clucene. Terms should be split in separate
       
   242                     words and passed to the search engine.
       
   243     \value WITHOUT  a field only provided in use with clucene. Terms should be split in separate
       
   244                     words and passed to the search engine.
       
   245     \value PHRASE   a field only provided in use with clucene. Terms should not be split in separate
       
   246                     words.
       
   247     \value ALL      a field only provided in use with clucene. Terms should be split in separate
       
   248                     words and passed to the search engine
       
   249     \value ATLEAST  a field only provided in use with clucene. Terms should be split in separate
       
   250                     words and passed to the search engine
       
   251 */
       
   252 
       
   253 /*!
       
   254     \class QHelpSearchEngine
       
   255     \since 4.4
       
   256     \inmodule QtHelp
       
   257     \brief The QHelpSearchEngine class provides access to widgets reusable
       
   258     to integrate fulltext search as well as to index and search documentation.
       
   259 
       
   260     Before the search engine can be used, one has to instantiate at least a
       
   261     QHelpEngineCore object that needs to be passed to the search engines constructor.
       
   262     This is required as the search engine needs to be connected to the help
       
   263     engines setupFinished() signal to know when it can start to index documentation.
       
   264 
       
   265     After starting the indexing process the signal indexingStarted() is emitted and
       
   266     on the end of the indexing process the indexingFinished() is emited. To stop
       
   267     the indexing one can call cancelIndexing().
       
   268 
       
   269     While the indexing process has finished, the search engine can now be used to search
       
   270     thru its index for a given term. To do this one may use the possibility of creating the
       
   271     QHelpSearchQuery list by self or reuse the QHelpSearchQueryWidget which has the inbuild
       
   272     functionality to set up a proper search querys list that get's passed to the search engines
       
   273     search() function.
       
   274 
       
   275     After the list of querys has been passed to the search engine, the signal searchingStarted()
       
   276     is emited and after the search has finished the searchingFinished() signal is emited. The
       
   277     search process can be stopped by calling cancelSearching().
       
   278 
       
   279     If the search succeeds, the searchingFinished() will be called with the search hits count,
       
   280     which can be reused to fetch the search hits from the search engine. Calling the hits()
       
   281     function with the range of hits you would like to get will return a list of the requested
       
   282     SearchHits. They basically constist at the moment of a pair of strings where the values
       
   283     of that pair are the documentation file path and the page title.
       
   284 
       
   285     To display the given hits use the QHelpSearchResultWidget or build up your own one if you need
       
   286     more advanced functionality. Note that the QHelpSearchResultWidget can not be instantiated
       
   287     directly, you must retrieve the widget from the search engine in use as all connections will be
       
   288     established for you by the widget itself.
       
   289 */
       
   290 
       
   291 /*!
       
   292     \fn void QHelpSearchEngine::indexingStarted()
       
   293 
       
   294     This signal is emitted when indexing process is started.
       
   295 */
       
   296 
       
   297 /*!
       
   298     \fn void QHelpSearchEngine::indexingFinished()
       
   299 
       
   300     This signal is emitted when the indexing process is complete.
       
   301 */
       
   302 
       
   303 /*!
       
   304     \fn void QHelpSearchEngine::searchingStarted()
       
   305 
       
   306     This signal is emitted when the search process is started.
       
   307 */
       
   308 
       
   309 /*!
       
   310     \fn void QHelpSearchEngine::searchingFinished(int hits)
       
   311 
       
   312     This signal is emitted when the search process is complete.
       
   313     The hit count is stored in \a hits.
       
   314 */
       
   315 
       
   316 /*!
       
   317     Constructs a new search engine with the given \a parent. The search engine
       
   318     uses the given \a helpEngine to access the documentation that needs to be indexed.
       
   319     The QHelpEngine's setupFinished() signal is automatically connected to the
       
   320     QHelpSearchEngine's indexing function, so that new documentation will be indexed
       
   321     after the signal is emited.
       
   322 */
       
   323 QHelpSearchEngine::QHelpSearchEngine(QHelpEngineCore *helpEngine, QObject *parent)
       
   324     : QObject(parent)
       
   325 {
       
   326     d = new QHelpSearchEnginePrivate(helpEngine);
       
   327 
       
   328     connect(helpEngine, SIGNAL(setupFinished()), this, SLOT(indexDocumentation()));
       
   329 
       
   330     connect(d, SIGNAL(indexingStarted()), this, SIGNAL(indexingStarted()));
       
   331     connect(d, SIGNAL(indexingFinished()), this, SIGNAL(indexingFinished()));
       
   332     connect(d, SIGNAL(searchingStarted()), this, SIGNAL(searchingStarted()));
       
   333     connect(d, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int)));
       
   334 }
       
   335 
       
   336 /*!
       
   337     Destructs the search engine.
       
   338 */
       
   339 QHelpSearchEngine::~QHelpSearchEngine()
       
   340 {
       
   341     delete d;
       
   342 }
       
   343 
       
   344 /*!
       
   345     Returns a widget to use as input widget. Depending on your search engine
       
   346     configuration you will get a different widget with more or less subwidgets.
       
   347 */
       
   348 QHelpSearchQueryWidget* QHelpSearchEngine::queryWidget()
       
   349 {
       
   350     if (!d->queryWidget)
       
   351         d->queryWidget = new QHelpSearchQueryWidget();
       
   352 
       
   353     return d->queryWidget;
       
   354 }
       
   355 
       
   356 /*!
       
   357     Returns a widget that can hold and display the search results.
       
   358 */
       
   359 QHelpSearchResultWidget* QHelpSearchEngine::resultWidget()
       
   360 {
       
   361     if (!d->resultWidget)
       
   362         d->resultWidget = new QHelpSearchResultWidget(this);
       
   363 
       
   364     return d->resultWidget;
       
   365 }
       
   366 
       
   367 /*!
       
   368     \obsolete
       
   369     Returns the amount of hits the search engine found.
       
   370     \sa hitCount()
       
   371 */
       
   372 int QHelpSearchEngine::hitsCount() const
       
   373 {
       
   374     return d->hitCount();
       
   375 }
       
   376 
       
   377 /*!
       
   378     \since 4.6
       
   379     Returns the amount of hits the search engine found.
       
   380 */
       
   381 int QHelpSearchEngine::hitCount() const
       
   382 {
       
   383     return d->hitCount();
       
   384 }
       
   385 
       
   386 /*!
       
   387     \typedef QHelpSearchEngine::SearchHit
       
   388 
       
   389     Typedef for QPair<QString, QString>.
       
   390     The values of that pair are the documentation file path and the page title.
       
   391 
       
   392     \sa hits()
       
   393 */
       
   394 
       
   395 /*!
       
   396     Returns a list of search hits within the range of \a start \a end.
       
   397 */
       
   398 QList<QHelpSearchEngine::SearchHit> QHelpSearchEngine::hits(int start, int end) const
       
   399 {
       
   400    return d->hits(start, end);
       
   401 }
       
   402 
       
   403 /*!
       
   404     Returns the list of queries last searched for.
       
   405     \since 4.5
       
   406 */
       
   407 QList<QHelpSearchQuery> QHelpSearchEngine::query() const
       
   408 {
       
   409     return d->m_queryList;
       
   410 }
       
   411 
       
   412 /*!
       
   413     Forces the search engine to reindex all documentation files.
       
   414 */
       
   415 void QHelpSearchEngine::reindexDocumentation()
       
   416 {
       
   417     d->updateIndex(true);
       
   418 }
       
   419 
       
   420 /*!
       
   421     Stops the indexing process.
       
   422 */
       
   423 void QHelpSearchEngine::cancelIndexing()
       
   424 {
       
   425     d->cancelIndexing();
       
   426 }
       
   427 
       
   428 /*!
       
   429     Stops the search process.
       
   430 */
       
   431 void QHelpSearchEngine::cancelSearching()
       
   432 {
       
   433     d->cancelSearching();
       
   434 }
       
   435 
       
   436 /*!
       
   437     Starts the search process using the given list of querys \a queryList
       
   438     build by the search field name and the values to search for.
       
   439 */
       
   440 void QHelpSearchEngine::search(const QList<QHelpSearchQuery> &queryList)
       
   441 {
       
   442     d->search(queryList);
       
   443 }
       
   444 
       
   445 void QHelpSearchEngine::indexDocumentation()
       
   446 {
       
   447     d->updateIndex();
       
   448 }
       
   449 
       
   450 QT_END_NAMESPACE