diff options
Diffstat (limited to 'src/webenginewidgets')
-rw-r--r-- | src/webenginewidgets/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebengineview.cpp | 31 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebengineview.h | 5 | ||||
-rw-r--r-- | src/webenginewidgets/api/qwebengineview_p.h | 9 | ||||
-rw-r--r-- | src/webenginewidgets/ui/autofillpopupwidget.cpp | 237 | ||||
-rw-r--r-- | src/webenginewidgets/ui/autofillpopupwidget_p.h | 94 |
6 files changed, 377 insertions, 0 deletions
diff --git a/src/webenginewidgets/CMakeLists.txt b/src/webenginewidgets/CMakeLists.txt index 1aa4ae1e2..97bde6b56 100644 --- a/src/webenginewidgets/CMakeLists.txt +++ b/src/webenginewidgets/CMakeLists.txt @@ -9,6 +9,7 @@ qt_internal_add_module(WebEngineWidgets api/qwebenginenotificationpresenter.cpp api/qwebenginenotificationpresenter_p.h api/qwebengineview.cpp api/qwebengineview.h api/qwebengineview_p.h qwebengine_accessible.cpp qwebengine_accessible.h + ui/autofillpopupwidget.cpp ui/autofillpopupwidget_p.h DEFINES QT_BUILD_WEBENGINEWIDGETS_LIB INCLUDE_DIRECTORIES diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 9fa5f11fc..5fdd995b8 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -43,12 +43,15 @@ #include "render_widget_host_view_qt_delegate_client.h" #include "render_widget_host_view_qt_delegate_item.h" #include "qwebengine_accessible.h" +#include "ui/autofillpopupwidget_p.h" #include <QtWebEngineCore/private/qwebenginepage_p.h> #include <QtWebEngineCore/qwebenginecontextmenurequest.h> #include <QtWebEngineCore/qwebenginehistory.h> #include <QtWebEngineCore/qwebenginehttprequest.h> #include <QtWebEngineCore/qwebengineprofile.h> + +#include "autofill_popup_controller.h" #include "color_chooser_controller.h" #include "web_contents_adapter.h" @@ -911,6 +914,34 @@ QWebEngineContextMenuRequest *QWebEngineViewPrivate::lastContextMenuRequest() co { return m_contextRequest; } + +void QWebEngineViewPrivate::showAutofillPopup(QtWebEngineCore::AutofillPopupController *controller, + const QRect &bounds, bool autoselectFirstSuggestion) +{ + Q_Q(QWebEngineView); + if (!m_autofillPopupWidget) + m_autofillPopupWidget.reset(new QtWebEngineWidgetUI::AutofillPopupWidget(controller, q)); + m_autofillPopupWidget->showPopup(q->mapToGlobal(bounds.bottomLeft()), bounds.width() + 2, + autoselectFirstSuggestion); + controller->notifyPopupShown(); +} + +void QWebEngineViewPrivate::hideAutofillPopup() +{ + if (!m_autofillPopupWidget) + return; + + Q_Q(QWebEngineView); + QTimer::singleShot(0, q, [this] { + if (m_autofillPopupWidget) { + QtWebEngineCore::AutofillPopupController *controller = + m_autofillPopupWidget->m_controller; + m_autofillPopupWidget.reset(); + controller->notifyPopupHidden(); + } + }); +} + /*! \fn QWebEngineView::renderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode) \since 5.6 diff --git a/src/webenginewidgets/api/qwebengineview.h b/src/webenginewidgets/api/qwebengineview.h index cc1495d24..b3dd66f85 100644 --- a/src/webenginewidgets/api/qwebengineview.h +++ b/src/webenginewidgets/api/qwebengineview.h @@ -47,6 +47,10 @@ #include <QtWebEngineWidgets/qtwebenginewidgetsglobal.h> #include <QtWebEngineCore/qwebenginepage.h> +namespace QtWebEngineWidgetUI { +class AutofillPopupWidget; +} + QT_BEGIN_NAMESPACE class QContextMenuEvent; @@ -169,6 +173,7 @@ private: Q_DECLARE_PRIVATE(QWebEngineView) QScopedPointer<QWebEngineViewPrivate> d_ptr; + friend class QtWebEngineWidgetUI::AutofillPopupWidget; friend class QWebEnginePage; friend class QWebEnginePagePrivate; #if QT_CONFIG(accessibility) diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h index e3c9468ce..44eb32203 100644 --- a/src/webenginewidgets/api/qwebengineview_p.h +++ b/src/webenginewidgets/api/qwebengineview_p.h @@ -56,12 +56,17 @@ #include "render_view_context_menu_qt.h" namespace QtWebEngineCore { +class AutofillPopupController; class QWebEngineContextMenuRequest; class WebEngineQuickWidget; class RenderWidgetHostViewQtDelegate; class RenderWidgetHostViewQtDelegateClient; } +namespace QtWebEngineWidgetUI { +class AutofillPopupWidget; +} + QT_BEGIN_NAMESPACE class QMenu; @@ -99,6 +104,9 @@ public: void didPrintPage(QPrinter *&printer, QSharedPointer<QByteArray> result) override; void didPrintPageToPdf(const QString &filePath, bool success) override; void printRequested() override; + void showAutofillPopup(QtWebEngineCore::AutofillPopupController *controller, + const QRect &bounds, bool autoselectFirstSuggestion) override; + void hideAutofillPopup() override; QWebEngineViewPrivate(); virtual ~QWebEngineViewPrivate(); @@ -117,6 +125,7 @@ public: bool m_dragEntered; mutable bool m_ownsPage; QWebEngineContextMenuRequest *m_contextRequest; + QScopedPointer<QtWebEngineWidgetUI::AutofillPopupWidget> m_autofillPopupWidget; }; class QContextMenuBuilder : public QtWebEngineCore::RenderViewContextMenuQt diff --git a/src/webenginewidgets/ui/autofillpopupwidget.cpp b/src/webenginewidgets/ui/autofillpopupwidget.cpp new file mode 100644 index 000000000..579869d9e --- /dev/null +++ b/src/webenginewidgets/ui/autofillpopupwidget.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "autofillpopupwidget_p.h" +#include "qwebengineview.h" +#include "qwebengineview_p.h" + +#include "autofill_popup_controller.h" + +#include <QApplication> +#include <QBoxLayout> +#include <QEvent> +#include <QKeyEvent> +#include <QListView> +#include <QMouseEvent> + +namespace QtWebEngineWidgetUI { + +AutofillPopupWidget::AutofillPopupWidget(QtWebEngineCore::AutofillPopupController *controller, + QWebEngineView *parent) + : QFrame(parent, Qt::Popup), m_controller(controller), m_webEngineView(parent) +{ + setAttribute(Qt::WA_WindowPropagation); + setAttribute(Qt::WA_X11NetWmWindowTypeCombo); + + // we need a vertical layout + QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this); + layout->setSpacing(0); + layout->setContentsMargins(QMargins()); + + m_listView = new QListView(m_webEngineView); + m_listView->setModel(m_controller->model()); + m_listView->setTextElideMode(Qt::ElideMiddle); + + // Based on QComboBoxPrivateContainer::setItemView + m_listView->setParent(this); + m_listView->setAttribute(Qt::WA_MacShowFocusRect, false); + layout->insertWidget(0, m_listView); + m_listView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + + m_listView->installEventFilter(this); + // Necessary for filtering QEvent::MouseMove: + m_listView->viewport()->installEventFilter(this); + + m_listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + // TODO: Implement vertical scrollbar. Chromium also has it. + m_listView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_listView->setMouseTracking(true); + + m_listView->setSelectionMode(QAbstractItemView::SingleSelection); + m_listView->setEditTriggers(QAbstractItemView::NoEditTriggers); + + // Some styles (Mac) have a margin at the top and bottom of the popup. + layout->insertSpacing(0, 0); + layout->addSpacing(0); + + connect(m_controller, &QtWebEngineCore::AutofillPopupController::currentIndexChanged, + m_listView, &QListView::setCurrentIndex); +} + +AutofillPopupWidget::~AutofillPopupWidget() { } + +// Based on QComboBox::showPopup() +void AutofillPopupWidget::showPopup(QPoint pos, int width, bool autoselectFirstSuggestion) +{ + QStyle *const style = m_webEngineView->style(); + QStyleOptionComboBox opt; + opt.initFrom(m_webEngineView); + + if (autoselectFirstSuggestion) + m_controller->selectFirstSuggestion(); + + QRect listRect(pos, QSize(width, 0)); + + // Calculate height + { + int listHeight = 0; + int rowCount = m_controller->model()->rowCount(); + for (int i = 0; i < rowCount; ++i) { + QModelIndex idx = m_controller->model()->index(i, 0); + listHeight += m_listView->visualRect(idx).height(); + } + if (rowCount > 1) + listHeight += (rowCount - 1) * m_listView->spacing() * 2; + + listRect.setHeight(listRect.height() + listHeight); + } + + // Calculate height margin + { + int heightMargin = m_listView->spacing() * 2; + + // Add the frame of the popup + const QMargins pm = contentsMargins(); + heightMargin += pm.top() + pm.bottom(); + + // Add the frame of the list view + const QMargins vm = m_listView->contentsMargins(); + heightMargin += vm.top() + vm.bottom(); + listRect.setHeight(listRect.height() + heightMargin); + } + + // Add space for margin at top and bottom if the style wants it + int styleMargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) * 2; + listRect.setHeight(listRect.height() + styleMargin); + + // Takes account of the mimium/maximum size of the popup + layout()->activate(); + listRect.setSize(listRect.size().expandedTo(minimumSize()).boundedTo(maximumSize())); + + setGeometry(listRect); + QFrame::show(); +} + +bool AutofillPopupWidget::eventFilter(QObject *object, QEvent *event) +{ + switch (event->type()) { + case QEvent::MouseMove: + if (isVisible()) { + QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); + QModelIndex indexUnderMouse = m_listView->indexAt(mouseEvent->position().toPoint()); + if (indexUnderMouse.isValid() + && indexUnderMouse.data(Qt::AccessibleDescriptionRole).toString() + != QLatin1String("separator")) { + m_controller->selectSuggestion(indexUnderMouse.row()); + } + } + return true; + case QEvent::MouseButtonRelease: { + QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); + if (mouseEvent->button() == Qt::LeftButton) { + m_controller->acceptSuggestion(); + return true; + } + break; + } + default: + break; + } + + return QFrame::eventFilter(object, event); +} + +void AutofillPopupWidget::keyPressEvent(QKeyEvent *event) +{ + // AutofillPopupControllerImpl::HandleKeyPressEvent() + // chrome/browser/ui/autofill/autofill_popup_controller_impl.cc + switch (event->key()) { + case Qt::Key_Up: + m_controller->selectPreviousSuggestion(); + return; + case Qt::Key_Down: + m_controller->selectNextSuggestion(); + return; + case Qt::Key_PageUp: + m_controller->selectFirstSuggestion(); + return; + case Qt::Key_PageDown: + m_controller->selectLastSuggestion(); + return; + case Qt::Key_Escape: + m_webEngineView->d_ptr->hideAutofillPopup(); + return; + case Qt::Key_Enter: + case Qt::Key_Return: + m_controller->acceptSuggestion(); + return; + case Qt::Key_Delete: + // Remove suggestion is not supported for datalist. + // Forward delete to view to be able to remove selected text. + break; + case Qt::Key_Tab: + m_controller->acceptSuggestion(); + break; + default: + break; + } + + QCoreApplication::sendEvent(m_webEngineView->focusWidget(), event); +} + +void AutofillPopupWidget::keyReleaseEvent(QKeyEvent *event) +{ + // Do not forward release events of the overridden key presses. + switch (event->key()) { + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_PageUp: + case Qt::Key_PageDown: + case Qt::Key_Escape: + case Qt::Key_Enter: + case Qt::Key_Return: + return; + default: + break; + } + + QCoreApplication::sendEvent(m_webEngineView->focusWidget(), event); +} + +} // namespace QtWebEngineWidgetUI diff --git a/src/webenginewidgets/ui/autofillpopupwidget_p.h b/src/webenginewidgets/ui/autofillpopupwidget_p.h new file mode 100644 index 000000000..064c4f824 --- /dev/null +++ b/src/webenginewidgets/ui/autofillpopupwidget_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AUTOFILLPOPUPWIDGET_P_H +#define AUTOFILLPOPUPWIDGET_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QFrame> + +namespace QtWebEngineCore { +class AutofillPopupController; +} + +QT_BEGIN_NAMESPACE +class QListView; +class QWebEngineView; +class QWebEngineViewPrivate; +QT_END_NAMESPACE + +namespace QtWebEngineWidgetUI { + +// Based on QComboBoxPrivateContainer +class AutofillPopupWidget : public QFrame +{ + Q_OBJECT +public: + AutofillPopupWidget(QtWebEngineCore::AutofillPopupController *controller, + QWebEngineView *parent); + ~AutofillPopupWidget(); + + void showPopup(QPoint pos, int width, bool autoselectFirstSuggestion); + +protected: + bool eventFilter(QObject *object, QEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + +private: + QtWebEngineCore::AutofillPopupController *m_controller; + QWebEngineView *m_webEngineView; + QListView *m_listView; + + friend class QT_PREPEND_NAMESPACE(QWebEngineViewPrivate); +}; + +} // namespace QtWebEngineWidgetUI + +#endif // AUTOFILLPOPUPWIDGET_P_H |