KTextEditor

documentcursor.h
1/*
2 SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org>
3 SPDX-FileCopyrightText: 2012-2013 Dominik Haumann <dhaumann@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#ifndef KTEXTEDITOR_DOCUMENT_CURSOR_H
9#define KTEXTEDITOR_DOCUMENT_CURSOR_H
10
11#include <ktexteditor/cursor.h>
12#include <ktexteditor/document.h>
13#include <ktexteditor_export.h>
14
15#include <QDebug>
16
17namespace KTextEditor
18{
19/**
20 * \class DocumentCursor documentcursor.h <KTextEditor/DocumentCursor>
21 *
22 * \short A Cursor which is bound to a specific Document.
23 *
24 * \section documentcursor_intro Introduction
25 * A DocumentCursor is an extension of the basic Cursor class.
26 * The DocumentCursor is bound to a specific Document instance.
27 * This way, the cursor provides additional functions like gotoNextLine(),
28 * gotoPreviousLine() and move() according to the WrapBehavior.
29 *
30 * The only difference to a MovingCursor is that the DocumentCursor's
31 * position does not automatically move on text manipulation.
32 *
33 * \section documentcursor_position Validity
34 *
35 * When constructing a DocumentCursor, a valid document pointer is required
36 * in the constructor. A null pointer will assert in debug builds.
37 * Further, a DocumentCursor should only be used as long as the Document
38 * exists, otherwise the DocumentCursor contains a dangling pointer to the
39 * previously assigned Document.
40 *
41 * \section documentcursor_example Example
42 *
43 * A DocumentCursor is created and used like this:
44 * \code
45 * KTextEditor::DocumentCursor docCursor(document);
46 * docCursor.setPosition(0, 0);
47 * docCursor.gotoNextLine();
48 * docCursor.move(5); // move 5 characters to the right
49 * \endcode
50 *
51 * \see KTextEditor::Cursor, KTextEditor::MovingCursor
52 *
53 * \author Dominik Haumann <dhaumann@kde.org>
54 */
55class KTEXTEDITOR_EXPORT DocumentCursor
56{
57 //
58 // sub types
59 //
60public:
61 /**
62 * Wrap behavior for end of line treatement used in move().
63 */
65 Wrap = 0x0, ///< wrap at end of line
66 NoWrap = 0x1 ///< do not wrap at end of line
67 };
68
69 //
70 // Constructor
71 //
72public:
73 /**
74 * Constructor that creates a DocumentCursor at the \e invalid position
75 * (-1, -1).
76 * \see isValid()
77 */
79
80 /**
81 * Constructor that creates a DocumentCursor located at \p position.
82 */
84
85 /**
86 * Constructor that creates a DocumentCursor located at \p line and \p column.
87 */
88 DocumentCursor(KTextEditor::Document *document, int line, int column);
89
90 /**
91 * Copy constructor. Make sure the Document of the DocumentCursor is
92 * valid.
93 */
94 DocumentCursor(const DocumentCursor &other);
95
96 //
97 // stuff that needs to be implemented by editor part cursors
98 //
99public:
100 /**
101 * Gets the document to which this cursor is bound.
102 * \return a pointer to the document
103 */
104 inline Document *document() const
105 {
106 return m_document;
107 }
108
109 /**
110 * Set the current cursor position to \e position.
111 * If \e position is not valid, meaning that either its line < 0 or its
112 * column < 0, then the document cursor will also be invalid
113 *
114 * \param position new cursor position
115 */
117 {
118 m_cursor = position;
119 }
120
121 /**
122 * Retrieve the line on which this cursor is situated.
123 * \return line number, where 0 is the first line.
124 */
125 inline int line() const
126 {
127 return m_cursor.line();
128 }
129
130 /**
131 * Retrieve the column on which this cursor is situated.
132 * \return column number, where 0 is the first column.
133 */
134 inline int column() const
135 {
136 return m_cursor.column();
137 }
138
139 /**
140 * Destruct the moving cursor.
141 */
143 {
144 }
145
146 //
147 // forbidden stuff
148 //
149public:
150 /**
151 * no default constructor, as we need a document.
152 */
153 DocumentCursor() = delete;
154
155 //
156 // convenience API
157 //
158public:
159 /**
160 * Check if the current position of this cursor is a valid position,
161 * i.e. whether line() >= 0 and column() >= 0.
162 * \return \e true, if the cursor position is valid, otherwise \e false
163 * \see KTextEditor::Cursor::isValid(), isValidTextPosition()
164 */
165 inline bool isValid() const
166 {
167 return m_cursor.isValid();
168 }
169
170 /**
171 * Check if this cursor is currently at a valid text position.
172 * A cursor position at (line, column) is valid, if
173 * - line >= 0 and line < lines() holds, and
174 * - column >= 0 and column <= lineLength(column).
175 *
176 * The text position is also invalid if it is inside a Unicode surrogate.
177 * Therefore, use this function when iterating over the characters of a line.
178 *
179 * \see KTextEditor::Document::isValidTextPosition(), isValid()
180 */
181 inline bool isValidTextPosition() const
182 {
183 return document()->isValidTextPosition(m_cursor);
184 }
185
186 /**
187 * Make sure the cursor position is at a valid text position according to
188 * the following rules.
189 * - If the cursor is invalid(), i.e. either line < 0 or column < 0, it is
190 * set to (0, 0).
191 * - If the cursor's line is past the number of lines in the document, the
192 * cursor is set to Document::documentEnd().
193 * - If the cursor's column is past the line length, the cursor column is
194 * set to the line length.
195 * - If the cursor is inside a Unicode surrogate, the cursor is moved to the
196 * beginning of the Unicode surrogate.
197 *
198 * After calling makeValid(), the cursor is guaranteed to be located at
199 * a valid text position.
200 * \see isValidTextPosition(), isValid()
201 */
202 void makeValid();
203
204 /**
205 * \overload
206 *
207 * Set the cursor position to \e line and \e column.
208 *
209 * \param line new cursor line
210 * \param column new cursor column
211 */
212 void setPosition(int line, int column);
213
214 /**
215 * Set the cursor line to \e line.
216 * \param line new cursor line
217 */
218 void setLine(int line);
219
220 /**
221 * Set the cursor column to \e column.
222 * \param column new cursor column
223 */
224 void setColumn(int column);
225
226 /**
227 * Determine if this cursor is located at column 0 of a valid text line.
228 *
229 * \return \e true if cursor is a valid text position and column()=0, otherwise \e false.
230 */
231 bool atStartOfLine() const;
232
233 /**
234 * Determine if this cursor is located at the end of the current line.
235 *
236 * \return \e true if the cursor is situated at the end of the line, otherwise \e false.
237 */
238 bool atEndOfLine() const;
239
240 /**
241 * Determine if this cursor is located at line 0 and column 0.
242 *
243 * \return \e true if the cursor is at start of the document, otherwise \e false.
244 */
245 bool atStartOfDocument() const;
246
247 /**
248 * Determine if this cursor is located at the end of the last line in the
249 * document.
250 *
251 * \return \e true if the cursor is at the end of the document, otherwise \e false.
252 */
253 bool atEndOfDocument() const;
254
255 /**
256 * Moves the cursor to the next line and sets the column to 0. If the cursor
257 * position is already in the last line of the document, the cursor position
258 * remains unchanged and the return value is \e false.
259 *
260 * \return \e true on success, otherwise \e false
261 */
262 bool gotoNextLine();
263
264 /**
265 * Moves the cursor to the previous line and sets the column to 0. If the
266 * cursor position is already in line 0, the cursor position remains
267 * unchanged and the return value is \e false.
268 *
269 * \return \e true on success, otherwise \e false
270 */
271 bool gotoPreviousLine();
272
273 /**
274 * Moves the cursor \p chars character forward or backwards. If \e wrapBehavior
275 * equals WrapBehavior::Wrap, the cursor is automatically wrapped to the
276 * next line at the end of a line.
277 *
278 * When moving backwards, the WrapBehavior does not have any effect.
279 * \note If the cursor could not be moved the amount of chars requested,
280 * the cursor is not moved at all!
281 *
282 * \return \e true on success, otherwise \e false
283 */
284 bool move(int chars, WrapBehavior wrapBehavior = Wrap);
285
286 /**
287 * Convert this clever cursor into a dumb one.
288 * @return normal cursor
289 */
290 inline Cursor toCursor() const
291 {
292 return m_cursor;
293 }
294
295 /**
296 * Convert this clever cursor into a dumb one. Equal to toCursor, allowing to use implicit conversion.
297 * @return normal cursor
298 */
299 inline operator Cursor() const
300 {
301 return m_cursor;
302 }
303
304 //
305 // operators for: DocumentCursor <-> DocumentCursor
306 //
307 /**
308 * Assignment operator. Same as the copy constructor. Make sure that
309 * the assigned Document is a valid document pointer.
310 */
312 {
313 m_document = other.m_document;
314 m_cursor = other.m_cursor;
315 return *this;
316 }
317
318 /**
319 * Equality operator.
320 *
321 * \note comparison between two invalid cursors is undefined.
322 * comparison between an invalid and a valid cursor will always be \e false.
323 *
324 * \param c1 first cursor to compare
325 * \param c2 second cursor to compare
326 * \return \e true, if c1's and c2's assigned document, line and column are \e equal.
327 */
328 inline friend bool operator==(DocumentCursor c1, DocumentCursor c2)
329 {
330 return c1.document() == c2.document() && c1.line() == c2.line() && c1.column() == c2.column();
331 }
332
333 /**
334 * Inequality operator.
335 * \param c1 first cursor to compare
336 * \param c2 second cursor to compare
337 * \return \e true, if c1's and c2's assigned document, line and column are \e not equal.
338 */
339 inline friend bool operator!=(DocumentCursor c1, DocumentCursor c2)
340 {
341 return !(c1 == c2);
342 }
343
344 /**
345 * Greater than operator.
346 * \param c1 first cursor to compare
347 * \param c2 second cursor to compare
348 * \return \e true, if c1's position is greater than c2's position,
349 * otherwise \e false.
350 */
351 inline friend bool operator>(DocumentCursor c1, DocumentCursor c2)
352 {
353 return c1.line() > c2.line() || (c1.line() == c2.line() && c1.column() > c2.column());
354 }
355
356 /**
357 * Greater than or equal to operator.
358 * \param c1 first cursor to compare
359 * \param c2 second cursor to compare
360 * \return \e true, if c1's position is greater than or equal to c2's
361 * position, otherwise \e false.
362 */
363 inline friend bool operator>=(DocumentCursor c1, DocumentCursor c2)
364 {
365 return c1.line() > c2.line() || (c1.line() == c2.line() && c1.column() >= c2.column());
366 }
367
368 /**
369 * Less than operator.
370 * \param c1 first cursor to compare
371 * \param c2 second cursor to compare
372 * \return \e true, if c1's position is greater than or equal to c2's
373 * position, otherwise \e false.
374 */
375 inline friend bool operator<(DocumentCursor c1, DocumentCursor c2)
376 {
377 return !(c1 >= c2);
378 }
379
380 /**
381 * Less than or equal to operator.
382 * \param c1 first cursor to compare
383 * \param c2 second cursor to compare
384 * \return \e true, if c1's position is lesser than or equal to c2's
385 * position, otherwise \e false.
386 */
387 inline friend bool operator<=(DocumentCursor c1, DocumentCursor c2)
388 {
389 return !(c1 > c2);
390 }
391
392 /**
393 * qDebug() stream operator. Writes this cursor to the debug output in a nicely formatted way.
394 * @param s debug stream
395 * @param cursor cursor to print
396 * @return debug stream
397 */
398 inline friend QDebug operator<<(QDebug s, const DocumentCursor *cursor)
399 {
400 if (cursor) {
401 s.nospace() << "(" << cursor->document() << ": " << cursor->line() << ", " << cursor->column() << ")";
402 } else {
403 s.nospace() << "(null document cursor)";
404 }
405 return s.space();
406 }
407
408 /**
409 * qDebug() stream operator. Writes this cursor to the debug output in a nicely formatted way.
410 * @param s debug stream
411 * @param cursor cursor to print
412 * @return debug stream
413 */
414 inline friend QDebug operator<<(QDebug s, const DocumentCursor &cursor)
415 {
416 return s << &cursor;
417 }
418
419private:
420 KTextEditor::Document *m_document;
421 KTextEditor::Cursor m_cursor;
422};
423
424}
425
426Q_DECLARE_TYPEINFO(KTextEditor::DocumentCursor, Q_RELOCATABLE_TYPE);
427
428#endif
The Cursor represents a position in a Document.
Definition cursor.h:75
A Cursor which is bound to a specific Document.
friend bool operator<=(DocumentCursor c1, DocumentCursor c2)
Less than or equal to operator.
friend bool operator<(DocumentCursor c1, DocumentCursor c2)
Less than operator.
friend bool operator==(DocumentCursor c1, DocumentCursor c2)
Equality operator.
Document * document() const
Gets the document to which this cursor is bound.
friend QDebug operator<<(QDebug s, const DocumentCursor *cursor)
qDebug() stream operator.
DocumentCursor & operator=(const DocumentCursor &other)
Assignment operator.
int column() const
Retrieve the column on which this cursor is situated.
friend bool operator>=(DocumentCursor c1, DocumentCursor c2)
Greater than or equal to operator.
friend bool operator!=(DocumentCursor c1, DocumentCursor c2)
Inequality operator.
void setPosition(KTextEditor::Cursor position)
Set the current cursor position to position.
bool isValid() const
Check if the current position of this cursor is a valid position, i.e.
Cursor toCursor() const
Convert this clever cursor into a dumb one.
bool isValidTextPosition() const
Check if this cursor is currently at a valid text position.
friend QDebug operator<<(QDebug s, const DocumentCursor &cursor)
qDebug() stream operator.
DocumentCursor()=delete
no default constructor, as we need a document.
friend bool operator>(DocumentCursor c1, DocumentCursor c2)
Greater than operator.
~DocumentCursor()
Destruct the moving cursor.
int line() const
Retrieve the line on which this cursor is situated.
WrapBehavior
Wrap behavior for end of line treatement used in move().
A KParts derived class representing a text document.
Definition document.h:284
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
QDebug & nospace()
QDebug & space()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:01:56 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.