mirror of
https://github.com/zealdocs/zeal.git
synced 2024-11-26 15:43:49 +03:00
feat(ui): add tree view navigation with directional keys and Alt
Fixes #1007.
This commit is contained in:
parent
6968e8e978
commit
03e0e1e05d
@ -58,6 +58,11 @@ WebControl::WebControl(QWidget *parent)
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void WebControl::focus()
|
||||
{
|
||||
m_webView->setFocus();
|
||||
}
|
||||
|
||||
int WebControl::zoomLevel() const
|
||||
{
|
||||
return m_webView->zoomLevel();
|
||||
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QListView>
|
||||
#include <QScrollBar>
|
||||
#include <QShortcut>
|
||||
#include <QSplitter>
|
||||
#include <QTimer>
|
||||
#include <QTreeView>
|
||||
@ -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.
|
||||
@ -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();
|
||||
@ -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();
|
||||
@ -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.
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,15 +311,43 @@ 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())
|
||||
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()) {
|
||||
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()
|
||||
{
|
||||
QStringList completions;
|
||||
@ -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:
|
||||
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <QModelIndexList>
|
||||
#include <QWidget>
|
||||
|
||||
class QItemSelection;
|
||||
class QSplitter;
|
||||
class QListView;
|
||||
class QTimer;
|
||||
@ -54,6 +55,7 @@ public:
|
||||
Registry::SearchModel *pageTocModel() const;
|
||||
|
||||
signals:
|
||||
void activated();
|
||||
void navigationRequested(const QUrl &url);
|
||||
|
||||
public slots:
|
||||
@ -61,7 +63,9 @@ public slots:
|
||||
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:
|
||||
|
Loading…
Reference in New Issue
Block a user