aboutsummaryrefslogtreecommitdiffstats
path: root/src/shared/help/indexwindow.cpp
diff options
context:
space:
mode:
authorEike Ziller <[email protected]>2014-09-29 17:35:04 +0200
committerEike Ziller <[email protected]>2014-10-10 10:14:38 +0200
commit9cc88836f7827504c92cdc0d380e83c65ba0dbe4 (patch)
tree27c78ab48d8b11805b2a5a885b29a6fd09104ada /src/shared/help/indexwindow.cpp
parenta10f20775623d95afd8d44722c86f23c5e7d50ad (diff)
Help: Make it possible to create multiple index views
This unfortunately means doing the filtering by hand, because filtering on the QHelpIndexModel would be shared between multiple views. Change-Id: Iae38952a92dbb1b4a9685aea6f057d96f0d0784f Reviewed-by: Eike Ziller <[email protected]>
Diffstat (limited to 'src/shared/help/indexwindow.cpp')
-rw-r--r--src/shared/help/indexwindow.cpp271
1 files changed, 220 insertions, 51 deletions
diff --git a/src/shared/help/indexwindow.cpp b/src/shared/help/indexwindow.cpp
index 529bfb2e836..6f5029a927f 100644
--- a/src/shared/help/indexwindow.cpp
+++ b/src/shared/help/indexwindow.cpp
@@ -38,18 +38,19 @@
#include <utils/fancylineedit.h>
#include <utils/hostosinfo.h>
+#include <utils/navigationtreeview.h>
#include <utils/styledbar.h>
+#include <QAbstractItemModel>
#include <QLayout>
#include <QLabel>
#include <QLineEdit>
#include <QKeyEvent>
#include <QMenu>
#include <QContextMenuEvent>
-#include <QListWidgetItem>
#include <QHelpEngine>
-#include <QHelpIndexWidget>
+#include <QHelpIndexModel>
using namespace Help::Internal;
@@ -63,9 +64,10 @@ IndexWindow::IndexWindow()
m_searchLineEdit->setPlaceholderText(QString());
m_searchLineEdit->setFiltering(true);
setFocusProxy(m_searchLineEdit);
- connect(m_searchLineEdit, SIGNAL(textChanged(QString)), this,
- SLOT(filterIndices(QString)));
+ connect(m_searchLineEdit, &QLineEdit::textChanged,
+ this, &IndexWindow::filterIndices);
m_searchLineEdit->installEventFilter(this);
+ m_searchLineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
QLabel *l = new QLabel(tr("&Look for:"));
l->setBuddy(m_searchLineEdit);
@@ -83,20 +85,22 @@ IndexWindow::IndexWindow()
toolbar->setLayout(tbLayout);
layout->addWidget(toolbar);
- QHelpEngine *engine = &LocalHelpManager::helpEngine();
- m_indexWidget = engine->indexWidget();
+ QHelpIndexModel *indexModel = LocalHelpManager::helpEngine().indexModel();
+ m_filteredIndexModel = new IndexFilterModel(this);
+ m_filteredIndexModel->setSourceModel(indexModel);
+ m_indexWidget = new Utils::NavigationTreeView(this);
+ m_indexWidget->setModel(m_filteredIndexModel);
+ m_indexWidget->setRootIsDecorated(false);
+ m_indexWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_indexWidget->installEventFilter(this);
- connect(engine->indexModel(), SIGNAL(indexCreationStarted()), this,
- SLOT(disableSearchLineEdit()));
- connect(engine->indexModel(), SIGNAL(indexCreated()), this,
- SLOT(enableSearchLineEdit()));
- connect(m_indexWidget, SIGNAL(linkActivated(QUrl,QString)), this,
- SIGNAL(linkActivated(QUrl)));
- connect(m_indexWidget, SIGNAL(linksActivated(QMap<QString,QUrl>,QString)),
- this, SIGNAL(linksActivated(QMap<QString,QUrl>,QString)));
- connect(m_searchLineEdit, SIGNAL(returnPressed()), m_indexWidget,
- SLOT(activateCurrentItem()));
- m_indexWidget->setFrameStyle(QFrame::NoFrame);
+ connect(indexModel, &QHelpIndexModel::indexCreationStarted,
+ this, &IndexWindow::disableSearchLineEdit);
+ connect(indexModel, &QHelpIndexModel::indexCreated,
+ this, &IndexWindow::enableSearchLineEdit);
+ connect(m_indexWidget, &Utils::NavigationTreeView::activated,
+ this, [this](const QModelIndex &index) { open(index); });
+ connect(m_searchLineEdit, &QLineEdit::returnPressed,
+ m_indexWidget, [this]() { open(m_indexWidget->currentIndex()); });
layout->addWidget(m_indexWidget);
m_indexWidget->viewport()->installEventFilter(this);
@@ -108,10 +112,15 @@ IndexWindow::~IndexWindow()
void IndexWindow::filterIndices(const QString &filter)
{
+ QModelIndex bestMatch;
if (filter.contains(QLatin1Char('*')))
- m_indexWidget->filterIndices(filter, filter);
+ bestMatch = m_filteredIndexModel->filter(filter, filter);
else
- m_indexWidget->filterIndices(filter, QString());
+ bestMatch = m_filteredIndexModel->filter(filter, QString());
+ if (bestMatch.isValid()) {
+ m_indexWidget->setCurrentIndex(bestMatch);
+ m_indexWidget->scrollTo(bestMatch);
+ }
}
bool IndexWindow::eventFilter(QObject *obj, QEvent *e)
@@ -150,9 +159,9 @@ bool IndexWindow::eventFilter(QObject *obj, QEvent *e)
QAction *action = menu.exec();
if (curTab == action)
- m_indexWidget->activateCurrentItem();
+ open(idx);
else if (newTab == action)
- open(m_indexWidget, idx);
+ open(idx, true/*newPage*/);
}
} else if (m_indexWidget && obj == m_indexWidget->viewport()
&& e->type() == QEvent::MouseButtonRelease) {
@@ -162,16 +171,10 @@ bool IndexWindow::eventFilter(QObject *obj, QEvent *e)
Qt::MouseButtons button = mouseEvent->button();
if (((button == Qt::LeftButton) && (mouseEvent->modifiers() & Qt::ControlModifier))
|| (button == Qt::MidButton)) {
- open(m_indexWidget, idx);
+ open(idx);
}
}
}
- else if (Utils::HostOsInfo::isMacHost() && obj == m_indexWidget
- && e->type() == QEvent::KeyPress) {
- QKeyEvent *ke = static_cast<QKeyEvent*>(e);
- if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter)
- m_indexWidget->activateCurrentItem();
- }
return QWidget::eventFilter(obj, e);
}
@@ -187,37 +190,203 @@ void IndexWindow::disableSearchLineEdit()
m_searchLineEdit->setDisabled(true);
}
-void IndexWindow::setSearchLineEditText(const QString &text)
+void IndexWindow::open(const QModelIndex &index, bool newPage)
{
- m_searchLineEdit->setText(text);
+ QString keyword = m_filteredIndexModel->data(index, Qt::DisplayRole).toString();
+ QMap<QString, QUrl> links = LocalHelpManager::helpEngine().indexModel()->linksForKeyword(keyword);
+
+ if (links.size() == 1) {
+ emit linkActivated(links.first(), newPage);
+ } else if (links.size() > 1) {
+ emit linksActivated(links, keyword, newPage);
+ }
}
-QString IndexWindow::searchLineEditText() const
+Qt::DropActions IndexFilterModel::supportedDragActions() const
{
- return m_searchLineEdit->text();
+ return sourceModel()->supportedDragActions();
}
-void IndexWindow::open(QHelpIndexWidget* indexWidget, const QModelIndex &index)
+QModelIndex IndexFilterModel::index(int row, int column, const QModelIndex &parent) const
{
- QHelpIndexModel *model = qobject_cast<QHelpIndexModel*>(indexWidget->model());
- if (model) {
- QString keyword = model->data(index, Qt::DisplayRole).toString();
- QMap<QString, QUrl> links = model->linksForKeyword(keyword);
+ Q_UNUSED(parent)
+ return createIndex(row, column);
+}
- QUrl url;
- if (links.count() > 1) {
- TopicChooser tc(this, keyword, links);
- if (tc.exec() == QDialog::Accepted)
- url = tc.link();
- } else if (links.count() == 1) {
- url = links.constBegin().value();
- } else {
- return;
- }
+QModelIndex IndexFilterModel::parent(const QModelIndex &child) const
+{
+ Q_UNUSED(child)
+ return QModelIndex();
+}
+
+int IndexFilterModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return m_toSource.size();
+}
+
+int IndexFilterModel::columnCount(const QModelIndex &parent) const
+{
+ return sourceModel()->columnCount(mapToSource(parent));
+}
- if (!HelpViewer::canOpenPage(url.path()))
- CentralWidget::instance()->setSource(url);
- else
- OpenPagesManager::instance().createPage(url);
+void IndexFilterModel::setSourceModel(QAbstractItemModel *sm)
+{
+ QAbstractItemModel *previousModel = sourceModel();
+ if (previousModel) {
+ disconnect(previousModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
+ disconnect(previousModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
+ disconnect(previousModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
+ disconnect(previousModel, SIGNAL(modelReset()),
+ this, SLOT(sourceModelReset()));
+ }
+ QAbstractProxyModel::setSourceModel(sm);
+ if (sm) {
+ connect(sm, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(sourceDataChanged(QModelIndex,QModelIndex)));
+ connect(sm, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(sourceRowsInserted(QModelIndex,int,int)));
+ connect(sm, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(sourceRowsRemoved(QModelIndex,int,int)));
+ connect(sm, SIGNAL(modelReset()),
+ this, SLOT(sourceModelReset()));
}
+ filter(m_filter, m_wildcard);
+}
+
+QModelIndex IndexFilterModel::sibling(int row, int column, const QModelIndex &idx) const
+{
+ return QAbstractItemModel::sibling(row, column, idx);
+}
+
+Qt::ItemFlags IndexFilterModel::flags(const QModelIndex &index) const
+{
+ Q_UNUSED(index)
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+}
+
+IndexFilterModel::IndexFilterModel(QObject *parent)
+ : QAbstractProxyModel(parent)
+{
+}
+
+QModelIndex IndexFilterModel::filter(const QString &filter, const QString &wildcard)
+{
+ beginResetModel();
+
+ m_filter = filter;
+ m_wildcard = wildcard;
+ m_toSource.clear();
+
+ // adapted copy from QHelpIndexModel
+
+ if (filter.isEmpty() && wildcard.isEmpty()) {
+ int count = sourceModel()->rowCount();
+ m_toSource.reserve(count);
+ for (int i = 0; i < count; ++i)
+ m_toSource.append(i);
+ endResetModel();
+ return index(0, 0);
+ }
+
+ QHelpIndexModel *indexModel = qobject_cast<QHelpIndexModel *>(sourceModel());
+ const QStringList indices = indexModel->stringList();
+ int goodMatch = -1;
+ int perfectMatch = -1;
+
+ if (!wildcard.isEmpty()) {
+ QRegExp regExp(wildcard, Qt::CaseInsensitive);
+ regExp.setPatternSyntax(QRegExp::Wildcard);
+ int i = 0;
+ foreach (const QString &index, indices) {
+ if (index.contains(regExp)) {
+ m_toSource.append(i);
+ if (perfectMatch == -1 && index.startsWith(filter, Qt::CaseInsensitive)) {
+ if (goodMatch == -1)
+ goodMatch = m_toSource.size() - 1;
+ if (filter.length() == index.length()){
+ perfectMatch = m_toSource.size() - 1;
+ }
+ } else if (perfectMatch > -1 && index == filter) {
+ perfectMatch = m_toSource.size() - 1;
+ }
+ }
+ ++i;
+ }
+ } else {
+ int i = 0;
+ foreach (const QString &index, indices) {
+ if (index.contains(filter, Qt::CaseInsensitive)) {
+ m_toSource.append(i);
+ if (perfectMatch == -1 && index.startsWith(filter, Qt::CaseInsensitive)) {
+ if (goodMatch == -1)
+ goodMatch = m_toSource.size() - 1;
+ if (filter.length() == index.length()){
+ perfectMatch = m_toSource.size() - 1;
+ }
+ } else if (perfectMatch > -1 && index == filter) {
+ perfectMatch = m_toSource.size() - 1;
+ }
+ }
+ ++i;
+ }
+ }
+
+ if (perfectMatch == -1)
+ perfectMatch = qMax(0, goodMatch);
+
+ endResetModel();
+ return index(perfectMatch, 0, QModelIndex());
+}
+
+QModelIndex IndexFilterModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ if (!proxyIndex.isValid() || proxyIndex.parent().isValid() || proxyIndex.row() >= m_toSource.size())
+ return QModelIndex();
+ return index(m_toSource.at(proxyIndex.row()), proxyIndex.column());
+}
+
+QModelIndex IndexFilterModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+ if (!sourceIndex.isValid() || sourceIndex.parent().isValid())
+ return QModelIndex();
+ int i = m_toSource.indexOf(sourceIndex.row());
+ if (i < 0)
+ return QModelIndex();
+ return index(i, sourceIndex.column());
+}
+
+void IndexFilterModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+ QModelIndex topLeftIndex = mapFromSource(topLeft);
+ if (!topLeftIndex.isValid())
+ topLeftIndex = index(0, topLeft.column());
+ QModelIndex bottomRightIndex = mapFromSource(bottomRight);
+ if (!bottomRightIndex.isValid())
+ bottomRightIndex = index(0, bottomRight.column());
+ emit dataChanged(topLeftIndex, bottomRightIndex);
+}
+
+void IndexFilterModel::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent)
+ Q_UNUSED(start)
+ Q_UNUSED(end)
+ filter(m_filter, m_wildcard);
+}
+
+void IndexFilterModel::sourceRowsInserted(const QModelIndex &parent, int start, int end)
+{
+ Q_UNUSED(parent)
+ Q_UNUSED(start)
+ Q_UNUSED(end)
+ filter(m_filter, m_wildcard);
+}
+void IndexFilterModel::sourceModelReset()
+{
+ filter(m_filter, m_wildcard);
}