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