KTextEditor

documentcursor.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org>
3 SPDX-FileCopyrightText: 2012 Dominik Haumann <dhaumann@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "documentcursor.h"
9
10namespace KTextEditor
11{
13 : m_document(document)
14 , m_cursor(KTextEditor::Cursor::invalid())
15{
16 // we require a valid document
17 Q_ASSERT(m_document);
18}
19
21 : m_document(document)
22 , m_cursor(position)
23{
24 // we require a valid document
25 Q_ASSERT(m_document);
26}
27
29 : m_document(document)
30 , m_cursor(line, column)
31{
32 // we require a valid document
33 Q_ASSERT(m_document);
34}
35
37 : m_document(other.m_document)
38 , m_cursor(other.m_cursor)
39{
40}
41
43{
44 const int line = m_cursor.line();
45 const int col = m_cursor.line();
46
47 if (line < 0) {
48 m_cursor.setPosition(0, 0);
49 } else if (line >= m_document->lines()) {
50 m_cursor = m_document->documentEnd();
51 } else if (col > m_document->lineLength(line)) {
52 m_cursor.setColumn(m_document->lineLength(line));
53 } else if (col < 0) {
54 m_cursor.setColumn(0);
55 } else if (!isValidTextPosition()) {
56 // inside a unicode surrogate (utf-32 character)
57 // -> move half one char left to the start of the utf-32 char
58 m_cursor.setColumn(col - 1);
59 }
60
61 Q_ASSERT(isValidTextPosition());
62}
63
64void DocumentCursor::setPosition(int line, int column)
65{
66 m_cursor.setPosition(line, column);
67}
68
70{
72}
73
75{
77}
78
80{
81 return isValidTextPosition() && column() == 0;
82}
83
85{
86 return isValidTextPosition() && column() == document()->lineLength(line());
87}
88
90{
91 return line() == 0 && column() == 0;
92}
93
95{
96 // avoid costly lineLength computation if we are not in the last line
97 // this is called often e.g. during search & replace, >> 2% of the total costs
98 const auto lastLine = document()->lines() - 1;
99 return line() == lastLine && column() == document()->lineLength(lastLine);
100}
101
103{
104 // only allow valid cursors
105 const bool ok = isValid() && (line() + 1 < document()->lines());
106
107 if (ok) {
108 setPosition(Cursor(line() + 1, 0));
109 }
110
111 return ok;
112}
113
115{
116 // only allow valid cursors
117 bool ok = (line() > 0) && (column() >= 0);
118
119 if (ok) {
120 setPosition(Cursor(line() - 1, 0));
121 }
122
123 return ok;
124}
125
126bool DocumentCursor::move(int chars, WrapBehavior wrapBehavior)
127{
128 if (!isValid()) {
129 return false;
130 }
131
132 // create temporary cursor to modify
133 Cursor c(m_cursor);
134
135 // forwards?
136 if (chars > 0) {
137 // cache lineLength to minimize calls of KTextEditor::DocumentPrivate::lineLength(), as
138 // results in locating the correct block in the text buffer every time,
139 // which is relatively slow
140 int lineLength = document()->lineLength(c.line());
141
142 // special case: cursor position is not in valid text, then the algo does
143 // not work for Wrap mode. Hence, catch this special case by setting
144 // c.column() to the lineLength()
145 if (wrapBehavior == Wrap && c.column() > lineLength) {
146 c.setColumn(lineLength);
147 }
148
149 while (chars != 0) {
150 if (wrapBehavior == Wrap) {
151 const int advance = qMin(lineLength - c.column(), chars);
152
153 if (chars > advance) {
154 if (c.line() + 1 >= document()->lines()) {
155 return false;
156 }
157
158 c.setPosition(c.line() + 1, 0);
159 chars -= advance + 1; // +1 because of end-of-line wrap
160
161 // advanced one line, so cache correct line length again
162 lineLength = document()->lineLength(c.line());
163 } else {
164 c.setColumn(c.column() + chars);
165 chars = 0;
166 }
167 } else { // NoWrap
168 c.setColumn(c.column() + chars);
169 chars = 0;
170 }
171 }
172 }
173
174 // backwards?
175 else {
176 while (chars != 0) {
177 const int back = qMin(c.column(), -chars);
178 if (-chars > back) {
179 if (c.line() == 0) {
180 return false;
181 }
182
183 c.setPosition(c.line() - 1, document()->lineLength(c.line() - 1));
184 chars += back + 1; // +1 because of wrap-around at start-of-line
185 } else {
186 c.setColumn(c.column() + chars);
187 chars = 0;
188 }
189 }
190 }
191
192 if (c != m_cursor) {
193 setPosition(c);
194 }
195 return true;
196}
197
198}
The Cursor represents a position in a Document.
Definition cursor.h:75
constexpr int column() const noexcept
Retrieve the column on which this cursor is situated.
Definition cursor.h:192
void setColumn(int column) noexcept
Set the cursor column to column.
Definition cursor.h:201
void setPosition(Cursor position) noexcept
Set the current cursor position to position.
Definition cursor.h:150
constexpr int line() const noexcept
Retrieve the line on which this cursor is situated.
Definition cursor.h:174
A Cursor which is bound to a specific Document.
bool atStartOfDocument() const
Determine if this cursor is located at line 0 and column 0.
bool atStartOfLine() const
Determine if this cursor is located at column 0 of a valid text line.
Document * document() const
Gets the document to which this cursor is bound.
void setColumn(int column)
Set the cursor column to column.
bool atEndOfLine() const
Determine if this cursor is located at the end of the current line.
int column() const
Retrieve the column on which this cursor is situated.
bool atEndOfDocument() const
Determine if this cursor is located at the end of the last line in the document.
void setPosition(KTextEditor::Cursor position)
Set the current cursor position to position.
bool move(int chars, WrapBehavior wrapBehavior=Wrap)
Moves the cursor chars character forward or backwards.
bool gotoNextLine()
Moves the cursor to the next line and sets the column to 0.
bool isValid() const
Check if the current position of this cursor is a valid position, i.e.
bool gotoPreviousLine()
Moves the cursor to the previous line and sets the column to 0.
void makeValid()
Make sure the cursor position is at a valid text position according to the following rules.
bool isValidTextPosition() const
Check if this cursor is currently at a valid text position.
DocumentCursor()=delete
no default constructor, as we need a document.
void setLine(int line)
Set the cursor line to line.
int line() const
Retrieve the line on which this cursor is situated.
WrapBehavior
Wrap behavior for end of line treatement used in move().
@ Wrap
wrap at end of line
A KParts derived class representing a text document.
Definition document.h:284
virtual int lines() const =0
Get the count of lines of the document.
virtual int lineLength(int line) const =0
Get the length of a given line in characters.
virtual Cursor documentEnd() const =0
End position of the document.
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:11:27 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.