diff options
author | Jarek Kobus <jaroslaw.kobus@qt.io> | 2017-02-03 13:59:39 +0100 |
---|---|---|
committer | Jarek Kobus <jaroslaw.kobus@qt.io> | 2017-03-09 07:49:59 +0000 |
commit | 060b9c9528971951b379785cb771c17ed7a50696 (patch) | |
tree | f8aa48773f0539b88976e361a5d80387aeeb2a47 | |
parent | d116ac573d80b6fdfdea4a56b7ae44f84e0ba6ad (diff) | |
download | qttools-060b9c9528971951b379785cb771c17ed7a50696.tar.gz |
Implement snippet functionality for search results
Change-Id: Idaeddb90ae39963e9b92912289f1ecbccd3669e2
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
-rw-r--r-- | src/assistant/help/help.pro | 1 | ||||
-rw-r--r-- | src/assistant/help/qhelpsearchengine.cpp | 74 | ||||
-rw-r--r-- | src/assistant/help/qhelpsearchengine.h | 26 | ||||
-rw-r--r-- | src/assistant/help/qhelpsearchindex_default_p.h | 78 | ||||
-rw-r--r-- | src/assistant/help/qhelpsearchindexreader.cpp | 8 | ||||
-rw-r--r-- | src/assistant/help/qhelpsearchindexreader_default.cpp | 50 | ||||
-rw-r--r-- | src/assistant/help/qhelpsearchindexreader_default_p.h | 11 | ||||
-rw-r--r-- | src/assistant/help/qhelpsearchindexreader_p.h | 10 | ||||
-rw-r--r-- | src/assistant/help/qhelpsearchresultwidget.cpp | 74 | ||||
-rw-r--r-- | src/assistant/help/qhelpsearchresultwidget.h | 1 |
10 files changed, 155 insertions, 178 deletions
diff --git a/src/assistant/help/help.pro b/src/assistant/help/help.pro index 5b0421ed0..cd8aa64b7 100644 --- a/src/assistant/help/help.pro +++ b/src/assistant/help/help.pro @@ -41,7 +41,6 @@ HEADERS += qhelpenginecore.h \ qhelpsearchengine.h \ qhelpsearchquerywidget.h \ qhelpsearchresultwidget.h \ - qhelpsearchindex_default_p.h \ qhelpsearchindexwriter_default_p.h \ qhelpsearchindexreader_default_p.h \ qhelpsearchindexreader_p.h diff --git a/src/assistant/help/qhelpsearchengine.cpp b/src/assistant/help/qhelpsearchengine.cpp index 5579c0cc3..d9c65b71e 100644 --- a/src/assistant/help/qhelpsearchengine.cpp +++ b/src/assistant/help/qhelpsearchengine.cpp @@ -58,6 +58,60 @@ QT_BEGIN_NAMESPACE using namespace fulltextsearch::qt; +class QHelpSearchResultData : public QSharedData +{ +public: + QUrl m_url; + QString m_title; + QString m_snippet; +}; + +QHelpSearchResult::QHelpSearchResult() + : d(new QHelpSearchResultData) +{ +} + + +QHelpSearchResult::QHelpSearchResult(const QHelpSearchResult &other) + : d(other.d) +{ +} + +QHelpSearchResult::QHelpSearchResult(const QUrl &url, const QString &title, const QString &snippet) + : d(new QHelpSearchResultData) +{ + d->m_url = url; + d->m_title = title; + d->m_snippet = snippet; +} + +QHelpSearchResult::~QHelpSearchResult() +{ +} + +QHelpSearchResult &QHelpSearchResult::operator=(const QHelpSearchResult &other) +{ + d = other.d; + return *this; +} + +QString QHelpSearchResult::title() const +{ + return d->m_title; +} + +QUrl QHelpSearchResult::url() const +{ + return d->m_url; +} + +QString QHelpSearchResult::snippet() const +{ + return d->m_snippet; +} + + + class QHelpSearchEnginePrivate : public QObject { Q_OBJECT @@ -67,7 +121,7 @@ signals: void indexingFinished(); void searchingStarted(); - void searchingFinished(int hits); + void searchingFinished(int searchResults); private: QHelpSearchEnginePrivate(QHelpEngineCore *helpEngine) @@ -94,11 +148,11 @@ private: return count; } - QList<QHelpSearchEngine::SearchHit> hits(int start, int end) const + QVector<QHelpSearchResult> searchResults(int start, int end) const { return indexReader ? - indexReader->hits(start, end) : - QList<QHelpSearchEngine::SearchHit>(); + indexReader->searchResults(start, end) : + QVector<QHelpSearchResult>(); } void updateIndex(bool reindex = false) @@ -360,6 +414,7 @@ int QHelpSearchEngine::hitCount() const return d->hitCount(); } +// TODO: obsolete the SearchHit typedef and hits methods /*! \typedef QHelpSearchEngine::SearchHit @@ -374,7 +429,16 @@ int QHelpSearchEngine::hitCount() const */ QList<QHelpSearchEngine::SearchHit> QHelpSearchEngine::hits(int start, int end) const { - return d->hits(start, end); + QList<QHelpSearchEngine::SearchHit> hits; + for (const QHelpSearchResult &result : searchResults(start, end)) + hits.append(qMakePair(result.url().toString(), result.title())); + return hits; +} + +// TODO: add a doc for searchResults() and for QHelpSearchResult class +QVector<QHelpSearchResult> QHelpSearchEngine::searchResults(int start, int end) const +{ + return d->searchResults(start, end); } /*! diff --git a/src/assistant/help/qhelpsearchengine.h b/src/assistant/help/qhelpsearchengine.h index db4876f8d..15314a65c 100644 --- a/src/assistant/help/qhelpsearchengine.h +++ b/src/assistant/help/qhelpsearchengine.h @@ -45,6 +45,7 @@ #include <QtCore/QMap> #include <QtCore/QUrl> #include <QtCore/QObject> +#include <QtCore/QSharedDataPointer> #include <QtCore/QString> #include <QtCore/QStringList> @@ -53,8 +54,9 @@ QT_BEGIN_NAMESPACE class QHelpEngineCore; class QHelpSearchQueryWidget; -class QHelpSearchResultWidget; class QHelpSearchEnginePrivate; +class QHelpSearchResultData; +class QHelpSearchResultWidget; class QHELP_EXPORT QHelpSearchQuery { @@ -70,6 +72,26 @@ public: QStringList wordList; }; +// TODO: Add doc for it + +class QHELP_EXPORT QHelpSearchResult +{ +public: + QHelpSearchResult(); + QHelpSearchResult(const QHelpSearchResult &other); + QHelpSearchResult(const QUrl &url, const QString &title, const QString &snippet); + ~QHelpSearchResult(); + + QHelpSearchResult &operator=(const QHelpSearchResult &other); + + QString title() const; + QUrl url() const; + QString snippet() const; + +private: + QSharedDataPointer<QHelpSearchResultData> d; +}; + class QHELP_EXPORT QHelpSearchEngine : public QObject { Q_OBJECT @@ -89,6 +111,8 @@ public: typedef QPair<QString, QString> SearchHit; QList<SearchHit> hits(int start, int end) const; + QVector<QHelpSearchResult> searchResults(int start, int end) const; + QList<QHelpSearchQuery> query() const; public Q_SLOTS: diff --git a/src/assistant/help/qhelpsearchindex_default_p.h b/src/assistant/help/qhelpsearchindex_default_p.h deleted file mode 100644 index 9f57612cd..000000000 --- a/src/assistant/help/qhelpsearchindex_default_p.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QHELPSEARCHINDEXDEFAULT_H -#define QHELPSEARCHINDEXDEFAULT_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the help generator tools. This header file may change from version -// to version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/QString> -#include <QtCore/QVector> -#include <QtCore/QDataStream> - -QT_BEGIN_NAMESPACE - -namespace QtHelpInternal { - -struct DocumentInfo { - - DocumentInfo() = default; - DocumentInfo(const QString &title, const QString &url) - : m_title(title), m_url(url) {} - - QString m_title; - QString m_url; -}; - -} // namespace QtHelpInternal - -using QtHelpInternal::DocumentInfo; - -QT_END_NAMESPACE - -#endif // QHELPSEARCHINDEXDEFAULT_H diff --git a/src/assistant/help/qhelpsearchindexreader.cpp b/src/assistant/help/qhelpsearchindexreader.cpp index 8037f0120..1aa7714f1 100644 --- a/src/assistant/help/qhelpsearchindexreader.cpp +++ b/src/assistant/help/qhelpsearchindexreader.cpp @@ -60,7 +60,7 @@ void QHelpSearchIndexReader::search(const QString &collectionFile, const QString { wait(); - m_hitList.clear(); + m_searchResults.clear(); m_cancel = false; m_query = queryList; m_collectionFile = collectionFile; @@ -72,14 +72,14 @@ void QHelpSearchIndexReader::search(const QString &collectionFile, const QString int QHelpSearchIndexReader::hitCount() const { QMutexLocker lock(&m_mutex); - return m_hitList.count(); + return m_searchResults.count(); } -QList<QHelpSearchEngine::SearchHit> QHelpSearchIndexReader::hits(int start, +QVector<QHelpSearchResult> QHelpSearchIndexReader::searchResults(int start, int end) const { QMutexLocker lock(&m_mutex); - return m_hitList.mid(start, end - start); + return m_searchResults.mid(start, end - start); } diff --git a/src/assistant/help/qhelpsearchindexreader_default.cpp b/src/assistant/help/qhelpsearchindexreader_default.cpp index 18e20a382..b57f3c344 100644 --- a/src/assistant/help/qhelpsearchindexreader_default.cpp +++ b/src/assistant/help/qhelpsearchindexreader_default.cpp @@ -107,13 +107,14 @@ static void bindNamespacesAndAttributes(QSqlQuery *query, const QMultiMap<QStrin } } -QVector<DocumentInfo> Reader::queryTable(const QSqlDatabase &db, +QVector<QHelpSearchResult> Reader::queryTable(const QSqlDatabase &db, const QString &tableName, const QString &term) const { const QString nsPlaceholders = namespacePlaceholders(m_namespaces); QSqlQuery query(db); - query.prepare(QLatin1String("SELECT url, title FROM ") + tableName + + query.prepare(QLatin1String("SELECT url, title, snippet(") + tableName + + QLatin1String(", -1, '<b>', '</b>', '...', '10') FROM ") + tableName + QLatin1String(" WHERE (") + nsPlaceholders + QLatin1String(") AND ") + tableName + QLatin1String(" MATCH ? ORDER BY rank")); @@ -121,15 +122,16 @@ QVector<DocumentInfo> Reader::queryTable(const QSqlDatabase &db, query.addBindValue(term); query.exec(); - QVector<DocumentInfo> documentsInfo; + QVector<QHelpSearchResult> results; while (query.next()) { const QString url = query.value(QLatin1String("url")).toString(); const QString title = query.value(QLatin1String("title")).toString(); - documentsInfo.append(DocumentInfo(title, url)); + const QString snippet = query.value(2).toString(); + results.append(QHelpSearchResult(url, title, snippet)); } - return documentsInfo; + return results; } void Reader::searchInDB(const QString &term) @@ -140,28 +142,29 @@ void Reader::searchInDB(const QString &term) db.setConnectOptions(QLatin1String("QSQLITE_OPEN_READONLY")); db.setDatabaseName(m_indexPath + QLatin1String("/fts")); if (db.open()) { - const QVector<DocumentInfo> titlesInfo = queryTable(db, - QLatin1String("titles"), term); - const QVector<DocumentInfo> contentsInfo = queryTable(db, - QLatin1String("contents"), term); + const QVector<QHelpSearchResult> titleResults = queryTable(db, + QLatin1String("titles"), term); + const QVector<QHelpSearchResult> contentResults = queryTable(db, + QLatin1String("contents"), term); // merge results form title and contents searches - m_hits = QVector<DocumentInfo>(); + m_searchResults = QVector<QHelpSearchResult>(); - QSet<QString> urls; - for (const DocumentInfo &info : titlesInfo) { - const QString url = info.m_url; + QSet<QUrl> urls; + + for (const QHelpSearchResult &result : titleResults) { + const QUrl &url = result.url(); if (!urls.contains(url)) { - m_hits.append(info); urls.insert(url); + m_searchResults.append(result); } } - for (const DocumentInfo &info : contentsInfo) { - const QString url = info.m_url; + for (const QHelpSearchResult &result : contentResults) { + const QUrl &url = result.url(); if (!urls.contains(url)) { - m_hits.append(info); urls.insert(url); + m_searchResults.append(result); } } } @@ -169,9 +172,9 @@ void Reader::searchInDB(const QString &term) QSqlDatabase::removeDatabase(uniqueId); } -QVector<DocumentInfo> Reader::hits() const +QVector<QHelpSearchResult> Reader::searchResults() const { - return m_hits; + return m_searchResults; } static bool attributesMatchFilter(const QStringList &attributes, @@ -244,13 +247,14 @@ void QHelpSearchIndexReaderDefault::run() } lock.unlock(); - m_hitList.clear(); + m_searchResults.clear(); m_reader.searchInDB(queryTerm); // TODO: should this be interruptible as well ??? - for (const DocumentInfo &docInfo : m_reader.hits()) - m_hitList.append(qMakePair(docInfo.m_url, docInfo.m_title)); + lock.relock(); + m_searchResults = m_reader.searchResults(); + lock.unlock(); - emit searchingFinished(m_hitList.count()); + emit searchingFinished(m_searchResults.count()); } } // namespace std diff --git a/src/assistant/help/qhelpsearchindexreader_default_p.h b/src/assistant/help/qhelpsearchindexreader_default_p.h index 0cea34ca2..0e9dcaed5 100644 --- a/src/assistant/help/qhelpsearchindexreader_default_p.h +++ b/src/assistant/help/qhelpsearchindexreader_default_p.h @@ -51,7 +51,6 @@ // We mean it. // -#include "qhelpsearchindex_default_p.h" #include "qhelpsearchindexreader_p.h" QT_FORWARD_DECLARE_CLASS(QSqlDatabase) @@ -68,16 +67,16 @@ public: void addNamespace(const QString &namespaceName, const QStringList &attributes); void searchInDB(const QString &term); - QVector<DocumentInfo> hits() const; + QVector<QHelpSearchResult> searchResults() const; private: - QVector<DocumentInfo> queryTable(const QSqlDatabase &db, - const QString &tableName, - const QString &term) const; + QVector<QHelpSearchResult> queryTable(const QSqlDatabase &db, + const QString &tableName, + const QString &term) const; QString m_indexPath; QMultiMap<QString, QStringList> m_namespaces; - QVector<DocumentInfo> m_hits; + QVector<QHelpSearchResult> m_searchResults; }; diff --git a/src/assistant/help/qhelpsearchindexreader_p.h b/src/assistant/help/qhelpsearchindexreader_p.h index b75b8dd2b..0a5ef11a5 100644 --- a/src/assistant/help/qhelpsearchindexreader_p.h +++ b/src/assistant/help/qhelpsearchindexreader_p.h @@ -55,10 +55,8 @@ #include <QtCore/QList> #include <QtCore/QMutex> -#include <QtCore/QObject> -#include <QtCore/QString> #include <QtCore/QThread> -#include <QtCore/QWaitCondition> +#include <QtCore/QVector> QT_BEGIN_NAMESPACE @@ -79,15 +77,15 @@ public: const QString &indexFilesFolder, const QList<QHelpSearchQuery> &queryList); int hitCount() const; - QList<QHelpSearchEngine::SearchHit> hits(int start, int end) const; + QVector<QHelpSearchResult> searchResults(int start, int end) const; signals: void searchingStarted(); - void searchingFinished(int hits); + void searchingFinished(int searchResults); protected: mutable QMutex m_mutex; - QList<QHelpSearchEngine::SearchHit> m_hitList; + QVector<QHelpSearchResult> m_searchResults; bool m_cancel = false; QString m_collectionFile; QList<QHelpSearchQuery> m_query; diff --git a/src/assistant/help/qhelpsearchresultwidget.cpp b/src/assistant/help/qhelpsearchresultwidget.cpp index 4c5f1b365..40ae94e72 100644 --- a/src/assistant/help/qhelpsearchresultwidget.cpp +++ b/src/assistant/help/qhelpsearchresultwidget.cpp @@ -56,45 +56,12 @@ QT_BEGIN_NAMESPACE -class QDefaultResultWidget : public QTreeWidget +class QResultWidget : public QTextBrowser { Q_OBJECT public: - QDefaultResultWidget(QWidget *parent = 0) - : QTreeWidget(parent) - { - header()->hide(); - connect(this, SIGNAL(itemActivated(QTreeWidgetItem*,int)), - this, SLOT(itemActivated(QTreeWidgetItem*,int))); - } - - void showResultPage(const QList<QHelpSearchEngine::SearchHit> hits) - { - for (const QHelpSearchEngine::SearchHit &hit : hits) - new QTreeWidgetItem(this, QStringList(hit.first) << hit.second); - } - -signals: - void requestShowLink(const QUrl &url); - -private slots: - void itemActivated(QTreeWidgetItem *item, int /* column */) - { - if (item) { - QString data = item->data(1, Qt::DisplayRole).toString(); - emit requestShowLink(data); - } - } -}; - - -class QCLuceneResultWidget : public QTextBrowser -{ - Q_OBJECT - -public: - QCLuceneResultWidget(QWidget *parent = 0) + QResultWidget(QWidget *parent = 0) : QTextBrowser(parent) { connect(this, SIGNAL(anchorClicked(QUrl)), @@ -102,25 +69,28 @@ public: setContextMenuPolicy(Qt::NoContextMenu); } - void showResultPage(const QList<QHelpSearchEngine::SearchHit> hits, bool isIndexing) + void showResultPage(const QVector<QHelpSearchResult> results, bool isIndexing) { - QString htmlFile = QString(QLatin1String("<html><head><title>%1</title></head><body>")) - .arg(tr("Search Results")); + QString htmlFile = QString(QLatin1String("<html><head><title>%1" + "</title></head><body>")).arg(tr("Search Results")); - int count = hits.count(); + int count = results.count(); if (count != 0) { if (isIndexing) - htmlFile += QString(QLatin1String("<div style=\"text-align:left; font-weight:bold; color:red\">" + htmlFile += QString(QLatin1String("<div style=\"text-align:left;" + " font-weight:bold; color:red\">" "%1 <span style=\"font-weight:normal; color:black\">" "%2</span></div></div><br>")).arg(tr("Note:")) .arg(tr("The search results may not be complete since the " "documentation is still being indexed.")); - for (const QHelpSearchEngine::SearchHit &hit : hits) { - htmlFile += QString(QLatin1String("<div style=\"text-align:left; font-weight:bold\"" - "><a href=\"%1\">%2</a><div style=\"color:green; font-weight:normal;" - " margin:5px\">%1</div></div><p></p>")) - .arg(hit.first).arg(hit.second); + for (const QHelpSearchResult &result : results) { + htmlFile += QString(QLatin1String("<div style=\"text-align:left;" + " font-weight:bold\"><a href=\"%1\">%2</a>" + "<div style=\"color:green; font-weight:normal;" + " margin:5px\">%3</div></div><p></p>")) + .arg(result.url().toString(), result.title(), + result.snippet()); } } else { htmlFile += QLatin1String("<div align=\"center\"><br><br><h2>") @@ -166,7 +136,7 @@ private slots: resultLastToShow += 20; resultFirstToShow += 20; - resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultTextBrowser->showResultPage(searchEngine->searchResults(resultFirstToShow, resultLastToShow), isIndexing); if (resultLastToShow >= searchEngine->hitCount()) updateNextButtonState(false); @@ -183,7 +153,7 @@ private slots: if (resultFirstToShow == resultLastToShow) resultFirstToShow -= 20; - resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultTextBrowser->showResultPage(searchEngine->searchResults(resultFirstToShow, resultLastToShow), isIndexing); updateNextButtonState(false); } @@ -196,7 +166,7 @@ private slots: resultLastToShow = 20; resultFirstToShow = 0; - resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultTextBrowser->showResultPage(searchEngine->searchResults(resultFirstToShow, resultLastToShow), isIndexing); updatePrevButtonState(false); } @@ -213,7 +183,7 @@ private slots: resultLastToShow -= count; resultFirstToShow = resultLastToShow -20; - resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultTextBrowser->showResultPage(searchEngine->searchResults(resultFirstToShow, resultLastToShow), isIndexing); if (resultFirstToShow == 0) updatePrevButtonState(false); @@ -249,7 +219,6 @@ private: , searchEngine(engine) , isIndexing(false) { - resultTreeWidget = 0; resultTextBrowser = 0; resultLastToShow = 20; @@ -305,8 +274,7 @@ private: QPointer<QHelpSearchEngine> searchEngine; - QDefaultResultWidget *resultTreeWidget; - QCLuceneResultWidget *resultTextBrowser; + QResultWidget *resultTextBrowser; int resultLastToShow; int resultFirstToShow; @@ -374,7 +342,7 @@ QHelpSearchResultWidget::QHelpSearchResultWidget(QHelpSearchEngine *engine) vLayout->addLayout(hBoxLayout); - d->resultTextBrowser = new QCLuceneResultWidget(this); + d->resultTextBrowser = new QResultWidget(this); vLayout->addWidget(d->resultTextBrowser); connect(d->resultTextBrowser, SIGNAL(requestShowLink(QUrl)), this, diff --git a/src/assistant/help/qhelpsearchresultwidget.h b/src/assistant/help/qhelpsearchresultwidget.h index 502fe56ad..95fe3b016 100644 --- a/src/assistant/help/qhelpsearchresultwidget.h +++ b/src/assistant/help/qhelpsearchresultwidget.h @@ -51,7 +51,6 @@ QT_BEGIN_NAMESPACE - class QHelpSearchResultWidgetPrivate; class QHELP_EXPORT QHelpSearchResultWidget : public QWidget |