main.qml 7.47 KB
Newer Older
1 2 3 4 5 6 7
/*
 *   SPDX-FileCopyrightText: 2014, 2016 Mikhail Ivchenko <ematirov@gmail.com>
 *   SPDX-FileCopyrightText: 2018 Kai Uwe Broulik <kde@privat.broulik.de>
 *   SPDX-FileCopyrightText: 2020 Sora Steenvoort <sora@dillbox.me>
 *
 *   SPDX-License-Identifier: GPL-2.0-or-later
 */
Mihail Ivchenko's avatar
Mihail Ivchenko committed
8 9

import QtQuick 2.0
10
import QtWebEngine 1.5
Mihail Ivchenko's avatar
Mihail Ivchenko committed
11
import QtQuick.Layouts 1.1
Nate Graham's avatar
Nate Graham committed
12 13
import org.kde.plasma.components 2.0 as PlasmaComponents // for Menu+MenuItem
import org.kde.plasma.components 3.0 as PlasmaComponents3
14
import org.kde.plasma.core 2.0 as PlasmaCore
Mihail Ivchenko's avatar
Mihail Ivchenko committed
15 16 17 18 19
import org.kde.plasma.extras 2.0 as PlasmaExtras

ColumnLayout {
    RowLayout{
        Layout.fillWidth: true
Nate Graham's avatar
Nate Graham committed
20 21
        PlasmaComponents3.Button {
            icon.name: "go-previous"
Mihail Ivchenko's avatar
Mihail Ivchenko committed
22 23 24
            onClicked: webview.goBack()
            enabled: webview.canGoBack
        }
Nate Graham's avatar
Nate Graham committed
25 26
        PlasmaComponents3.Button {
            icon.name: "go-next"
Mihail Ivchenko's avatar
Mihail Ivchenko committed
27 28 29
            onClicked: webview.goForward()
            enabled: webview.canGoForward
        }
Nate Graham's avatar
Nate Graham committed
30
        PlasmaComponents3.TextField {
Mihail Ivchenko's avatar
Mihail Ivchenko committed
31
            Layout.fillWidth: true
32 33 34 35 36 37 38
            onAccepted: {
                var url = text;
                if (url.indexOf(":/") < 0) {
                    url = "http://" + url;
                }
                webview.url = url;
            }
39 40 41 42 43 44
            onActiveFocusChanged: {
                if (activeFocus) {
                    selectAll();
                }
            }

Mihail Ivchenko's avatar
Mihail Ivchenko committed
45 46
            text: webview.url
        }
47 48

        // this shows page-related information such as blocked popups
Nate Graham's avatar
Nate Graham committed
49
        PlasmaComponents3.ToolButton {
50 51 52 53 54 55 56 57 58 59 60
            id: infoButton

            // callback invoked when button is clicked
            property var cb

            // button itself adds sufficient visual padding
            Layout.leftMargin: -parent.spacing
            Layout.rightMargin: -parent.spacing

            onClicked: cb();

Nate Graham's avatar
Nate Graham committed
61 62 63 64 65
            PlasmaComponents3.ToolTip {
                id: tooltip
            }

            function show(text, icon, tooltipText, cb) {
66
                infoButton.text = text;
Nate Graham's avatar
Nate Graham committed
67 68
                infoButton.icon.name = icon;
                tooltip.text = tooltipText;
69 70 71 72 73 74 75 76 77
                infoButton.cb = cb;
                infoButton.visible = true;
            }

            function dismiss() {
                infoButton.visible = false;
            }
        }

Nate Graham's avatar
Nate Graham committed
78 79
        PlasmaComponents3.Button {
            icon.name: webview.loading ? "process-stop" : "view-refresh"
80
            onClicked: webview.loading ? webview.stop() : webview.reload()
Mihail Ivchenko's avatar
Mihail Ivchenko committed
81 82
        }
    }
83 84

    Item {
Mihail Ivchenko's avatar
Mihail Ivchenko committed
85 86
        Layout.fillWidth: true
        Layout.fillHeight: true
87 88

        // TODO use contentsSize but that crashes, now mostly for some sane initial size
89 90
        Layout.preferredWidth: PlasmaCore.Units.gridUnit * 36
        Layout.preferredHeight: PlasmaCore.Units.gridUnit * 18
91 92 93 94 95

        // Binding it to e.g. width will be super slow on resizing
        Timer {
            id: updateZoomTimer
            interval: 100
96 97 98 99 100

            readonly property int minViewWidth: plasmoid.configuration.minViewWidth
            readonly property bool useMinViewWidth: plasmoid.configuration.useMinViewWidth
            readonly property int constantZoomFactor: plasmoid.configuration.constantZoomFactor

101
            onTriggered: {
102 103 104 105 106 107 108 109 110 111 112 113 114 115
                var newZoom = 1;
                if (useMinViewWidth) {
                    // Try to fit contents for a smaller screen
                    newZoom = Math.min(1, webview.width / minViewWidth);
                    // make sure value is valid
                    newZoom = Math.max(0.25, newZoom);
                } else {
                    newZoom = constantZoomFactor / 100.0;
                }
                webview.zoomFactor = newZoom;
                // setting the zoom factor does not always work on the first try; also, numbers get rounded
                if (Math.round(1000 * webview.zoomFactor) != Math.round(1000 * newZoom)) {
                    updateZoomTimer.restart();
                }
116
            }
117 118 119 120 121 122 123 124 125 126 127 128
        }

        // This reimplements WebEngineView context menu for links to add a "open externally" entry
        // since you cannot add custom items there yet
        // there's a FIXME comment about that in QQuickWebEngineViewPrivate::contextMenuRequested
        PlasmaComponents.Menu {
            id: linkContextMenu
            visualParent: webview

            property string link

            PlasmaComponents.MenuItem {
129
                text: i18nc("@action:inmenu", "Open Link in Browser")
130 131 132
                icon:  "internet-web-browser"
                onClicked: Qt.openUrlExternally(linkContextMenu.link)
            }
133

134
            PlasmaComponents.MenuItem {
135
                text: i18nc("@action:inmenu", "Copy Link Address")
136 137 138
                icon: "edit-copy"
                onClicked: webview.triggerWebAction(WebEngineView.CopyLinkToClipboard)
            }
139 140 141
        }

        WebEngineView {
Mihail Ivchenko's avatar
Mihail Ivchenko committed
142 143
            id: webview
            anchors.fill: parent
144 145
            onUrlChanged: plasmoid.configuration.url = url;
            Component.onCompleted: url = plasmoid.configuration.url;
146

147 148 149 150 151 152 153 154 155 156 157 158 159 160
            readonly property bool useMinViewWidth : plasmoid.configuration.useMinViewWidth

            Connections {
                target: plasmoid.configuration
                
                onMinViewWidthChanged: updateZoomTimer.start()

                onUseMinViewWidthChanged: updateZoomTimer.start()

                onConstantZoomFactorChanged: updateZoomTimer.start()

                onUseConstantZoomChanged: updateZoomTimer.start()
            }

161 162 163 164 165 166 167 168
            onLinkHovered: {
                if (hoveredUrl.toString() !== "") {
                    mouseArea.cursorShape = Qt.PointingHandCursor;
                } else {
                    mouseArea.cursorShape = Qt.ArrowCursor;
                }
            }

169 170 171 172 173 174
            onWidthChanged: {
                if (useMinViewWidth) {
                    updateZoomTimer.start()
                }
            }

175
            onLoadingChanged: {
176 177
                if (loadRequest.status === WebEngineLoadRequest.LoadStartedStatus) {
                    infoButton.dismiss();
178
                } else if (loadRequest.status === WebEngineLoadRequest.LoadSucceededStatus && useMinViewWidth) {
179 180 181
                    updateZoomTimer.start();
                }
            }
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203

            onContextMenuRequested: {
                if (request.mediaType === ContextMenuRequest.MediaTypeNone && request.linkUrl.toString() !== "") {
                    linkContextMenu.link = request.linkUrl;
                    linkContextMenu.open(request.x, request.y);
                    request.accepted = true;
                }
            }

            onNewViewRequested: {
                var url = request.requestedUrl;

                if (request.userInitiated) {
                    Qt.openUrlExternally(url);
                } else {
                    infoButton.show(i18nc("An unwanted popup was blocked", "Popup blocked"), "document-close",
                                    i18n("Click here to open the following blocked popup:\n%1", url), function () {
                        Qt.openUrlExternally(url);
                        infoButton.dismiss();
                    });
                }
            }
Mihail Ivchenko's avatar
Mihail Ivchenko committed
204 205
        }

206 207 208 209 210 211 212 213 214 215 216 217 218
        MouseArea {
            id: mouseArea
            anchors.fill: parent
            acceptedButtons: Qt.BackButton | Qt.ForwardButton
            onPressed: {
                if (mouse.button === Qt.BackButton) {
                    webview.goBack();
                } else if (mouse.button === Qt.ForwardButton) {
                    webview.goForward();
                }
            }
        }
    }
Mihail Ivchenko's avatar
Mihail Ivchenko committed
219
}