1 | /* This file is part of the KDE project |
2 | Copyright (C) 2003-2005 Hamish Rodda <rodda@kde.org> |
3 | Copyright (C) 2001-2005 Christoph Cullmann <cullmann@kde.org> |
4 | Copyright (C) 2014 Dominik Haumann <dhaumann@kde.org> |
5 | Copyright (C) 2002 Christian Couder <christian@kdevelop.org> |
6 | Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org> |
7 | Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de> |
8 | |
9 | This library is free software; you can redistribute it and/or |
10 | modify it under the terms of the GNU Library General Public |
11 | License as published by the Free Software Foundation; either |
12 | version 2 of the License, or (at your option) any later version. |
13 | |
14 | This library is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | Library General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Library General Public License |
20 | along with this library; see the file COPYING.LIB. If not, write to |
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
22 | Boston, MA 02110-1301, USA. |
23 | */ |
24 | |
25 | #ifndef KTEXTEDITOR_CURSOR_H |
26 | #define KTEXTEDITOR_CURSOR_H |
27 | |
28 | #include <ktexteditor_export.h> |
29 | |
30 | #include <QDebug> |
31 | #include <QtGlobal> |
32 | |
33 | namespace KTextEditor |
34 | { |
35 | class Document; |
36 | class Range; |
37 | |
38 | /** |
39 | * \short The Cursor represents a position in a Document. |
40 | * |
41 | * \section kte_cursor_intro Introduction |
42 | * A Cursor represents a position in a Document through a tuple |
43 | * of two int%s, namely the line() and column(). A Cursor maintains |
44 | * no affiliation with a particular Document, meaning that it remains |
45 | * constant if not changed through the Cursor API. |
46 | * |
47 | * \section kte_cursor_notes Important Notes |
48 | * |
49 | * Working with a cursor, one should be aware of the following notes: |
50 | * - Lines and columns start a 0. |
51 | * - The Cursor class is designed to be passed by value (only 8 Bytes). |
52 | * - Think of cursors as having their position at the start of a character, |
53 | * not in the middle of one. |
54 | * - invalid() Cursor%s are located at (-1, -1). In addition, a Cursor |
55 | * is invalid(), if either its line() and/or its column() is arbitrarily |
56 | * negative, i.e. < 0. |
57 | * - All Cursor%s with line() >= 0 and column() >= 0 are valid. In this case |
58 | * isValid() returns \e true. |
59 | * - A Cursor has a non-virtual destructor. Hence, you cannot derive from Cursor. |
60 | * |
61 | * \section kte_cursor_properties Cursor Efficiency |
62 | * |
63 | * The Cursor consists of just two int%s, the line() and the column(). |
64 | * Therefore, a Cursor instance takes 8 Bytes of memory. Further, a Cursor |
65 | * is a non-virtual class, turning it into a primitive old data type (POD). |
66 | * Thus, it can be moved and copied very efficiently. |
67 | * |
68 | * \section kte_cursor_more Additional Concepts |
69 | * |
70 | * In addition to the Cursor, the KTextEditor API provides advanced concepts: |
71 | * - The DocumentCursor is a Cursor bound to a specific Document. In addition |
72 | * to the Cursor API, it provides convenience functions like |
73 | * DocumentCursor::isValidTextPosition() or DocumentCursor::move(). |
74 | * The DocumentCursor does not maintain its position, though. |
75 | * - The MovingCursor is also bound to a specific Document. In addition to the |
76 | * DocumentCursor, the MovingCursor maintains its position, meaning that |
77 | * whenever the Document changes, the MovingCursor moves, too. |
78 | * - The Cursor forms the basis for the Range. |
79 | * |
80 | * \sa DocumentCursor, MovingCursor, Range |
81 | */ |
82 | class KTEXTEDITOR_EXPORT Cursor |
83 | { |
84 | public: |
85 | /** |
86 | * The default constructor creates a cursor at position (0, 0). |
87 | */ |
88 | Q_DECL_CONSTEXPR Cursor() Q_DECL_NOEXCEPT |
89 | { |
90 | } |
91 | |
92 | /** |
93 | * This constructor creates a cursor initialized with \p line |
94 | * and \p column. |
95 | * \param line line for cursor |
96 | * \param column column for cursor |
97 | */ |
98 | Q_DECL_CONSTEXPR Cursor(int line, int column) Q_DECL_NOEXCEPT |
99 | : m_line(line) |
100 | , m_column(column) |
101 | { |
102 | } |
103 | |
104 | /** |
105 | * Returns whether the current position of this cursor is a valid position |
106 | * (line + column must both be >= 0). |
107 | * |
108 | * @note If you want to check, whether a cursor position is a valid |
109 | * \e text-position, use DocumentCursor::isValidTextPosition(), |
110 | * or Document::isValidTextPosition(). |
111 | */ |
112 | Q_DECL_CONSTEXPR inline bool isValid() const Q_DECL_NOEXCEPT { |
113 | return m_line >= 0 && m_column >= 0; |
114 | } |
115 | |
116 | /** |
117 | * Returns an invalid cursor. |
118 | * The returned cursor position is set to (-1, -1). |
119 | * \see isValid() |
120 | */ |
121 | Q_DECL_CONSTEXPR static Cursor invalid() Q_DECL_NOEXCEPT { |
122 | return Cursor(-1, -1); |
123 | } |
124 | |
125 | /** |
126 | * Returns a cursor representing the start of any document - i.e., line 0, column 0. |
127 | */ |
128 | Q_DECL_CONSTEXPR static Cursor start() Q_DECL_NOEXCEPT { |
129 | return Cursor(); |
130 | } |
131 | |
132 | /** |
133 | * Returns the cursor position as string in the format "(line, column)". |
134 | * \see fromString() |
135 | */ |
136 | QString toString() const { |
137 | return QLatin1Char('(') + QString::number(m_line) |
138 | + QStringLiteral(", " ) + QString::number(m_column) |
139 | + QLatin1Char(')'); |
140 | } |
141 | |
142 | /** |
143 | * Returns a Cursor created from the string \p str containing the format |
144 | * "(line, column)". In case the string cannot be parsed, Cursor::invalid() |
145 | * is returned. |
146 | * \see toString() |
147 | */ |
148 | static Cursor fromString(const QString& str) Q_DECL_NOEXCEPT { |
149 | return fromString(str.leftRef(-1)); |
150 | } |
151 | |
152 | /** |
153 | * Returns a Cursor created from the string \p str containing the format |
154 | * "(line, column)". In case the string cannot be parsed, Cursor::invalid() |
155 | * is returned. |
156 | * \see toString() |
157 | */ |
158 | static Cursor fromString(const QStringRef& str) Q_DECL_NOEXCEPT; |
159 | |
160 | /** |
161 | * \name Position |
162 | * |
163 | * The following functions provide access to, and manipulation of, the cursor's position. |
164 | * \{ |
165 | */ |
166 | /** |
167 | * Set the current cursor position to \e position. |
168 | * |
169 | * \param position new cursor position |
170 | */ |
171 | inline void setPosition(const Cursor &position) Q_DECL_NOEXCEPT { |
172 | m_line = position.m_line; |
173 | m_column = position.m_column; |
174 | } |
175 | |
176 | /** |
177 | * \overload |
178 | * |
179 | * Set the cursor position to \e line and \e column. |
180 | * |
181 | * \param line new cursor line |
182 | * \param column new cursor column |
183 | */ |
184 | inline void setPosition(int line, int column) Q_DECL_NOEXCEPT { |
185 | m_line = line; |
186 | m_column = column; |
187 | } |
188 | |
189 | /** |
190 | * Retrieve the line on which this cursor is situated. |
191 | * \return line number, where 0 is the first line. |
192 | */ |
193 | Q_DECL_CONSTEXPR inline int line() const Q_DECL_NOEXCEPT { |
194 | return m_line; |
195 | } |
196 | |
197 | /** |
198 | * Set the cursor line to \e line. |
199 | * \param line new cursor line |
200 | */ |
201 | inline void setLine(int line) Q_DECL_NOEXCEPT { |
202 | m_line = line; |
203 | } |
204 | |
205 | /** |
206 | * Retrieve the column on which this cursor is situated. |
207 | * \return column number, where 0 is the first column. |
208 | */ |
209 | Q_DECL_CONSTEXPR inline int column() const Q_DECL_NOEXCEPT { |
210 | return m_column; |
211 | } |
212 | |
213 | /** |
214 | * Set the cursor column to \e column. |
215 | * \param column new cursor column |
216 | */ |
217 | inline void setColumn(int column) Q_DECL_NOEXCEPT { |
218 | m_column = column; |
219 | } |
220 | |
221 | /** |
222 | * Determine if this cursor is located at the start of a line (= at column 0). |
223 | * \return \e true if the cursor is situated at the start of the line, \e false if it isn't. |
224 | */ |
225 | Q_DECL_CONSTEXPR inline bool atStartOfLine() const Q_DECL_NOEXCEPT { |
226 | return m_column == 0; |
227 | } |
228 | |
229 | /** |
230 | * Determine if this cursor is located at the start of a document (= at position (0, 0)). |
231 | * \return \e true if the cursor is situated at the start of the document, \e false if it isn't. |
232 | */ |
233 | Q_DECL_CONSTEXPR inline bool atStartOfDocument() const Q_DECL_NOEXCEPT { |
234 | return m_line == 0 && m_column == 0; |
235 | } |
236 | |
237 | /** |
238 | * Get both the line and column of the cursor position. |
239 | * \param line will be filled with current cursor line |
240 | * \param column will be filled with current cursor column |
241 | */ |
242 | inline void position(int &line, int &column) const Q_DECL_NOEXCEPT { |
243 | line = m_line; |
244 | column = m_column; |
245 | } |
246 | //!\} |
247 | |
248 | /** |
249 | * Addition operator. Takes two cursors and returns their summation. |
250 | * \param c1 the first position |
251 | * \param c2 the second position |
252 | * \return a the summation of the two input cursors |
253 | */ |
254 | Q_DECL_CONSTEXPR inline friend Cursor operator+(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT { |
255 | return Cursor(c1.line() + c2.line(), c1.column() + c2.column()); |
256 | } |
257 | |
258 | /** |
259 | * Addition assignment operator. Adds \p c2 to this cursor. |
260 | * \param c1 the cursor being added to |
261 | * \param c2 the position to add |
262 | * \return a reference to the cursor which has just been added to |
263 | */ |
264 | inline friend Cursor &operator+=(Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT { |
265 | c1.setPosition(c1.line() + c2.line(), c1.column() + c2.column()); |
266 | return c1; |
267 | } |
268 | |
269 | /** |
270 | * Subtraction operator. Takes two cursors and returns the subtraction |
271 | * of \p c2 from \p c1. |
272 | * |
273 | * \param c1 the first position |
274 | * \param c2 the second position |
275 | * \return a cursor representing the subtraction of \p c2 from \p c1 |
276 | */ |
277 | Q_DECL_CONSTEXPR inline friend Cursor operator-(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT { |
278 | return Cursor(c1.line() - c2.line(), c1.column() - c2.column()); |
279 | } |
280 | |
281 | /** |
282 | * Subtraction assignment operator. Subtracts \p c2 from \p c1. |
283 | * \param c1 the cursor being subtracted from |
284 | * \param c2 the position to subtract |
285 | * \return a reference to the cursor which has just been subtracted from |
286 | */ |
287 | inline friend Cursor &operator-=(Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT { |
288 | c1.setPosition(c1.line() - c2.line(), c1.column() - c2.column()); |
289 | return c1; |
290 | } |
291 | |
292 | /** |
293 | * Equality operator. |
294 | * |
295 | * \note comparison between two invalid cursors is undefined. |
296 | * comparison between and invalid and a valid cursor will always be \e false. |
297 | * |
298 | * \param c1 first cursor to compare |
299 | * \param c2 second cursor to compare |
300 | * \return \e true, if c1's and c2's line and column are \e equal. |
301 | */ |
302 | Q_DECL_CONSTEXPR inline friend bool operator==(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT { |
303 | return c1.line() == c2.line() && c1.column() == c2.column(); |
304 | } |
305 | |
306 | /** |
307 | * Inequality operator. |
308 | * \param c1 first cursor to compare |
309 | * \param c2 second cursor to compare |
310 | * \return \e true, if c1's and c2's line and column are \e not equal. |
311 | */ |
312 | Q_DECL_CONSTEXPR inline friend bool operator!=(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT { |
313 | return !(c1 == c2); |
314 | } |
315 | |
316 | /** |
317 | * Greater than operator. |
318 | * \param c1 first cursor to compare |
319 | * \param c2 second cursor to compare |
320 | * \return \e true, if c1's position is greater than c2's position, |
321 | * otherwise \e false. |
322 | */ |
323 | Q_DECL_CONSTEXPR inline friend bool operator>(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT { |
324 | return c1.line() > c2.line() || (c1.line() == c2.line() && c1.m_column > c2.m_column); |
325 | } |
326 | |
327 | /** |
328 | * Greater than or equal to operator. |
329 | * \param c1 first cursor to compare |
330 | * \param c2 second cursor to compare |
331 | * \return \e true, if c1's position is greater than or equal to c2's |
332 | * position, otherwise \e false. |
333 | */ |
334 | Q_DECL_CONSTEXPR inline friend bool operator>=(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT{ |
335 | return c1.line() > c2.line() || (c1.line() == c2.line() && c1.m_column >= c2.m_column); |
336 | } |
337 | |
338 | /** |
339 | * Less than operator. |
340 | * \param c1 first cursor to compare |
341 | * \param c2 second cursor to compare |
342 | * \return \e true, if c1's position is greater than or equal to c2's |
343 | * position, otherwise \e false. |
344 | */ |
345 | Q_DECL_CONSTEXPR inline friend bool operator<(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT { |
346 | return !(c1 >= c2); |
347 | } |
348 | |
349 | /** |
350 | * Less than or equal to operator. |
351 | * \param c1 first cursor to compare |
352 | * \param c2 second cursor to compare |
353 | * \return \e true, if c1's position is lesser than or equal to c2's |
354 | * position, otherwise \e false. |
355 | */ |
356 | Q_DECL_CONSTEXPR inline friend bool operator<=(const Cursor &c1, const Cursor &c2) Q_DECL_NOEXCEPT { |
357 | return !(c1 > c2); |
358 | } |
359 | |
360 | /** |
361 | * qDebug() stream operator. Writes this cursor to the debug output in a nicely formatted way. |
362 | */ |
363 | inline friend QDebug operator<< (QDebug s, const Cursor &cursor) { |
364 | s.nospace() << "(" << cursor.line() << ", " << cursor.column() << ")" ; |
365 | return s.space(); |
366 | } |
367 | |
368 | private: |
369 | /** |
370 | * \internal |
371 | * |
372 | * Cursor line |
373 | */ |
374 | int m_line = 0; |
375 | |
376 | /** |
377 | * \internal |
378 | * |
379 | * Cursor column |
380 | */ |
381 | int m_column = 0; |
382 | }; |
383 | |
384 | } // namespace KTextEditor |
385 | |
386 | Q_DECLARE_TYPEINFO(KTextEditor::Cursor, Q_MOVABLE_TYPE); |
387 | Q_DECLARE_METATYPE(KTextEditor::Cursor) |
388 | |
389 | /** |
390 | * QHash function for KTextEditor::Cursor. |
391 | * Returns the hash value for @p cursor. |
392 | */ |
393 | inline uint qHash(const KTextEditor::Cursor& cursor, uint seed = 0) Q_DECL_NOTHROW |
394 | { |
395 | return qHash(qMakePair(cursor.line(), cursor.column()), seed); |
396 | } |
397 | |
398 | namespace QTest |
399 | { |
400 | // forward declaration of template in qtestcase.h |
401 | template<typename T> char* toString(const T&); |
402 | |
403 | /** |
404 | * QTestLib integration to have nice output in e.g. QCOMPARE failures. |
405 | */ |
406 | template<> |
407 | KTEXTEDITOR_EXPORT char *toString(const KTextEditor::Cursor &cursor); |
408 | } |
409 | |
410 | #endif |
411 | |
412 | |