diff --git a/src/src.pro b/src/src.pro index 64c1703fe80a96ed5b990fdc135fb9249cc5262b..00e8301be6651693e0bb3a8e3cf04ba985e15db4 100644 --- a/src/src.pro +++ b/src/src.pro @@ -34,8 +34,10 @@ isQMLTestSupportApiEnabled() { # FIXME: We probably want a bit more control over config options to tweak what to build/ship or not. # Another example of where this could be necessary is to make it easy to build proprietery codecs support. -!contains(WEBENGINE_CONFIG, no_ui_delegates): SUBDIRS += webengine/ui - +!contains(WEBENGINE_CONFIG, no_ui_delegates) { + SUBDIRS += webengine/ui \ + webengine/ui2 +} qtHaveModule(widgets) { SUBDIRS += webenginewidgets plugins.depends = webenginewidgets diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 02484548b6bf4a8441ddc9d281732fbb2f4a54cc..f49ac155ef0d049b7ff7f2b52edcdfb112e1da9b 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -145,8 +145,7 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() , m_dpiScale(1.0) , m_backgroundColor(Qt::white) , m_defaultZoomFactor(1.0) - // QTBUG-53467 - , m_menuEnabled(true) + , m_ui2Enabled(false) { // The gold standard for mobile web content is 160 dpi, and the devicePixelRatio expected // is the (possibly quantized) ratio of device dpi to 160 dpi. @@ -164,8 +163,26 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() // 1x, 2x, 3x etc assets that fit an integral number of pixels. setDevicePixelRatio(qMax(1, qRound(webPixelRatio))); } + if (platform == QLatin1Literal("eglfs")) - m_menuEnabled = false; + m_ui2Enabled = true; + + const QByteArray dialogSet = qgetenv("QTWEBENGINE_DIALOG_SET"); + + if (!dialogSet.isEmpty()) { + if (dialogSet == QByteArrayLiteral("QtQuickControls2")) { + m_ui2Enabled = true; + } else if (dialogSet == QByteArrayLiteral("QtQuickControls1") + && m_ui2Enabled) { + m_ui2Enabled = false; + qWarning("QTWEBENGINE_DIALOG_SET=QtQuickControls1 forces use of Qt Quick Controls 1 " + "on an eglfs backend. This can crash your application!"); + } else { + qWarning("Ignoring QTWEBENGINE_DIALOG_SET environment variable set to %s. Accepted " + "values are \"QtQuickControls1\" and \"QtQuickControls2\"", dialogSet.data()); + } + } + #ifndef QT_NO_ACCESSIBILITY QAccessible::installFactory(&webAccessibleFactory); #endif // QT_NO_ACCESSIBILITY @@ -189,7 +206,7 @@ UIDelegatesManager *QQuickWebEngineViewPrivate::ui() { Q_Q(QQuickWebEngineView); if (m_uIDelegatesManager.isNull()) - m_uIDelegatesManager.reset(new UIDelegatesManager(q)); + m_uIDelegatesManager.reset(m_ui2Enabled ? new UI2DelegatesManager(q) : new UIDelegatesManager(q)); return m_uIDelegatesManager.data(); } @@ -216,12 +233,6 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu { Q_Q(QQuickWebEngineView); - if (!m_menuEnabled) { - qWarning("You are trying to open context menu on eglfs backend, which is not currently supported\n" - "See QTBUG-53467."); - return false; - } - // Assign the WebEngineView as the parent of the menu, so mouse events are properly propagated // on OSX. QObject *menu = ui()->addMenu(q, QString(), data.pos); @@ -354,7 +365,7 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu } // Now fire the popup() method on the top level menu - QMetaObject::invokeMethod(menu, "popup"); + ui()->showMenu(menu); return true; } diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 98efb822cb182d09aabdc4ffd5fa76ab8c8c14ec..7e5e07b95b543c872c73e2c6ec58b3a08c252a23 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -239,8 +239,7 @@ private: qreal m_dpiScale; QColor m_backgroundColor; qreal m_defaultZoomFactor; - // QTBUG-53467 - bool m_menuEnabled; + bool m_ui2Enabled; }; #ifndef QT_NO_ACCESSIBILITY diff --git a/src/webengine/ui/PromptDialog.qml b/src/webengine/ui/PromptDialog.qml index 657bf7631fc1962eb72cc529d33224a21056b064..d9fc61cf80c946b923e1f96b293548b77646ac63 100644 --- a/src/webengine/ui/PromptDialog.qml +++ b/src/webengine/ui/PromptDialog.qml @@ -53,6 +53,10 @@ ApplicationWindow { height: 100 flags: Qt.Dialog + onClosing: { + rejected(); + } + function open() { show(); } diff --git a/src/webengine/ui2/AlertDialog.qml b/src/webengine/ui2/AlertDialog.qml new file mode 100644 index 0000000000000000000000000000000000000000..4f63c5b70751c6f7b2822d6b808cab6aa6a36722 --- /dev/null +++ b/src/webengine/ui2/AlertDialog.qml @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.0 + +Dialog { + property alias text: message.text + property bool handled: false + signal accepted() + signal rejected() + title: qsTr("Alert Dialog") + modality: Qt.NonModal + + //handle the case where users simply closes the dialog + onVisibilityChanged: { + if (visible == false && handled == false) { + handled = true; + rejected(); + } else { + handled = false; + } + } + + function acceptDialog() { + accepted(); + handled = true; + close(); + } + + contentItem: ColumnLayout { + id: rootLayout + anchors.fill: parent + anchors.margins: 4 + property int minimumWidth: rootLayout.implicitWidth + rootLayout.doubleMargins + property int minimumHeight: rootLayout.implicitHeight + rootLayout.doubleMargins + property int doubleMargins: anchors.margins * 2 + SystemPalette { id: palette; colorGroup: SystemPalette.Active } + RowLayout { + Layout.alignment: Qt.AlignRight + spacing: 8 + Image { + source: "information.png" + } + Text { + id: message + Layout.fillWidth: true + color: palette.windowText + } + } + Item { + Layout.fillHeight: true + } + Controls.Button { + Layout.alignment: Qt.AlignHCenter + text: qsTr("OK") + onClicked: acceptDialog() + } + } +} diff --git a/src/webengine/ui2/AuthenticationDialog.qml b/src/webengine/ui2/AuthenticationDialog.qml new file mode 100644 index 0000000000000000000000000000000000000000..52fcce3f12cdd6621a7cd70701f9f2199c3aaee4 --- /dev/null +++ b/src/webengine/ui2/AuthenticationDialog.qml @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.0 + +Dialog { + property alias text: message.text + property bool handled: false + signal accepted(string user, string password) + signal rejected() + title: qsTr("Authentication Required") + modality: Qt.NonModal + + //handle the case where users simply closes the dialog + onVisibilityChanged: { + if (visible == false && handled == false) { + handled = true; + rejected(); + } else { + handled = false; + } + } + + function acceptDialog() { + accepted(userField.text, passwordField.text); + handled = true; + close(); + } + + function rejectDialog() { + rejected(); + handled = true; + close(); + } + + contentItem: ColumnLayout { + id: rootLayout + anchors.fill: parent + anchors.margins: 4 + property int minimumWidth: rootLayout.implicitWidth + rootLayout.doubleMargins + property int minimumHeight: rootLayout.implicitHeight + rootLayout.doubleMargins + + property int doubleMargins: anchors.margins * 2 + + SystemPalette { id: palette; colorGroup: SystemPalette.Active } + Text { + id: message + color: palette.windowText + } + GridLayout { + columns: 2 + Controls.Label { + text: qsTr("Username:") + color: palette.windowText + } + Controls.TextField { + id: userField + focus: true + Layout.fillWidth: true + onAccepted: { + if (userField.text && passwordField.text) + acceptDialog(); + } + } + Controls.Label { + text: qsTr("Password:") + color: palette.windowText + } + Controls.TextField { + id: passwordField + Layout.fillWidth: true + echoMode: TextInput.Password + onAccepted: { + if (userField.text && passwordField.text) + acceptDialog(); + } + } + } + Item { + Layout.fillHeight: true + } + RowLayout { + Layout.alignment: Qt.AlignRight + spacing: 8 + Controls.Button { + id: cancelButton + text: qsTr("Cancel") + onClicked: rejectDialog() + } + Controls.Button { + text: qsTr("Log In") + onClicked: acceptDialog() + } + } + } +} diff --git a/src/webengine/ui2/ConfirmDialog.qml b/src/webengine/ui2/ConfirmDialog.qml new file mode 100644 index 0000000000000000000000000000000000000000..0649d3654874d1f4d6e868392a924483657aeb46 --- /dev/null +++ b/src/webengine/ui2/ConfirmDialog.qml @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.0 + +Dialog { + property alias text: message.text + property bool handled: false + signal accepted() + signal rejected() + title: qsTr("Alert Dialog") + modality: Qt.NonModal + + //handle the case where users simply closes the dialog + onVisibilityChanged: { + if (visible == false && handled == false) { + handled = true; + rejected(); + } else { + handled = false; + } + } + + function acceptDialog() { + accepted(); + handled = true; + close(); + } + + function rejectDialog() { + rejected(); + handled = true; + close(); + } + + contentItem: ColumnLayout { + id: rootLayout + anchors.fill: parent + anchors.margins: 4 + property int minimumWidth: rootLayout.implicitWidth + rootLayout.doubleMargins + property int minimumHeight: rootLayout.implicitHeight + rootLayout.doubleMargins + property int doubleMargins: anchors.margins * 2 + SystemPalette { id: palette; colorGroup: SystemPalette.Active } + RowLayout { + Layout.alignment: Qt.AlignRight + spacing: 8 + Image { + source: "question.png" + } + Text { + id: message + Layout.fillWidth: true + color: palette.windowText + } + } + Item { + Layout.fillHeight: true + } + RowLayout { + Layout.alignment: Qt.AlignRight + spacing: 8 + Controls.Button { + text: qsTr("OK") + onClicked: acceptDialog() + } + Controls.Button { + text: qsTr("Cancel") + onClicked: rejectDialog() + } + } + } +} diff --git a/src/webengine/ui2/Menu.qml b/src/webengine/ui2/Menu.qml new file mode 100644 index 0000000000000000000000000000000000000000..0e7b869f5113b739d89f9a8a7ab442374e288385 --- /dev/null +++ b/src/webengine/ui2/Menu.qml @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls + +Controls.Menu { + id: menu + signal done() + + // Use private API for now + onAboutToHide: doneTimer.start() + + // WORKAROUND On Mac the Menu may be destroyed before the MenuItem + // is actually triggered (see qtbase commit 08cc9b9991ae9ab51) + Timer { + id: doneTimer + interval: 100 + onTriggered: menu.done() + } +} diff --git a/src/webengine/ui2/MenuItem.qml b/src/webengine/ui2/MenuItem.qml new file mode 100644 index 0000000000000000000000000000000000000000..9bf8aac5ef9b5b1cf8fe6542a37160895320956c --- /dev/null +++ b/src/webengine/ui2/MenuItem.qml @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls + +Controls.MenuItem { } + diff --git a/src/webengine/ui2/MenuSeparator.qml b/src/webengine/ui2/MenuSeparator.qml new file mode 100644 index 0000000000000000000000000000000000000000..0c664084a1fc4da88bd959d52e8caf7c2fb9ac7a --- /dev/null +++ b/src/webengine/ui2/MenuSeparator.qml @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +import QtQuick 2.5 + +Item { id: dummy } diff --git a/src/webengine/ui2/PromptDialog.qml b/src/webengine/ui2/PromptDialog.qml new file mode 100644 index 0000000000000000000000000000000000000000..880213e365403e35e8183df22584360a72d80c58 --- /dev/null +++ b/src/webengine/ui2/PromptDialog.qml @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 2.0 as Controls +import QtQuick.Layouts 1.0 +import QtQuick.Dialogs 1.2 + +Dialog { + property alias text: message.text + property alias prompt: field.text + property bool handled: false + signal input(string text) + signal accepted() + signal rejected() + title: qsTr("Prompt Dialog") + modality: Qt.NonModal + + //handle the case where users simply closes the dialog + onVisibilityChanged: { + if (visible == false && handled == false) { + handled = true; + rejected(); + } else { + handled = false; + } + } + + function acceptDialog() { + input(field.text); + accepted(); + handled = true; + close(); + } + + function rejectDialog() { + rejected(); + handled = true; + close(); + } + + contentItem: ColumnLayout { + id: rootLayout + anchors.fill: parent + anchors.margins: 4 + property int minimumWidth: rootLayout.implicitWidth + rootLayout.doubleMargins + property int minimumHeight: rootLayout.implicitHeight + rootLayout.doubleMargins + property int doubleMargins: anchors.margins * 2 + SystemPalette { id: palette; colorGroup: SystemPalette.Active } + Text { + id: message + Layout.fillWidth: true + color: palette.windowText + } + Controls.TextField { + id:field + focus: true + Layout.fillWidth: true + onAccepted: acceptDialog() + } + Item { + Layout.fillHeight: true + } + RowLayout { + Layout.alignment: Qt.AlignRight + spacing: 8 + Controls.Button { + text: qsTr("OK") + onClicked: acceptDialog() + } + Controls.Button { + text: qsTr("Cancel") + onClicked: rejectDialog() + } + } + } + +} diff --git a/src/webengine/ui2/information.png b/src/webengine/ui2/information.png new file mode 100644 index 0000000000000000000000000000000000000000..0a2eb87d108d2a24b71559998627570a252ebe69 Binary files /dev/null and b/src/webengine/ui2/information.png differ diff --git a/src/webengine/ui2/qmldir b/src/webengine/ui2/qmldir new file mode 100644 index 0000000000000000000000000000000000000000..8ab0d367178079cfa7c463a25f83951ffd3f19c2 --- /dev/null +++ b/src/webengine/ui2/qmldir @@ -0,0 +1,2 @@ +# Internal module +module QtWebEngine/Controls2Delegates diff --git a/src/webengine/ui2/question.png b/src/webengine/ui2/question.png new file mode 100644 index 0000000000000000000000000000000000000000..2dd92fd7915a09de670b8b6022ddcf02d4cc90e1 Binary files /dev/null and b/src/webengine/ui2/question.png differ diff --git a/src/webengine/ui2/ui2.pro b/src/webengine/ui2/ui2.pro new file mode 100644 index 0000000000000000000000000000000000000000..612999929aecb9926aacad123392cf75ef7b4651 --- /dev/null +++ b/src/webengine/ui2/ui2.pro @@ -0,0 +1,17 @@ +TARGETPATH = QtWebEngine/Controls2Delegates + +QML_FILES += \ + # Authentication Dialog + AuthenticationDialog.qml \ + # JS Dialogs + AlertDialog.qml \ + ConfirmDialog.qml \ + PromptDialog.qml \ + # Menus. Based on Qt Quick Controls + Menu.qml \ + MenuItem.qml \ + MenuSeparator.qml \ + information.png \ + question.png + +load(qml_module) diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index 769a3001634e3f778dc1c2479a6a98d31af7c02d..608ce2ab318b62e4fa5f2eacc67d7dadd2b91d45 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -81,22 +81,6 @@ static QString fileNameForComponent(UIDelegatesManager::ComponentType type) return QString(); } -static QString getUIDelegatesImportDir(QQmlEngine *engine) { - static QString importDir; - static bool initialized = false; - if (initialized) - return importDir; - Q_FOREACH (const QString &path, engine->importPathList()) { - QFileInfo fi(path % QLatin1String("/QtWebEngine/UIDelegates/")); - if (fi.exists()) { - importDir = fi.absolutePath(); - break; - } - } - initialized = true; - return importDir; -} - static QPoint calculateToolTipPosition(QPoint &position, QSize &toolTip) { QRect screen; QList<QScreen *> screens = QGuiApplication::screens(); @@ -150,16 +134,32 @@ UIDelegatesManager::UIDelegatesManager(QQuickWebEngineView *view) { } +UIDelegatesManager::~UIDelegatesManager() +{ +} + #define COMPONENT_MEMBER_CASE_STATEMENT(TYPE, COMPONENT) \ case TYPE: \ component = &COMPONENT##Component; \ break; +bool UIDelegatesManager::initializeImportDirs(QStringList &dirs, QQmlEngine *engine) { + foreach (const QString &path, engine->importPathList()) { + QFileInfo fi(path % QLatin1String("/QtWebEngine/UIDelegates/")); + if (fi.exists()) { + dirs << fi.absolutePath(); + return true; + } + } + return false; +} + bool UIDelegatesManager::ensureComponentLoaded(ComponentType type) { QQmlEngine* engine = qmlEngine(m_view); - if (getUIDelegatesImportDir(engine).isNull()) + if (m_importDirs.isEmpty() && !initializeImportDirs(m_importDirs, engine)) return false; + QQmlComponent **component; switch (type) { FOR_EACH_COMPONENT_TYPE(COMPONENT_MEMBER_CASE_STATEMENT, NO_SEPARATOR) @@ -176,20 +176,25 @@ bool UIDelegatesManager::ensureComponentLoaded(ComponentType type) #endif if (!engine) return false; - QFileInfo fi(getUIDelegatesImportDir(engine) % QLatin1Char('/') % fileName); - if (!fi.exists()) - return false; - // FIXME: handle async loading - *component = (new QQmlComponent(engine, QUrl::fromLocalFile(fi.absoluteFilePath()), QQmlComponent::PreferSynchronous, m_view)); - - if ((*component)->status() != QQmlComponent::Ready) { - Q_FOREACH (const QQmlError& err, (*component)->errors()) - qWarning("QtWebEngine: component error: %s\n", qPrintable(err.toString())); - delete *component; - *component = 0; - return false; + + foreach (const QString &importDir, m_importDirs) { + QFileInfo fi(importDir % QLatin1Char('/') % fileName); + if (!fi.exists()) + continue; + // FIXME: handle async loading + *component = (new QQmlComponent(engine, QUrl::fromLocalFile(fi.absoluteFilePath()), + QQmlComponent::PreferSynchronous, m_view)); + + if ((*component)->status() != QQmlComponent::Ready) { + foreach (const QQmlError &err, (*component)->errors()) + qWarning("QtWebEngine: component error: %s\n", qPrintable(err.toString())); + delete *component; + *component = nullptr; + return false; + } + return true; } - return true; + return false; } #define CHECK_QML_SIGNAL_PROPERTY(prop, location) \ @@ -241,11 +246,11 @@ QObject *UIDelegatesManager::addMenu(QObject *parentMenu, const QString &title, { Q_ASSERT(parentMenu); if (!ensureComponentLoaded(Menu)) - return 0; + return nullptr; QQmlContext *context = qmlContext(m_view); QObject *menu = menuComponent->beginCreate(context); // set visual parent for non-Window-based menus - if (QQuickItem* item = qobject_cast<QQuickItem*>(menu)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(menu)) item->setParentItem(m_view); if (!title.isEmpty()) @@ -321,7 +326,7 @@ void UIDelegatesManager::showDialog(QSharedPointer<JavaScriptDialogController> d QQmlContext *context = qmlContext(m_view); QObject *dialog = dialogComponent->beginCreate(context); // set visual parent for non-Window-based dialogs - if (QQuickItem* item = qobject_cast<QQuickItem*>(dialog)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(dialog)) item->setParentItem(m_view); dialog->setParent(m_view); QQmlProperty textProp(dialog, QStringLiteral("text")); @@ -347,8 +352,6 @@ void UIDelegatesManager::showDialog(QSharedPointer<JavaScriptDialogController> d CHECK_QML_SIGNAL_PROPERTY(inputSignal, dialogComponent->url()); static int setTextIndex = dialogController->metaObject()->indexOfSlot("textProvided(QString)"); QObject::connect(dialog, inputSignal.method(), dialogController.data(), dialogController->metaObject()->method(setTextIndex)); - QQmlProperty closingSignal(dialog, QStringLiteral("onClosing")); - QObject::connect(dialog, closingSignal.method(), dialogController.data(), dialogController->metaObject()->method(rejectIndex)); } dialogComponent->completeCreate(); @@ -369,7 +372,7 @@ void UIDelegatesManager::showColorDialog(QSharedPointer<ColorChooserController> QQmlContext *context = qmlContext(m_view); QObject *colorDialog = colorDialogComponent->beginCreate(context); - if (QQuickItem* item = qobject_cast<QQuickItem*>(colorDialog)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(colorDialog)) item->setParentItem(m_view); colorDialog->setParent(m_view); @@ -409,7 +412,7 @@ void UIDelegatesManager::showDialog(QSharedPointer<AuthenticationDialogControlle QQmlContext *context = qmlContext(m_view); QObject *authenticationDialog = authenticationDialogComponent->beginCreate(context); // set visual parent for non-Window-based dialogs - if (QQuickItem* item = qobject_cast<QQuickItem*>(authenticationDialog)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(authenticationDialog)) item->setParentItem(m_view); authenticationDialog->setParent(m_view); @@ -450,7 +453,7 @@ void UIDelegatesManager::showFilePicker(FilePickerController *controller) QQmlContext *context = qmlContext(m_view); QObject *filePicker = filePickerComponent->beginCreate(context); - if (QQuickItem* item = qobject_cast<QQuickItem*>(filePicker)) + if (QQuickItem *item = qobject_cast<QQuickItem*>(filePicker)) item->setParentItem(m_view); filePicker->setParent(m_view); filePickerComponent->completeCreate(); @@ -491,6 +494,11 @@ void UIDelegatesManager::showFilePicker(FilePickerController *controller) QMetaObject::invokeMethod(filePicker, "open"); } +void UIDelegatesManager::showMenu(QObject *menu) +{ + QMetaObject::invokeMethod(menu, "popup"); +} + void UIDelegatesManager::showMessageBubble(const QRect &anchor, const QString &mainText, const QString &subText) { if (!ensureComponentLoaded(MessageBubble)) @@ -557,4 +565,84 @@ void UIDelegatesManager::showToolTip(const QString &text) QMetaObject::invokeMethod(m_toolTip.data(), "open"); } +UI2DelegatesManager::UI2DelegatesManager(QQuickWebEngineView *view) : UIDelegatesManager(view) +{ + +} + +bool UI2DelegatesManager::initializeImportDirs(QStringList &dirs, QQmlEngine *engine) +{ + foreach (const QString &path, engine->importPathList()) { + QFileInfo fi1(path % QLatin1String("/QtWebEngine/Controls2Delegates/")); + QFileInfo fi2(path % QLatin1String("/QtWebEngine/UIDelegates/")); + if (fi1.exists() && fi2.exists()) { + dirs << fi1.absolutePath() << fi2.absolutePath(); + return true; + } + } + return false; +} + +QObject *UI2DelegatesManager::addMenu(QObject *parentMenu, const QString &title, const QPoint &pos) +{ + Q_ASSERT(parentMenu); + if (!ensureComponentLoaded(Menu)) + return nullptr; + QQmlContext *context = qmlContext(m_view); + QObject *menu = menuComponent->beginCreate(context); + + // set visual parent for non-Window-based menus + if (QQuickItem *item = qobject_cast<QQuickItem*>(menu)) + item->setParentItem(m_view); + + if (!title.isEmpty()) + menu->setProperty("title", title); + if (!pos.isNull()) { + menu->setProperty("x", pos.x()); + menu->setProperty("y", pos.y()); + } + + menu->setParent(parentMenu); + QQmlProperty doneSignal(menu, QStringLiteral("onDone")); + CHECK_QML_SIGNAL_PROPERTY(doneSignal, menuComponent->url()) + static int deleteLaterIndex = menu->metaObject()->indexOfSlot("deleteLater()"); + QObject::connect(menu, doneSignal.method(), menu, menu->metaObject()->method(deleteLaterIndex)); + menuComponent->completeCreate(); + return menu; +} + +void UI2DelegatesManager::addMenuItem(MenuItemHandler *menuItemHandler, const QString &text, + const QString &/*iconName*/, bool enabled, + bool checkable, bool checked) +{ + Q_ASSERT(menuItemHandler); + if (!ensureComponentLoaded(MenuItem)) + return; + + QObject *it = menuItemComponent->beginCreate(qmlContext(m_view)); + + it->setProperty("text", text); + it->setProperty("enabled", enabled); + it->setProperty("checked", checked); + it->setProperty("checkable", checkable); + + QQmlProperty signal(it, QStringLiteral("onTriggered")); + CHECK_QML_SIGNAL_PROPERTY(signal, menuItemComponent->url()); + QObject::connect(it, signal.method(), menuItemHandler, + QMetaMethod::fromSignal(&MenuItemHandler::triggered)); + menuItemComponent->completeCreate(); + + QObject *menu = menuItemHandler->parent(); + it->setParent(menu); + + QQmlListReference entries(menu, defaultPropertyName(menu), qmlEngine(m_view)); + if (entries.isValid()) + entries.append(it); +} + +void UI2DelegatesManager::showMenu(QObject *menu) +{ + QMetaObject::invokeMethod(menu, "open"); +} + } // namespace QtWebEngineCore diff --git a/src/webengine/ui_delegates_manager.h b/src/webengine/ui_delegates_manager.h index 43d1e6985736547a4a77271628d6cc48b3537d1f..b1eb65513af998d9e945e2e8be32f32cfc4c51b0 100644 --- a/src/webengine/ui_delegates_manager.h +++ b/src/webengine/ui_delegates_manager.h @@ -74,6 +74,7 @@ class QQmlContext; class QQmlComponent; class QQuickItem; class QQuickWebEngineView; +class QQmlEngine; QT_END_NAMESPACE namespace QtWebEngineCore { @@ -103,27 +104,35 @@ public: }; UIDelegatesManager(QQuickWebEngineView *); + virtual ~UIDelegatesManager(); - void addMenuItem(MenuItemHandler *menuItemHandler, const QString &text, const QString &iconName = QString(), - bool enabled = true, bool checkable = false, bool checked = true); + virtual bool initializeImportDirs(QStringList &dirs, QQmlEngine *engine); + virtual void addMenuItem(MenuItemHandler *menuItemHandler, const QString &text, + const QString &iconName = QString(), + bool enabled = true, + bool checkable = false, bool checked = true); void addMenuSeparator(QObject *menu); - QObject *addMenu(QObject *parentMenu, const QString &title, const QPoint &pos = QPoint()); + virtual QObject *addMenu(QObject *parentMenu, const QString &title, + const QPoint &pos = QPoint()); QQmlContext *creationContextForComponent(QQmlComponent *); void showColorDialog(QSharedPointer<ColorChooserController>); void showDialog(QSharedPointer<JavaScriptDialogController>); void showDialog(QSharedPointer<AuthenticationDialogController>); void showFilePicker(FilePickerController *controller); - void showMessageBubble(const QRect &anchor, const QString &mainText, const QString &subText); + virtual void showMenu(QObject *menu); + void showMessageBubble(const QRect &anchor, const QString &mainText, + const QString &subText); void hideMessageBubble(); void moveMessageBubble(const QRect &anchor); void showToolTip(const QString &text); -private: +protected: bool ensureComponentLoaded(ComponentType); QQuickWebEngineView *m_view; QScopedPointer<QQuickItem> m_messageBubbleItem; QScopedPointer<QObject> m_toolTip; + QStringList m_importDirs; FOR_EACH_COMPONENT_TYPE(MEMBER_DECLARATION, SEMICOLON_SEPARATOR) @@ -131,6 +140,24 @@ private: }; +// delegate manager for qtquickcontrols2 with fallback to qtquickcontrols1 + +class UI2DelegatesManager : public UIDelegatesManager +{ +public: + UI2DelegatesManager(QQuickWebEngineView *); + bool initializeImportDirs(QStringList &dirs, QQmlEngine *engine) override; + QObject *addMenu(QObject *parentMenu, const QString &title, + const QPoint &pos = QPoint()) override; + void addMenuItem(MenuItemHandler *menuItemHandler, const QString &text, + const QString &iconName = QString(), + bool enabled = true, + bool checkable = false, bool checked = false) override; + void showMenu(QObject *menu) override; + Q_DISABLE_COPY(UI2DelegatesManager) + +}; + } // namespace QtWebEngineCore #endif // UI_DELEGATES_MANAGER_H diff --git a/sync.profile b/sync.profile index e4a88e0c2b1fcc9f4473ae29cee3dfe562e274f9..e713faee4cb685ab5df9ca88c31b73746965f9ec 100644 --- a/sync.profile +++ b/sync.profile @@ -24,5 +24,6 @@ "qttools" => "", # FIXME: take examples out into their own module to avoid a potential circular dependency later ? "qtquickcontrols" => "", + "qtquickcontrols2" => "", "qtwebchannel" => "", );