summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@digia.com>2014-09-29 17:35:04 +0200
committerEike Ziller <eike.ziller@digia.com>2014-10-10 10:14:38 +0200
commit9cc88836f7827504c92cdc0d380e83c65ba0dbe4 (patch)
tree27c78ab48d8b11805b2a5a885b29a6fd09104ada
parenta10f20775623d95afd8d44722c86f23c5e7d50ad (diff)
downloadqt-creator-9cc88836f7827504c92cdc0d380e83c65ba0dbe4.tar.gz
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 <eike.ziller@digia.com>
-rw-r--r--src/plugins/help/centralwidget.cpp13
-rw-r--r--src/plugins/help/centralwidget.h5
-rw-r--r--src/plugins/help/helpplugin.cpp8
-rw-r--r--src/shared/help/indexwindow.cpp271
-rw-r--r--src/shared/help/indexwindow.h65
5 files changed, 292 insertions, 70 deletions
diff --git a/src/plugins/help/centralwidget.cpp b/src/plugins/help/centralwidget.cpp
index 23e4d98292..fa052a69d8 100644
--- a/src/plugins/help/centralwidget.cpp
+++ b/src/plugins/help/centralwidget.cpp
@@ -31,6 +31,7 @@
#include "helpviewer.h"
#include "localhelpmanager.h"
+#include "openpagesmanager.h"
#include "topicchooser.h"
#include <utils/qtcassert.h>
@@ -76,10 +77,18 @@ CentralWidget *CentralWidget::instance()
return gStaticCentralWidget;
}
+void CentralWidget::open(const QUrl &url, bool newPage)
+{
+ if (newPage)
+ OpenPagesManager::instance().createPage(url);
+ else
+ setSource(url);
+}
+
void CentralWidget::showTopicChooser(const QMap<QString, QUrl> &links,
- const QString &keyword)
+ const QString &keyword, bool newPage)
{
TopicChooser tc(this, keyword, links);
if (tc.exec() == QDialog::Accepted)
- setSource(tc.link());
+ open(tc.link(), newPage);
}
diff --git a/src/plugins/help/centralwidget.h b/src/plugins/help/centralwidget.h
index 37d310459e..808175a0c9 100644
--- a/src/plugins/help/centralwidget.h
+++ b/src/plugins/help/centralwidget.h
@@ -50,8 +50,11 @@ public:
static CentralWidget *instance();
+ void open(const QUrl &url, bool newPage = false);
+
public slots:
- void showTopicChooser(const QMap<QString, QUrl> &links, const QString &key);
+ void showTopicChooser(const QMap<QString, QUrl> &links, const QString &key,
+ bool newPage = false);
};
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
index 1a1a3e0bb1..429541278b 100644
--- a/src/plugins/help/helpplugin.cpp
+++ b/src/plugins/help/helpplugin.cpp
@@ -299,10 +299,10 @@ void HelpPlugin::setupUi()
indexWindow->setWindowTitle(tr(SB_INDEX));
m_indexItem = new SideBarItem(indexWindow, QLatin1String(SB_INDEX));
- connect(indexWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget,
- SLOT(setSource(QUrl)));
- connect(indexWindow, SIGNAL(linksActivated(QMap<QString,QUrl>,QString)),
- m_centralWidget, SLOT(showTopicChooser(QMap<QString,QUrl>,QString)));
+ connect(indexWindow, &IndexWindow::linkActivated,
+ m_centralWidget, &CentralWidget::open);
+ connect(indexWindow, &IndexWindow::linksActivated,
+ m_centralWidget, &CentralWidget::showTopicChooser);
QMap<QString, Command*> shortcutMap;
QAction *action = new QAction(tr("Activate Index in Help mode"), m_splitter);
diff --git a/src/shared/help/indexwindow.cpp b/src/shared/help/indexwindow.cpp
index 529bfb2e83..6f5029a927 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);
}
diff --git a/src/shared/help/indexwindow.h b/src/shared/help/indexwindow.h
index 1e5f17d53b..0be2a52d88 100644
--- a/src/shared/help/indexwindow.h
+++ b/src/shared/help/indexwindow.h
@@ -30,15 +30,57 @@
#ifndef INDEXWINDOW_H
#define INDEXWINDOW_H
+#include <QAbstractProxyModel>
+#include <QList>
#include <QUrl>
#include <QWidget>
QT_BEGIN_NAMESPACE
-class QHelpIndexWidget;
+class QHelpIndexModel;
class QModelIndex;
QT_END_NAMESPACE
-namespace Utils { class FancyLineEdit; }
+namespace Utils {
+class FancyLineEdit;
+class NavigationTreeView;
+}
+
+namespace Help {
+namespace Internal {
+
+class IndexFilterModel : public QAbstractProxyModel
+{
+ Q_OBJECT
+
+public:
+ IndexFilterModel(QObject *parent);
+
+ QModelIndex filter(const QString &filter, const QString &wildcard);
+ QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
+ QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
+ Qt::DropActions supportedDragActions() const;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex &child) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ void setSourceModel(QAbstractItemModel *sm);
+
+ // QAbstractProxyModel::sibling is broken in Qt 5
+ QModelIndex sibling(int row, int column, const QModelIndex &idx) const;
+
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+private slots:
+ void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
+ void sourceRowsInserted(const QModelIndex &parent, int start, int end);
+ void sourceModelReset();
+
+private:
+ QString m_filter;
+ QString m_wildcard;
+ QList<int> m_toSource;
+};
class IndexWindow : public QWidget
{
@@ -48,25 +90,24 @@ public:
IndexWindow();
~IndexWindow();
- void setSearchLineEditText(const QString &text);
- QString searchLineEditText() const;
-
signals:
- void linkActivated(const QUrl &link);
+ void linkActivated(const QUrl &link, bool newPage);
void linksActivated(const QMap<QString, QUrl> &links,
- const QString &keyword);
+ const QString &keyword, bool newPage);
-private slots:
+private:
void filterIndices(const QString &filter);
void enableSearchLineEdit();
void disableSearchLineEdit();
-
-private:
bool eventFilter(QObject *obj, QEvent *e);
- void open(QHelpIndexWidget* indexWidget, const QModelIndex &index);
+ void open(const QModelIndex &index, bool newPage = false);
Utils::FancyLineEdit *m_searchLineEdit;
- QHelpIndexWidget *m_indexWidget;
+ Utils::NavigationTreeView *m_indexWidget;
+ IndexFilterModel *m_filteredIndexModel;
};
+} // Internal
+} // Help
+
#endif // INDEXWINDOW_H