mirror of
https://github.com/zealdocs/zeal.git
synced 2024-09-11 14:25:52 +03:00
ui: Add in-page search toolbar (#861)
This commit is contained in:
parent
7d39f3fbb4
commit
38d14735b6
@ -2,6 +2,7 @@ add_subdirectory(qxtglobalshortcut)
|
||||
|
||||
list(APPEND Widgets_SOURCES
|
||||
widgets/searchedit.cpp
|
||||
widgets/searchtoolbar.cpp
|
||||
widgets/shortcutedit.cpp
|
||||
widgets/toolbarframe.cpp
|
||||
widgets/webview.cpp
|
||||
|
@ -183,7 +183,7 @@ MainWindow::MainWindow(Core::Application *app, QWidget *parent) :
|
||||
// Edit
|
||||
ui->actionFind->setShortcut(QKeySequence::Find);
|
||||
connect(ui->actionFind, &QAction::triggered, this, [this]() {
|
||||
currentTab()->showSearchBar();
|
||||
currentTab()->activateSearchBar();
|
||||
});
|
||||
|
||||
connect(ui->actionPreferences, &QAction::triggered, [this]() {
|
||||
|
229
src/libs/ui/widgets/searchtoolbar.cpp
Normal file
229
src/libs/ui/widgets/searchtoolbar.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 Oleg Shparber
|
||||
** Contact: https://go.zealdocs.org/l/contact
|
||||
**
|
||||
** This file is part of Zeal.
|
||||
**
|
||||
** Zeal is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Zeal is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with Zeal. If not, see <https://www.gnu.org/licenses/>.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "searchtoolbar.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QKeyEvent>
|
||||
#include <QStyle>
|
||||
#include <QToolButton>
|
||||
#include <QWebPage>
|
||||
#include <QWebView>
|
||||
|
||||
using namespace Zeal::WidgetUi;
|
||||
|
||||
SearchToolBar::SearchToolBar(QWebView *webView, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_webView(webView)
|
||||
{
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(4, 4, 4, 4);
|
||||
layout->setSpacing(4);
|
||||
|
||||
m_lineEdit = new QLineEdit();
|
||||
m_lineEdit->installEventFilter(this);
|
||||
m_lineEdit->setPlaceholderText(tr("Find in page"));
|
||||
m_lineEdit->setMaximumWidth(200);
|
||||
connect(m_lineEdit, &QLineEdit::textChanged, this, &SearchToolBar::findNext);
|
||||
connect(m_lineEdit, &QLineEdit::textChanged, this, &SearchToolBar::updateHighlight);
|
||||
layout->addWidget(m_lineEdit);
|
||||
|
||||
m_findPreviousButton = new QToolButton();
|
||||
m_findPreviousButton->setAutoRaise(true);
|
||||
m_findPreviousButton->setIcon(qApp->style()->standardIcon(QStyle::SP_ArrowBack));
|
||||
m_findPreviousButton->setToolTip(tr("Previous result"));
|
||||
connect(m_findPreviousButton, &QToolButton::clicked, this, &SearchToolBar::findPrevious);
|
||||
layout->addWidget(m_findPreviousButton);
|
||||
|
||||
// A workaround for QAbstractButton lacking support for multiple shortcuts.
|
||||
QAction *action = new QAction(m_findPreviousButton);
|
||||
action->setShortcuts(QKeySequence::FindPrevious);
|
||||
// TODO: Investigate why direct connection does not work.
|
||||
//connect(action, &QAction::triggered, m_findPreviousButton, &QToolButton::animateClick);
|
||||
connect(action, &QAction::triggered, this, [this]() { m_findPreviousButton->animateClick(); });
|
||||
addAction(action);
|
||||
|
||||
m_findNextButton = new QToolButton();
|
||||
m_findNextButton->setAutoRaise(true);
|
||||
m_findNextButton->setIcon(qApp->style()->standardIcon(QStyle::SP_ArrowForward));
|
||||
m_findNextButton->setToolTip(tr("Next result"));
|
||||
connect(m_findNextButton, &QToolButton::clicked, this, &SearchToolBar::findNext);
|
||||
layout->addWidget(m_findNextButton);
|
||||
|
||||
action = new QAction(m_findNextButton);
|
||||
action->setShortcuts(QKeySequence::FindNext);
|
||||
connect(action, &QAction::triggered, this, [this]() { m_findNextButton->animateClick(); });
|
||||
addAction(action);
|
||||
|
||||
m_highlightAllButton = new QToolButton();
|
||||
m_highlightAllButton->setAutoRaise(true);
|
||||
m_highlightAllButton->setCheckable(true);
|
||||
m_highlightAllButton->setText(tr("High&light All"));
|
||||
connect(m_highlightAllButton, &QToolButton::toggled, this, &SearchToolBar::updateHighlight);
|
||||
layout->addWidget(m_highlightAllButton);
|
||||
|
||||
m_matchCaseButton = new QToolButton();
|
||||
m_matchCaseButton->setAutoRaise(true);
|
||||
m_matchCaseButton->setCheckable(true);
|
||||
m_matchCaseButton->setText(tr("Mat&ch Case"));
|
||||
connect(m_matchCaseButton, &QToolButton::toggled, this, &SearchToolBar::updateHighlight);
|
||||
layout->addWidget(m_matchCaseButton);
|
||||
|
||||
layout->addStretch();
|
||||
|
||||
QToolButton *closeButton = new QToolButton();
|
||||
closeButton->setAutoRaise(true);
|
||||
closeButton->setIcon(qApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
|
||||
closeButton->setToolTip(tr("Close find bar"));
|
||||
connect(closeButton, &QToolButton::clicked, this, &QWidget::hide);
|
||||
layout->addWidget(closeButton);
|
||||
|
||||
setLayout(layout);
|
||||
|
||||
setMaximumHeight(sizeHint().height());
|
||||
setMinimumWidth(sizeHint().width());
|
||||
}
|
||||
|
||||
void SearchToolBar::setText(const QString &text)
|
||||
{
|
||||
m_lineEdit->setText(text);
|
||||
}
|
||||
|
||||
void SearchToolBar::activate()
|
||||
{
|
||||
show();
|
||||
|
||||
m_lineEdit->selectAll();
|
||||
m_lineEdit->setFocus();
|
||||
}
|
||||
|
||||
bool SearchToolBar::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
if (object == m_lineEdit && event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
|
||||
switch (keyEvent->key()) {
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
if (keyEvent->modifiers().testFlag(Qt::ShiftModifier)) {
|
||||
findPrevious();
|
||||
} else {
|
||||
findNext();
|
||||
}
|
||||
return true;
|
||||
case Qt::Key_Down:
|
||||
case Qt::Key_Up:
|
||||
case Qt::Key_PageDown:
|
||||
case Qt::Key_PageUp:
|
||||
QCoreApplication::sendEvent(m_webView, event);
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return QWidget::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void SearchToolBar::hideEvent(QHideEvent *event)
|
||||
{
|
||||
hideHighlight();
|
||||
m_webView->setFocus();
|
||||
QWidget::hideEvent(event);
|
||||
}
|
||||
|
||||
void SearchToolBar::showEvent(QShowEvent *event)
|
||||
{
|
||||
activate();
|
||||
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
void SearchToolBar::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SearchToolBar::findNext()
|
||||
{
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QWebPage::FindFlags ff = QWebPage::FindWrapsAroundDocument;
|
||||
#if QT_VERSION >= 0x050700
|
||||
ff.setFlag(QWebPage::FindCaseSensitively, m_matchCaseButton->isChecked());
|
||||
#else
|
||||
if (m_matchCaseButton->isChecked()) {
|
||||
ff |= QWebPage::FindCaseSensitively;
|
||||
}
|
||||
#endif
|
||||
m_webView->findText(m_lineEdit->text(), ff);
|
||||
}
|
||||
|
||||
void SearchToolBar::findPrevious()
|
||||
{
|
||||
if (!isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QWebPage::FindFlags ff = QWebPage::FindWrapsAroundDocument;
|
||||
#if QT_VERSION >= 0x050700
|
||||
ff.setFlag(QWebPage::FindCaseSensitively, m_matchCaseButton->isChecked());
|
||||
ff.setFlag(QWebPage::FindBackward);
|
||||
#else
|
||||
if (m_matchCaseButton->isChecked()) {
|
||||
ff |= QWebPage::FindCaseSensitively;
|
||||
}
|
||||
|
||||
ff |= QWebPage::FindBackward;
|
||||
#endif
|
||||
m_webView->findText(m_lineEdit->text(), ff);
|
||||
}
|
||||
|
||||
void SearchToolBar::hideHighlight()
|
||||
{
|
||||
m_webView->findText(QString(), QWebPage::HighlightAllOccurrences);
|
||||
}
|
||||
|
||||
void SearchToolBar::updateHighlight()
|
||||
{
|
||||
hideHighlight();
|
||||
|
||||
if (m_highlightAllButton->isChecked()) {
|
||||
QWebPage::FindFlags ff = QWebPage::HighlightAllOccurrences;
|
||||
#if QT_VERSION >= 0x050700
|
||||
ff.setFlag(QWebPage::FindCaseSensitively, m_matchCaseButton->isChecked());
|
||||
#else
|
||||
if (m_matchCaseButton->isChecked()) {
|
||||
ff |= QWebPage::FindCaseSensitively;
|
||||
}
|
||||
#endif
|
||||
m_webView->findText(m_lineEdit->text(), ff);
|
||||
}
|
||||
}
|
71
src/libs/ui/widgets/searchtoolbar.h
Normal file
71
src/libs/ui/widgets/searchtoolbar.h
Normal file
@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 Oleg Shparber
|
||||
** Contact: https://go.zealdocs.org/l/contact
|
||||
**
|
||||
** This file is part of Zeal.
|
||||
**
|
||||
** Zeal is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** Zeal is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with Zeal. If not, see <https://www.gnu.org/licenses/>.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ZEAL_WIDGETUI_SEARCHTOOLBAR_H
|
||||
#define ZEAL_WIDGETUI_SEARCHTOOLBAR_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QLineEdit;
|
||||
class QToolButton;
|
||||
class QWebView;
|
||||
|
||||
namespace Zeal {
|
||||
namespace WidgetUi {
|
||||
|
||||
class SearchToolBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SearchToolBar(QWebView *webView, QWidget *parent = nullptr);
|
||||
|
||||
void setText(const QString &text);
|
||||
void activate();
|
||||
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
||||
protected:
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
|
||||
private:
|
||||
void findNext();
|
||||
void findPrevious();
|
||||
|
||||
void hideHighlight();
|
||||
void updateHighlight();
|
||||
|
||||
QLineEdit *m_lineEdit = nullptr;
|
||||
QToolButton *m_findNextButton = nullptr;
|
||||
QToolButton *m_findPreviousButton = nullptr;
|
||||
QToolButton *m_highlightAllButton = nullptr;
|
||||
QToolButton *m_matchCaseButton = nullptr;
|
||||
|
||||
QWebView *m_webView = nullptr;
|
||||
};
|
||||
|
||||
} // namespace WidgetUi
|
||||
} // namespace Zeal
|
||||
|
||||
#endif // ZEAL_WIDGETUI_SEARCHTOOLBAR_H
|
@ -33,8 +33,8 @@
|
||||
|
||||
using namespace Zeal::WidgetUi;
|
||||
|
||||
WebView::WebView(QWidget *parent) :
|
||||
QWebView(parent)
|
||||
WebView::WebView(QWidget *parent)
|
||||
: QWebView(parent)
|
||||
{
|
||||
setAttribute(Qt::WA_AcceptTouchEvents, false);
|
||||
page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "webviewtab.h"
|
||||
|
||||
#include "searchtoolbar.h"
|
||||
#include "webview.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
@ -36,24 +37,14 @@
|
||||
|
||||
using namespace Zeal::WidgetUi;
|
||||
|
||||
WebViewTab::WebViewTab(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
m_searchLineEdit(new QLineEdit(this))
|
||||
WebViewTab::WebViewTab(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
m_searchLineEdit->hide();
|
||||
m_searchLineEdit->installEventFilter(this);
|
||||
connect(m_searchLineEdit, &QLineEdit::textChanged, this, &WebViewTab::find);
|
||||
|
||||
m_webView = new WebView();
|
||||
connect(m_webView, &QWebView::loadFinished, this, [this](bool ok) {
|
||||
Q_UNUSED(ok)
|
||||
moveLineEdit();
|
||||
});
|
||||
|
||||
connect(m_webView->page(), &QWebPage::linkHovered, [this](const QString &link) {
|
||||
if (link.startsWith(QLatin1String("file:")) || link.startsWith(QLatin1String("qrc:")))
|
||||
return;
|
||||
@ -81,32 +72,6 @@ void WebViewTab::setZoomLevel(int level)
|
||||
m_webView->setZoomLevel(level);
|
||||
}
|
||||
|
||||
bool WebViewTab::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
if (object == m_searchLineEdit && event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
switch (keyEvent->key()) {
|
||||
case Qt::Key_Escape:
|
||||
hideSearchBar();
|
||||
return true;
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
findNext(m_searchLineEdit->text(), keyEvent->modifiers() & Qt::ShiftModifier);
|
||||
return true;
|
||||
case Qt::Key_Down:
|
||||
case Qt::Key_Up:
|
||||
case Qt::Key_PageDown:
|
||||
case Qt::Key_PageUp:
|
||||
QCoreApplication::sendEvent(m_webView, event);
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void WebViewTab::load(const QUrl &url)
|
||||
{
|
||||
m_webView->load(url);
|
||||
@ -122,6 +87,23 @@ QSize WebViewTab::sizeHint() const
|
||||
return m_webView->sizeHint();
|
||||
}
|
||||
|
||||
void WebViewTab::activateSearchBar()
|
||||
{
|
||||
if (m_searchToolBar == nullptr) {
|
||||
m_searchToolBar = new SearchToolBar(m_webView);
|
||||
layout()->addWidget(m_searchToolBar);
|
||||
}
|
||||
|
||||
if (m_webView->hasSelection()) {
|
||||
const QString selectedText = m_webView->selectedText().simplified();
|
||||
if (!selectedText.isEmpty()) {
|
||||
m_searchToolBar->setText(selectedText);
|
||||
}
|
||||
}
|
||||
|
||||
m_searchToolBar->activate();
|
||||
}
|
||||
|
||||
void WebViewTab::back()
|
||||
{
|
||||
m_webView->back();
|
||||
@ -132,22 +114,6 @@ void WebViewTab::forward()
|
||||
m_webView->forward();
|
||||
}
|
||||
|
||||
void WebViewTab::showSearchBar()
|
||||
{
|
||||
m_searchLineEdit->show();
|
||||
m_searchLineEdit->setFocus();
|
||||
if (!m_searchLineEdit->text().isEmpty()) {
|
||||
m_searchLineEdit->selectAll();
|
||||
find(m_searchLineEdit->text());
|
||||
}
|
||||
}
|
||||
|
||||
void WebViewTab::hideSearchBar()
|
||||
{
|
||||
m_searchLineEdit->hide();
|
||||
m_webView->findText(QString(), QWebPage::HighlightAllOccurrences);
|
||||
}
|
||||
|
||||
bool WebViewTab::canGoBack() const
|
||||
{
|
||||
return m_webView->history()->canGoBack();
|
||||
@ -177,7 +143,7 @@ void WebViewTab::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Slash:
|
||||
showSearchBar();
|
||||
activateSearchBar();
|
||||
event->accept();
|
||||
break;
|
||||
default:
|
||||
@ -186,13 +152,6 @@ void WebViewTab::keyPressEvent(QKeyEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
void WebViewTab::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
m_webView->resize(event->size().width(), event->size().height());
|
||||
moveLineEdit();
|
||||
}
|
||||
|
||||
void WebViewTab::find(const QString &text)
|
||||
{
|
||||
if (m_webView->selectedText() != text) {
|
||||
@ -215,12 +174,3 @@ void WebViewTab::findNext(const QString &text, bool backward)
|
||||
|
||||
m_webView->findText(text, flags);
|
||||
}
|
||||
|
||||
void WebViewTab::moveLineEdit()
|
||||
{
|
||||
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
||||
frameWidth += m_webView->page()->currentFrame()->scrollBarGeometry(Qt::Vertical).width();
|
||||
|
||||
m_searchLineEdit->move(rect().right() - frameWidth - m_searchLineEdit->sizeHint().width(), rect().top());
|
||||
m_searchLineEdit->raise();
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ class QWebHistory;
|
||||
namespace Zeal {
|
||||
namespace WidgetUi {
|
||||
|
||||
class SearchToolBar;
|
||||
class WebView;
|
||||
|
||||
class WebViewTab : public QWidget
|
||||
@ -54,30 +55,25 @@ public:
|
||||
int zoomLevel() const;
|
||||
void setZoomLevel(int level);
|
||||
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
||||
signals:
|
||||
void linkClicked(const QUrl &url);
|
||||
void titleChanged(const QString &title);
|
||||
void urlChanged(const QUrl &url);
|
||||
|
||||
public slots:
|
||||
void activateSearchBar();
|
||||
void back();
|
||||
void forward();
|
||||
void showSearchBar();
|
||||
void hideSearchBar();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
void find(const QString &text);
|
||||
void findNext(const QString &text, bool backward = false);
|
||||
void moveLineEdit();
|
||||
|
||||
QLineEdit *m_searchLineEdit = nullptr;
|
||||
WebView *m_webView = nullptr;
|
||||
SearchToolBar *m_searchToolBar = nullptr;
|
||||
};
|
||||
|
||||
} // namespace WidgetUi
|
||||
|
Loading…
Reference in New Issue
Block a user