Changeset View
Changeset View
Standalone View
Standalone View
applets/notifications/package/contents/ui/SelectableLabel.qml
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * Copyright 2011 Marco Martin <notmart@gmail.com> | ||||
3 | * Copyright 2014, 2019 Kai Uwe Broulik <kde@privat.broulik.de> | ||||
4 | * | ||||
5 | * This program is free software; you can redistribute it and/or | ||||
6 | * modify it under the terms of the GNU General Public License as | ||||
7 | * published by the Free Software Foundation; either version 2 of | ||||
8 | * the License or (at your option) version 3 or any later version | ||||
9 | * accepted by the membership of KDE e.V. (or its successor approved | ||||
10 | * by the membership of KDE e.V.), which shall act as a proxy | ||||
11 | * defined in Section 14 of version 3 of the license. | ||||
12 | * | ||||
13 | * This program is distributed in the hope that it will be useful, | ||||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
16 | * GNU General Public License for more details. | ||||
17 | * | ||||
18 | * You should have received a copy of the GNU General Public License | ||||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/> | ||||
20 | */ | ||||
21 | | ||||
22 | import QtQuick 2.8 | ||||
23 | import QtQuick.Layouts 1.1 | ||||
24 | | ||||
25 | import org.kde.plasma.core 2.0 as PlasmaCore | ||||
26 | import org.kde.plasma.components 2.0 as PlasmaComponents | ||||
27 | import org.kde.plasma.extras 2.0 as PlasmaExtras | ||||
28 | | ||||
29 | // NOTE This wrapper item is needed for QQC ScrollView to work | ||||
30 | // In NotificationItem we just do SelectableLabel {} and then it gets confused | ||||
31 | // as to which is the "contentItem" | ||||
32 | Item { | ||||
33 | id: bodyTextContainer | ||||
34 | | ||||
35 | property alias text: bodyText.text | ||||
36 | property alias font: bodyText.font | ||||
37 | | ||||
38 | property int cursorShape | ||||
39 | | ||||
40 | property QtObject contextMenu: null | ||||
41 | | ||||
42 | signal clicked(var mouse) | ||||
43 | signal linkActivated(string link) | ||||
44 | | ||||
45 | implicitWidth: bodyText.paintedWidth | ||||
46 | implicitHeight: bodyText.paintedHeight | ||||
47 | | ||||
48 | PlasmaExtras.ScrollArea { | ||||
49 | id: bodyTextScrollArea | ||||
50 | | ||||
51 | anchors.fill: parent | ||||
52 | | ||||
53 | flickableItem.boundsBehavior: Flickable.StopAtBounds | ||||
54 | flickableItem.flickableDirection: Flickable.VerticalFlick | ||||
55 | horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff | ||||
56 | | ||||
57 | TextEdit { | ||||
58 | id: bodyText | ||||
59 | width: bodyTextScrollArea.width | ||||
60 | // TODO check that this doesn't causes infinite loops when it starts adding and removing the scrollbar | ||||
61 | //width: bodyTextScrollArea.viewport.width | ||||
62 | //enabled: !Settings.isMobile | ||||
63 | | ||||
64 | color: PlasmaCore.ColorScope.textColor | ||||
65 | selectedTextColor: theme.viewBackgroundColor | ||||
66 | selectionColor: theme.viewFocusColor | ||||
67 | font.capitalization: theme.defaultFont.capitalization | ||||
68 | font.family: theme.defaultFont.family | ||||
69 | font.italic: theme.defaultFont.italic | ||||
70 | font.letterSpacing: theme.defaultFont.letterSpacing | ||||
71 | font.pointSize: theme.defaultFont.pointSize | ||||
72 | font.strikeout: theme.defaultFont.strikeout | ||||
73 | font.underline: theme.defaultFont.underline | ||||
74 | font.weight: theme.defaultFont.weight | ||||
75 | font.wordSpacing: theme.defaultFont.wordSpacing | ||||
76 | renderType: Text.NativeRendering | ||||
77 | selectByMouse: true | ||||
78 | readOnly: true | ||||
79 | wrapMode: Text.Wrap | ||||
80 | textFormat: TextEdit.RichText | ||||
81 | | ||||
82 | onLinkActivated: bodyTextContainer.linkActivated(link) | ||||
83 | | ||||
84 | // ensure selecting text scrolls the view as needed... | ||||
85 | onCursorRectangleChanged: { | ||||
86 | var flick = bodyTextScrollArea.flickableItem | ||||
87 | if (flick.contentY >= cursorRectangle.y) { | ||||
88 | flick.contentY = cursorRectangle.y | ||||
89 | } else if (flick.contentY + flick.height <= cursorRectangle.y + cursorRectangle.height) { | ||||
90 | flick.contentY = cursorRectangle.y + cursorRectangle.height - flick.height | ||||
91 | } | ||||
92 | } | ||||
93 | MouseArea { | ||||
94 | property int selectionStart | ||||
95 | property point mouseDownPos: Qt.point(-999, -999); | ||||
96 | | ||||
97 | anchors.fill: parent | ||||
98 | acceptedButtons: Qt.RightButton | Qt.LeftButton | ||||
99 | cursorShape: { | ||||
100 | if (bodyText.hoveredLink) { | ||||
101 | return Qt.PointingHandCursor; | ||||
102 | } else if (bodyText.selectionStart !== bodyText.selectionEnd) { | ||||
103 | return Qt.IBeamCursor; | ||||
104 | } else { | ||||
105 | return bodyTextContainer.cursorShape || Qt.IBeamCursor; | ||||
106 | } | ||||
107 | } | ||||
108 | preventStealing: true // don't let us accidentally drag the Flickable | ||||
109 | | ||||
110 | onPressed: { | ||||
111 | if (mouse.button === Qt.RightButton) { | ||||
112 | contextMenu = contextMenuComponent.createObject(bodyText); | ||||
113 | contextMenu.link = bodyText.linkAt(mouse.x, mouse.y); | ||||
114 | | ||||
115 | contextMenu.closed.connect(function() { | ||||
116 | contextMenu.destroy(); | ||||
117 | contextMenu = null; | ||||
118 | }); | ||||
119 | contextMenu.open(mouse.x, mouse.y); | ||||
120 | return; | ||||
121 | } | ||||
122 | | ||||
123 | mouseDownPos = Qt.point(mouse.x, mouse.y); | ||||
124 | selectionStart = bodyText.positionAt(mouse.x, mouse.y); | ||||
125 | var pos = bodyText.positionAt(mouse.x, mouse.y); | ||||
126 | // deselect() would scroll to the end which we don't want | ||||
127 | bodyText.select(pos, pos); | ||||
128 | } | ||||
129 | | ||||
130 | onReleased: { | ||||
131 | // emulate "onClicked" | ||||
132 | var manhattanLength = Math.abs(mouseDownPos.x - mouse.x) + Math.abs(mouseDownPos.y - mouse.y); | ||||
133 | if (manhattanLength <= Qt.styleHints.startDragDistance) { | ||||
134 | var link = bodyText.linkAt(mouse.x, mouse.y); | ||||
135 | if (link) { | ||||
136 | Qt.openUrlExternally(link); | ||||
137 | } else { | ||||
138 | bodyTextContainer.clicked(mouse); | ||||
139 | } | ||||
140 | } | ||||
141 | | ||||
142 | // emulate selection clipboard | ||||
143 | if (bodyText.selectedText) { | ||||
144 | plasmoid.nativeInterface.setSelectionClipboardText(bodyText.selectedText); | ||||
145 | } | ||||
146 | | ||||
147 | mouseDownPos = Qt.point(-999, -999); | ||||
148 | } | ||||
149 | | ||||
150 | // HACK to be able to select text whilst still getting all mouse events to the MouseArea | ||||
151 | onPositionChanged: { | ||||
152 | if (pressed) { | ||||
153 | var pos = bodyText.positionAt(mouseX, mouseY); | ||||
154 | if (selectionStart < pos) { | ||||
155 | bodyText.select(selectionStart, pos); | ||||
156 | } else { | ||||
157 | bodyText.select(pos, selectionStart); | ||||
158 | } | ||||
159 | } | ||||
160 | } | ||||
161 | } | ||||
162 | } | ||||
163 | } | ||||
164 | | ||||
165 | Component { | ||||
166 | id: contextMenuComponent | ||||
167 | | ||||
168 | EditContextMenu { | ||||
169 | target: bodyText | ||||
170 | } | ||||
171 | } | ||||
172 | } |