KTextAddons

textautogeneratelistviewtextselection.cpp
1/*
2 SPDX-FileCopyrightText: 2021 David Faure <faure@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "textautogeneratelistviewtextselection.h"
8#include "textautogeneratelistviewdelegate.h"
9
10#include <QTextCursor>
11#include <QTextDocument>
12#include <QTextDocumentFragment>
13using namespace TextAutogenerateText;
14
15TextAutogenerateListViewTextSelection::TextAutogenerateListViewTextSelection(TextAutogenerateListViewDelegate *delegate, QObject *parent)
16 : QObject(parent)
17 , mDelegate(delegate)
18{
19}
20
21bool TextAutogenerateListViewTextSelection::hasSelection() const
22{
23 return mStartIndex.isValid() && mEndIndex.isValid() && ((mStartPos > -1 && mEndPos > -1 && mStartPos != mEndPos));
24}
25
26TextAutogenerateListViewTextSelection::OrderedPositions TextAutogenerateListViewTextSelection::orderedPositions() const
27{
28 Q_ASSERT(!mStartIndex.isValid() || !mEndIndex.isValid() || mStartIndex.model() == mEndIndex.model());
29 TextAutogenerateListViewTextSelection::OrderedPositions ret{mStartIndex.row(), mStartPos, mEndIndex.row(), mEndPos};
30 if (ret.fromRow > ret.toRow) {
31 std::swap(ret.fromRow, ret.toRow);
32 std::swap(ret.fromCharPos, ret.toCharPos);
33 }
34 return ret;
35}
36
37QTextCursor TextAutogenerateListViewTextSelection::selectionForIndex(const QModelIndex &index, QTextDocument *doc) const
38{
39 if (!hasSelection()) {
40 return {};
41 }
42 Q_ASSERT(index.model() == mStartIndex.model());
43 Q_ASSERT(index.model() == mEndIndex.model());
44
45 const OrderedPositions ordered = orderedPositions();
46 int fromCharPos = ordered.fromCharPos;
47 int toCharPos = ordered.toCharPos;
48 // qDebug() << "BEFORE toCharPos" << toCharPos << " fromCharPos " << fromCharPos;
49 QTextCursor cursor(doc);
50
51 // qDebug() << "AFTER toCharPos" << toCharPos << " fromCharPos " << fromCharPos;
52 const int row = index.row();
53 if (row == ordered.fromRow)
54 cursor.setPosition(qMax(fromCharPos, 0));
55 else if (row > ordered.fromRow)
56 cursor.setPosition(0);
57 else
58 return {};
59 if (row == ordered.toRow)
60 cursor.setPosition(qMax(toCharPos, 0), QTextCursor::KeepAnchor);
61 else if (row < ordered.toRow)
62 cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
63 else
64 return {};
65 return cursor;
66}
67
68void TextAutogenerateListViewTextSelection::selectionText(const OrderedPositions ordered,
69 Format format,
70 int row,
71 const QModelIndex &index,
72 QTextDocument *doc,
73 QString &str) const
74{
75 const QTextCursor cursor = selectionForIndex(index, doc);
76 const QTextDocumentFragment fragment(cursor);
77 str += format == Format::Text ? fragment.toPlainText() : fragment.toHtml();
78 if (row < ordered.toRow) {
79 str += QLatin1Char('\n');
80 }
81}
82
83QString TextAutogenerateListViewTextSelection::selectedText(Format format) const
84{
85 if (!hasSelection()) {
86 return {};
87 }
88 const OrderedPositions ordered = orderedPositions();
89 QString str;
90 for (int row = ordered.fromRow; row <= ordered.toRow; ++row) {
91 const QModelIndex index = QModelIndex(mStartIndex).siblingAtRow(row);
92 QTextDocument *doc = mDelegate->documentForIndex(index, -1);
93 if (doc) {
94 selectionText(ordered, format, row, index, doc, str);
95 }
96 }
97 return str;
98}
99
100bool TextAutogenerateListViewTextSelection::contains(const QModelIndex &index, int charPos) const
101{
102 if (!hasSelection()) {
103 return false;
104 }
105 Q_ASSERT(index.model() == mStartIndex.model());
106 const int row = index.row();
107 const OrderedPositions ordered = orderedPositions();
108 if (row == ordered.fromRow) {
109 if (row == ordered.toRow) // single line selection
110 return ordered.fromCharPos <= charPos && charPos <= ordered.toCharPos;
111 return ordered.fromCharPos <= charPos;
112 } else if (row == ordered.toRow) {
113 return charPos <= ordered.toCharPos;
114 } else {
115 return row > ordered.fromRow && row < ordered.toRow;
116 }
117}
118
119void TextAutogenerateListViewTextSelection::clear()
120{
121 const QModelIndex index = mStartIndex;
122 const OrderedPositions ordered = orderedPositions();
123
124 mStartIndex = QPersistentModelIndex{};
125 mEndIndex = QPersistentModelIndex{};
126 mStartPos = -1;
127 mEndPos = -1;
128
129 // Repaint indexes that are no longer selected
130 if (ordered.fromRow > -1) {
131 if (ordered.toRow > -1) {
132 for (int row = ordered.fromRow; row <= ordered.toRow; ++row) {
133 Q_EMIT repaintNeeded(index.siblingAtRow(row));
134 }
135 } else {
136 Q_EMIT repaintNeeded(index);
137 }
138 }
139}
140
141void TextAutogenerateListViewTextSelection::setTextSelectionStart(const QModelIndex &index, int charPos)
142{
143 clear();
144 Q_ASSERT(index.isValid());
145 mStartIndex = index;
146 mStartPos = charPos;
147}
148
149void TextAutogenerateListViewTextSelection::setTextSelectionEnd(const QModelIndex &index, int charPos)
150{
151 int from = mEndIndex.row();
152 int to = index.row();
153 if (from != -1 && from != to) {
154 mEndIndex = index;
155
156 if (from > to) { // reducing (moving the end up)
157 std::swap(from, to);
158 ++from; // 'from' is @p index, it's under the mouse anyway
159 } else { // extending (moving the down)
160 --to; // 'to' is @p index, it's under the mouse anyway
161 }
162
163 // Repaint indexes that are no longer selected
164 // or that got selected when moving the mouse down fast
165 for (int row = from; row <= to; ++row) {
166 Q_EMIT repaintNeeded(index.siblingAtRow(row));
167 }
168 }
169 Q_ASSERT(index.isValid());
170 mEndIndex = index;
171 mEndPos = charPos;
172}
173
174void TextAutogenerateListViewTextSelection::selectWord(const QModelIndex &index, int charPos, QTextDocument *doc)
175{
176 QTextCursor cursor(doc);
177 cursor.setPosition(charPos);
178 clear();
180 mStartIndex = index;
181 mEndIndex = index;
182 mStartPos = cursor.selectionStart();
183 mEndPos = cursor.selectionEnd();
184}
185
186void TextAutogenerateListViewTextSelection::selectWordUnderCursor(const QModelIndex &index, int charPos)
187{
188 QTextDocument *doc = mDelegate->documentForIndex(index, -1);
189 selectWord(index, charPos, doc);
190}
191
192void TextAutogenerateListViewTextSelection::selectMessage(const QModelIndex &index)
193{
194 Q_ASSERT(index.isValid());
195 clear();
196 mStartIndex = index;
197 mEndIndex = index;
198 mStartPos = 0;
199 QTextDocument *doc = mDelegate->documentForIndex(index, -1);
200 if (doc) {
201 mEndPos = doc->characterCount() - 1;
202 }
203}
204
205bool TextAutogenerateListViewTextSelection::mightStartDrag() const
206{
207 return mMightStartDrag;
208}
209
210void TextAutogenerateListViewTextSelection::setMightStartDrag(bool newMightStartDrag)
211{
212 mMightStartDrag = newMightStartDrag;
213}
214
215#include "moc_textautogeneratelistviewtextselection.cpp"
bool isValid() const const
const QAbstractItemModel * model() const const
int row() const const
QModelIndex siblingAtRow(int row) const const
Q_EMITQ_EMIT
void select(SelectionType selection)
int selectionEnd() const const
int selectionStart() const const
void setPosition(int pos, MoveMode m)
int characterCount() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 25 2025 12:06:13 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.