tools/assistant/lib/qhelpsearchresultwidget.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 "qhelpsearchresultwidget.h"
       
    43 
       
    44 #include <QtCore/QList>
       
    45 #include <QtCore/QString>
       
    46 #include <QtCore/QPointer>
       
    47 #include <QtCore/QStringList>
       
    48 
       
    49 #include <QtGui/QLabel>
       
    50 #include <QtGui/QLayout>
       
    51 #include <QtGui/QMouseEvent>
       
    52 #include <QtGui/QHeaderView>
       
    53 #include <QtGui/QSpacerItem>
       
    54 #include <QtGui/QToolButton>
       
    55 #include <QtGui/QTreeWidget>
       
    56 #include <QtGui/QTextBrowser>
       
    57 #include <QtGui/QTreeWidgetItem>
       
    58 
       
    59 QT_BEGIN_NAMESPACE
       
    60 
       
    61 class QDefaultResultWidget : public QTreeWidget
       
    62 {
       
    63     Q_OBJECT
       
    64 
       
    65 public:
       
    66     QDefaultResultWidget(QWidget *parent = 0)
       
    67         : QTreeWidget(parent)
       
    68     {
       
    69         header()->hide();
       
    70         connect(this, SIGNAL(itemActivated(QTreeWidgetItem*, int)),
       
    71             this, SLOT(itemActivated(QTreeWidgetItem*, int)));
       
    72     }
       
    73 
       
    74     void showResultPage(const QList<QHelpSearchEngine::SearchHit> hits)
       
    75     {
       
    76         foreach (const QHelpSearchEngine::SearchHit hit, hits)
       
    77             new QTreeWidgetItem(this, QStringList(hit.first) << hit.second);
       
    78     }
       
    79 
       
    80 signals:
       
    81     void requestShowLink(const QUrl &url);
       
    82 
       
    83 private slots:
       
    84     void itemActivated(QTreeWidgetItem *item, int /* column */)
       
    85     {
       
    86         if (item) {
       
    87             QString data = item->data(1, Qt::DisplayRole).toString();
       
    88             emit requestShowLink(data);
       
    89         }
       
    90     }
       
    91 };
       
    92 
       
    93 
       
    94 class QCLuceneResultWidget : public QTextBrowser
       
    95 {
       
    96     Q_OBJECT
       
    97 
       
    98 public:
       
    99     QCLuceneResultWidget(QWidget *parent = 0)
       
   100         : QTextBrowser(parent)
       
   101     {
       
   102         connect(this, SIGNAL(anchorClicked(const QUrl&)),
       
   103             this, SIGNAL(requestShowLink(const QUrl&)));
       
   104         setContextMenuPolicy(Qt::NoContextMenu);
       
   105     }
       
   106 
       
   107     void showResultPage(const QList<QHelpSearchEngine::SearchHit> hits, bool isIndexing)
       
   108     {
       
   109         QString htmlFile = QString(QLatin1String("<html><head><title>%1</title></head><body>"))
       
   110             .arg(tr("Search Results"));
       
   111 
       
   112         int count = hits.count();
       
   113         if (count != 0) {
       
   114             if (isIndexing)
       
   115                 htmlFile += QString(QLatin1String("<div style=\"text-align:left; font-weight:bold; color:red\">"
       
   116                     "%1&nbsp;<span style=\"font-weight:normal; color:black\">"
       
   117                     "%2</span></div></div><br>")).arg(tr("Note:"))
       
   118                     .arg(tr("The search results may not be complete since the "
       
   119                             "documentation is still being indexed!"));
       
   120 
       
   121             foreach (const QHelpSearchEngine::SearchHit hit, hits) {
       
   122                 htmlFile += QString(QLatin1String("<div style=\"text-align:left; font-weight:bold\""
       
   123                 "><a href=\"%1\">%2</a><div style=\"color:green; font-weight:normal;"
       
   124                 " margin:5px\">%1</div></div><p></p>"))
       
   125                 .arg(hit.first).arg(hit.second);
       
   126             }
       
   127         } else {
       
   128             htmlFile += QLatin1String("<div align=\"center\"><br><br><h2>")
       
   129                     + tr("Your search did not match any documents.")
       
   130                     + QLatin1String("</h2><div>");
       
   131             if (isIndexing)
       
   132                 htmlFile += QLatin1String("<div align=\"center\"><h3>")
       
   133                     + tr("(The reason for this might be that the documentation "
       
   134                          "is still being indexed.)")
       
   135                     + QLatin1String("</h3><div>");
       
   136         }
       
   137 
       
   138         htmlFile += QLatin1String("</body></html>");
       
   139 
       
   140         setHtml(htmlFile);
       
   141     }
       
   142 
       
   143 signals:
       
   144     void requestShowLink(const QUrl &url);
       
   145 
       
   146 private slots:
       
   147     void setSource(const QUrl & /* name */) {}
       
   148 };
       
   149 
       
   150 
       
   151 class QHelpSearchResultWidgetPrivate : public QObject
       
   152 {
       
   153     Q_OBJECT
       
   154 
       
   155 private slots:
       
   156     void setResults(int hitsCount)
       
   157     {
       
   158         if (!searchEngine.isNull()) {
       
   159 #if defined(QT_CLUCENE_SUPPORT)
       
   160             showFirstResultPage();
       
   161             updateNextButtonState(((hitsCount > 20) ? true : false));
       
   162 #else
       
   163             resultTreeWidget->clear();
       
   164             resultTreeWidget->showResultPage(searchEngine->hits(0, hitsCount));
       
   165 #endif
       
   166         }
       
   167     }
       
   168 
       
   169     void showNextResultPage()
       
   170     {
       
   171         if (!searchEngine.isNull()
       
   172             && resultLastToShow < searchEngine->hitsCount()) {
       
   173             resultLastToShow += 20;
       
   174             resultFirstToShow += 20;
       
   175 
       
   176             resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow,
       
   177                 resultLastToShow), isIndexing);
       
   178             if (resultLastToShow >= searchEngine->hitsCount())
       
   179                 updateNextButtonState(false);
       
   180         }
       
   181         updateHitRange();
       
   182     }
       
   183 
       
   184     void showLastResultPage()
       
   185     {
       
   186         if (!searchEngine.isNull()) {
       
   187             resultLastToShow = searchEngine->hitsCount();
       
   188             resultFirstToShow = resultLastToShow - (resultLastToShow % 20);
       
   189 
       
   190             if (resultFirstToShow == resultLastToShow)
       
   191                 resultFirstToShow -= 20;
       
   192 
       
   193             resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow,
       
   194                 resultLastToShow), isIndexing);
       
   195             updateNextButtonState(false);
       
   196         }
       
   197         updateHitRange();
       
   198     }
       
   199 
       
   200     void showFirstResultPage()
       
   201     {
       
   202         if (!searchEngine.isNull()) {
       
   203             resultLastToShow = 20;
       
   204             resultFirstToShow = 0;
       
   205 
       
   206             resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow,
       
   207                 resultLastToShow), isIndexing);
       
   208             updatePrevButtonState(false);
       
   209         }
       
   210         updateHitRange();
       
   211     }
       
   212 
       
   213     void showPreviousResultPage()
       
   214     {
       
   215         if (!searchEngine.isNull()) {
       
   216             int count = resultLastToShow % 20;
       
   217             if (count == 0 || resultLastToShow != searchEngine->hitsCount())
       
   218                 count = 20;
       
   219 
       
   220             resultLastToShow -= count;
       
   221             resultFirstToShow = resultLastToShow -20;
       
   222 
       
   223             resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow,
       
   224                 resultLastToShow), isIndexing);
       
   225             if (resultFirstToShow == 0)
       
   226                 updatePrevButtonState(false);
       
   227         }
       
   228         updateHitRange();
       
   229     }
       
   230 
       
   231     void updatePrevButtonState(bool state = true)
       
   232     {
       
   233         firstResultPage->setEnabled(state);
       
   234         previousResultPage->setEnabled(state);
       
   235     }
       
   236 
       
   237     void updateNextButtonState(bool state = true)
       
   238     {
       
   239         nextResultPage->setEnabled(state);
       
   240         lastResultPage->setEnabled(state);
       
   241     }
       
   242 
       
   243     void indexingStarted()
       
   244     {
       
   245         isIndexing = true;
       
   246     }
       
   247 
       
   248     void indexingFinished()
       
   249     {
       
   250         isIndexing = false;
       
   251     }
       
   252 
       
   253 private:
       
   254     QHelpSearchResultWidgetPrivate(QHelpSearchEngine *engine)
       
   255         : QObject()
       
   256         , searchEngine(engine)
       
   257         , isIndexing(false)
       
   258     {
       
   259         resultTreeWidget = 0;
       
   260         resultTextBrowser = 0;
       
   261 
       
   262         resultLastToShow = 20;
       
   263         resultFirstToShow = 0;
       
   264 
       
   265         firstResultPage = 0;
       
   266         previousResultPage = 0;
       
   267         hitsLabel = 0;
       
   268         nextResultPage = 0;
       
   269         lastResultPage = 0;
       
   270 
       
   271         connect(searchEngine, SIGNAL(indexingStarted()),
       
   272             this, SLOT(indexingStarted()));
       
   273         connect(searchEngine, SIGNAL(indexingFinished()),
       
   274             this, SLOT(indexingFinished()));
       
   275     }
       
   276 
       
   277     ~QHelpSearchResultWidgetPrivate()
       
   278     {
       
   279         delete searchEngine;
       
   280     }
       
   281 
       
   282     QToolButton* setupToolButton(const QString &iconPath)
       
   283     {
       
   284         QToolButton *button = new QToolButton();
       
   285         button->setEnabled(false);
       
   286         button->setAutoRaise(true);
       
   287         button->setIcon(QIcon(iconPath));
       
   288         button->setIconSize(QSize(12, 12));
       
   289         button->setMaximumSize(QSize(16, 16));
       
   290 
       
   291         return button;
       
   292     }
       
   293 
       
   294     void updateHitRange()
       
   295     {
       
   296         int last = 0;
       
   297         int first = 0;
       
   298         int count = 0;
       
   299 
       
   300         if (!searchEngine.isNull()) {
       
   301             count = searchEngine->hitsCount();
       
   302             if (count > 0) {
       
   303                 first = resultFirstToShow +1;
       
   304                 last = resultLastToShow > count ? count : resultLastToShow;
       
   305             }
       
   306         }
       
   307         hitsLabel->setText(tr("%1 - %2 of %3 Hits").arg(first).arg(last).arg(count));
       
   308     }
       
   309 
       
   310 private:
       
   311     friend class QHelpSearchResultWidget;
       
   312 
       
   313     QPointer<QHelpSearchEngine> searchEngine;
       
   314 
       
   315     QDefaultResultWidget *resultTreeWidget;
       
   316     QCLuceneResultWidget *resultTextBrowser;
       
   317 
       
   318     int resultLastToShow;
       
   319     int resultFirstToShow;
       
   320     bool isIndexing;
       
   321 
       
   322     QToolButton *firstResultPage;
       
   323     QToolButton *previousResultPage;
       
   324     QLabel *hitsLabel;
       
   325     QToolButton *nextResultPage;
       
   326     QToolButton *lastResultPage;
       
   327 };
       
   328 
       
   329 #include "qhelpsearchresultwidget.moc"
       
   330 
       
   331 
       
   332 /*!
       
   333     \class QHelpSearchResultWidget
       
   334     \since 4.4
       
   335     \inmodule QtHelp
       
   336     \brief The QHelpSearchResultWidget class provides either a tree
       
   337     widget or a text browser depending on the used search engine to display
       
   338     the hits found by the search.
       
   339 */
       
   340 
       
   341 /*!
       
   342     \fn void QHelpSearchResultWidget::requestShowLink(const QUrl &link)
       
   343 
       
   344     This signal is emitted when a item is activated and its associated
       
   345     \a link should be shown.
       
   346 */
       
   347 
       
   348 QHelpSearchResultWidget::QHelpSearchResultWidget(QHelpSearchEngine *engine)
       
   349     : QWidget(0)
       
   350     , d(new QHelpSearchResultWidgetPrivate(engine))
       
   351 {
       
   352     QVBoxLayout *vLayout = new QVBoxLayout(this);
       
   353     vLayout->setMargin(0);
       
   354     vLayout->setSpacing(0);
       
   355 
       
   356 #if defined(QT_CLUCENE_SUPPORT)
       
   357     QHBoxLayout *hBoxLayout = new QHBoxLayout();
       
   358 #ifndef Q_OS_MAC
       
   359     hBoxLayout->setMargin(0);
       
   360     hBoxLayout->setSpacing(0);
       
   361 #endif
       
   362     hBoxLayout->addWidget(d->firstResultPage = d->setupToolButton(
       
   363         QString::fromUtf8(":/trolltech/assistant/images/3leftarrow.png")));
       
   364 
       
   365     hBoxLayout->addWidget(d->previousResultPage = d->setupToolButton(
       
   366         QString::fromUtf8(":/trolltech/assistant/images/1leftarrow.png")));
       
   367 
       
   368     d->hitsLabel = new QLabel(tr("0 - 0 of 0 Hits"), this);
       
   369     d->hitsLabel->setEnabled(false);
       
   370     hBoxLayout->addWidget(d->hitsLabel);
       
   371     d->hitsLabel->setAlignment(Qt::AlignCenter);
       
   372     d->hitsLabel->setMinimumSize(QSize(150, d->hitsLabel->height()));
       
   373 
       
   374     hBoxLayout->addWidget(d->nextResultPage = d->setupToolButton(
       
   375         QString::fromUtf8(":/trolltech/assistant/images/1rightarrow.png")));
       
   376 
       
   377     hBoxLayout->addWidget(d->lastResultPage = d->setupToolButton(
       
   378         QString::fromUtf8(":/trolltech/assistant/images/3rightarrow.png")));
       
   379 
       
   380     QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
       
   381     hBoxLayout->addItem(spacer);
       
   382 
       
   383     vLayout->addLayout(hBoxLayout);
       
   384 
       
   385     d->resultTextBrowser = new QCLuceneResultWidget(this);
       
   386     vLayout->addWidget(d->resultTextBrowser);
       
   387 
       
   388     connect(d->resultTextBrowser, SIGNAL(requestShowLink(const QUrl&)), this,
       
   389         SIGNAL(requestShowLink(const QUrl&)));
       
   390 
       
   391     connect(d->nextResultPage, SIGNAL(clicked()), d, SLOT(showNextResultPage()));
       
   392     connect(d->lastResultPage, SIGNAL(clicked()), d, SLOT(showLastResultPage()));
       
   393     connect(d->firstResultPage, SIGNAL(clicked()), d, SLOT(showFirstResultPage()));
       
   394     connect(d->previousResultPage, SIGNAL(clicked()), d, SLOT(showPreviousResultPage()));
       
   395 
       
   396     connect(d->firstResultPage, SIGNAL(clicked()), d, SLOT(updateNextButtonState()));
       
   397     connect(d->previousResultPage, SIGNAL(clicked()), d, SLOT(updateNextButtonState()));
       
   398     connect(d->nextResultPage, SIGNAL(clicked()), d, SLOT(updatePrevButtonState()));
       
   399     connect(d->lastResultPage, SIGNAL(clicked()), d, SLOT(updatePrevButtonState()));
       
   400 
       
   401 #else
       
   402     d->resultTreeWidget = new QDefaultResultWidget(this);
       
   403     vLayout->addWidget(d->resultTreeWidget);
       
   404     connect(d->resultTreeWidget, SIGNAL(requestShowLink(const QUrl&)), this,
       
   405         SIGNAL(requestShowLink(const QUrl&)));
       
   406 #endif
       
   407 
       
   408     connect(engine, SIGNAL(searchingFinished(int)), d, SLOT(setResults(int)));
       
   409 }
       
   410 
       
   411 /*!
       
   412     Destroys the search result widget.
       
   413 */
       
   414 QHelpSearchResultWidget::~QHelpSearchResultWidget()
       
   415 {
       
   416     delete d;
       
   417 }
       
   418 
       
   419 /*!
       
   420     Returns a reference of the URL that the item at \a point owns, or an
       
   421     empty URL if no item exists at that point.
       
   422 */
       
   423 QUrl QHelpSearchResultWidget::linkAt(const QPoint &point)
       
   424 {
       
   425     QUrl url;
       
   426 #if defined(QT_CLUCENE_SUPPORT)
       
   427     if (d->resultTextBrowser)
       
   428         url = d->resultTextBrowser->anchorAt(point);
       
   429 #else
       
   430     if (d->resultTreeWidget) {
       
   431         QTreeWidgetItem *item = d->resultTreeWidget->itemAt(point);
       
   432         if (item)
       
   433             url = item->data(1, Qt::DisplayRole).toString();
       
   434     }
       
   435 #endif
       
   436     return url;
       
   437 }
       
   438 
       
   439 QT_END_NAMESPACE