Skip to content

Commit

Permalink
feat(ui): add tree view navigation with directional keys and Alt
Browse files Browse the repository at this point in the history
Fixes #1007.
  • Loading branch information
trollixx committed Jan 3, 2020
1 parent 6968e8e commit 03e0e1e
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 29 deletions.
6 changes: 5 additions & 1 deletion src/libs/browser/webcontrol.cpp
Expand Up @@ -58,6 +58,11 @@ WebControl::WebControl(QWidget *parent)
setLayout(layout);
}

void WebControl::focus()
{
m_webView->setFocus();
}

int WebControl::zoomLevel() const
{
return m_webView->zoomLevel();
Expand Down Expand Up @@ -99,7 +104,6 @@ void WebControl::setWebBridgeObject(const QString &name, QObject *object)
void WebControl::load(const QUrl &url)
{
m_webView->load(url);
m_webView->setFocus();
}

void WebControl::activateSearchBar()
Expand Down
1 change: 1 addition & 0 deletions src/libs/browser/webcontrol.h
Expand Up @@ -41,6 +41,7 @@ class WebControl final : public QWidget
public:
explicit WebControl(QWidget *parent = nullptr);

void focus();
void load(const QUrl &url);
bool canGoBack() const;
bool canGoForward() const;
Expand Down
4 changes: 4 additions & 0 deletions src/libs/ui/browsertab.cpp
Expand Up @@ -161,6 +161,8 @@ BrowserTab *BrowserTab::clone(QWidget *parent) const

if (m_searchSidebar) {
tab->m_searchSidebar = m_searchSidebar->clone();
connect(tab->m_searchSidebar, &SearchSidebar::activated,
tab->m_webControl, &Browser::WebControl::focus);
connect(tab->m_searchSidebar, &SearchSidebar::navigationRequested,
tab->m_webControl, &Browser::WebControl::load);
}
Expand Down Expand Up @@ -189,6 +191,8 @@ SearchSidebar *BrowserTab::searchSidebar()
if (m_searchSidebar == nullptr) {
// Create SearchSidebar managed by this tab.
m_searchSidebar = new SearchSidebar();
connect(m_searchSidebar, &SearchSidebar::activated,
m_webControl, &Browser::WebControl::focus);
connect(m_searchSidebar, &SearchSidebar::navigationRequested,
m_webControl, &Browser::WebControl::load);
}
Expand Down
81 changes: 54 additions & 27 deletions src/libs/ui/searchsidebar.cpp
Expand Up @@ -41,6 +41,7 @@
#include <QKeyEvent>
#include <QListView>
#include <QScrollBar>
#include <QShortcut>
#include <QSplitter>
#include <QTimer>
#include <QTreeView>
Expand Down Expand Up @@ -80,8 +81,20 @@ SearchSidebar::SearchSidebar(const SearchSidebar *other, QWidget *parent)
delegate->setDecorationRoles({Registry::ItemDataRole::DocsetIconRole, Qt::DecorationRole});
m_treeView->setItemDelegate(delegate);

connect(m_treeView, &QTreeView::activated, this, &SearchSidebar::indexActivated);
connect(m_treeView, &QTreeView::clicked, this, &SearchSidebar::indexActivated);
connect(m_treeView, &QTreeView::activated, this, &SearchSidebar::navigateToIndexAndActivate);
connect(m_treeView, &QTreeView::clicked, this, &SearchSidebar::navigateToIndex);

// Setup Alt+Up, Alt+Down, etc shortcuts.
const auto keyList = {Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right,
Qt::Key_PageUp, Qt::Key_PageDown,
Qt::Key_Home, Qt::Key_End};
for (const auto key : keyList) {
auto shortcut = new QShortcut(key | Qt::AltModifier, this);
connect(shortcut, &QShortcut::activated, this, [this, key]() {
QKeyEvent event(QKeyEvent::KeyPress, key, Qt::NoModifier);
QCoreApplication::sendEvent(m_treeView, &event);
});
}

// Setup page TOC view.
// TODO: Move to a separate Sidebar View.
Expand All @@ -106,8 +119,8 @@ SearchSidebar::SearchSidebar(const SearchSidebar *other, QWidget *parent)
});
m_pageTocView->setModel(m_pageTocModel);

connect(m_pageTocView, &QListView::activated, this, &SearchSidebar::indexActivated);
connect(m_pageTocView, &QListView::clicked, this, &SearchSidebar::indexActivated);
connect(m_pageTocView, &QListView::activated, this, &SearchSidebar::navigateToIndexAndActivate);
connect(m_pageTocView, &QListView::clicked, this, &SearchSidebar::navigateToIndex);

