Implement selection across multiple MessageDelegates

BUG: 457669
This commit is contained in:
Tobias Fella
2022-11-26 18:10:10 +01:00
parent 99ad4130d9
commit 405c2c3d2d
3 changed files with 96 additions and 3 deletions

View File

@@ -13,6 +13,13 @@ import org.kde.neochat 1.0
TimelineContainer {
id: messageDelegate
function positionAt(x, y) {
let point = label.mapFromItem(messageDelegate, x, y)
return label.positionAt(point.x, point.y)
}
property alias selectedText: label.selectedText
property bool isEmote: false
onOpenContextMenu: openMessageContext(model, label.selectedText, Controller.plainText(label.textDocument))
@@ -22,6 +29,7 @@ TimelineContainer {
id: label
Layout.fillWidth: true
isEmote: messageDelegate.isEmote
isDelegate: true
}
Loader {
id: linkPreviewLoader

View File

@@ -16,6 +16,8 @@ TextEdit {
property bool isEmote: false
property bool isDelegate: false
readonly property var linkRegex: /(href=["'])?(\b(https?):\/\/[^\s\<\>\"\'\\]+)/g
property string textMessage: model.display.includes("http")
? model.display.replace(linkRegex, function() {
@@ -41,8 +43,11 @@ TextEdit {
persistentSelection: true
// Work around QTBUG 93281
Component.onCompleted: if (text.includes("<img")) {
Controller.forceRefreshTextDocument(contentLabel.textDocument, contentLabel)
Component.onCompleted: {
updateSelection();
if (text.includes("<img")) {
Controller.forceRefreshTextDocument(contentLabel.textDocument, contentLabel)
}
}
text: "<style>
@@ -103,4 +108,26 @@ a{
enabled: !parent.hoveredLink && !spoilerRevealed
onTapped: spoilerRevealed = true
}
Connections {
target: selectionArea
enabled: contentLabel.isDelegate
function onSelectionChanged() {
updateSelection();
}
}
function updateSelection() {
if (index < selectionArea.lowerIndex || index > selectionArea.upperIndex) {
contentLabel.select(0, 0);
} else if (index > selectionArea.lowerIndex && index < selectionArea.upperIndex) {
contentLabel.selectAll();
} else if (index === selectionArea.selectionStartIndex && index === selectionArea.selectionEndIndex) {
contentLabel.select(selectionArea.upperPos, selectionArea.lowerPos);
} else if (index === selectionArea.upperIndex) {
contentLabel.select(selectionArea.upperPos, contentLabel.length);
} else if (index === selectionArea.lowerIndex) {
contentLabel.select(0, selectionArea.lowerPos);
}
}
}

View File

@@ -549,8 +549,66 @@ Kirigami.ScrollablePage {
}
}
}
}
function indexAtRelative(x, y) {
return indexAt(x + contentX, y + contentY)
}
MouseArea {
id: selectionArea
property int selectionStartIndex
property int selectionEndIndex
property int selectionStartPos
property int selectionEndPos
property int upperIndex: selectionStartIndex > selectionEndIndex ? selectionStartIndex : selectionEndIndex
property int upperPos: selectionStartIndex > selectionEndIndex ? selectionStartPos : (selectionStartIndex == selectionEndIndex ? (selectionStartPos > selectionEndPos ? selectionEndPos : selectionStartPos) : selectionEndPos)
property int lowerIndex: selectionStartIndex > selectionEndIndex ? selectionEndIndex : selectionStartIndex
property int lowerPos: selectionStartIndex > selectionEndIndex ? selectionEndPos : (selectionStartIndex == selectionEndIndex ? (selectionStartPos > selectionEndPos ? selectionStartPos : selectionEndPos) : selectionStartPos)
signal selectionChanged
anchors.fill: parent
function indexAndPos(x, y) {
const index = messageListView.indexAtRelative(x, y);
if (index == -1) {
return;
}
const item = messageListView.itemAtIndex(index);
const relItemY = item.y - messageListView.contentY;
const pos = item.positionAt(x, y - relItemY);
return [index, pos]
}
onPressed: {
[selectionEndIndex, selectionEndPos] = indexAndPos(mouse.x, mouse.y);
[selectionStartIndex, selectionStartPos] = indexAndPos(mouse.x, mouse.y);
selectionChanged();
}
onPositionChanged: {
if (!pressed) {
return
}
[selectionEndIndex, selectionEndPos] = indexAndPos(mouse.x, mouse.y);
selectionChanged();
}
}
Kirigami.Action {
onTriggered: {
var text = ""
for (let i = selectionArea.upperIndex; i >= selectionArea.lowerIndex; i--) {
text += messageListView.itemAtIndex(i).selectedText
if (i > selectionArea.lowerIndex) {
text += " "
}
}
Clipboard.saveText(text)
}
shortcut: "Ctrl+C"
}
}
footer: ChatBox {
id: chatBox