1 /****************************************************************************
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
6 ** This file is part of the QtBrowser project.
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 2 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.GPLv2 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU General Public License version 2 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 3.0 as published by the Free Software
28 ** Foundation and appearing in the file LICENSE.GPL included in the
29 ** packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 3.0 requirements will be
31 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ****************************************************************************/
39 import QtWebEngine 1.1
40 import QtQuick.Controls 1.4
41 import QtQuick.Controls.Styles 1.4
42 import QtQuick.Layouts 1.2
43 import QtGraphicalEffects 1.0
45 import io.qt.browser 1.0
51 property int itemWidth: browserWindow.width / 2
52 property int itemHeight: browserWindow.height / 2
54 property bool interactive: true
56 property alias currentIndex: pathView.currentIndex
57 property alias count: pathView.count
59 property string viewState: "page"
62 if (viewState == "page")
63 homeScreen.state = "disabled"
66 property QtObject otrProfile: WebEngineProfile {
70 property QtObject defaultProfile: WebEngineProfile {
71 storageName: "YABProfile"
79 property alias webView: webEngineView
80 property alias title: webEngineView.title
82 property var image: QtObject {
83 property var snapshot: null
84 property string url: "about:blank"
87 visible: opacity != 0.0
90 NumberAnimation { duration: animationDuration }
98 findBar.visible = !findBar.visible
99 if (findBar.visible) {
100 findTextField.forceActiveFocus()
105 FeaturePermissionBar {
124 profile: settingsView.privateBrowsingEnabled ? otrProfile : defaultProfile
125 enabled: root.interactive
127 function takeSnapshot() {
128 if (webEngineView.url == "" || webEngineView.url == "about:blank") {
129 tabItem.image.url = "about:blank"
130 tabItem.image.snapshot = null
134 if (tabItem.image.url == webEngineView.url || tabItem.opacity != 1.0)
137 tabItem.image.url = webEngineView.url
138 webEngineView.grabToImage(function(result) {
139 tabItem.image.snapshot = result;
140 console.log("takeSnapshot("+result.url+")")
144 // Trigger a refresh to check if the new url is bookmarked.
145 onUrlChanged: navigation.refresh()
148 settings.autoLoadImages: settingsView.autoLoadImages
149 settings.javascriptEnabled: !settingsView.javaScriptDisabled
151 // This should be enabled as we can switch to Qt 5.6 (i.e. import QtWebEngine 1.2)
152 // settings.pluginsEnabled: settingsView.pluginsEnabled
156 navigation.state = "enabled"
159 onCertificateError: {
160 if (!acceptedCertificates.shouldAutoAccept(error)){
162 sslDialog.enqueue(error)
164 error.ignoreCertificateError()
168 onNewViewRequested: {
169 webEngineView.takeSnapshot()
171 if (!request.userInitiated) {
172 print("Warning: Blocked a popup window.")
176 tab = tabView.createEmptyTab()
181 if (request.destination == WebEngineView.NewViewInTab) {
182 pathView.positionViewAtIndex(tabView.count - 1, PathView.Center)
183 request.openIn(tab.webView)
184 } else if (request.destination == WebEngineView.NewViewInBackgroundTab) {
185 var index = pathView.currentIndex
186 request.openIn(tab.webView)
187 pathView.positionViewAtIndex(index, PathView.Center)
188 } else if (request.destination == WebEngineView.NewViewInDialog) {
189 request.openIn(tab.webView)
191 request.openIn(tab.webView)
195 onFeaturePermissionRequested: {
196 permBar.securityOrigin = securityOrigin;
197 permBar.requestedFeature = feature;
198 permBar.visible = true;
204 visible: desaturation != 0.0
205 anchors.fill: webEngineView
206 source: webEngineView
207 desaturation: root.interactive ? 0.0 : 1.0
209 Behavior on desaturation {
210 NumberAnimation { duration: animationDuration }
216 visible: radius != 0.0
217 anchors.fill: desaturate
219 radius: desaturate.desaturation * 25
224 enabled: root.interactive
225 target: webEngineView
227 onTouchYChanged: browserWindow.touchY = tracker.touchY
228 onYVelocityChanged: browserWindow.velocityY = yVelocity
230 browserWindow.touchY = tracker.touchY
231 browserWindow.velocityY = yVelocity
232 browserWindow.touchReference = tracker.touchY
233 browserWindow.touchGesture = true
234 navigation.state = "tracking"
237 browserWindow.velocityY = yVelocity
238 browserWindow.touchGesture = false
239 navigation.state = "tracking"
241 onScrollDirectionChanged: {
242 browserWindow.velocityY = 0
243 browserWindow.touchReference = tracker.touchY
249 if (inputPanel.state === "visible")
251 if (webEngineView.url == "" || webEngineView.url == "about:blank")
256 visible: opacity != 0.0
260 y: placeholder.height - navigation.y
261 anchors.horizontalCenter: parent.horizontalCenter
262 source: "qrc:///icon"
267 top: placeholder.bottom
269 horizontalCenter: placeholder.horizontalCenter
271 font.family: defaultFontFamily
274 text: "Qt WebBrowser"
277 Behavior on opacity {
278 NumberAnimation { duration: animationDuration }
285 right: webEngineView.right
286 left: webEngineView.left
287 top: webEngineView.top
289 height: toolBarSize / 2 + 10
300 bottom: parent.bottom
306 Layout.fillWidth: true
308 webEngineView.findText(text)
310 style: TextFieldStyle {
312 font.family: defaultFontFamily
314 selectionColor: uiHighlightColor
315 selectedTextColor: "black"
316 placeholderTextColor: placeholderColor
317 background: Rectangle {
319 implicitHeight: toolBarSize / 2
320 border.color: textFieldStrokeColor
329 bottom: parent.bottom
337 bottom: parent.bottom
339 color: uiSeparatorColor
342 id: findBackwardButton
343 iconSource: "qrc:///back"
344 implicitHeight: parent.height
345 onClicked: webEngineView.findText(findTextField.text, WebEngineView.FindBackward)
351 bottom: parent.bottom
353 color: uiSeparatorColor
356 id: findForwardButton
357 iconSource: "qrc:///forward"
358 implicitHeight: parent.height
359 onClicked: webEngineView.findText(findTextField.text)
365 bottom: parent.bottom
367 color: uiSeparatorColor
371 iconSource: "qrc:///stop"
372 implicitHeight: parent.height
373 onClicked: findBar.visible = false
384 function makeCurrent(index) {
386 pathView.positionViewAtIndex(index, PathView.Center)
390 function createEmptyTab() {
391 var tab = add(tabComponent)
395 function add(component) {
396 if (listModel.count === tabViewMaxTabs) {
397 homeScreen.messageBox.state = "tabsfull"
398 homeScreen.state = "enabled"
399 homeScreen.forceActiveFocus()
403 var element = {"item": null }
404 element.item = component.createObject(root, { "width": root.width, "height": root.height, "opacity": 0.0 })
406 if (element.item == null) {
407 console.log("PageView::add(): Error creating object");
411 listModel.append(element)
415 function remove(index) {
416 pathView.interactive = false
417 pathView.currentItem.state = ""
418 pathView.currentItem.visible = false
419 listModel.remove(index)
420 pathView.decrementCurrentIndex()
421 pathView.interactive = true
422 if (listModel.count == 0)
423 engine.rootWindow.close()
426 function get(index) {
427 return listModel.get(index)
438 property real visibility: 0.0
439 property bool isCurrentItem: PathView.isCurrentItem
441 visible: PathView.onPath && visibility != 0.0
442 state: isCurrentItem ? root.viewState : "list"
445 NumberAnimation { duration: animationDuration }
451 PropertyChanges { target: wrapper; width: root.width; height: root.height; visibility: 0.0 }
452 PropertyChanges { target: pathView; interactive: false }
453 PropertyChanges { target: item; opacity: 1.0 }
454 PropertyChanges { target: navigation; state: "enabled" }
458 PropertyChanges { target: wrapper; width: itemWidth; height: itemHeight; visibility: 1.0 }
459 PropertyChanges { target: pathView; interactive: true }
460 PropertyChanges { target: item; opacity: 0.0 }
464 transitions: Transition {
466 PropertyAnimation { property: "visibility"; duration: animationDuration; easing.type : Easing.InSine }
467 PropertyAnimation { properties: "x,y"; duration: animationDuration; easing.type: Easing.InSine }
468 PropertyAnimation { properties: "width,height"; duration: animationDuration; easing.type: Easing.InSine }
472 width: itemWidth; height: itemHeight
474 if (pathView.count == 1)
476 if (pathView.count < 4)
477 return isCurrentItem ? 1.0 : 0.5
482 var index1 = pathView.currentIndex - 2
483 var index2 = pathView.currentIndex - 1
484 var index4 = (pathView.currentIndex + 1) % pathView.count
485 var index5 = (pathView.currentIndex + 2) % pathView.count
488 index1 = pathView.count + index1
490 index2 = pathView.count + index2
508 enabled: pathView.interactive
509 anchors.fill: wrapper
511 mouse.accepted = true
515 if (index == pathView.currentIndex) {
516 if (root.viewState == "list")
517 root.viewState = "page"
520 pathView.currentIndex = index
526 property real size: 24
530 horizontalCenter: parent.horizontalCenter
532 color: iconOverlayColor
534 width: snapshot.width
535 height: snapshot.height
541 samples: shadow.size * 2
543 transparentBorder: true
544 visible: wrapper.visibility == 1.0
553 if (!item.image.snapshot)
554 return "qrc:///about"
555 return item.image.snapshot.url
559 enabled: index == pathView.currentIndex && !pathView.moving && !pathView.flicking && wrapper.visibility == 1.0
560 opacity: enabled ? 1.0 : 0.0
561 visible: wrapper.visibility == 1.0
562 width: image.sourceSize.width
563 height: image.sourceSize.height - 2
565 color: iconOverlayColor
567 horizontalCenter: parent.right
568 verticalCenter: parent.top
573 if (closeButton.pressed)
581 source: "qrc:///delete"
586 mouse.accepted = true
587 remove(pathView.currentIndex)
591 Behavior on opacity {
592 NumberAnimation { duration: animationDuration / 2 }
596 anchors.fill: wrapper
603 horizontalCenter: parent.horizontalCenter
605 horizontalAlignment: Text.AlignHCenter
606 width: parent.width - image.width
607 elide: Text.ElideRight
610 font.family: defaultFontFamily
611 color: settingsView.privateBrowsingEnabled ? "white" : "#0B508C"
612 visible: wrapper.isCurrentItem && wrapper.visibility == 1.0
628 highlightMoveDuration: animationDuration
629 highlightRangeMode: PathView.StrictlyEnforceRange
630 snapMode: PathView.SnapToItem
631 preferredHighlightBegin: 0.5
632 preferredHighlightEnd: 0.5
634 dragMargin: itemHeight
636 focus: pathView.interactive
638 property real offset: 30
640 property real margin: {
642 return root.width / 4 - offset
644 return root.width / 8 + offset
646 return root.width / 8 - offset
651 property real middle: {
653 return (pathView.height / 2) - (currentItem.visibility * 50)
654 return (pathView.height / 2 - 50)
658 startX: pathView.margin
659 startY: pathView.middle
661 PathPercent { value: 0.0 }
662 PathAttribute { name: "itemZ"; value: 0 }
664 x: (pathView.width - itemWidth) / 2 + 106
667 PathPercent { value: 0.49 }
668 PathAttribute { name: "itemZ"; value: 6 }
670 PathLine { relativeX: 0; relativeY: 0 }
673 x: (pathView.width - itemWidth) / 2 + itemWidth - 106
676 PathPercent { value: 0.51 }
678 PathLine { relativeX: 0; relativeY: 0 }
680 PathAttribute { name: "itemZ"; value: 4 }
682 x: pathView.width - pathView.margin
685 PathPercent { value: 1 }
686 PathAttribute { name: "itemZ"; value: 2 }
689 Keys.onLeftPressed: decrementCurrentIndex()
690 Keys.onRightPressed: incrementCurrentIndex()