diff options
author | Jarek Kobus <jaroslaw.kobus@qt.io> | 2018-07-27 15:06:43 +0200 |
---|---|---|
committer | Jarek Kobus <jaroslaw.kobus@qt.io> | 2018-11-12 09:08:58 +0000 |
commit | 1f0b89f8e8da682a4bf0f82c077c363b4d43a707 (patch) | |
tree | b9d0f5bf3b1796c8ccfe62e3b9f49c8dcfee677e | |
parent | 2095b1598ebe1d3ee91f9eeb1f7a13a4cbbf36f9 (diff) |
Add new filter API, enclosed in QHelpFilterEngine
Implement new filter mechanism and provide component
filtering.
Task-number: QTCREATORBUG-19724
Task-number: QTCREATORBUG-7301
Change-Id: I48400e3bc969495a66c3002fed13a7c3ddb1e249
Reviewed-by: Kai Koehne <kai.koehne@qt.io>
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
29 files changed, 1150 insertions, 605 deletions
diff --git a/src/assistant/assistant/filternamedialog.cpp b/src/assistant/assistant/filternamedialog.cpp index 33b19cff8..4c17d3332 100644 --- a/src/assistant/assistant/filternamedialog.cpp +++ b/src/assistant/assistant/filternamedialog.cpp @@ -25,7 +25,6 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "tracer.h" #include <QtWidgets/QPushButton> @@ -36,7 +35,6 @@ QT_BEGIN_NAMESPACE FilterNameDialog::FilterNameDialog(QWidget *parent) : QDialog(parent) { - TRACE_OBJ m_ui.setupUi(this); connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, &QDialog::accept); @@ -47,15 +45,19 @@ FilterNameDialog::FilterNameDialog(QWidget *parent) m_ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); } +void FilterNameDialog::setFilterName(const QString &filter) +{ + m_ui.lineEdit->setText(filter); + m_ui.lineEdit->selectAll(); +} + QString FilterNameDialog::filterName() const { - TRACE_OBJ return m_ui.lineEdit->text(); } void FilterNameDialog::updateOkButton() { - TRACE_OBJ m_ui.buttonBox->button(QDialogButtonBox::Ok) ->setDisabled(m_ui.lineEdit->text().isEmpty()); } diff --git a/src/assistant/assistant/filternamedialog.h b/src/assistant/assistant/filternamedialog.h index 8e46bfd0b..522b611af 100644 --- a/src/assistant/assistant/filternamedialog.h +++ b/src/assistant/assistant/filternamedialog.h @@ -40,6 +40,8 @@ class FilterNameDialog : public QDialog public: FilterNameDialog(QWidget *parent = nullptr); + + void setFilterName(const QString &filter); QString filterName() const; private slots: diff --git a/src/assistant/assistant/helpenginewrapper.cpp b/src/assistant/assistant/helpenginewrapper.cpp index 3aef5bb99..17e4bde8c 100644 --- a/src/assistant/assistant/helpenginewrapper.cpp +++ b/src/assistant/assistant/helpenginewrapper.cpp @@ -39,13 +39,13 @@ #include <QtCore/QTimer> #include <QtHelp/QHelpContentModel> #include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpFilterEngine> #include <QtHelp/QHelpIndexModel> #include <QtHelp/QHelpSearchEngine> QT_BEGIN_NAMESPACE namespace { - const QString Unfiltered; const QString AppFontKey(QLatin1String("appFont")); const QString AppWritingSystemKey(QLatin1String("appWritingSystem")); const QString BookmarksKey(QLatin1String("Bookmarks")); @@ -104,14 +104,6 @@ private: QMap<QString, RecentSignal> m_recentQchUpdates; }; -const QString HelpEngineWrapper::TrUnfiltered() -{ - static QString s; - if (s.isEmpty()) - s = HelpEngineWrapper::tr("Unfiltered"); - return s; -} - HelpEngineWrapper *HelpEngineWrapper::helpEngineWrapper = nullptr; HelpEngineWrapper &HelpEngineWrapper::instance(const QString &collectionFile) @@ -154,8 +146,6 @@ HelpEngineWrapper::HelpEngineWrapper(const QString &collectionFile) this, &HelpEngineWrapper::documentationRemoved); connect(d, &HelpEngineWrapperPrivate::documentationUpdated, this, &HelpEngineWrapper::documentationUpdated); - connect(d->m_helpEngine, &QHelpEngineCore::currentFilterChanged, - this, &HelpEngineWrapper::handleCurrentFilterChanged); connect(d->m_helpEngine, &QHelpEngineCore::setupFinished, this, &HelpEngineWrapper::setupFinished); } @@ -259,43 +249,6 @@ bool HelpEngineWrapper::setupData() return d->m_helpEngine->setupData(); } -bool HelpEngineWrapper::addCustomFilter(const QString &filterName, - const QStringList &attributes) -{ - TRACE_OBJ - return d->m_helpEngine->addCustomFilter(filterName, attributes); -} - -bool HelpEngineWrapper::removeCustomFilter(const QString &filterName) -{ - TRACE_OBJ - return d->m_helpEngine->removeCustomFilter(filterName); -} - -void HelpEngineWrapper::setCurrentFilter(const QString ¤tFilter) -{ - TRACE_OBJ - const QString &filter - = currentFilter == TrUnfiltered() ? Unfiltered : currentFilter; - d->m_helpEngine->setCurrentFilter(filter); -} - -const QString HelpEngineWrapper::currentFilter() const -{ - TRACE_OBJ - const QString &filter = d->m_helpEngine->currentFilter(); - return filter == Unfiltered ? TrUnfiltered() : filter; -} - -const QStringList HelpEngineWrapper::customFilters() const -{ - TRACE_OBJ - QStringList filters = d->m_helpEngine->customFilters(); - filters.removeOne(Unfiltered); - filters.prepend(TrUnfiltered()); - return filters; -} - QUrl HelpEngineWrapper::findFile(const QUrl &url) const { TRACE_OBJ @@ -314,22 +267,15 @@ QMap<QString, QUrl> HelpEngineWrapper::linksForIdentifier(const QString &id) con return d->m_helpEngine->linksForIdentifier(id); } -const QStringList HelpEngineWrapper::filterAttributes() const -{ - TRACE_OBJ - return d->m_helpEngine->filterAttributes(); -} - -const QStringList HelpEngineWrapper::filterAttributes(const QString &filterName) const +QString HelpEngineWrapper::error() const { TRACE_OBJ - return d->m_helpEngine->filterAttributes(filterName); + return d->m_helpEngine->error(); } -QString HelpEngineWrapper::error() const +QHelpFilterEngine *HelpEngineWrapper::filterEngine() const { - TRACE_OBJ - return d->m_helpEngine->error(); + return d->m_helpEngine->filterEngine(); } const QStringList HelpEngineWrapper::qtDocInfo(const QString &component) const @@ -694,14 +640,6 @@ void HelpEngineWrapper::setBrowserWritingSystem(QFontDatabase::WritingSystem sys d->m_helpEngine->setCustomValue(BrowserWritingSystemKey, system); } -void HelpEngineWrapper::handleCurrentFilterChanged(const QString &filter) -{ - TRACE_OBJ - const QString &filterToReport - = filter == Unfiltered ? TrUnfiltered() : filter; - emit currentFilterChanged(filterToReport); -} - bool HelpEngineWrapper::showTabs() const { TRACE_OBJ @@ -753,9 +691,8 @@ HelpEngineWrapperPrivate::HelpEngineWrapperPrivate(const QString &collectionFile m_qchWatcher(new QFileSystemWatcher(this)) { TRACE_OBJ - if (!m_helpEngine->customFilters().contains(Unfiltered)) - m_helpEngine->addCustomFilter(Unfiltered, QStringList()); initFileSystemWatchers(); + m_helpEngine->setUsesFilterEngine(true); } void HelpEngineWrapperPrivate::initFileSystemWatchers() diff --git a/src/assistant/assistant/helpenginewrapper.h b/src/assistant/assistant/helpenginewrapper.h index 08474f697..6026a0473 100644 --- a/src/assistant/assistant/helpenginewrapper.h +++ b/src/assistant/assistant/helpenginewrapper.h @@ -45,6 +45,7 @@ class QHelpContentWidget; class QHelpIndexModel; class QHelpIndexWidget; class QHelpSearchEngine; +class QHelpFilterEngine; enum { ShowHomePage = 0, @@ -76,19 +77,13 @@ public: const QString collectionFile() const; bool registerDocumentation(const QString &docFile); bool unregisterDocumentation(const QString &namespaceName); - bool addCustomFilter(const QString &filterName, - const QStringList &attributes); - bool removeCustomFilter(const QString &filterName); - void setCurrentFilter(const QString &filterName); - const QString currentFilter() const; - const QStringList customFilters() const; QUrl findFile(const QUrl &url) const; QByteArray fileData(const QUrl &url) const; QMap<QString, QUrl> linksForIdentifier(const QString &id) const; - const QStringList filterAttributes() const; - const QStringList filterAttributes(const QString &filterName) const; QString error() const; + QHelpFilterEngine *filterEngine() const; + /* * To be called after assistant has finished looking for new documentation. * This will mainly cause the search index to be updated, if necessary. @@ -175,8 +170,6 @@ public: bool showTabs() const; void setShowTabs(bool show); - static const QString TrUnfiltered(); - bool fullTextSearchFallbackEnabled() const; const QByteArray topicChooserGeometry() const; @@ -189,12 +182,8 @@ signals: void documentationUpdated(const QString &namespaceName); // Forwarded from QHelpEngineCore. - void currentFilterChanged(const QString ¤tFilter); void setupFinished(); -private slots: - void handleCurrentFilterChanged(const QString &filter); - private: HelpEngineWrapper(const QString &collectionFile); ~HelpEngineWrapper(); diff --git a/src/assistant/assistant/mainwindow.cpp b/src/assistant/assistant/mainwindow.cpp index 392af9224..c9c120950 100644 --- a/src/assistant/assistant/mainwindow.cpp +++ b/src/assistant/assistant/mainwindow.cpp @@ -80,6 +80,7 @@ #include <QtHelp/QHelpEngineCore> #include <QtHelp/QHelpIndexModel> #include <QtHelp/QHelpSearchEngine> +#include <QtHelp/QHelpFilterEngine> #include <cstdlib> @@ -268,8 +269,8 @@ MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) if (!m_cmdLine->currentFilter().isEmpty()) { const QString &curFilter = m_cmdLine->currentFilter(); - if (helpEngineWrapper.customFilters().contains(curFilter)) - helpEngineWrapper.setCurrentFilter(curFilter); + if (helpEngineWrapper.filterEngine()->filters().contains(curFilter)) + helpEngineWrapper.filterEngine()->setActiveFilter(curFilter); } if (usesDefaultCollection()) @@ -737,9 +738,9 @@ void MainWindow::setupFilterToolbar() connect(&helpEngine, &HelpEngineWrapper::setupFinished, this, &MainWindow::setupFilterCombo, Qt::QueuedConnection); - connect(m_filterCombo, QOverload<const QString &>::of(&QComboBox::activated), + connect(m_filterCombo, QOverload<int>::of(&QComboBox::activated), this, &MainWindow::filterDocumentation); - connect(&helpEngine, &HelpEngineWrapper::currentFilterChanged, + connect(helpEngine.filterEngine(), &QHelpFilterEngine::filterActivated, this, &MainWindow::currentFilterChanged); setupFilterCombo(); @@ -1048,21 +1049,27 @@ void MainWindow::setupFilterCombo() { TRACE_OBJ HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); - QString curFilter = m_filterCombo->currentText(); - if (curFilter.isEmpty()) - curFilter = helpEngine.currentFilter(); + const QString currentFilter = helpEngine.filterEngine()->activeFilter(); m_filterCombo->clear(); - m_filterCombo->addItems(helpEngine.customFilters()); - int idx = m_filterCombo->findText(curFilter); + m_filterCombo->addItem(tr("Unfiltered")); + const QStringList allFilters = helpEngine.filterEngine()->filters(); + if (!allFilters.isEmpty()) + m_filterCombo->insertSeparator(1); + for (const QString &filter : allFilters) + m_filterCombo->addItem(filter, filter); + + int idx = m_filterCombo->findData(currentFilter); if (idx < 0) idx = 0; m_filterCombo->setCurrentIndex(idx); } -void MainWindow::filterDocumentation(const QString &customFilter) +void MainWindow::filterDocumentation(int filterIndex) { TRACE_OBJ - HelpEngineWrapper::instance().setCurrentFilter(customFilter); + + const QString filter = m_filterCombo->itemData(filterIndex).toString(); + HelpEngineWrapper::instance().filterEngine()->setActiveFilter(filter); } void MainWindow::expandTOC(int depth) @@ -1143,8 +1150,9 @@ QString MainWindow::defaultHelpCollectionFileName() void MainWindow::currentFilterChanged(const QString &filter) { TRACE_OBJ - const int index = m_filterCombo->findText(filter); - Q_ASSERT(index != -1); + int index = m_filterCombo->findData(filter); + if (index < 0) + index = 0; m_filterCombo->setCurrentIndex(index); } diff --git a/src/assistant/assistant/mainwindow.h b/src/assistant/assistant/mainwindow.h index 86451f839..c5bf5837e 100644 --- a/src/assistant/assistant/mainwindow.h +++ b/src/assistant/assistant/mainwindow.h @@ -90,7 +90,7 @@ private slots: void showNewAddress(const QUrl &url); void showTopicChooser(const QMap<QString, QUrl> &links, const QString &keyword); void updateApplicationFont(); - void filterDocumentation(const QString &customFilter); + void filterDocumentation(int filterIndex); void setupFilterCombo(); void lookForNewQtDocumentation(); void indexingStarted(); diff --git a/src/assistant/assistant/openpagesmanager.cpp b/src/assistant/assistant/openpagesmanager.cpp index 3151cb534..f3acb4656 100644 --- a/src/assistant/assistant/openpagesmanager.cpp +++ b/src/assistant/assistant/openpagesmanager.cpp @@ -237,7 +237,7 @@ void OpenPagesManager::closeOrReloadPages(const QString &nameSpace, bool tryRelo HelpViewer *page = m_model->pageAt(i); if (page->source().host() != nameSpace) continue; - if (tryReload && HelpEngineWrapper::instance().findFile(page->source()).isValid()) + if (tryReload && HelpEngineWrapper::instance().findFile(page->source()).isValid()) page->reload(); else if (m_model->rowCount() == 1) page->setSource(QUrl(QLatin1String("about:blank"))); diff --git a/src/assistant/assistant/preferencesdialog.cpp b/src/assistant/assistant/preferencesdialog.cpp index 4647f154f..bcc661690 100644 --- a/src/assistant/assistant/preferencesdialog.cpp +++ b/src/assistant/assistant/preferencesdialog.cpp @@ -32,106 +32,20 @@ #include "fontpanel.h" #include "helpenginewrapper.h" #include "openpagesmanager.h" -#include "tracer.h" -#include <QtCore/QAbstractListModel> -#include <QtCore/QtAlgorithms> -#include <QtCore/QFileSystemWatcher> -#include <QtCore/QSortFilterProxyModel> -#include <QtCore/QVector> - -#include <QtWidgets/QDesktopWidget> -#include <QtWidgets/QFileDialog> #include <QtGui/QFontDatabase> -#include <QtWidgets/QHeaderView> -#include <QtWidgets/QMenu> #include <QtWidgets/QMessageBox> #include <QtHelp/QHelpEngineCore> +#include <QtHelp/QHelpFilterData> +#include <QtHelp/QHelpFilterEngine> +#include <QtHelp/QHelpCollectionDetails> -#include <algorithm> - -QT_BEGIN_NAMESPACE - -struct RegisteredDocEntry -{ - QString nameSpace; - QString fileName; -}; - -typedef QVector<RegisteredDocEntry> RegisteredDocEntries; - -class RegisteredDocsModel : public QAbstractListModel { -public: - - explicit RegisteredDocsModel(const RegisteredDocEntries &e = RegisteredDocEntries(), QObject *parent = nullptr) - : QAbstractListModel(parent), m_docEntries(e) {} - - int rowCount(const QModelIndex & = QModelIndex()) const override { return m_docEntries.size(); } - QVariant data(const QModelIndex &index, int role) const override; - - bool contains(const QString &nameSpace) const - { - return m_docEntries.cend() != - std::find_if(m_docEntries.cbegin(), m_docEntries.cend(), - [nameSpace] (const RegisteredDocEntry &e) { return e.nameSpace == nameSpace; }); - } - - void append(const RegisteredDocEntry &e); - - const RegisteredDocEntries &docEntries() const { return m_docEntries; } - void setDocEntries(const RegisteredDocEntries &); - -private: - RegisteredDocEntries m_docEntries; -}; - -QVariant RegisteredDocsModel::data(const QModelIndex &index, int role) const -{ - QVariant result; - const int row = index.row(); - if (index.isValid() && row < m_docEntries.size()) { - switch (role) { - case Qt::DisplayRole: - result = QVariant(m_docEntries.at(row).nameSpace); - break; - case Qt::ToolTipRole: - result = QVariant(QDir::toNativeSeparators(m_docEntries.at(row).fileName)); - break; - default: - break; - } - } - return result; -} - -void RegisteredDocsModel::append(const RegisteredDocEntry &e) -{ - beginInsertRows(QModelIndex(), m_docEntries.size(), m_docEntries.size()); - m_docEntries.append(e); - endInsertRows(); -} +#include <QtWidgets/QFileDialog> -void RegisteredDocsModel::setDocEntries(const RegisteredDocEntries &e) -{ - beginResetModel(); - m_docEntries = e; - endResetModel(); -} +#include <QtDebug> -static RegisteredDocEntries registeredDocEntries(const HelpEngineWrapper &wrapper) -{ - RegisteredDocEntries result; - const QStringList &nameSpaces = wrapper.registeredDocumentations(); - result.reserve(nameSpaces.size()); - for (const QString &nameSpace : nameSpaces) { - RegisteredDocEntry entry; - entry.nameSpace = nameSpace; - entry.fileName = wrapper.documentationFileName(nameSpace); - result.append(entry); - } - return result; -} +QT_BEGIN_NAMESPACE PreferencesDialog::PreferencesDialog(QWidget *parent) : QDialog(parent) @@ -141,52 +55,50 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) , m_hideFiltersTab(!helpEngine.filterFunctionalityEnabled()) , m_hideDocsTab(!helpEngine.documentationManagerEnabled()) { - TRACE_OBJ m_ui.setupUi(this); - m_registeredDocsModel = - new RegisteredDocsModel(m_hideDocsTab ? RegisteredDocEntries() : registeredDocEntries(helpEngine)); - m_registereredDocsFilterModel = new QSortFilterProxyModel(m_ui.registeredDocsListView); - m_registereredDocsFilterModel->setSourceModel(m_registeredDocsModel); - m_ui.registeredDocsListView->setModel(m_registereredDocsFilterModel); - connect(m_ui.registeredDocsFilterLineEdit, &QLineEdit::textChanged, - m_registereredDocsFilterModel, &QSortFilterProxyModel::setFilterFixedString); + // TODO: filter docs via lineedit connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, - this, &PreferencesDialog::applyChanges); + this, &PreferencesDialog::okClicked); + connect(m_ui.buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, + this, &PreferencesDialog::applyClicked); connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, &QDialog::reject); - if (!m_hideFiltersTab) { - m_ui.attributeWidget->header()->hide(); - m_ui.attributeWidget->setRootIsDecorated(false); - - connect(m_ui.attributeWidget, &QTreeWidget::itemChanged, - this, &PreferencesDialog::updateFilterMap); - connect(m_ui.filterWidget, &QListWidget::currentItemChanged, - this, &PreferencesDialog::updateAttributes); + m_originalSetup = readOriginalSetup(); + m_currentSetup = m_originalSetup; - connect(m_ui.filterAddButton, &QAbstractButton::clicked, - this, &PreferencesDialog::addFilter); - connect(m_ui.filterRemoveButton, &QAbstractButton::clicked, - this, &PreferencesDialog::removeFilter); - - updateFilterPage(); + if (m_hideDocsTab) { + m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.docsTab)); } else { - m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.filtersTab)); - } - - if (!m_hideDocsTab) { connect(m_ui.docAddButton, &QAbstractButton::clicked, - this, &PreferencesDialog::addDocumentationLocal); + this, &PreferencesDialog::addDocumentation); connect(m_ui.docRemoveButton, &QAbstractButton::clicked, this, &PreferencesDialog::removeDocumentation); - m_docsBackup.reserve(m_registeredDocsModel->rowCount()); - for (const RegisteredDocEntry &e : m_registeredDocsModel->docEntries()) - m_docsBackup.append(e.nameSpace); + updateDocumentationPage(); + } + + if (m_hideFiltersTab) { + m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.filtersTab)); } else { - m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.docsTab)); + connect(m_ui.componentWidget, &OptionsWidget::optionSelectionChanged, + this, &PreferencesDialog::componentsChanged); + connect(m_ui.filterWidget, &QListWidget::currentItemChanged, + this, &PreferencesDialog::filterSelected); + connect(m_ui.filterWidget, &QListWidget::itemDoubleClicked, + this, &PreferencesDialog::renameFilterClicked); + + // TODO: repeat these actions on context menu + connect(m_ui.filterAddButton, &QAbstractButton::clicked, + this, &PreferencesDialog::addFilterClicked); + connect(m_ui.filterRenameButton, &QAbstractButton::clicked, + this, &PreferencesDialog::renameFilterClicked); + connect(m_ui.filterRemoveButton, &QAbstractButton::clicked, + this, &PreferencesDialog::removeFilterClicked); + + updateFilterPage(); } updateFontSettingsPage(); @@ -198,7 +110,6 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) PreferencesDialog::~PreferencesDialog() { - TRACE_OBJ if (m_appFontChanged) { helpEngine.setAppFont(m_appFontPanel->selectedFont()); helpEngine.setUseAppFont(m_appFontPanel->isChecked()); @@ -222,259 +133,365 @@ PreferencesDialog::~PreferencesDialog() helpEngine.setStartOption(option); } +FilterSetup PreferencesDialog::readOriginalSetup() const +{ + FilterSetup filterSetup; + + filterSetup.m_namespaceToComponent = helpEngine.filterEngine()->namespaceToComponent(); + for (auto it = filterSetup.m_namespaceToComponent.constBegin(); + it != filterSetup.m_namespaceToComponent.constEnd(); ++it) { + const QString namespaceName = it.key(); + const QString namespaceFileName = helpEngine.documentationFileName(namespaceName); + filterSetup.m_namespaceToFileName.insert(namespaceName, namespaceFileName); + filterSetup.m_fileNameToNamespace.insert(namespaceFileName, namespaceName); + filterSetup.m_componentToNamespace[it.value()].append(namespaceName); + } + const QStringList allFilters = helpEngine.filterEngine()->filters(); + for (const QString &filter : allFilters) + filterSetup.m_filterToComponents.insert(filter, helpEngine.filterEngine()->filterData(filter).components()); + + return filterSetup; +} + void PreferencesDialog::showDialog() { - TRACE_OBJ if (exec() != Accepted) m_appFontChanged = m_browserFontChanged = false; } void PreferencesDialog::updateFilterPage() { - TRACE_OBJ + if (m_hideFiltersTab) + return; + + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + + m_currentSetup = m_originalSetup; + m_ui.filterWidget->clear(); - m_ui.attributeWidget->clear(); + m_ui.componentWidget->clear(); + m_itemToFilter.clear(); + m_filterToItem.clear(); + + for (const QString &filterName : m_currentSetup.m_filterToComponents.keys()) { + QListWidgetItem *item = new QListWidgetItem(filterName); + m_ui.filterWidget->addItem(item); + m_itemToFilter.insert(item, filterName); + m_filterToItem.insert(filterName, item); + if (filterName == currentFilter) + m_ui.filterWidget->setCurrentItem(item); + } - m_filterMapBackup.clear(); - const QStringList &filters = helpEngine.customFilters(); - for (const QString &filter : filters) { - if (filter == HelpEngineWrapper::TrUnfiltered()) - continue; - QStringList atts = helpEngine.filterAttributes(filter); - m_filterMapBackup.insert(filter, atts); - if (!m_filterMap.contains(filter)) - m_filterMap.insert(filter, atts); + if (!m_ui.filterWidget->currentItem() && !m_filterToItem.isEmpty()) + m_ui.filterWidget->setCurrentItem(m_filterToItem.first()); + + updateCurrentFilter(); +} + +void PreferencesDialog::updateCurrentFilter() +{ + if (m_hideFiltersTab) + return; + + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + + const bool filterSelected = !currentFilter.isEmpty(); + m_ui.componentWidget->setEnabled(filterSelected); + m_ui.filterRenameButton->setEnabled(filterSelected); + m_ui.filterRemoveButton->setEnabled(filterSelected); + + m_ui.componentWidget->setOptions(m_currentSetup.m_componentToNamespace.keys(), + m_currentSetup.m_filterToComponents.value(currentFilter)); +} + +void PreferencesDialog::updateDocumentationPage() +{ + if (m_hideDocsTab) + return; + + m_ui.registeredDocsListWidget->clear(); + m_namespaceToItem.clear(); + m_itemToNamespace.clear(); + + for (const QString &namespaceName : m_currentSetup.m_namespaceToFileName.keys()) { + QListWidgetItem *item = new QListWidgetItem(namespaceName); + m_namespaceToItem.insert(namespaceName, item); + m_itemToNamespace.insert(item, namespaceName); + m_ui.registeredDocsListWidget->addItem(item); } +} + +void PreferencesDialog::filterSelected(QListWidgetItem *item) +{ + Q_UNUSED(item) + + updateCurrentFilter(); +} + +void PreferencesDialog::componentsChanged(const QStringList &components) +{ + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + if (currentFilter.isEmpty()) + return; + + m_currentSetup.m_filterToComponents[currentFilter] = components; +} - m_ui.filterWidget->addItems(m_filterMap.keys()); +QString PreferencesDialog::suggestedNewFilterName(const QString &initialFilterName) const +{ + QString newFilterName = initialFilterName; - for (const QString &a : helpEngine.filterAttributes()) - new QTreeWidgetItem(m_ui.attributeWidget, QStringList() << a); + int counter = 1; + while (m_filterToItem.contains(newFilterName)) { + newFilterName = initialFilterName + QLatin1Char(' ') + + QString::number(++counter); + } - if (!m_filterMap.isEmpty()) - m_ui.filterWidget->setCurrentRow(0); + return newFilterName; } -void PreferencesDialog::updateAttributes(QListWidgetItem *item) +QString PreferencesDialog::getUniqueFilterName(const QString &windowTitle, + const QString &initialFilterName) { - TRACE_OBJ - const QStringList &checkedList = item ? m_filterMap.value(item->text()) : QStringList(); - - for (int i = 0; i < m_ui.attributeWidget->topLevelItemCount(); ++i) { - QTreeWidgetItem *itm = m_ui.attributeWidget->topLevelItem(i); - if (checkedList.contains(itm->text(0))) - itm->setCheckState(0, Qt::Checked); - else - itm->setCheckState(0, Qt::Unchecked); + QString newFilterName = initialFilterName; + while (1) { + FilterNameDialog dialog(this); + dialog.setWindowTitle(windowTitle); + dialog.setFilterName(newFilterName); + if (dialog.exec() == QDialog::Rejected) + return QString(); + + newFilterName = dialog.filterName(); + if (!m_filterToItem.contains(newFilterName)) + break; + + if (QMessageBox::warning(this, tr("Filter Exists"), + tr("The filter \"%1\" already exists.") + .arg(newFilterName), + QMessageBox::Retry | QMessageBox::Cancel) + == QMessageBox::Cancel) { + return QString(); + } } + + return newFilterName; +} + +void PreferencesDialog::addFilterClicked() +{ + const QString newFilterName = getUniqueFilterName(tr("Add Filter"), + suggestedNewFilterName(tr("New Filter"))); + if (newFilterName.isEmpty()) + return; + + addFilter(newFilterName, QStringList()); } -void PreferencesDialog::updateFilterMap() +void PreferencesDialog::renameFilterClicked() { - TRACE_OBJ - if (!m_ui.filterWidget->currentItem()) + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + if (currentFilter.isEmpty()) return; - QString filter = m_ui.filterWidget->currentItem()->text(); - if (!m_filterMap.contains(filter)) + + const QString newFilterName = getUniqueFilterName(tr("Rename Filter"), currentFilter); + if (newFilterName.isEmpty()) return; - QStringList newAtts; - QTreeWidgetItem *itm = nullptr; - for (int i = 0; i < m_ui.attributeWidget->topLevelItemCount(); ++i) { - itm = m_ui.attributeWidget->topLevelItem(i); - if (itm->checkState(0) == Qt::Checked) - newAtts.append(itm->text(0)); - } - m_filterMap[filter] = newAtts; + const QStringList oldComponents = m_currentSetup.m_filterToComponents.value(currentFilter); + removeFilter(currentFilter); + addFilter(newFilterName, oldComponents); } -void PreferencesDialog::addFilter() +void PreferencesDialog::removeFilterClicked() { - TRACE_OBJ - FilterNameDialog dia(this); - if (dia.exec() == QDialog::Rejected) + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + if (currentFilter.isEmpty()) return; - QString filterName = dia.filterName(); - if (!m_filterMap.contains(filterName)) { - m_filterMap.insert(filterName, QStringList()); - m_ui.filterWidget->addItem(filterName); + if (QMessageBox::question(this, tr("Remove Filter"), + tr("Are you sure you want to remove the \"%1\" filter?") + .arg(currentFilter), + QMessageBox::Yes | QMessageBox::No) + != QMessageBox::Yes) { + return; } - QList<QListWidgetItem*> lst = m_ui.filterWidget - ->findItems(filterName, Qt::MatchCaseSensitive); - m_ui.filterWidget->setCurrentItem(lst.first()); + removeFilter(currentFilter); } -void PreferencesDialog::removeFilter() +void PreferencesDialog::addFilter(const QString &filterName, const QStringList &components) { - TRACE_OBJ - QListWidgetItem *item = - m_ui.filterWidget ->takeItem(m_ui.filterWidget->currentRow()); - if (!item) - return; + QListWidgetItem *item = new QListWidgetItem(filterName); + m_currentSetup.m_filterToComponents.insert(filterName, components); + m_filterToItem.insert(filterName, item); + m_itemToFilter.insert(item, filterName); + m_ui.filterWidget->insertItem(m_filterToItem.keys().indexOf(filterName), item); + + m_ui.filterWidget->setCurrentItem(item); + updateCurrentFilter(); +} - m_filterMap.remove(item->text()); - m_removedFilters.append(item->text()); +void PreferencesDialog::removeFilter(const QString &filterName) +{ + QListWidgetItem *item = m_filterToItem.value(filterName); + m_itemToFilter.remove(item); + m_filterToItem.remove(filterName); delete item; - if (m_ui.filterWidget->count()) - m_ui.filterWidget->setCurrentRow(0); + + m_currentSetup.m_filterToComponents.remove(filterName); } -void PreferencesDialog::addDocumentationLocal() +void PreferencesDialog::addDocumentation() { - TRACE_OBJ const QStringList &fileNames = QFileDialog::getOpenFileNames(this, tr("Add Documentation"), QString(), tr("Qt Compressed Help Files (*.qch)")); if (fileNames.isEmpty()) return; - QStringList invalidFiles; - QStringList alreadyRegistered; + bool added = false; + for (const QString &fileName : fileNames) { - const QString nameSpace = QHelpEngineCore::namespaceName(fileName); - if (nameSpace.isEmpty()) { - invalidFiles.append(fileName); + const QHelpCollectionDetails details = QHelpCollectionDetails::helpDetails(fileName); + const QString namespaceName = details.namespaceName(); + + if (m_currentSetup.m_namespaceToFileName.contains(namespaceName)) continue; - } - if (m_registeredDocsModel->contains(nameSpace)) { - alreadyRegistered.append(nameSpace); - continue; - } + if (m_currentSetup.m_fileNameToNamespace.contains(fileName)) + continue; - if (helpEngine.registerDocumentation(fileName)) { - RegisteredDocEntry entry; - entry.nameSpace = nameSpace; - entry.fileName = fileName; - m_registeredDocsModel->append(entry); - m_unregDocs.removeAll(nameSpace); - } - } + const QString component = details.component(); + m_currentSetup.m_namespaceToFileName.insert(namespaceName, fileName); + m_currentSetup.m_fileNameToNamespace.insert(fileName, namespaceName); - if (!invalidFiles.isEmpty() || !alreadyRegistered.isEmpty()) { - QString message; - if (!alreadyRegistered.isEmpty()) { - for (const QString &ns : qAsConst(alreadyRegistered)) { - message += tr("The namespace %1 is already registered!") - .arg(QString("<b>%1</b>").arg(ns)) + QLatin1String("<br>"); - } - if (!invalidFiles.isEmpty()) - message.append(QLatin1String("<br>")); - } + m_currentSetup.m_namespaceToComponent.insert(namespaceName, component); + m_currentSetup.m_componentToNamespace[component].append(namespaceName); - if (!invalidFiles.isEmpty()) { - message += tr("The specified file is not a valid Qt Help File!"); - message.append(QLatin1String("<ul>")); - for (const QString &file : qAsConst(invalidFiles)) - message += QLatin1String("<li>") + file + QLatin1String("</li>"); - message.append(QLatin1String("</ul>")); - } - QMessageBox::warning(this, tr("Add Documentation"), message); + QListWidgetItem *item = new QListWidgetItem(namespaceName); + m_namespaceToItem.insert(namespaceName, item); + m_itemToNamespace.insert(item, namespaceName); + m_ui.registeredDocsListWidget->insertItem(m_namespaceToItem.keys().indexOf(namespaceName), item); + + added = true; } - updateFilterPage(); + if (added) + updateCurrentFilter(); } -QList<int> PreferencesDialog::currentRegisteredDocsSelection() const +void PreferencesDialog::removeDocumentation() { - QList<int> result; - for (const QModelIndex &index : m_ui.registeredDocsListView->selectionModel()->selectedRows()) - result.append(m_registereredDocsFilterModel->mapToSource(index).row()); - std::sort(result.begin(), result.end()); - return result; + const QList<QListWidgetItem *> selectedItems = m_ui.registeredDocsListWidget->selectedItems(); + if (selectedItems.isEmpty()) + return; + + for (QListWidgetItem *item : selectedItems) { + const QString namespaceName = m_itemToNamespace.value(item); + m_itemToNamespace.remove(item); + m_namespaceToItem.remove(namespaceName); + delete item; + + const QString fileName = m_currentSetup.m_namespaceToFileName.value(namespaceName); + const QString component = m_currentSetup.m_namespaceToComponent.value(namespaceName); + m_currentSetup.m_namespaceToComponent.remove(namespaceName); + m_currentSetup.m_namespaceToFileName.remove(namespaceName); + m_currentSetup.m_fileNameToNamespace.remove(fileName); + m_currentSetup.m_componentToNamespace[component].removeOne(namespaceName); + if (m_currentSetup.m_componentToNamespace[component].isEmpty()) + m_currentSetup.m_componentToNamespace.remove(component); + } + + updateCurrentFilter(); } -void PreferencesDialog::removeDocumentation() +void PreferencesDialog::okClicked() { - TRACE_OBJ + applyChanges(); + accept(); +} - const QList<int> currentSelection = currentRegisteredDocsSelection(); - if (currentSelection.isEmpty()) - return; +void PreferencesDialog::applyClicked() +{ + applyChanges(); + m_originalSetup = readOriginalSetup(); + m_currentSetup = m_originalSetup; + updateDocumentationPage(); + updateFilterPage(); +} - RegisteredDocEntries entries = m_registeredDocsModel->docEntries(); - - bool foundBefore = false; - for (int i = currentSelection.size() - 1; i >= 0; --i) { - const int row = currentSelection.at(i); - const QString &ns = entries.at(row).nameSpace; - if (!foundBefore && OpenPagesManager::instance()->pagesOpenForNamespace(ns)) { - if (0 == QMessageBox::information(this, tr("Remove Documentation"), - tr("Some documents currently opened in Assistant reference the " - "documentation you are attempting to remove. Removing the " - "documentation will close those documents."), tr("Cancel"), - tr("OK"))) return; - foundBefore = true; - } +template <class T> +static QMap<QString, T> subtract(const QMap<QString, T> &minuend, + const QMap<QString, T> &subtrahend) +{ + QMap<QString, T> result = minuend; - m_unregDocs.append(ns); - entries.removeAt(row); + for (auto itSubtrahend = subtrahend.cbegin(); itSubtrahend != subtrahend.cend(); ++itSubtrahend) { + auto itResult = result.find(itSubtrahend.key()); + if (itResult != result.end() && itSubtrahend.value() == itResult.value()) + result.erase(itResult); } - m_registeredDocsModel->setDocEntries(entries); - - if (m_registereredDocsFilterModel->rowCount()) { - const QModelIndex &first = m_registereredDocsFilterModel->index(0, 0); - m_ui.registeredDocsListView->selectionModel()->setCurrentIndex(first, - QItemSelectionModel::ClearAndSelect); - } + return result; } void PreferencesDialog::applyChanges() { - TRACE_OBJ - bool filtersWereChanged = false; - if (!m_hideFiltersTab) { - if (m_filterMap.count() != m_filterMapBackup.count()) { - filtersWereChanged = true; - } else { - for (auto it = m_filterMapBackup.cbegin(), end = m_filterMapBackup.cend(); it != end && !filtersWereChanged; ++it) { - if (!m_filterMap.contains(it.key())) { - filtersWereChanged = true; - } else { - const QStringList &a = it.value(); - const QStringList &b = m_filterMap.value(it.key()); - if (a.count() != b.count()) { - filtersWereChanged = true; - } else { - for (const QString &aStr : a) { - if (!b.contains(aStr)) { - filtersWereChanged = true; - break; - } - } - } - } - } - } + bool changed = false; + + const QMap<QString, QString> docsToRemove = subtract( + m_originalSetup.m_namespaceToFileName, + m_currentSetup.m_namespaceToFileName); + const QMap<QString, QString> docsToAdd = subtract( + m_currentSetup.m_namespaceToFileName, + m_originalSetup.m_namespaceToFileName); + + for (const QString &namespaceName : docsToRemove.keys()) { + if (!helpEngine.unregisterDocumentation(namespaceName)) + qWarning() << "Cannot unregister documentation:" << namespaceName; + changed = true; } - if (filtersWereChanged) { - for (const QString &filter : qAsConst(m_removedFilters)) - helpEngine.removeCustomFilter(filter); - for (auto it = m_filterMap.cbegin(), end = m_filterMap.cend(); it != end; ++it) - helpEngine.addCustomFilter(it.key(), it.value()); + for (const QString &fileName : docsToAdd.values()) { + if (!helpEngine.registerDocumentation(fileName)) + qWarning() << "Cannot register documentation file:" << fileName; + changed = true; } - for (const QString &doc : qAsConst(m_unregDocs)) { - OpenPagesManager::instance()->closePages(doc); - helpEngine.unregisterDocumentation(doc); + const QMap<QString, QStringList> filtersToRemove = subtract( + m_originalSetup.m_filterToComponents, + m_currentSetup.m_filterToComponents); + const QMap<QString, QStringList> filtersToAdd = subtract( + m_currentSetup.m_filterToComponents, + m_originalSetup.m_filterToComponents); + + const QString ¤tFilter = helpEngine.filterEngine()->activeFilter(); + + for (const QString &filter : filtersToRemove.keys()) { + helpEngine.filterEngine()->removeFilter(filter); + if (currentFilter == filter && !filtersToAdd.contains(filter)) + helpEngine.filterEngine()->setActiveFilter(QString()); + changed = true; } - if (filtersWereChanged || !m_unregDocs.isEmpty()) + for (auto it = filtersToAdd.cbegin(); it != filtersToAdd.cend(); ++it) { + QHelpFilterData data; + data.setComponents(it.value()); + helpEngine.filterEngine()->setFilterData(it.key(), data); + changed = true; + } + + // in order to update the filtercombobox and indexwidget + // according to the new filter configuration + if (changed) helpEngine.setupData(); helpEngine.setShowTabs(m_ui.showTabs->isChecked()); if (m_showTabs != m_ui.showTabs->isChecked()) emit updateUserInterface(); - - accept(); } void PreferencesDialog::updateFontSettingsPage() { - TRACE_OBJ m_browserFontPanel = new FontPanel(this); m_browserFontPanel->setCheckable(true); m_ui.stackedWidget_2->insertWidget(0, m_browserFontPanel); @@ -526,35 +543,30 @@ void PreferencesDialog::updateFontSettingsPage() void PreferencesDialog::appFontSettingToggled(bool on) { - TRACE_OBJ Q_UNUSED(on) m_appFontChanged = true; } void PreferencesDialog::appFontSettingChanged(int index) { - TRACE_OBJ Q_UNUSED(index) m_appFontChanged = true; } void PreferencesDialog::browserFontSettingToggled(bool on) { - TRACE_OBJ Q_UNUSED(on) m_browserFontChanged = true; } void PreferencesDialog::browserFontSettingChanged(int index) { - TRACE_OBJ Q_UNUSED(index) m_browserFontChanged = true; } void PreferencesDialog::updateOptionsPage() { - TRACE_OBJ m_ui.homePageLineEdit->setText(helpEngine.homePage()); int option = helpEngine.startOption(); @@ -573,13 +585,11 @@ void PreferencesDialog::updateOptionsPage() void PreferencesDialog::setBlankPage() { - TRACE_OBJ m_ui.homePageLineEdit->setText(QLatin1String("about:blank")); } void PreferencesDialog::setCurrentPage() { - TRACE_OBJ QString homepage = CentralWidget::instance()->currentSource().toString(); if (homepage.isEmpty()) homepage = QLatin1String("help"); @@ -589,7 +599,6 @@ void PreferencesDialog::setCurrentPage() void PreferencesDialog::setDefaultPage() { - TRACE_OBJ m_ui.homePageLineEdit->setText(helpEngine.defaultHomePage()); } diff --git a/src/assistant/assistant/preferencesdialog.h b/src/assistant/assistant/preferencesdialog.h index 72dd81eda..1e45d9b6d 100644 --- a/src/assistant/assistant/preferencesdialog.h +++ b/src/assistant/assistant/preferencesdialog.h @@ -36,9 +36,17 @@ QT_BEGIN_NAMESPACE class FontPanel; class HelpEngineWrapper; -class RegisteredDocsModel; class QFileSystemWatcher; -class QSortFilterProxyModel; + +struct FilterSetup { + QMap<QString, QString> m_namespaceToComponent; + QMap<QString, QStringList> m_componentToNamespace; + + QMap<QString, QString> m_namespaceToFileName; + QMap<QString, QString> m_fileNameToNamespace; + + QMap<QString, QStringList> m_filterToComponents; +}; class PreferencesDialog : public QDialog { @@ -51,12 +59,17 @@ public: void showDialog(); private slots: - void updateAttributes(QListWidgetItem *item); - void updateFilterMap(); - void addFilter(); - void removeFilter(); - void addDocumentationLocal(); + void filterSelected(QListWidgetItem *item); + void componentsChanged(const QStringList &components); + void addFilterClicked(); + void renameFilterClicked(); + void removeFilterClicked(); + void addFilter(const QString &filterName, const QStringList &components); + void removeFilter(const QString &filterName); + void addDocumentation(); void removeDocumentation(); + void okClicked(); + void applyClicked(); void applyChanges(); void appFontSettingToggled(bool on); void appFontSettingChanged(int index); @@ -73,19 +86,27 @@ signals: void updateUserInterface(); private: + QString suggestedNewFilterName(const QString &initialFilterName) const; + QString getUniqueFilterName(const QString &windowTitle, + const QString &initialFilterName = QString()); void updateFilterPage(); + void updateCurrentFilter(); + void updateDocumentationPage(); void updateFontSettingsPage(); void updateOptionsPage(); - QList<int> currentRegisteredDocsSelection() const; + FilterSetup readOriginalSetup() const; Ui::PreferencesDialogClass m_ui; - QMap<QString, QStringList> m_filterMapBackup; - QMap<QString, QStringList> m_filterMap; - QStringList m_removedFilters; - QStringList m_docsBackup; - RegisteredDocsModel *m_registeredDocsModel; - QSortFilterProxyModel *m_registereredDocsFilterModel; - QStringList m_unregDocs; + + FilterSetup m_originalSetup; + FilterSetup m_currentSetup; + + QMap<QString, QListWidgetItem *> m_namespaceToItem; + QHash<QListWidgetItem *, QString> m_itemToNamespace; + + QMap<QString, QListWidgetItem *> m_filterToItem; + QHash<QListWidgetItem *, QString> m_itemToFilter; + FontPanel *m_appFontPanel; FontPanel *m_browserFontPanel; bool m_appFontChanged; diff --git a/src/assistant/assistant/preferencesdialog.ui b/src/assistant/assistant/preferencesdialog.ui index ebefa2458..70a90dd74 100644 --- a/src/assistant/assistant/preferencesdialog.ui +++ b/src/assistant/assistant/preferencesdialog.ui @@ -6,24 +6,24 @@ <rect> <x>0</x> <y>0</y> - <width>375</width> - <height>342</height> + <width>378</width> + <height>341</height> </rect> </property> <property name="windowTitle"> <string>Preferences</string> </property> - <layout class="QVBoxLayout"> + <layout class="QVBoxLayout" name="verticalLayout_6"> <item> <widget class="QTabWidget" name="tabWidget"> <property name="currentIndex"> - <number>0</number> + <number>1</number> </property> <widget class="QWidget" name="fontsTab"> <attribute name="title"> <string>Fonts</string> </attribute> - <layout class="QGridLayout"> + <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <layout class="QHBoxLayout"> <item> @@ -69,45 +69,46 @@ <attribute name="title"> <string>Filters</string> </attribute> - <layout class="QGridLayout"> - <item row="0" column="0" colspan="2"> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>Filter:</string> </property> </widget> </item> - <item row="0" column="2"> + <item row="0" column="3"> <widget class="QLabel" name="label_2"> <property name="frameShape"> <enum>QFrame::NoFrame</enum> </property> <property name="text"> - <string>Attributes:</string> + <string>Components:</string> </property> </widget> </item> - <item row="1" column="0" colspan="2"> + <item row="1" column="0" colspan="3"> <widget class="QListWidget" name="filterWidget"/> </item> - <item row="1" column="2" rowspan="2"> - <widget class="QTreeWidget" name="attributeWidget"> - <column> - <property name="text"> - <string>1</string> - </property> - </column> - </widget> + <item row="1" column="3"> + <widget class="OptionsWidget" name="componentWidget" native="true"/> </item> <item row="2" column="0"> - <widget class="QPushButton" name="filterAddButton"> + <widget class="QToolButton" name="filterAddButton"> <property name="text"> - <string>Add</string> + <string>Add...</string> </property> </widget> </item> <item row="2" column="1"> - <widget class="QPushButton" name="filterRemoveButton"> + <widget class="QToolButton" name="filterRenameButton"> + <property name="text"> + <string>Rename...</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QToolButton" name="filterRemoveButton"> <property name="text"> <string>Remove</string> </property> @@ -119,73 +120,62 @@ <attribute name="title"> <string>Documentation</string> </attribute> - <layout class="QVBoxLayout" name="verticalLayout_5"> - <item> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>Registered Documentation:</string> </property> </widget> </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item row="1" column="0"> + <widget class="QLineEdit" name="registeredDocsFilterLineEdit"> + <property name="placeholderText"> + <string><Filter></string> + </property> + <property name="clearButtonEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="1" rowspan="2"> + <layout class="QVBoxLayout" name="verticalLayout_4"> <item> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <item> - <widget class="QLineEdit" name="registeredDocsFilterLineEdit"> - <property name="placeholderText"> - <string><Filter></string> - </property> - <property name="clearButtonEnabled"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QListView" name="registeredDocsListView"> - <property name="selectionMode"> - <enum>QAbstractItemView::ExtendedSelection</enum> - </property> - </widget> - </item> - </layout> + <widget class="QPushButton" name="docAddButton"> + <property name="text"> + <string>Add...</string> + </property> + </widget> </item> <item> - <layout class="QVBoxLayout"> - <property name="spacing"> - <number>6</number> + <widget class="QPushButton" name="docRemoveButton"> + <property name="text"> + <string>Remove</string> </property> - <item> - <widget class="QPushButton" name="docAddButton"> - <property name="text"> - <string>Add...</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="docRemoveButton"> - <property name="text"> - <string>Remove</string> - </property> - </widget> - </item> - <item> - <spacer> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> + </widget> + </item> + <item> + <spacer> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> </item> </layout> </item> + <item row="2" column="0"> + <widget class="QListWidget" name="registeredDocsListWidget"> + <property name="selectionMode"> + <enum>QAbstractItemView::ExtendedSelection</enum> + </property> + </widget> + </item> </layout> </widget> <widget class="QWidget" name="optionsTab"> @@ -348,38 +338,23 @@ </widget> </item> <item> - <layout class="QHBoxLayout"> - <property name="spacing"> - <number>6</number> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> - <item> - <spacer> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - </layout> + </widget> </item> </layout> </widget> <layoutdefault spacing="6" margin="11"/> + <customwidgets> + <customwidget> + <class>OptionsWidget</class> + <extends>QWidget</extends> + <header>optionswidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> <resources/> <connections> <connection> diff --git a/src/assistant/assistant/remotecontrol.cpp b/src/assistant/assistant/remotecontrol.cpp index cab7b5db6..7fdbee41e 100644 --- a/src/assistant/assistant/remotecontrol.cpp +++ b/src/assistant/assistant/remotecontrol.cpp @@ -42,6 +42,7 @@ #include <QtWidgets/QApplication> #include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpFilterEngine> #include <QtHelp/QHelpIndexWidget> #include <QtHelp/QHelpSearchQueryWidget> @@ -223,12 +224,12 @@ void RemoteControl::handleExpandTocCommand(const QString &arg) void RemoteControl::handleSetCurrentFilterCommand(const QString &arg) { TRACE_OBJ - if (helpEngine.customFilters().contains(arg)) { + if (helpEngine.filterEngine()->filters().contains(arg)) { if (m_caching) { clearCache(); m_currentFilter = arg; } else { - helpEngine.setCurrentFilter(arg); + helpEngine.filterEngine()->setActiveFilter(arg); } } } @@ -270,7 +271,7 @@ void RemoteControl::applyCache() if (!links.isEmpty()) CentralWidget::instance()->setSource(links.first()); } else if (!m_currentFilter.isEmpty()) { - helpEngine.setCurrentFilter(m_currentFilter); + helpEngine.filterEngine()->setActiveFilter(m_currentFilter); } if (m_syncContents) diff --git a/src/assistant/help/help.pro b/src/assistant/help/help.pro index 5bdc501fc..a1616b233 100644 --- a/src/assistant/help/help.pro +++ b/src/assistant/help/help.pro @@ -14,6 +14,7 @@ SOURCES += qhelpenginecore.cpp \ qhelpengine.cpp \ qhelpcollectiondetails.cpp \ qhelpfilterdata.cpp \ + qhelpfilterengine.cpp \ qhelpdbreader.cpp \ qhelpcontentwidget.cpp \ qhelpindexwidget.cpp \ @@ -31,6 +32,7 @@ HEADERS += qhelpenginecore.h \ qhelpengine_p.h \ qhelpcollectiondetails.h \ qhelpfilterdata.h \ + qhelpfilterengine.h \ qhelp_global.h \ qhelpdbreader_p.h \ qhelpcontentwidget.h \ diff --git a/src/assistant/help/qhelpcollectionhandler.cpp b/src/assistant/help/qhelpcollectionhandler.cpp index e59acaac5..0cb6264dd 100644 --- a/src/assistant/help/qhelpcollectionhandler.cpp +++ b/src/assistant/help/qhelpcollectionhandler.cpp @@ -925,8 +925,8 @@ bool QHelpCollectionHandler::fileExists(const QUrl &url) const if (fileInfo.namespaceName.isEmpty()) return false; - m_query->prepare(QLatin1String("SELECT COUNT (DISTINCT NamespaceTable.Id)" - "FROM" + m_query->prepare(QLatin1String("SELECT COUNT (DISTINCT NamespaceTable.Id) " + "FROM " "FileNameTable, " "NamespaceTable, " "FolderTable " diff --git a/src/assistant/help/qhelpcontentwidget.cpp b/src/assistant/help/qhelpcontentwidget.cpp index 412e14528..901c4c56b 100644 --- a/src/assistant/help/qhelpcontentwidget.cpp +++ b/src/assistant/help/qhelpcontentwidget.cpp @@ -76,15 +76,18 @@ public: ~QHelpContentProvider() override; void collectContents(const QString &customFilterName); void stopCollecting(); - QHelpContentItem *rootItem(); + QHelpContentItem *takeContentItem(); private: void run() override; QHelpEnginePrivate *m_helpEngine; + QString m_currentFilter; QStringList m_filterAttributes; - QQueue<QHelpContentItem*> m_rootItems; + QString m_collectionFile; + QHelpContentItem *m_rootItem = nullptr; QMutex m_mutex; + bool m_usesFilterEngine = false; bool m_abort = false; }; @@ -194,7 +197,10 @@ QHelpContentProvider::~QHelpContentProvider() void QHelpContentProvider::collectContents(const QString &customFilterName) { m_mutex.lock(); + m_currentFilter = customFilterName; m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName); + m_collectionFile = m_helpEngine->collectionHandler->collectionFile(); + m_usesFilterEngine = m_helpEngine->usesFilterEngine; m_mutex.unlock(); if (isRunning()) @@ -215,16 +221,16 @@ void QHelpContentProvider::stopCollecting() // either way never resetting m_abort to false from within the run() method m_abort = false; } - qDeleteAll(m_rootItems); - m_rootItems.clear(); + delete m_rootItem; + m_rootItem = nullptr; } -QHelpContentItem *QHelpContentProvider::rootItem() +QHelpContentItem *QHelpContentProvider::takeContentItem() { QMutexLocker locker(&m_mutex); - if (m_rootItems.isEmpty()) - return nullptr; - return m_rootItems.dequeue(); + QHelpContentItem *content = m_rootItem; + m_rootItem = nullptr; + return content; } // TODO: this is a copy from helpcollectionhandler, make it common @@ -258,8 +264,12 @@ void QHelpContentProvider::run() m_mutex.lock(); QHelpContentItem * const rootItem = new QHelpContentItem(QString(), QString(), nullptr); + const QString currentFilter = m_currentFilter; const QStringList attributes = m_filterAttributes; - const QString collectionFile = m_helpEngine->collectionHandler->collectionFile(); + const QString collectionFile = m_collectionFile; + const bool usesFilterEngine = m_usesFilterEngine; + delete m_rootItem; + m_rootItem = nullptr; m_mutex.unlock(); if (collectionFile.isEmpty()) @@ -269,8 +279,9 @@ void QHelpContentProvider::run() if (!collectionHandler.openCollectionFile()) return; - const QList<QHelpCollectionHandler::ContentsData> result - = collectionHandler.contentsForFilter(attributes); + const QList<QHelpCollectionHandler::ContentsData> result = usesFilterEngine + ? collectionHandler.contentsForFilter(currentFilter) + : collectionHandler.contentsForFilter(attributes); for (const auto &contentsData : result) { m_mutex.lock(); @@ -328,7 +339,7 @@ CHECK_DEPTH: } m_mutex.lock(); - m_rootItems.enqueue(rootItem); + m_rootItem = rootItem; m_abort = false; m_mutex.unlock(); } @@ -375,11 +386,6 @@ QHelpContentModel::~QHelpContentModel() delete d; } -void QHelpContentModel::invalidateContents(bool onShutDown) -{ - Q_UNUSED(onShutDown) -} - /*! Creates new contents by querying the help system for contents specified for the \a customFilterName. @@ -405,7 +411,7 @@ void QHelpContentModel::insertContents() if (d->qhelpContentProvider->isRunning()) return; - QHelpContentItem * const newRootItem = d->qhelpContentProvider->rootItem(); + QHelpContentItem * const newRootItem = d->qhelpContentProvider->takeContentItem(); if (!newRootItem) return; beginResetModel(); diff --git a/src/assistant/help/qhelpcontentwidget.h b/src/assistant/help/qhelpcontentwidget.h index 01594d60f..b316ebba9 100644 --- a/src/assistant/help/qhelpcontentwidget.h +++ b/src/assistant/help/qhelpcontentwidget.h @@ -100,7 +100,6 @@ Q_SIGNALS: private Q_SLOTS: void insertContents(); - void invalidateContents(bool onShutDown = false); private: QHelpContentModel(QHelpEnginePrivate *helpEngine); diff --git a/src/assistant/help/qhelpengine.cpp b/src/assistant/help/qhelpengine.cpp index 28825e2ed..19e44cd91 100644 --- a/src/assistant/help/qhelpengine.cpp +++ b/src/assistant/help/qhelpengine.cpp @@ -44,6 +44,7 @@ #include "qhelpindexwidget.h" #include "qhelpsearchengine.h" #include "qhelpcollectionhandler_p.h" +#include "qhelpfilterengine.h" #include <QtCore/QDir> #include <QtCore/QFile> @@ -68,6 +69,8 @@ void QHelpEnginePrivate::init(const QString &collectionFile, this, &QHelpEnginePrivate::scheduleApplyCurrentFilter); connect(helpEngineCore, &QHelpEngineCore::currentFilterChanged, this, &QHelpEnginePrivate::scheduleApplyCurrentFilter); + connect(helpEngineCore->filterEngine(), &QHelpFilterEngine::filterActivated, + this, &QHelpEnginePrivate::scheduleApplyCurrentFilter); } void QHelpEnginePrivate::scheduleApplyCurrentFilter() @@ -85,8 +88,11 @@ void QHelpEnginePrivate::scheduleApplyCurrentFilter() void QHelpEnginePrivate::applyCurrentFilter() { m_isApplyCurrentFilterScheduled = false; - contentModel->createContents(currentFilter); - indexModel->createIndex(currentFilter); + const QString filter = usesFilterEngine + ? q->filterEngine()->activeFilter() + : currentFilter; + contentModel->createContents(filter); + indexModel->createIndex(filter); } void QHelpEnginePrivate::setContentsWidgetBusy() diff --git a/src/assistant/help/qhelpengine_p.h b/src/assistant/help/qhelpengine_p.h index 847715eb3..558013e77 100644 --- a/src/assistant/help/qhelpengine_p.h +++ b/src/assistant/help/qhelpengine_p.h @@ -68,6 +68,7 @@ class QHelpIndexModel; class QHelpIndexWidget; class QHelpSearchEngine; class QHelpCollectionHandler; +class QHelpFilterEngine; class QHelpEngineCorePrivate : public QObject { @@ -82,10 +83,12 @@ public: bool setup(); QHelpCollectionHandler *collectionHandler = nullptr; + QHelpFilterEngine *filterEngine = nullptr; QString currentFilter; QString error; bool needsSetup = true; bool autoSaveFilter = true; + bool usesFilterEngine = false; protected: QHelpEngineCore *q; diff --git a/src/assistant/help/qhelpenginecore.cpp b/src/assistant/help/qhelpenginecore.cpp index fc6366d2a..6f1794a60 100644 --- a/src/assistant/help/qhelpenginecore.cpp +++ b/src/assistant/help/qhelpenginecore.cpp @@ -41,6 +41,7 @@ #include "qhelpengine_p.h" #include "qhelpdbreader_p.h" #include "qhelpcollectionhandler_p.h" +#include "qhelpfilterengine.h" #include <QtCore/QDir> #include <QtCore/QFile> @@ -59,6 +60,7 @@ void QHelpEngineCorePrivate::init(const QString &collectionFile, collectionHandler = new QHelpCollectionHandler(collectionFile, helpEngineCore); connect(collectionHandler, &QHelpCollectionHandler::error, this, &QHelpEngineCorePrivate::errorReceived); + filterEngine->setCollectionHandler(collectionHandler); needsSetup = true; } @@ -111,11 +113,14 @@ void QHelpEngineCorePrivate::errorReceived(const QString &msg) depends on the currently set custom filter. Depending on the filter, the function may return different results. - Every help engine can contain any number of custom filters. A custom - filter is defined by a name and set of filter attributes and can be - added to the help engine by calling addCustomFilter(). Analogous, - it is removed by calling removeCustomFilter(). customFilters() returns - all defined filters. + The help engine can contain any number of custom filters. + The management of the filters, including adding new filters, + changing filter definitions, or removing existing filters, + is done through the QHelpFilterEngine class, which can be accessed + by the filterEngine() method. This replaces older filter API that is + deprecated since Qt 5.13. Please call setUsesFilterEngine() with + \c true to enable the new functionality. + The help engine also offers the possibility to set and read values in a persistant way comparable to ini files or Windows registry @@ -152,6 +157,9 @@ void QHelpEngineCorePrivate::errorReceived(const QString &msg) /*! \fn void QHelpEngineCore::currentFilterChanged(const QString &newFilter) + \obsolete + + QHelpFilterEngine::filterActivated() should be used instead. This signal is emitted when the current filter is changed to \a newFilter. @@ -173,6 +181,7 @@ QHelpEngineCore::QHelpEngineCore(const QString &collectionFile, QObject *parent) : QObject(parent) { d = new QHelpEngineCorePrivate(); + d->filterEngine = new QHelpFilterEngine(this); d->init(collectionFile, this); } @@ -184,6 +193,7 @@ QHelpEngineCore::QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate, : QObject(parent) { d = helpEngineCorePrivate; + d->filterEngine = new QHelpFilterEngine(this); } /*! @@ -222,6 +232,19 @@ void QHelpEngineCore::setCollectionFile(const QString &fileName) } /*! + \since 5.13 + + Returns the filter engine associated with this help engine. + The filter engine allows for adding, changing, and removing existing + filters for this help engine. To use the engine you also have to call + \l setUsesFilterEngine() set to \c true. +*/ +QHelpFilterEngine *QHelpEngineCore::filterEngine() const +{ + return d->filterEngine; +} + +/*! Sets up the help engine by processing the information found in the collection file and returns true if successful; otherwise returns false. @@ -345,6 +368,10 @@ QStringList QHelpEngineCore::registeredDocumentations() const } /*! + \obsolete + + QHelpFilterEngine::filters() should be used instead. + Returns a list of custom filters. \sa addCustomFilter(), removeCustomFilter() @@ -357,6 +384,10 @@ QStringList QHelpEngineCore::customFilters() const } /*! + \obsolete + + QHelpFilterEngine::setFilterData() should be used instead. + Adds the new custom filter \a filterName. The filter attributes are specified by \a attributes. If the filter already exists, its attribute set is replaced. The function returns true if @@ -373,6 +404,10 @@ bool QHelpEngineCore::addCustomFilter(const QString &filterName, } /*! + \obsolete + + QHelpFilterEngine::removeFilter() should be used instead. + Returns true if the filter \a filterName was removed successfully, otherwise false. @@ -386,6 +421,10 @@ bool QHelpEngineCore::removeCustomFilter(const QString &filterName) } /*! + \obsolete + + QHelpFilterEngine::availableComponents() should be used instead. + Returns a list of all defined filter attributes. */ QStringList QHelpEngineCore::filterAttributes() const @@ -396,6 +435,10 @@ QStringList QHelpEngineCore::filterAttributes() const } /*! + \obsolete + + QHelpFilterEngine::filterData() should be used instead. + Returns a list of filter attributes used by the custom filter \a filterName. */ @@ -407,10 +450,13 @@ QStringList QHelpEngineCore::filterAttributes(const QString &filterName) const } /*! + \obsolete \property QHelpEngineCore::currentFilter \brief the name of the custom filter currently applied. \since 4.5 + QHelpFilterEngine::activeFilter() should be used instead. + Setting this property will save the new custom filter permanently in the help collection file. To set a custom filter without saving it permanently, disable the auto save filter mode. @@ -446,6 +492,10 @@ void QHelpEngineCore::setCurrentFilter(const QString &filterName) } /*! + \obsolete + + QHelpFilterEngine::filterData() should be used instead. + Returns a list of filter attributes for the different filter sections defined in the Qt compressed help file with the given namespace \a namespaceName. @@ -459,6 +509,10 @@ QList<QStringList> QHelpEngineCore::filterAttributeSets(const QString &namespace } /*! + \obsolete + + files() should be used instead. + Returns a list of files contained in the Qt compressed help file \a namespaceName. The files can be filtered by \a filterAttributes as well as by their extension \a extensionFilter (e.g. 'html'). @@ -485,22 +539,55 @@ QList<QUrl> QHelpEngineCore::files(const QString namespaceName, } /*! - Returns an invalid URL if the file \a url cannot be found. - If the file exists, either the same url is returned or a - different url if the file is located in a different namespace - which is merged via a common virtual folder. + Returns a list of files contained in the Qt compressed help file + for \a namespaceName. The files can be filtered by \a filterName as + well as by their extension \a extensionFilter (for example, 'html'). +*/ +QList<QUrl> QHelpEngineCore::files(const QString namespaceName, + const QString &filterName, + const QString &extensionFilter) +{ + QList<QUrl> res; + if (!d->setup()) + return res; + + QUrl url; + url.setScheme(QLatin1String("qthelp")); + url.setAuthority(namespaceName); + + const QStringList &files = d->collectionHandler->files( + namespaceName, filterName, extensionFilter); + for (const QString &file : files) { + url.setPath(QLatin1String("/") + file); + res.append(url); + } + return res; +} + +/*! + Returns the corrected URL for the \a url that may refer to + a different namespace defined by the virtual folder defined + as a part of the \a url. If the virtual folder matches the namespace + of the \a url, the method just checks if the file exists and returns + the same \a url. When the virtual folder doesn't match the namespace + of the \a url, it tries to find the best matching namespace according + to the active filter. When the namespace is found, it returns the + corrected URL if the file exists, otherwise it returns an invalid URL. */ QUrl QHelpEngineCore::findFile(const QUrl &url) const { if (!d->setup()) return url; - const QStringList &attributes = filterAttributes(currentFilter()); - QUrl result = d->collectionHandler->findFile(url, attributes); + QUrl result = d->usesFilterEngine + ? d->collectionHandler->findFile(url, d->filterEngine->activeFilter()) + : d->collectionHandler->findFile(url, filterAttributes(currentFilter())); // obsolete if (!result.isEmpty()) return result; - result = d->collectionHandler->findFile(url, QStringList()); + result = d->usesFilterEngine + ? d->collectionHandler->findFile(url, QString()) + : d->collectionHandler->findFile(url, QStringList()); // obsolete if (!result.isEmpty()) return result; @@ -522,30 +609,37 @@ QByteArray QHelpEngineCore::fileData(const QUrl &url) const } /*! - Returns documents found for the \a id. The map contains the - document titles and their URLs. - The returned map contents depends on the current filter, meaning only the keywords - registered for the current filter will be returned. + Returns a map of the documents found for the \a id. The map contains the + document titles and their URLs. The returned map contents depend on + the current filter, and therefore only the identifiers registered for + the current filter will be returned. */ QMap<QString, QUrl> QHelpEngineCore::linksForIdentifier(const QString &id) const { if (!d->setup()) return QMap<QString, QUrl>(); + if (d->usesFilterEngine) + return d->collectionHandler->linksForIdentifier(id, d->filterEngine->activeFilter()); + + // obsolete return d->collectionHandler->linksForIdentifier(id, filterAttributes(d->currentFilter)); } /*! - \since 4.5 - - Returns all documents found for the \a keyword. The returned map consists of the - document titles and their URLs. + Returns a map of all the documents found for the \a keyword. The map + contains the document titles and URLs. The returned map contents depend + on the current filter, and therefore only the keywords registered for + the current filter will be returned. */ QMap<QString, QUrl> QHelpEngineCore::linksForKeyword(const QString &keyword) const { if (!d->setup()) return QMap<QString, QUrl>(); + if (d->usesFilterEngine) + return d->collectionHandler->linksForKeyword(keyword, d->filterEngine->activeFilter()); + return d->collectionHandler->linksForKeyword(keyword, filterAttributes(d->currentFilter)); } @@ -621,7 +715,7 @@ QString QHelpEngineCore::error() const \since 4.5 If QHelpEngineCore is in auto save filter mode, the current filter is - automatically saved when it is changed by the setCurrentFilter() + automatically saved when it is changed by the QHelpFilterEngine::setActiveFilter() function. The filter is saved persistently in the help collection file. By default, this mode is on. @@ -636,4 +730,29 @@ bool QHelpEngineCore::autoSaveFilter() const return d->autoSaveFilter; } +/*! + \since 5.13 + + Enables or disables the new filter engine functionality + inside the help engine, according to the passed \a uses parameter. + + \sa filterEngine() +*/ +void QHelpEngineCore::setUsesFilterEngine(bool uses) +{ + d->usesFilterEngine = uses; +} + +/*! + \since 5.13 + + Returns whether the help engine uses the new filter functionality. + + \sa filterEngine() +*/ +bool QHelpEngineCore::usesFilterEngine() const +{ + return d->usesFilterEngine; +} + QT_END_NAMESPACE diff --git a/src/assistant/help/qhelpenginecore.h b/src/assistant/help/qhelpenginecore.h index 6a2bf0e7d..91950290e 100644 --- a/src/assistant/help/qhelpenginecore.h +++ b/src/assistant/help/qhelpenginecore.h @@ -49,8 +49,8 @@ QT_BEGIN_NAMESPACE - class QHelpEngineCorePrivate; +class QHelpFilterEngine; class QHELP_EXPORT QHelpEngineCore : public QObject { @@ -63,6 +63,8 @@ public: explicit QHelpEngineCore(const QString &collectionFile, QObject *parent = nullptr); virtual ~QHelpEngineCore(); + QHelpFilterEngine *filterEngine() const; + bool setupData(); QString collectionFile() const; @@ -74,7 +76,10 @@ public: bool registerDocumentation(const QString &documentationFileName); bool unregisterDocumentation(const QString &namespaceName); QString documentationFileName(const QString &namespaceName); + QStringList registeredDocumentations() const; + QByteArray fileData(const QUrl &url) const; +#if QT_DEPRECATED_SINCE(5,13) QStringList customFilters() const; bool removeCustomFilter(const QString &filterName); bool addCustomFilter(const QString &filterName, @@ -86,13 +91,16 @@ public: QString currentFilter() const; void setCurrentFilter(const QString &filterName); - QStringList registeredDocumentations() const; QList<QStringList> filterAttributeSets(const QString &namespaceName) const; QList<QUrl> files(const QString namespaceName, const QStringList &filterAttributes, const QString &extensionFilter = QString()); +#endif + + QList<QUrl> files(const QString namespaceName, + const QString &filterName, + const QString &extensionFilter = QString()); QUrl findFile(const QUrl &url) const; - QByteArray fileData(const QUrl &url) const; QMap<QString, QUrl> linksForIdentifier(const QString &id) const; QMap<QString, QUrl> linksForKeyword(const QString &keyword) const; @@ -110,12 +118,18 @@ public: void setAutoSaveFilter(bool save); bool autoSaveFilter() const; + void setUsesFilterEngine(bool uses); + bool usesFilterEngine() const; + Q_SIGNALS: void setupStarted(); void setupFinished(); - void currentFilterChanged(const QString &newFilter); void warning(const QString &msg); + +#if QT_DEPRECATED_SINCE(5,13) + void currentFilterChanged(const QString &newFilter); void readersAboutToBeInvalidated(); +#endif protected: QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate, diff --git a/src/assistant/help/qhelpfilterdata.cpp b/src/assistant/help/qhelpfilterdata.cpp index 0cd6ad3fb..3063136ed 100644 --- a/src/assistant/help/qhelpfilterdata.cpp +++ b/src/assistant/help/qhelpfilterdata.cpp @@ -54,31 +54,65 @@ public: QStringList m_components; }; +/*! + \class QHelpFilterData + \since 5.13 + \inmodule QtHelp + \brief The QHelpFilterData class provides details for the filters + used by QHelpFilterEngine. + + By using setComponents() you may constrain the search results to + documents that belong only to components specified on the given list. + + \sa QHelpFilterEngine +*/ + +/*! + Constructs the empty filter. +*/ QHelpFilterData::QHelpFilterData() : d(new QHelpFilterDataPrivate) { } +/*! + Constructs a copy of \a other. +*/ QHelpFilterData::QHelpFilterData(const QHelpFilterData &other) : d(other.d) { } +/*! + Destroys the filter. +*/ QHelpFilterData::~QHelpFilterData() { } +/*! + Assigns \a other to this filter and returns a reference to this filter. +*/ QHelpFilterData &QHelpFilterData::operator=(const QHelpFilterData &other) { d = other.d; return *this; } +/*! + Specifies the component list that is used for filtering + the search results. Only the results which match the \a components + will be returned. +*/ void QHelpFilterData::setComponents(const QStringList &components) { d->m_components = components; } +/*! + Returns the component list that is used for filtering + the search results. +*/ QStringList QHelpFilterData::components() const { return d->m_components; diff --git a/src/assistant/help/qhelpfilterengine.cpp b/src/assistant/help/qhelpfilterengine.cpp new file mode 100644 index 000000000..6a57e1cdc --- /dev/null +++ b/src/assistant/help/qhelpfilterengine.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#include "qhelpfilterengine.h" +#include "qhelpenginecore.h" +#include "qhelpfilterdata.h" +#include "qhelpdbreader_p.h" +#include "qhelpcollectionhandler_p.h" + +#include <QtCore/QThread> + +QT_BEGIN_NAMESPACE + +static const char ActiveFilter[] = "activeFilter"; + +class QHelpFilterEnginePrivate +{ +public: + bool setup(); + + QHelpFilterEngine *q = nullptr; + QHelpEngineCore *m_helpEngine = nullptr; + QHelpCollectionHandler *m_collectionHandler = nullptr; + QString m_currentFilter; + bool m_needsSetup = true; +}; + +bool QHelpFilterEnginePrivate::setup() +{ + if (!m_collectionHandler) + return false; + + if (!m_needsSetup) + return true; + + if (!m_helpEngine->setupData()) + return false; + + m_needsSetup = false; + + const QString filter = m_collectionHandler->customValue( + QLatin1String(ActiveFilter), QString()).toString(); + if (!filter.isEmpty() && m_collectionHandler->filters().contains(filter)) + m_currentFilter = filter; + + emit q->filterActivated(m_currentFilter); + return true; +} + +////////////// + +/*! + \class QHelpFilterEngine + \since 5.13 + \inmodule QtHelp + \brief The QHelpFilterEngine class provides a filtered view of the + help contents. + + The filter engine allows the management of filters associated with + a QHelpEngineCore instance. The help engine internally creates an + instance of the filter engine, which can be accessed by calling + QHelpEngineCore::filterEngine(). Therefore, the public constructor + of this class is disabled. + + The filters are identified by a filter name string. Filter details are + described by the \l QHelpFilterData class. + + The filter engine allows for adding new filters and changing the existing + filters' data through the setFilterData() method. An existing filter can + be removed through the removeFilter() method. + + Out of the registered filters one can be marked as the active one. + The active filter will be used by the associated help engine for returning + filtered results of many different functions, such as content, index, or + search results. If no filter is marked active, the help engine returns the + full results list available. + + The active filter is returned by activeFilter() and it can be changed by + setActiveFilter(). + + \sa QHelpEngineCore +*/ + +/*! + \fn void QHelpFilterEngine::filterActivated(const QString &newFilter) + + This signal is emitted when the active filter is set. \a newFilter + specifies the name of the filter. + + \sa setActiveFilter() +*/ + +/*! + \internal + Constructs the filter engine for \a helpEngine. +*/ +QHelpFilterEngine::QHelpFilterEngine(QHelpEngineCore *helpEngine) + : QObject(helpEngine), + d(new QHelpFilterEnginePrivate) +{ + d->q = this; + d->m_helpEngine = helpEngine; +} + +/*! + \internal + Destroys the existing filter engine. +*/ +QHelpFilterEngine::~QHelpFilterEngine() +{ + delete d; +} + +/*! + \internal + Sets the \a collectionHandler to be used for this filter engine. +*/ +void QHelpFilterEngine::setCollectionHandler(QHelpCollectionHandler *collectionHandler) +{ + d->m_collectionHandler = collectionHandler; + d->m_currentFilter = QString(); + d->m_needsSetup = true; +} + +/*! + Returns the map of all the available namespaces as keys + together with their associated components as values. +*/ +QMap<QString, QString> QHelpFilterEngine::namespaceToComponent() const +{ + if (!d->setup()) + return QMap<QString, QString>(); + return d->m_collectionHandler->namespaceToComponent(); +} + +/*! + Returns the list of all filter names defined inside the filter engine. +*/ +QStringList QHelpFilterEngine::filters() const +{ + if (!d->setup()) + return QStringList(); + return d->m_collectionHandler->filters(); +} + +/*! + Returns the list of all available components defined in all + registered documentation files. +*/ +QStringList QHelpFilterEngine::availableComponents() const +{ + if (!d->setup()) + return QStringList(); + return d->m_collectionHandler->availableComponents(); +} + +/*! + Returns the filter details associated with \a filterName. +*/ +QHelpFilterData QHelpFilterEngine::filterData(const QString &filterName) const +{ + if (!d->setup()) + return QHelpFilterData(); + return d->m_collectionHandler->filterData(filterName); +} + +/*! + Changes the existing filter details of the filter identified by + \a filterName to \a filterData. If the filter does not exist, a + new filter is created. + + Returns \c true if setting the filter succeeded, otherwise returns \c false. +*/ +bool QHelpFilterEngine::setFilterData(const QString &filterName, const QHelpFilterData &filterData) +{ + if (!d->setup()) + return false; + return d->m_collectionHandler->setFilterData(filterName, filterData); +} + +/*! + Removes the filter identified by \a filterName. + + Returns \c true if removing the filter succeeded, otherwise returns + \c false. +*/ +bool QHelpFilterEngine::removeFilter(const QString &filterName) +{ + if (!d->setup()) + return false; + return d->m_collectionHandler->removeFilter(filterName); +} + +/*! + Returns the name of the currently active filter. +*/ +QString QHelpFilterEngine::activeFilter() const +{ + if (!d->setup()) + return QString(); + return d->m_currentFilter; +} + +/*! + Changes the currently active filter to \a filterName. + + Returns \c true if changing the filter succeeded, otherwise + returns \c false. +*/ +bool QHelpFilterEngine::setActiveFilter(const QString &filterName) +{ + if (!d->setup()) + return false; + + if (filterName == d->m_currentFilter) + return true; + + if (!filterName.isEmpty() && !d->m_collectionHandler->filters().contains(filterName)) + return false; + + d->m_currentFilter = filterName; + d->m_collectionHandler->setCustomValue(QLatin1String(ActiveFilter), + d->m_currentFilter); + + emit filterActivated(d->m_currentFilter); + + return true; +} + +/*! + Returns the list of all registered documentation namespaces that match + the filter identified by \a filterName. +*/ +QStringList QHelpFilterEngine::namespacesForFilter(const QString &filterName) const +{ + if (!d->setup()) + return QStringList(); + return d->m_collectionHandler->namespacesForFilter(filterName); +} + +QT_END_NAMESPACE diff --git a/src/assistant/help/qhelpfilterengine.h b/src/assistant/help/qhelpfilterengine.h new file mode 100644 index 000000000..717b0ed60 --- /dev/null +++ b/src/assistant/help/qhelpfilterengine.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QHELPFILTERENGINE_H +#define QHELPFILTERENGINE_H + +#include <QtHelp/qhelp_global.h> + +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QUrl; +template <class K, class T> +class QMap; + +class QHelpCollectionHandler; +class QHelpEngineCore; +class QHelpFilterData; +class QHelpFilterEnginePrivate; + +class QHELP_EXPORT QHelpFilterEngine : public QObject +{ + Q_OBJECT +public: + QMap<QString, QString> namespaceToComponent() const; + + QStringList filters() const; + + QString activeFilter() const; + bool setActiveFilter(const QString &filterName); + + QStringList availableComponents() const; + + QHelpFilterData filterData(const QString &filterName) const; + bool setFilterData(const QString &filterName, const QHelpFilterData &filterData); + + bool removeFilter(const QString &filterName); + + QStringList namespacesForFilter(const QString &filterName) const; + +Q_SIGNALS: + void filterActivated(const QString &newFilter); + +protected: + explicit QHelpFilterEngine(QHelpEngineCore *helpEngine); + virtual ~QHelpFilterEngine(); + +private: + void setCollectionHandler(QHelpCollectionHandler *collectionHandler); + + QHelpFilterEnginePrivate *d; + friend class QHelpEngineCore; + friend class QHelpEngineCorePrivate; +}; + +QT_END_NAMESPACE + +#endif // QHELPFILTERENGINE_H diff --git a/src/assistant/help/qhelpindexwidget.cpp b/src/assistant/help/qhelpindexwidget.cpp index e76dd4fb4..fa70dd438 100644 --- a/src/assistant/help/qhelpindexwidget.cpp +++ b/src/assistant/help/qhelpindexwidget.cpp @@ -65,8 +65,9 @@ private: void run() override; QHelpEnginePrivate *m_helpEngine; - QStringList m_indices; + QString m_currentFilter; QStringList m_filterAttributes; + QStringList m_indices; mutable QMutex m_mutex; }; @@ -98,6 +99,7 @@ QHelpIndexProvider::~QHelpIndexProvider() void QHelpIndexProvider::collectIndices(const QString &customFilterName) { m_mutex.lock(); + m_currentFilter = customFilterName; m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName); m_mutex.unlock(); @@ -122,9 +124,10 @@ QStringList QHelpIndexProvider::indices() const void QHelpIndexProvider::run() { m_mutex.lock(); - m_indices.clear(); + const QString currentFilter = m_currentFilter; const QStringList attributes = m_filterAttributes; const QString collectionFile = m_helpEngine->collectionHandler->collectionFile(); + m_indices = QStringList(); m_mutex.unlock(); if (collectionFile.isEmpty()) @@ -134,7 +137,9 @@ void QHelpIndexProvider::run() if (!collectionHandler.openCollectionFile()) return; - const QStringList result = collectionHandler.indicesForFilter(attributes); + const QStringList result = m_helpEngine->usesFilterEngine + ? collectionHandler.indicesForFilter(currentFilter) + : collectionHandler.indicesForFilter(attributes); m_mutex.lock(); m_indices = result; @@ -181,11 +186,6 @@ QHelpIndexModel::~QHelpIndexModel() delete d; } -void QHelpIndexModel::invalidateIndex(bool onShutDown) -{ - Q_UNUSED(onShutDown) -} - /*! Creates a new index by querying the help system for keywords for the specified \a customFilterName. diff --git a/src/assistant/help/qhelpindexwidget.h b/src/assistant/help/qhelpindexwidget.h index 46d4937b7..58dda5e39 100644 --- a/src/assistant/help/qhelpindexwidget.h +++ b/src/assistant/help/qhelpindexwidget.h @@ -70,7 +70,6 @@ Q_SIGNALS: private Q_SLOTS: void insertIndices(); - void invalidateIndex(bool onShutDown = false); private: QHelpIndexModel(QHelpEnginePrivate *helpEngine); diff --git a/src/assistant/help/qhelpsearchengine.cpp b/src/assistant/help/qhelpsearchengine.cpp index 3ee9904e2..af7247cc3 100644 --- a/src/assistant/help/qhelpsearchengine.cpp +++ b/src/assistant/help/qhelpsearchengine.cpp @@ -231,7 +231,8 @@ private: m_searchInput = searchInput; indexReader->cancelSearching(); - indexReader->search(helpEngine->collectionFile(), indexFilesFolder(), searchInput); + indexReader->search(helpEngine->collectionFile(), indexFilesFolder(), + searchInput, helpEngine->usesFilterEngine()); } void cancelSearching() diff --git a/src/assistant/help/qhelpsearchindexreader.cpp b/src/assistant/help/qhelpsearchindexreader.cpp index 71be91f9f..8aaa5cc47 100644 --- a/src/assistant/help/qhelpsearchindexreader.cpp +++ b/src/assistant/help/qhelpsearchindexreader.cpp @@ -56,7 +56,7 @@ void QHelpSearchIndexReader::cancelSearching() } void QHelpSearchIndexReader::search(const QString &collectionFile, const QString &indexFilesFolder, - const QString &searchInput) + const QString &searchInput, bool usesFilterEngine) { wait(); @@ -65,6 +65,7 @@ void QHelpSearchIndexReader::search(const QString &collectionFile, const QString m_searchInput = searchInput; m_collectionFile = collectionFile; m_indexFilesFolder = indexFilesFolder; + m_usesFilterEngine = usesFilterEngine; start(QThread::NormalPriority); } diff --git a/src/assistant/help/qhelpsearchindexreader_default.cpp b/src/assistant/help/qhelpsearchindexreader_default.cpp index 25f9a13f2..650d8227f 100644 --- a/src/assistant/help/qhelpsearchindexreader_default.cpp +++ b/src/assistant/help/qhelpsearchindexreader_default.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qhelpenginecore.h" +#include "qhelpfilterengine.h" #include "qhelpsearchindexreader_default_p.h" #include <QtCore/QSet> @@ -52,12 +53,20 @@ namespace qt { void Reader::setIndexPath(const QString &path) { m_indexPath = path; - m_namespaces.clear(); + m_namespaceAttributes.clear(); + m_filterEngineNamespaceList.clear(); + m_useFilterEngine = false; } -void Reader::addNamespace(const QString &namespaceName, const QStringList &attributes) +void Reader::addNamespaceAttributes(const QString &namespaceName, const QStringList &attributes) { - m_namespaces.insert(namespaceName, attributes); + m_namespaceAttributes.insert(namespaceName, attributes); +} + +void Reader::setFilterEngineNamespaceList(const QStringList &namespaceList) +{ + m_useFilterEngine = true; + m_filterEngineNamespaceList = namespaceList; } static QString namespacePlaceholders(const QMultiMap<QString, QStringList> &namespaces) @@ -106,18 +115,42 @@ static void bindNamespacesAndAttributes(QSqlQuery *query, const QMultiMap<QStrin } } +static QString namespacePlaceholders(const QStringList &namespaceList) +{ + QString placeholders; + bool firstNS = true; + for (int i = namespaceList.count(); i; --i) { + if (firstNS) + firstNS = false; + else + placeholders += QLatin1String(" OR "); + placeholders += QLatin1String("namespace = ?"); + } + return placeholders; +} + +static void bindNamespacesAndAttributes(QSqlQuery *query, const QStringList &namespaceList) +{ + for (const QString &ns : namespaceList) + query->addBindValue(ns); +} + QVector<QHelpSearchResult> Reader::queryTable(const QSqlDatabase &db, const QString &tableName, const QString &searchInput) const { - const QString &nsPlaceholders = namespacePlaceholders(m_namespaces); + const QString nsPlaceholders = m_useFilterEngine + ? namespacePlaceholders(m_filterEngineNamespaceList) + : namespacePlaceholders(m_namespaceAttributes); QSqlQuery query(db); 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")); - bindNamespacesAndAttributes(&query, m_namespaces); + m_useFilterEngine + ? bindNamespacesAndAttributes(&query, m_filterEngineNamespaceList) + : bindNamespacesAndAttributes(&query, m_namespaceAttributes); query.addBindValue(searchInput); query.exec(); @@ -140,6 +173,7 @@ void Reader::searchInDB(const QString &searchInput) QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), uniqueId); db.setConnectOptions(QLatin1String("QSQLITE_OPEN_READONLY")); db.setDatabaseName(m_indexPath + QLatin1String("/fts")); + if (db.open()) { const QVector<QHelpSearchResult> titleResults = queryTable(db, QLatin1String("titles"), searchInput); @@ -197,6 +231,7 @@ void QHelpSearchIndexReaderDefault::run() const QString searchInput = m_searchInput; const QString collectionFile = m_collectionFile; const QString indexPath = m_indexFilesFolder; + const bool usesFilterEngine = m_usesFilterEngine; lock.unlock(); @@ -207,26 +242,31 @@ void QHelpSearchIndexReaderDefault::run() if (!engine.setupData()) return; - const QStringList ®isteredDocs = engine.registeredDocumentations(); - emit searchingStarted(); - const QStringList ¤tFilter = engine.filterAttributes(engine.currentFilter()); - // setup the reader m_reader.setIndexPath(indexPath); - for (const QString &namespaceName : registeredDocs) { - const QList<QStringList> &attributeSets = - engine.filterAttributeSets(namespaceName); - for (const QStringList &attributes : attributeSets) { - if (attributesMatchFilter(attributes, currentFilter)) { - m_reader.addNamespace(namespaceName, attributes); + if (usesFilterEngine) { + m_reader.setFilterEngineNamespaceList( + engine.filterEngine()->namespacesForFilter( + engine.filterEngine()->activeFilter())); + } else { + const QStringList ®isteredDocs = engine.registeredDocumentations(); + const QStringList ¤tFilter = engine.filterAttributes(engine.currentFilter()); + + for (const QString &namespaceName : registeredDocs) { + const QList<QStringList> &attributeSets = + engine.filterAttributeSets(namespaceName); + + for (const QStringList &attributes : attributeSets) { + if (attributesMatchFilter(attributes, currentFilter)) { + m_reader.addNamespaceAttributes(namespaceName, attributes); + } } } } - lock.relock(); if (m_cancel) { emit searchingFinished(0); // TODO: check this, speed issue while locking??? diff --git a/src/assistant/help/qhelpsearchindexreader_default_p.h b/src/assistant/help/qhelpsearchindexreader_default_p.h index b31b532c6..c183a2357 100644 --- a/src/assistant/help/qhelpsearchindexreader_default_p.h +++ b/src/assistant/help/qhelpsearchindexreader_default_p.h @@ -64,7 +64,8 @@ class Reader { public: void setIndexPath(const QString &path); - void addNamespace(const QString &namespaceName, const QStringList &attributes); + void addNamespaceAttributes(const QString &namespaceName, const QStringList &attributes); + void setFilterEngineNamespaceList(const QStringList &namespaceList); void searchInDB(const QString &term); QVector<QHelpSearchResult> searchResults() const; @@ -74,9 +75,11 @@ private: const QString &tableName, const QString &searchInput) const; - QString m_indexPath; - QMultiMap<QString, QStringList> m_namespaces; + QMultiMap<QString, QStringList> m_namespaceAttributes; + QStringList m_filterEngineNamespaceList; QVector<QHelpSearchResult> m_searchResults; + QString m_indexPath; + bool m_useFilterEngine = false; }; diff --git a/src/assistant/help/qhelpsearchindexreader_p.h b/src/assistant/help/qhelpsearchindexreader_p.h index f6f3ee305..57295693b 100644 --- a/src/assistant/help/qhelpsearchindexreader_p.h +++ b/src/assistant/help/qhelpsearchindexreader_p.h @@ -74,7 +74,8 @@ public: void cancelSearching(); void search(const QString &collectionFile, const QString &indexFilesFolder, - const QString &searchInput); + const QString &searchInput, + bool usesFilterEngine = false); int searchResultCount() const; QVector<QHelpSearchResult> searchResults(int start, int end) const; @@ -89,6 +90,7 @@ protected: QString m_collectionFile; QString m_searchInput; QString m_indexFilesFolder; + bool m_usesFilterEngine = false; private: void run() override = 0; |