// Setup search input box.
m_searchEdit = new SearchEdit();
Expand Down Expand Up @@ -164,14 +177,7 @@ SearchSidebar::SearchSidebar(const SearchSidebar *other, QWidget *parent)

// Connect to the new selection model.
connect(m_treeView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, [this](const QItemSelection &selected) {
if (selected.isEmpty()) {
return;
}

m_delayedNavigationTimer->setProperty("index", selected.indexes().first());
m_delayedNavigationTimer->start();
});
this, &SearchSidebar::navigateToSelectionWithDelay);
}

m_treeView->reset();
Expand Down Expand Up @@ -213,10 +219,7 @@ SearchSidebar::SearchSidebar(const SearchSidebar *other, QWidget *parent)
return;
}

indexActivated(index);

// Get focus back.
m_searchEdit->setFocus(Qt::MouseFocusReason);
navigateToIndex(index);
});

// Setup Docset Registry.
Expand Down Expand Up @@ -274,14 +277,7 @@ void SearchSidebar::setTreeViewModel(QAbstractItemModel *model, bool isRootDecor

// Connect to the new selection model.
connect(m_treeView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, [this](const QItemSelection &selected) {
if (selected.isEmpty()) {
return;
}

m_delayedNavigationTimer->setProperty("index", selected.indexes().first());
m_delayedNavigationTimer->start();
});
this, &SearchSidebar::navigateToSelectionWithDelay);
}
}

Expand Down Expand Up @@ -315,13 +311,41 @@ void SearchSidebar::search(const Registry::SearchQuery &query)
m_searchEdit->setText(query.toString());
}

void SearchSidebar::indexActivated(const QModelIndex &index)
void SearchSidebar::navigateToIndex(const QModelIndex &index)
{
// When triggered by click, cancel delayed navigation request caused by the selection change.
if (m_delayedNavigationTimer->isActive()
&& m_delayedNavigationTimer->property("index").toModelIndex() == index) {
m_delayedNavigationTimer->stop();
}

const QVariant url = index.data(Registry::ItemDataRole::UrlRole);
if (url.isNull()) {
return;
}

emit navigationRequested(url.toUrl());
}

void SearchSidebar::navigateToIndexAndActivate(const QModelIndex &index)
{
const QVariant url = index.data(Registry::ItemDataRole::UrlRole);
if (url.isNull())
if (url.isNull()) {
return;
}

emit navigationRequested(url.toUrl());
emit activated();
}

void SearchSidebar::navigateToSelectionWithDelay(const QItemSelection &selection)
{
if (selection.isEmpty()) {
return;
}

m_delayedNavigationTimer->setProperty("index", selection.indexes().first());
m_delayedNavigationTimer->start();
}

void SearchSidebar::setupSearchBoxCompletions()
Expand All @@ -347,6 +371,9 @@ bool SearchSidebar::eventFilter(QObject *object, QEvent *event)
if (object == m_searchEdit && event->type() == QEvent::KeyPress) {
auto e = static_cast<QKeyEvent *>(event);
switch (e->key()) {
case Qt::Key_Return:
emit activated();
break;
case Qt::Key_Home:
case Qt::Key_End:
case Qt::Key_Left:
Expand All @@ -355,13 +382,13 @@ bool SearchSidebar::eventFilter(QObject *object, QEvent *event)
break;
}
[[clang::fallthrough]];
case Qt::Key_Return:
case Qt::Key_Down:
case Qt::Key_Up:
case Qt::Key_PageDown:
case Qt::Key_PageUp:
QCoreApplication::sendEvent(m_treeView, event);
break;

}
}

Expand Down
6 changes: 5 additions & 1 deletion src/libs/ui/searchsidebar.h
Expand Up @@ -28,6 +28,7 @@
#include <QModelIndexList>
#include <QWidget>

class QItemSelection;
class QSplitter;
class QListView;
class QTimer;
Expand All @@ -54,14 +55,17 @@ class SearchSidebar final : public Sidebar::View
Registry::SearchModel *pageTocModel() const;

signals:
void activated();
void navigationRequested(const QUrl &url);

public slots:
void focusSearchEdit(bool clear = false);
void search(const Registry::SearchQuery &query);

private slots:
void indexActivated(const QModelIndex &index);
void navigateToIndex(const QModelIndex &index);
void navigateToIndexAndActivate(const QModelIndex &index);
void navigateToSelectionWithDelay(const QItemSelection &selection);
void setupSearchBoxCompletions();

protected:
Expand Down

0 comments on commit 03e0e1e

Please sign in to comment.