KTextEditor

documentcursor.h
1 /*
2  SPDX-FileCopyrightText: 2010 Christoph Cullmann <[email protected]>
3  SPDX-FileCopyrightText: 2012-2013 Dominik Haumann <[email protected]>
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 
17 namespace 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 <[email protected]>
54  */
55 class KTEXTEDITOR_EXPORT DocumentCursor
56 {
57  //
58  // sub types
59  //
60 public:
61  /**
62  * Wrap behavior for end of line treatement used in move().
63  */
64  enum WrapBehavior {
65  Wrap = 0x0, ///< wrap at end of line
66  NoWrap = 0x1 ///< do not wrap at end of line
67  };
68 
69  //
70  // Constructor
71  //
72 public:
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  */
83  DocumentCursor(KTextEditor::Document *document, const KTextEditor::Cursor &position);
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  //
99 public:
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  //
149 private:
150  /**
151  * no default constructor, as we need a document.
152  */
153  DocumentCursor();
154 
155  //
156  // convenience API
157  //
158 public:
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==(const DocumentCursor &c1, const 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!=(const DocumentCursor &c1, const 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>(const DocumentCursor &c1, const 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>=(const DocumentCursor &c1, const 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<(const DocumentCursor &c1, const 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<=(const DocumentCursor &c1, const 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 
419 private:
420  KTextEditor::Document *m_document;
421  KTextEditor::Cursor m_cursor;
422 };
423 
424 }
425 
426 Q_DECLARE_TYPEINFO(KTextEditor::DocumentCursor, Q_MOVABLE_TYPE);
427 
428 #endif
void setPosition(KTextEditor::Cursor position)
Set the current cursor position to position.
friend bool operator<(const DocumentCursor &c1, const DocumentCursor &c2)
Less than operator.
WrapBehavior
Wrap behavior for end of line treatement used in move().
QDebug & nospace()
friend bool operator<=(const DocumentCursor &c1, const DocumentCursor &c2)
Less than or equal to operator.
A Cursor which is bound to a specific Document.
QDebug & space()
Cursor toCursor() const
Convert this clever cursor into a dumb one.
friend QDebug operator<<(QDebug s, const DocumentCursor *cursor)
qDebug() stream operator.
Document * document() const
Gets the document to which this cursor is bound.
The Cursor represents a position in a Document.
Definition: cursor.h:71
friend bool operator==(const DocumentCursor &c1, const DocumentCursor &c2)
Equality operator.
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
Definition: katetextblock.h:22
~DocumentCursor()
Destruct the moving cursor.
bool isValid() const
Check if the current position of this cursor is a valid position, i.e.
int column() const
Retrieve the column on which this cursor is situated.
int line() const
Retrieve the line on which this cursor is situated.
friend bool operator>=(const DocumentCursor &c1, const DocumentCursor &c2)
Greater than or equal to operator.
friend bool operator!=(const DocumentCursor &c1, const DocumentCursor &c2)
Inequality operator.
friend QDebug operator<<(QDebug s, const DocumentCursor &cursor)
qDebug() stream operator.
DocumentCursor & operator=(const DocumentCursor &other)
Assignment operator.
friend bool operator>(const DocumentCursor &c1, const DocumentCursor &c2)
Greater than operator.
bool isValidTextPosition() const
Check if this cursor is currently at a valid text position.
A KParts derived class representing a text document.
Definition: document.h:185
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Dec 5 2023 03:51:10 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.