diff --git a/CQtDeployer.pro b/CQtDeployer.pro index a4380f2..b5948da 100644 --- a/CQtDeployer.pro +++ b/CQtDeployer.pro @@ -15,14 +15,17 @@ SUBDIRS += QuasarAppLib \ UnitTests \ tests/TestOnlyC \ tests/TestQtWidgets \ - tests/TestQMLWidgets + tests/TestQMLWidgets \ + tests/quicknanobrowser } contains(DEFINES, WITHOUT_TESTS) { SUBDIRS -= UnitTests \ tests/TestOnlyC \ tests/TestQtWidgets \ - tests/TestQMLWidgets + tests/TestQMLWidgets \ + tests/quicknanobrowser + } CQtDeployer.depends=QuasarAppLib diff --git a/Deploy/extracter.cpp b/Deploy/extracter.cpp index affe9e6..b00f532 100644 --- a/Deploy/extracter.cpp +++ b/Deploy/extracter.cpp @@ -35,6 +35,30 @@ bool Extracter::deployMSVC() { return _fileManager->copyFile(msvcInstaller, DeployCore::_config->targetDir); } +bool Extracter::extractWebEngine() { + auto test = static_cast(_qtModules) & static_cast(DeployCore::QtModule::QtWebEngineModule); + if (test) { + +#ifdef Q_OS_UNIX + auto webEngeneBin = DeployCore::_config->qtDir + "/libexec/QtWebEngineProcess"; +#else + auto webEngeneBin = DeployCore::_config->qtDir + "/bin/QtWebEngineProcess.exe"; +#endif + auto destWebEngine = DeployCore::_config->targetDir + DeployCore::_config->distroStruct.getBinOutDir(); + auto resOut = DeployCore::_config->targetDir + DeployCore::_config->distroStruct.getResOutDir(); + auto res = DeployCore::_config->qtDir + "/resources/"; + + if (!_fileManager->copyFile(webEngeneBin, destWebEngine)) { + return false; + } + if (!_fileManager->copyFolder(res, resOut)) { + return false; + } + } + + return true; +} + bool Extracter::copyPlugin(const QString &plugin) { QStringList listItems; @@ -159,6 +183,10 @@ void Extracter::deploy() { copyTr(); + if (!extractWebEngine()) { + QuasarAppUtils::Params::verboseLog("deploy webEngine failed", QuasarAppUtils::Error); + } + if (!deployMSVC()) { QuasarAppUtils::Params::verboseLog("deploy msvc failed"); } diff --git a/Deploy/extracter.h b/Deploy/extracter.h index 1f833ef..fec6cec 100644 --- a/Deploy/extracter.h +++ b/Deploy/extracter.h @@ -42,6 +42,7 @@ class DEPLOYSHARED_EXPORT Extracter { void extractLib(const QString & file); bool deployMSVC(); + bool extractWebEngine(); bool copyPlugin(const QString &plugin); diff --git a/Deploy/metafilemanager.cpp b/Deploy/metafilemanager.cpp index 0a5917a..de76295 100644 --- a/Deploy/metafilemanager.cpp +++ b/Deploy/metafilemanager.cpp @@ -52,6 +52,7 @@ bool MetaFileManager::createRunScriptLinux(const QString &target) { "export QML_IMPORT_PATH=\"$BASE_DIR\"" + DeployCore::_config->distroStruct.getQmlOutDir() + ":QML_IMPORT_PATH\n" "export QML2_IMPORT_PATH=\"$BASE_DIR\"" + DeployCore::_config->distroStruct.getQmlOutDir() + ":QML2_IMPORT_PATH\n" "export QT_PLUGIN_PATH=\"$BASE_DIR\"" + DeployCore::_config->distroStruct.getPluginsOutDir() + ":QT_PLUGIN_PATH\n" + "export QTWEBENGINEPROCESS_PATH=\"$BASE_DIR\"" + DeployCore::_config->distroStruct.getBinOutDir() + "/QtWebEngineProcess\n" "export QTDIR=\"$BASE_DIR\"\n" "export " "QT_QPA_PLATFORM_PLUGIN_PATH=\"$BASE_DIR\"" + DeployCore::_config->distroStruct.getPluginsOutDir() + diff --git a/UnitTests/tst_deploytest.cpp b/UnitTests/tst_deploytest.cpp index 47dff08..af53078 100644 --- a/UnitTests/tst_deploytest.cpp +++ b/UnitTests/tst_deploytest.cpp @@ -105,6 +105,8 @@ private slots: void testMSVC(); + void testWebEngine(); + }; bool deploytest::runProcess(const QString &DistroPath, @@ -440,6 +442,36 @@ void deploytest::testMSVC() { } +void deploytest::testWebEngine() { + TestUtils utils; + + +#ifdef Q_OS_UNIX + QString bin = TestBinDir + "quicknanobrowser"; + QString qmake = TestQtDir + "bin/qmake"; + +#else + QString bin = TestBinDir + "quicknanobrowser.exe"; + QString qmake = TestQtDir + "bin/qmake.exe"; + +#endif + + auto comapareTree = utils.createTree( + { + "./Distro/QtWidgetsProject.sh", + "./Distro/bin/QtWidgetsProject", + "./Distro/lib/libicudata.so", + "./Distro/lib/libicui18n.so", + "./Distro/lib/libicuuc.so" + }); + + + runTestParams({"-bin", bin, "clear" , + "-qmake", qmake, + "-qmlDir", TestBinDir + "/../quicknanobrowser"}, &comapareTree); + +} + void deploytest::testQmlExtrct() { QmlCreator creator("./"); auto imports = creator.getQmlImports(); diff --git a/tests/quicknanobrowser/ApplicationRoot.qml b/tests/quicknanobrowser/ApplicationRoot.qml new file mode 100644 index 0000000..adae6f5 --- /dev/null +++ b/tests/quicknanobrowser/ApplicationRoot.qml @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtWebEngine 1.9 + +QtObject { + id: root + + property QtObject defaultProfile: WebEngineProfile { + storageName: "Profile" + offTheRecord: false + useForGlobalCertificateVerification: true + } + + property QtObject otrProfile: WebEngineProfile { + offTheRecord: true + } + + property Component browserWindowComponent: BrowserWindow { + applicationRoot: root + onClosing: destroy() + } + property Component browserDialogComponent: BrowserDialog { + onClosing: destroy() + } + function createWindow(profile) { + var newWindow = browserWindowComponent.createObject(root); + newWindow.currentWebView.profile = profile; + profile.downloadRequested.connect(newWindow.onDownloadRequested); + return newWindow; + } + function createDialog(profile) { + var newDialog = browserDialogComponent.createObject(root); + newDialog.currentWebView.profile = profile; + return newDialog; + } + function load(url) { + var browserWindow = createWindow(defaultProfile); + browserWindow.currentWebView.url = url; + } +} diff --git a/tests/quicknanobrowser/BrowserDialog.qml b/tests/quicknanobrowser/BrowserDialog.qml new file mode 100644 index 0000000..c2b6737 --- /dev/null +++ b/tests/quicknanobrowser/BrowserDialog.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Window 2.2 +import QtWebEngine 1.9 + +Window { + id: window + property alias currentWebView: webView + flags: Qt.Dialog | Qt.WindowStaysOnTopHint + width: 800 + height: 600 + visible: true + onClosing: destroy() + WebEngineView { + id: webView + anchors.fill: parent + + onGeometryChangeRequested: function(geometry) { + window.x = geometry.x + window.y = geometry.y + window.width = geometry.width + window.height = geometry.height + } + } +} diff --git a/tests/quicknanobrowser/BrowserWindow.qml b/tests/quicknanobrowser/BrowserWindow.qml new file mode 100644 index 0000000..7fb87a2 --- /dev/null +++ b/tests/quicknanobrowser/BrowserWindow.qml @@ -0,0 +1,654 @@ +/**************************************************************************** +** +** 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt.labs.settings 1.0 +import QtQml 2.2 +import QtQuick 2.2 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Private 1.0 as QQCPrivate +import QtQuick.Controls.Styles 1.0 +import QtQuick.Dialogs 1.2 +import QtQuick.Layouts 1.0 +import QtQuick.Window 2.1 +import QtWebEngine 1.9 + +ApplicationWindow { + id: browserWindow + property QtObject applicationRoot + property Item currentWebView: tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null + property int previousVisibility: Window.Windowed + + width: 1300 + height: 900 + visible: true + title: currentWebView && currentWebView.title + + // Make sure the Qt.WindowFullscreenButtonHint is set on OS X. + Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint + + // Create a styleItem to determine the platform. + // When using style "mac", ToolButtons are not supposed to accept focus. + QQCPrivate.StyleItem { id: styleItem } + property bool platformIsMac: styleItem.style == "mac" + + Settings { + id : appSettings + property alias autoLoadImages: loadImages.checked + property alias javaScriptEnabled: javaScriptEnabled.checked + property alias errorPageEnabled: errorPageEnabled.checked + property alias pluginsEnabled: pluginsEnabled.checked + property alias fullScreenSupportEnabled: fullScreenSupportEnabled.checked + property alias autoLoadIconsForPage: autoLoadIconsForPage.checked + property alias touchIconsEnabled: touchIconsEnabled.checked + property alias webRTCPublicInterfacesOnly : webRTCPublicInterfacesOnly.checked + property alias devToolsEnabled: devToolsEnabled.checked + property alias pdfViewerEnabled: pdfViewerEnabled.checked + } + + Action { + shortcut: "Ctrl+D" + onTriggered: { + downloadView.visible = !downloadView.visible; + } + } + Action { + id: focus + shortcut: "Ctrl+L" + onTriggered: { + addressBar.forceActiveFocus(); + addressBar.selectAll(); + } + } + Action { + shortcut: StandardKey.Refresh + onTriggered: { + if (currentWebView) + currentWebView.reload(); + } + } + Action { + shortcut: StandardKey.AddTab + onTriggered: { + tabs.createEmptyTab(tabs.count != 0 ? currentWebView.profile : defaultProfile); + tabs.currentIndex = tabs.count - 1; + addressBar.forceActiveFocus(); + addressBar.selectAll(); + } + } + Action { + shortcut: StandardKey.Close + onTriggered: { + currentWebView.triggerWebAction(WebEngineView.RequestClose); + } + } + Action { + shortcut: "Escape" + onTriggered: { + if (currentWebView.state == "FullScreen") { + browserWindow.visibility = browserWindow.previousVisibility; + fullScreenNotification.hide(); + currentWebView.triggerWebAction(WebEngineView.ExitFullScreen); + } + } + } + Action { + shortcut: "Ctrl+0" + onTriggered: currentWebView.zoomFactor = 1.0 + } + Action { + shortcut: StandardKey.ZoomOut + onTriggered: currentWebView.zoomFactor -= 0.1 + } + Action { + shortcut: StandardKey.ZoomIn + onTriggered: currentWebView.zoomFactor += 0.1 + } + + Action { + shortcut: StandardKey.Copy + onTriggered: currentWebView.triggerWebAction(WebEngineView.Copy) + } + Action { + shortcut: StandardKey.Cut + onTriggered: currentWebView.triggerWebAction(WebEngineView.Cut) + } + Action { + shortcut: StandardKey.Paste + onTriggered: currentWebView.triggerWebAction(WebEngineView.Paste) + } + Action { + shortcut: "Shift+"+StandardKey.Paste + onTriggered: currentWebView.triggerWebAction(WebEngineView.PasteAndMatchStyle) + } + Action { + shortcut: StandardKey.SelectAll + onTriggered: currentWebView.triggerWebAction(WebEngineView.SelectAll) + } + Action { + shortcut: StandardKey.Undo + onTriggered: currentWebView.triggerWebAction(WebEngineView.Undo) + } + Action { + shortcut: StandardKey.Redo + onTriggered: currentWebView.triggerWebAction(WebEngineView.Redo) + } + Action { + shortcut: StandardKey.Back + onTriggered: currentWebView.triggerWebAction(WebEngineView.Back) + } + Action { + shortcut: StandardKey.Forward + onTriggered: currentWebView.triggerWebAction(WebEngineView.Forward) + } + + toolBar: ToolBar { + id: navigationBar + RowLayout { + anchors.fill: parent + ToolButton { + enabled: currentWebView && (currentWebView.canGoBack || currentWebView.canGoForward) + menu:Menu { + id: historyMenu + + Instantiator { + model: currentWebView && currentWebView.navigationHistory.items + MenuItem { + text: model.title + onTriggered: currentWebView.goBackOrForward(model.offset) + checkable: !enabled + checked: !enabled + enabled: model.offset + } + + onObjectAdded: function(index, object) { + historyMenu.insertItem(index, object) + } + onObjectRemoved: function(index, object) { + historyMenu.removeItem(object) + } + } + } + } + + ToolButton { + id: backButton + iconSource: "icons/go-previous.png" + onClicked: currentWebView.goBack() + enabled: currentWebView && currentWebView.canGoBack + activeFocusOnTab: !browserWindow.platformIsMac + } + ToolButton { + id: forwardButton + iconSource: "icons/go-next.png" + onClicked: currentWebView.goForward() + enabled: currentWebView && currentWebView.canGoForward + activeFocusOnTab: !browserWindow.platformIsMac + } + ToolButton { + id: reloadButton + iconSource: currentWebView && currentWebView.loading ? "icons/process-stop.png" : "icons/view-refresh.png" + onClicked: currentWebView && currentWebView.loading ? currentWebView.stop() : currentWebView.reload() + activeFocusOnTab: !browserWindow.platformIsMac + } + TextField { + id: addressBar + Image { + anchors.verticalCenter: addressBar.verticalCenter; + x: 5 + z: 2 + id: faviconImage + width: 16; height: 16 + sourceSize: Qt.size(width, height) + source: currentWebView && currentWebView.icon + } + style: TextFieldStyle { + padding { + left: 26; + } + } + focus: true + Layout.fillWidth: true + text: currentWebView && currentWebView.url + onAccepted: currentWebView.url = utils.fromUserInput(text) + } + ToolButton { + id: settingsMenuButton + menu: Menu { + MenuItem { + id: loadImages + text: "Autoload images" + checkable: true + checked: WebEngine.settings.autoLoadImages + } + MenuItem { + id: javaScriptEnabled + text: "JavaScript On" + checkable: true + checked: WebEngine.settings.javascriptEnabled + } + MenuItem { + id: errorPageEnabled + text: "ErrorPage On" + checkable: true + checked: WebEngine.settings.errorPageEnabled + } + MenuItem { + id: pluginsEnabled + text: "Plugins On" + checkable: true + checked: true + } + MenuItem { + id: fullScreenSupportEnabled + text: "FullScreen On" + checkable: true + checked: WebEngine.settings.fullScreenSupportEnabled + } + MenuItem { + id: offTheRecordEnabled + text: "Off The Record" + checkable: true + checked: currentWebView && currentWebView.profile === otrProfile + onToggled: function(checked) { + if (currentWebView) { + currentWebView.profile = checked ? otrProfile : defaultProfile; + } + } + } + MenuItem { + id: httpDiskCacheEnabled + text: "HTTP Disk Cache" + checkable: currentWebView && !currentWebView.profile.offTheRecord + checked: currentWebView && (currentWebView.profile.httpCacheType === WebEngineProfile.DiskHttpCache) + onToggled: function(checked) { + if (currentWebView) { + currentWebView.profile.httpCacheType = checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache; + } + } + } + MenuItem { + id: autoLoadIconsForPage + text: "Icons On" + checkable: true + checked: WebEngine.settings.autoLoadIconsForPage + } + MenuItem { + id: touchIconsEnabled + text: "Touch Icons On" + checkable: true + checked: WebEngine.settings.touchIconsEnabled + enabled: autoLoadIconsForPage.checked + } + MenuItem { + id: webRTCPublicInterfacesOnly + text: "WebRTC Public Interfaces Only" + checkable: true + checked: WebEngine.settings.webRTCPublicInterfacesOnly + } + MenuItem { + id: devToolsEnabled + text: "Open DevTools" + checkable: true + checked: false + } + MenuItem { + id: pdfViewerEnabled + text: "PDF viewer enabled" + checkable: true + checked: WebEngine.settings.pdfViewerEnabled + } + } + } + } + ProgressBar { + id: progressBar + height: 3 + anchors { + left: parent.left + top: parent.bottom + right: parent.right + leftMargin: -parent.leftMargin + rightMargin: -parent.rightMargin + } + style: ProgressBarStyle { + background: Item {} + } + z: -2; + minimumValue: 0 + maximumValue: 100 + value: (currentWebView && currentWebView.loadProgress < 100) ? currentWebView.loadProgress : 0 + } + } + + TabView { + id: tabs + function createEmptyTab(profile) { + var tab = addTab("", tabComponent); + // We must do this first to make sure that tab.active gets set so that tab.item gets instantiated immediately. + tab.active = true; + tab.title = Qt.binding(function() { return tab.item.title }); + tab.item.profile = profile; + return tab; + } + + anchors.top: parent.top + anchors.bottom: devToolsView.top + anchors.left: parent.left + anchors.right: parent.right + Component.onCompleted: createEmptyTab(defaultProfile) + + // Add custom tab view style so we can customize the tabs to include a close button + style: TabViewStyle { + property color frameColor: "#999" + property color fillColor: "#eee" + property color nonSelectedColor: "#ddd" + frameOverlap: 1 + frame: Rectangle { + color: "#eee" + border.color: frameColor + } + tab: Rectangle { + id: tabRectangle + color: styleData.selected ? fillColor : nonSelectedColor + border.width: 1 + border.color: frameColor + implicitWidth: Math.max(text.width + 30, 80) + implicitHeight: Math.max(text.height + 10, 20) + Rectangle { height: 1 ; width: parent.width ; color: frameColor} + Rectangle { height: parent.height ; width: 1; color: frameColor} + Rectangle { x: parent.width - 2; height: parent.height ; width: 1; color: frameColor} + Text { + id: text + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 6 + text: styleData.title + elide: Text.ElideRight + color: styleData.selected ? "black" : frameColor + } + Button { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: 4 + height: 12 + style: ButtonStyle { + background: Rectangle { + implicitWidth: 12 + implicitHeight: 12 + color: control.hovered ? "#ccc" : tabRectangle.color + Text {text: "x" ; anchors.centerIn: parent ; color: "gray"} + }} + onClicked: tabs.removeTab(styleData.index); + } + } + } + + Component { + id: tabComponent + WebEngineView { + id: webEngineView + focus: true + + onLinkHovered: function(hoveredUrl) { + if (hoveredUrl == "") + hideStatusText.start(); + else { + statusText.text = hoveredUrl; + statusBubble.visible = true; + hideStatusText.stop(); + } + } + + states: [ + State { + name: "FullScreen" + PropertyChanges { + target: tabs + frameVisible: false + tabsVisible: false + } + PropertyChanges { + target: navigationBar + visible: false + } + } + ] + settings.autoLoadImages: appSettings.autoLoadImages + settings.javascriptEnabled: appSettings.javaScriptEnabled + settings.errorPageEnabled: appSettings.errorPageEnabled + settings.pluginsEnabled: appSettings.pluginsEnabled + settings.fullScreenSupportEnabled: appSettings.fullScreenSupportEnabled + settings.autoLoadIconsForPage: appSettings.autoLoadIconsForPage + settings.touchIconsEnabled: appSettings.touchIconsEnabled + settings.webRTCPublicInterfacesOnly: appSettings.webRTCPublicInterfacesOnly + settings.pdfViewerEnabled: appSettings.pdfViewerEnabled + + onCertificateError: function(error) { + error.defer(); + sslDialog.enqueue(error); + } + + onNewViewRequested: function(request) { + if (!request.userInitiated) + print("Warning: Blocked a popup window."); + else if (request.destination === WebEngineView.NewViewInTab) { + var tab = tabs.createEmptyTab(currentWebView.profile); + tabs.currentIndex = tabs.count - 1; + request.openIn(tab.item); + } else if (request.destination === WebEngineView.NewViewInBackgroundTab) { + var backgroundTab = tabs.createEmptyTab(currentWebView.profile); + request.openIn(backgroundTab.item); + } else if (request.destination === WebEngineView.NewViewInDialog) { + var dialog = applicationRoot.createDialog(currentWebView.profile); + request.openIn(dialog.currentWebView); + } else { + var window = applicationRoot.createWindow(currentWebView.profile); + request.openIn(window.currentWebView); + } + } + + onFullScreenRequested: function(request) { + if (request.toggleOn) { + webEngineView.state = "FullScreen"; + browserWindow.previousVisibility = browserWindow.visibility; + browserWindow.showFullScreen(); + fullScreenNotification.show(); + } else { + webEngineView.state = ""; + browserWindow.visibility = browserWindow.previousVisibility; + fullScreenNotification.hide(); + } + request.accept(); + } + + onQuotaRequested: function(request) { + if (request.requestedSize <= 5 * 1024 * 1024) + request.accept(); + else + request.reject(); + } + + onRegisterProtocolHandlerRequested: function(request) { + console.log("accepting registerProtocolHandler request for " + + request.scheme + " from " + request.origin); + request.accept(); + } + + onRenderProcessTerminated: function(terminationStatus, exitCode) { + var status = ""; + switch (terminationStatus) { + case WebEngineView.NormalTerminationStatus: + status = "(normal exit)"; + break; + case WebEngineView.AbnormalTerminationStatus: + status = "(abnormal exit)"; + break; + case WebEngineView.CrashedTerminationStatus: + status = "(crashed)"; + break; + case WebEngineView.KilledTerminationStatus: + status = "(killed)"; + break; + } + + print("Render process exited with code " + exitCode + " " + status); + reloadTimer.running = true; + } + + onWindowCloseRequested: { + if (tabs.count == 1) + browserWindow.close(); + else + tabs.removeTab(tabs.currentIndex); + } + + onSelectClientCertificate: function(selection) { + selection.certificates[0].select(); + } + + Timer { + id: reloadTimer + interval: 0 + running: false + repeat: false + onTriggered: currentWebView.reload() + } + } + } + } + WebEngineView { + id: devToolsView + visible: devToolsEnabled.checked + height: visible ? 400 : 0 + inspectedView: visible && tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + onNewViewRequested: function(request) { + var tab = tabs.createEmptyTab(currentWebView.profile); + tabs.currentIndex = tabs.count - 1; + request.openIn(tab.item); + } + } + MessageDialog { + id: sslDialog + + property var certErrors: [] + icon: StandardIcon.Warning + standardButtons: StandardButton.No | StandardButton.Yes + title: "Server's certificate not trusted" + text: "Do you wish to continue?" + detailedText: "If you wish so, you may continue with an unverified certificate. " + + "Accepting an unverified certificate means " + + "you may not be connected with the host you tried to connect to.\n" + + "Do you wish to override the security check and continue?" + onYes: { + certErrors.shift().ignoreCertificateError(); + presentError(); + } + onNo: reject() + onRejected: reject() + + function reject(){ + certErrors.shift().rejectCertificate(); + presentError(); + } + function enqueue(error){ + certErrors.push(error); + presentError(); + } + function presentError(){ + visible = certErrors.length > 0 + } + } + + FullScreenNotification { + id: fullScreenNotification + } + + DownloadView { + id: downloadView + visible: false + anchors.fill: parent + } + + function onDownloadRequested(download) { + downloadView.visible = true; + downloadView.append(download); + download.accept(); + } + + Rectangle { + id: statusBubble + color: "oldlace" + property int padding: 8 + visible: false + + anchors.left: parent.left + anchors.bottom: parent.bottom + width: statusText.paintedWidth + padding + height: statusText.paintedHeight + padding + + Text { + id: statusText + anchors.centerIn: statusBubble + elide: Qt.ElideMiddle + + Timer { + id: hideStatusText + interval: 750 + onTriggered: { + statusText.text = ""; + statusBubble.visible = false; + } + } + } + } +} diff --git a/tests/quicknanobrowser/DownloadView.qml b/tests/quicknanobrowser/DownloadView.qml new file mode 100644 index 0000000..545a502 --- /dev/null +++ b/tests/quicknanobrowser/DownloadView.qml @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import QtWebEngine 1.9 +import QtQuick.Layouts 1.0 + +Rectangle { + id: downloadView + color: "lightgray" + + ListModel { + id: downloadModel + property var downloads: [] + } + + function append(download) { + downloadModel.append(download); + downloadModel.downloads.push(download); + } + + Component { + id: downloadItemDelegate + + Rectangle { + width: listView.width + height: childrenRect.height + anchors.margins: 10 + radius: 3 + color: "transparent" + border.color: "black" + Rectangle { + id: progressBar + + property real progress: downloadModel.downloads[index] + ? downloadModel.downloads[index].receivedBytes / downloadModel.downloads[index].totalBytes : 0 + + radius: 3 + color: width == listView.width ? "green" : "#2b74c7" + width: listView.width * progress + height: cancelButton.height + + Behavior on width { + SmoothedAnimation { duration: 100 } + } + } + Rectangle { + anchors { + left: parent.left + right: parent.right + leftMargin: 20 + } + Label { + id: label + text: path + anchors { + verticalCenter: cancelButton.verticalCenter + left: parent.left + right: cancelButton.left + } + } + Button { + id: cancelButton + anchors.right: parent.right + iconSource: "icons/process-stop.png" + onClicked: { + var download = downloadModel.downloads[index]; + + download.cancel(); + + downloadModel.downloads = downloadModel.downloads.filter(function (el) { + return el.id !== download.id; + }); + downloadModel.remove(index); + } + } + } + } + + } + ListView { + id: listView + anchors { + topMargin: 10 + top: parent.top + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + width: parent.width - 20 + spacing: 5 + + model: downloadModel + delegate: downloadItemDelegate + + Text { + visible: !listView.count + horizontalAlignment: Text.AlignHCenter + height: 30 + anchors { + top: parent.top + left: parent.left + right: parent.right + } + font.pixelSize: 20 + text: "No active downloads." + } + + Rectangle { + color: "gray" + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + height: 30 + Button { + id: okButton + text: "OK" + anchors.centerIn: parent + onClicked: { + downloadView.visible = false; + } + } + } + } +} diff --git a/tests/quicknanobrowser/FullScreenNotification.qml b/tests/quicknanobrowser/FullScreenNotification.qml new file mode 100644 index 0000000..55f5f00 --- /dev/null +++ b/tests/quicknanobrowser/FullScreenNotification.qml @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 + +Rectangle { + id: fullScreenNotification + width: 500 + height: 40 + color: "white" + radius: 7 + + visible: false + opacity: 0 + + function show() { + visible = true; + opacity = 1; + reset.start(); + } + + function hide() { + reset.stop(); + opacity = 0; + } + + Behavior on opacity { + NumberAnimation { + duration: 750 + onStopped: { + if (opacity == 0) + visible = false; + } + } + } + + Timer { + id: reset + interval: 5000 + onTriggered: hide() + } + + anchors.horizontalCenter: parent.horizontalCenter + y: 125 + + Text { + id: message + width: parent.width + + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + wrapMode: Text.WordWrap + elide: Text.ElideNone + clip: true + + text: qsTr("You are now in fullscreen mode. Press ESC to quit!") + } +} diff --git a/tests/quicknanobrowser/doc/images/quicknanobrowser-demo.jpg b/tests/quicknanobrowser/doc/images/quicknanobrowser-demo.jpg new file mode 100644 index 0000000..12693bb Binary files /dev/null and b/tests/quicknanobrowser/doc/images/quicknanobrowser-demo.jpg differ diff --git a/tests/quicknanobrowser/doc/src/quicknanobrowser.qdoc b/tests/quicknanobrowser/doc/src/quicknanobrowser.qdoc new file mode 100644 index 0000000..48a63c7 --- /dev/null +++ b/tests/quicknanobrowser/doc/src/quicknanobrowser.qdoc @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example webengine/quicknanobrowser + \title WebEngine Quick Nano Browser + \ingroup webengine-examples + \brief A web browser implemented using the WebEngineView QML type. + + \image quicknanobrowser-demo.jpg + + \e {Quick Nano Browser} demonstrates how to use the \l{Qt WebEngine QML Types} + {Qt WebEngine QML types} to develop a small web browser application that consists of a browser + window with a title bar, toolbar, tab view, and status bar. The web content is loaded in a web + engine view within the tab view. If certificate errors occur, users are prompted for action in a + message dialog. The status bar pops up to display the URL of a hovered link. + + A web page can issue a request for being displayed in fullscreen mode. Users can allow full + screen mode by using a toolbar button. They can leave fullscreen mode by using a keyboard + shortcut. Additional toolbar buttons enable moving backwards and forwards in the browser + history, reloading tab content, and opening a settings menu for enabling the following features: + JavaScript, plugins, fullscreen mode, off the record, HTTP disk cache, autoloading images, and + ignoring certificate errors. + + \include examples-run.qdocinc + + \section1 Creating the Main Browser Window + + When the browser main window is loaded, it creates an empty tab using the default profile. Each + tab is a web engine view that fills the main window. + + We create the main window in the \e BrowserWindow.qml file using the ApplicationWindow type: + + \quotefromfile webengine/quicknanobrowser/BrowserWindow.qml + \skipto ApplicationWindow + \printuntil currentWebView + \dots + \skipto width + \printuntil title + + We use the TabView Qt Quick control to create an empty tab view that fills the main window. We + set the tab active first, to make sure that the tab item is immediately instantiated: + + \skipto TabView + \printuntil Component.onCompleted + + The tab contains a web engine view that loads web content: + + \printuntil focus + + We use the \l Action type to create new tabs: + + \quotefromfile webengine/quicknanobrowser/BrowserWindow.qml + \skipto reload + \skipto Action + \printuntil } + + We use the \l TextField Qt Quick Control within a \l ToolBar to create an address bar that + shows the current URL and where users can enter another URL: + + \skipto toolBar + \printuntil anchors.fill + \dots + \skipto TextField + \printuntil addressBar + \dots + \skipto focus + \printuntil /^\ {16}\}/ + + \section1 Handling Certificate Errors + + If the certificate of the site being loaded triggers a certificate error, we call the + \l{WebEngineCertificateError::}{defer()} QML method to pause the URL request and wait for user + input: + + \quotefromfile webengine/quicknanobrowser/BrowserWindow.qml + \skipto onCertificateError + \printuntil } + + We use the MessageDialog type to prompt users to continue or cancel the loading of the web page. + If users select \uicontrol Yes, we call the + \l{WebEngineCertificateError::}{ignoreCertificateError()} method to ignore the error and + continue loading content from the URL. If users select \uicontrol No, we call the + \l{WebEngineCertificateError::}{rejectCertificate()} method to reject the request and stop + loading content from the URL: + + \skipto MessageDialog + \printuntil /^\ {4}\}/ + + \section1 Entering and Leaving Fullscreen Mode + + We create a menu item for allowing fullscreen mode in a settings menu that we place on the tool + bar. Also, we create an action for leaving fullscreen mode by using a keyboard shortcut. + We call the \l{FullScreenRequest::}{accept()} method to accept the fullscreen request. + The methdod sets the \l{WebEngineView::}{isFullScreen} property to be equal to the + \l{FullScreenRequest::}{toggleOn} property. + + \quotefromfile webengine/quicknanobrowser/BrowserWindow.qml + \skipto onFullScreenRequested + \printuntil /^\ {16}\}/ + + When entering fullscreen mode, we display a notification using the FullScreenNotification custom + type that we create in \e FullScreenNotification.qml. + + We use the \l Action type in the settings menu to create a shortcut for leaving fullscreen mode + by pressing the escape key: + + \quotefromfile webengine/quicknanobrowser/BrowserWindow.qml + \skipto Settings + \printuntil appSettings + \skipto fullScreenSupportEnabled + \printuntil Action + \skipto Escape + \printuntil /^\ {4}\}/ + + \section1 Files and Attributions + + The example uses icons from the Tango Icon Library: + + \table + \row + \li \l{quicknanobrowser-tango}{Tango Icon Library} + \li Public Domain + \endtable +*/ diff --git a/tests/quicknanobrowser/icons/3rdparty/COPYING b/tests/quicknanobrowser/icons/3rdparty/COPYING new file mode 100644 index 0000000..9549050 --- /dev/null +++ b/tests/quicknanobrowser/icons/3rdparty/COPYING @@ -0,0 +1 @@ +The icons in this repository are herefore released into the Public Domain. diff --git a/tests/quicknanobrowser/icons/3rdparty/go-next.png b/tests/quicknanobrowser/icons/3rdparty/go-next.png new file mode 100644 index 0000000..6f3f65d Binary files /dev/null and b/tests/quicknanobrowser/icons/3rdparty/go-next.png differ diff --git a/tests/quicknanobrowser/icons/3rdparty/go-previous.png b/tests/quicknanobrowser/icons/3rdparty/go-previous.png new file mode 100644 index 0000000..93be3d1 Binary files /dev/null and b/tests/quicknanobrowser/icons/3rdparty/go-previous.png differ diff --git a/tests/quicknanobrowser/icons/3rdparty/process-stop.png b/tests/quicknanobrowser/icons/3rdparty/process-stop.png new file mode 100644 index 0000000..b68290b Binary files /dev/null and b/tests/quicknanobrowser/icons/3rdparty/process-stop.png differ diff --git a/tests/quicknanobrowser/icons/3rdparty/qt_attribution.json b/tests/quicknanobrowser/icons/3rdparty/qt_attribution.json new file mode 100644 index 0000000..a3d5563 --- /dev/null +++ b/tests/quicknanobrowser/icons/3rdparty/qt_attribution.json @@ -0,0 +1,24 @@ +{ + "Id": "quicknanobrowser-tango", + "Name": "Tango Icon Library", + "QDocModule": "qtwebengine", + "QtUsage": "Used in WebEngine Quick Nano Browser example.", + + "QtParts": [ "examples" ], + "Description": "Selected icons from the Tango Icon Library", + "Homepage": "http://tango.freedesktop.org/Tango_Icon_Library", + "Version": "0.8.90", + "DownloadLocation": "http://tango.freedesktop.org/releases/tango-icon-theme-0.8.90.tar.gz", + "LicenseId": "DocumentRef-PublicDomain", + "License": "Public Domain", + "LicenseFile": "COPYING", + "Copyright": "Ulisse Perusin +Steven Garrity +Lapo Calamandrei +Ryan Collier +Rodney Dawes +Andreas Nilsson +Tuomas Kuosmanen +Garrett LeSage +Jakub Steiner " +} diff --git a/tests/quicknanobrowser/icons/3rdparty/view-refresh.png b/tests/quicknanobrowser/icons/3rdparty/view-refresh.png new file mode 100644 index 0000000..cab4d02 Binary files /dev/null and b/tests/quicknanobrowser/icons/3rdparty/view-refresh.png differ diff --git a/tests/quicknanobrowser/main.cpp b/tests/quicknanobrowser/main.cpp new file mode 100644 index 0000000..343882f --- /dev/null +++ b/tests/quicknanobrowser/main.cpp @@ -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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "utils.h" + +#ifndef QT_NO_WIDGETS +#include +typedef QApplication Application; +#else +#include +typedef QGuiApplication Application; +#endif +#include +#include +#include + +static QUrl startupUrl() +{ + QUrl ret; + QStringList args(qApp->arguments()); + args.takeFirst(); + for (const QString &arg : qAsConst(args)) { + if (arg.startsWith(QLatin1Char('-'))) + continue; + ret = Utils::fromUserInput(arg); + if (ret.isValid()) + return ret; + } + return QUrl(QStringLiteral("https://www.qt.io")); +} + +int main(int argc, char **argv) +{ + QCoreApplication::setOrganizationName("QtExamples"); + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + Application app(argc, argv); + + QtWebEngine::initialize(); + + QQmlApplicationEngine appEngine; + Utils utils; + appEngine.rootContext()->setContextProperty("utils", &utils); + appEngine.load(QUrl("qrc:/ApplicationRoot.qml")); + if (!appEngine.rootObjects().isEmpty()) + QMetaObject::invokeMethod(appEngine.rootObjects().first(), "load", Q_ARG(QVariant, startupUrl())); + else + qFatal("Failed to load sources"); + + return app.exec(); +} diff --git a/tests/quicknanobrowser/quicknanobrowser.pro b/tests/quicknanobrowser/quicknanobrowser.pro new file mode 100644 index 0000000..de9beb0 --- /dev/null +++ b/tests/quicknanobrowser/quicknanobrowser.pro @@ -0,0 +1,24 @@ +requires(qtConfig(accessibility)) + +TEMPLATE = app +TARGET = quicknanobrowser + +HEADERS = utils.h +SOURCES = main.cpp + +OTHER_FILES += ApplicationRoot.qml \ + BrowserDialog.qml \ + BrowserWindow.qml \ + DownloadView.qml \ + FullScreenNotification.qml + +RESOURCES += resources.qrc + +QT += qml quick webengine + +qtHaveModule(widgets) { + QT += widgets # QApplication is required to get native styling with QtQuickControls +} + + +DESTDIR="$$PWD/../build" diff --git a/tests/quicknanobrowser/resources.qrc b/tests/quicknanobrowser/resources.qrc new file mode 100644 index 0000000..af52c47 --- /dev/null +++ b/tests/quicknanobrowser/resources.qrc @@ -0,0 +1,15 @@ + + + ApplicationRoot.qml + BrowserDialog.qml + BrowserWindow.qml + DownloadView.qml + FullScreenNotification.qml + + + icons/3rdparty/go-next.png + icons/3rdparty/go-previous.png + icons/3rdparty/process-stop.png + icons/3rdparty/view-refresh.png + + diff --git a/tests/quicknanobrowser/utils.h b/tests/quicknanobrowser/utils.h new file mode 100644 index 0000000..260a0c9 --- /dev/null +++ b/tests/quicknanobrowser/utils.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef UTILS_H +#define UTILS_H + +#include +#include + +class Utils : public QObject { + Q_OBJECT +public: + Q_INVOKABLE static QUrl fromUserInput(const QString& userInput); +}; + +inline QUrl Utils::fromUserInput(const QString& userInput) +{ + QFileInfo fileInfo(userInput); + if (fileInfo.exists()) + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + return QUrl::fromUserInput(userInput); +} + +#endif // UTILS_H