diff options
author | Eike Ziller <[email protected]> | 2014-09-29 17:35:04 +0200 |
---|---|---|
committer | Eike Ziller <[email protected]> | 2014-10-10 10:14:38 +0200 |
commit | 9cc88836f7827504c92cdc0d380e83c65ba0dbe4 (patch) | |
tree | 27c78ab48d8b11805b2a5a885b29a6fd09104ada /src/shared/help/indexwindow.cpp | |
parent | a10f20775623d95afd8d44722c86f23c5e7d50ad (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.cpp | 271 |
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); } |