1/* This file is part of the KDE project
2 *
3 * Copyright (C) 2010 Christoph Cullmann <cullmann@kde.org>
4 *
5 * Based on code of the SmartCursor/Range by:
6 * Copyright (C) 2003-2005 Hamish Rodda <rodda@kde.org>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#ifndef KTEXTEDITOR_MOVINGCURSOR_H
25#define KTEXTEDITOR_MOVINGCURSOR_H
26
27#include <ktexteditor_export.h>
28#include <ktexteditor/cursor.h>
29#include <ktexteditor/document.h>
30
31#include <QDebug>
32
33namespace KTextEditor
34{
35
36class MovingRange;
37
38/**
39 * \short A Cursor which is bound to a specific Document, and maintains its position.
40 *
41 * \ingroup kte_group_moving_classes
42 *
43 * A MovingCursor is an extension of the basic Cursor class. It maintains its
44 * position in the document. As a result of this, MovingCursor%s may not be copied, as they need
45 * to maintain a connection to the associated Document.
46 *
47 * Create a new MovingCursor like this:
48 * \code
49 * // Retrieve the MovingInterface
50 * KTextEditor::MovingInterface* moving =
51 * qobject_cast<KTextEditor::MovingInterface*>( yourDocument );
52 *
53 * if ( moving ) {
54 * KTextEditor::MovingCursor* cursor = moving->newMovingCursor();
55 * }
56 * \endcode
57 *
58 * When finished with a MovingCursor, simply delete it.
59 * If the document the cursor belong to is deleted, it will get deleted automatically.
60 *
61 * \sa Cursor, Range, MovingRange and MovingInterface.
62 *
63 * \author Christoph Cullmann \<cullmann@kde.org\>
64 *
65 * \since 4.5
66 */
67class KTEXTEDITOR_EXPORT MovingCursor
68{
69 //
70 // sub types
71 //
72public:
73 /**
74 * Insert behavior of this cursor, should it stay if text is insert at its position
75 * or should it move.
76 */
77 enum InsertBehavior {
78 StayOnInsert = 0x0, ///< stay on insert
79 MoveOnInsert = 0x1 ///< move on insert
80 };
81
82 /**
83 * Wrap behavior for end of line treatement used in move().
84 */
85 enum WrapBehavior {
86 Wrap = 0x0, ///< wrap at end of line
87 NoWrap = 0x1 ///< do not wrap at end of line
88 };
89
90 //
91 // stuff that needs to be implemented by editor part cursors
92 //
93public:
94 /**
95 * Set insert behavior.
96 * @param insertBehavior new insert behavior
97 */
98 virtual void setInsertBehavior(InsertBehavior insertBehavior) = 0;
99
100 /**
101 * Get current insert behavior.
102 * @return current insert behavior
103 */
104 virtual InsertBehavior insertBehavior() const = 0;
105
106 /**
107 * Gets the document to which this cursor is bound.
108 * \return a pointer to the document
109 */
110 virtual Document *document() const = 0;
111
112 /**
113 * Get range this cursor belongs to, if any
114 * @return range this pointer is part of, else 0
115 */
116 virtual MovingRange *range() const = 0;
117
118 /**
119 * Set the current cursor position to \e position.
120 *
121 * \param position new cursor position
122 */
123 virtual void setPosition(const KTextEditor::Cursor &position) = 0;
124
125 /**
126 * Retrieve the line on which this cursor is situated.
127 * \return line number, where 0 is the first line.
128 */
129 virtual int line() const = 0;
130
131 /**
132 * Retrieve the column on which this cursor is situated.
133 * \return column number, where 0 is the first column.
134 */
135 virtual int column() const = 0;
136
137 /**
138 * Destruct the moving cursor.
139 */
140 virtual ~MovingCursor();
141
142 //
143 // forbidden stuff
144 //
145protected:
146 /**
147 * For inherited class only.
148 */
149 MovingCursor();
150
151private:
152 /**
153 * no copy constructor, don't allow this to be copied.
154 */
155 MovingCursor(const MovingCursor &);
156
157 /**
158 * no assignment operator, no copying around clever cursors.
159 */
160 MovingCursor &operator= (const MovingCursor &);
161
162 //
163 // convenience API
164 //
165public:
166
167 /**
168 * Returns whether the current position of this cursor is a valid position,
169 * i.e. whether line() >= 0 and column() >= 0.
170 *
171 * \return \e true , if the cursor position is valid, otherwise \e false
172 */
173 inline bool isValid() const {
174 return line() >= 0 && column() >= 0;
175 }
176
177 /**
178 * Check whether this MovingCursor is located at a valid text position.
179 * A cursor position at (line, column) is valid, if
180 * - line >= 0 and line < document()->lines() holds, and
181 * - column >= 0 and column <= lineLength(column).
182 *
183 * Further, the text position is also invalid if it is inside a Unicode
184 * surrogate (utf-32 character).
185 *
186 * \return \e true, if the cursor is a valid text position, otherwise \e false
187 *
188 * \see Document::isValidTextPosition()
189 */
190 inline bool isValidTextPosition() const {
191 return document()->isValidTextPosition(toCursor());
192 }
193
194 /**
195 * \overload
196 *
197 * Set the cursor position to \e line and \e column.
198 *
199 * \param line new cursor line
200 * \param column new cursor column
201 */
202 void setPosition(int line, int column);
203
204 /**
205 * Set the cursor line to \e line.
206 * \param line new cursor line
207 */
208 void setLine(int line);
209
210 /**
211 * Set the cursor column to \e column.
212 * \param column new cursor column
213 */
214 void setColumn(int column);
215
216 /**
217 * Determine if this cursor is located at column 0 of a valid text line.
218 *
219 * \return \e true if cursor is a valid text position and column()=0, otherwise \e false.
220 */
221 bool atStartOfLine() const;
222
223 /**
224 * Determine if this cursor is located at the end of the current line.
225 *
226 * \return \e true if the cursor is situated at the end of the line, otherwise \e false.
227 */
228 bool atEndOfLine() const;
229
230 /**
231 * Determine if this cursor is located at line 0 and column 0.
232 *
233 * \return \e true if the cursor is at start of the document, otherwise \e false.
234 */
235 bool atStartOfDocument() const;
236
237 /**
238 * Determine if this cursor is located at the end of the last line in the
239 * document.
240 *
241 * \return \e true if the cursor is at the end of the document, otherwise \e false.
242 */
243 bool atEndOfDocument() const;
244
245 /**
246 * Moves the cursor to the next line and sets the column to 0. If the cursor
247 * position is already in the last line of the document, the cursor position
248 * remains unchanged and the return value is \e false.
249 *
250 * \return \e true on success, otherwise \e false
251 */
252 bool gotoNextLine();
253
254 /**
255 * Moves the cursor to the previous line and sets the column to 0. If the
256 * cursor position is already in line 0, the cursor position remains
257 * unchanged and the return value is \e false.
258 *
259 * \return \e true on success, otherwise \e false
260 */
261 bool gotoPreviousLine();
262
263 /**
264 * Moves the cursor \p chars character forward or backwards. If \e wrapBehavior
265 * equals WrapBehavior::Wrap, the cursor is automatically wrapped to the
266 * next line at the end of a line.
267 *
268 * When moving backwards, the WrapBehavior does not have any effect.
269 * \note If the cursor could not be moved the amount of chars requested,
270 * the cursor is not moved at all!
271 *
272 * \return \e true on success, otherwise \e false
273 */
274 bool move(int chars, WrapBehavior wrapBehavior = Wrap);
275
276 /**
277 * Convert this clever cursor into a dumb one.
278 * Even if this cursor belongs to a range, the created one not.
279 * @return normal cursor
280 */
281 const Cursor toCursor() const {
282 return Cursor(line(), column());
283 }
284
285 /**
286 * Convert this clever cursor into a dumb one. Equal to toCursor, allowing to use implicit conversion.
287 * Even if this cursor belongs to a range, the created one not.
288 * @return normal cursor
289 */
290 operator Cursor() const {
291 return Cursor(line(), column());
292 }
293
294//
295// operators for: MovingCursor <-> MovingCursor
296//
297 /**
298 * Equality operator.
299 *
300 * \note comparison between two invalid cursors is undefined.
301 * comparison between an invalid and a valid cursor will always be \e false.
302 *
303 * \param c1 first cursor to compare
304 * \param c2 second cursor to compare
305 * \return \e true, if c1's and c2's line and column are \e equal.
306 */
307 inline friend bool operator==(const MovingCursor &c1, const MovingCursor &c2) {
308 return c1.line() == c2.line() && c1.column() == c2.column();
309 }
310
311 /**
312 * Inequality operator.
313 * \param c1 first cursor to compare
314 * \param c2 second cursor to compare
315 * \return \e true, if c1's and c2's line and column are \e not equal.
316 */
317 inline friend bool operator!=(const MovingCursor &c1, const MovingCursor &c2) {
318 return !(c1 == c2);
319 }
320
321 /**
322 * Greater than operator.
323 * \param c1 first cursor to compare
324 * \param c2 second cursor to compare
325 * \return \e true, if c1's position is greater than c2's position,
326 * otherwise \e false.
327 */
328 inline friend bool operator>(const MovingCursor &c1, const MovingCursor &c2) {
329 return c1.line() > c2.line() || (c1.line() == c2.line() && c1.column() > c2.column());
330 }
331
332 /**
333 * Greater than or equal to operator.
334 * \param c1 first cursor to compare
335 * \param c2 second cursor to compare
336 * \return \e true, if c1's position is greater than or equal to c2's
337 * position, otherwise \e false.
338 */
339 inline friend bool operator>=(const MovingCursor &c1, const MovingCursor &c2) {
340 return c1.line() > c2.line() || (c1.line() == c2.line() && c1.column() >= c2.column());
341 }
342
343 /**
344 * Less than operator.
345 * \param c1 first cursor to compare
346 * \param c2 second cursor to compare
347 * \return \e true, if c1's position is greater than or equal to c2's
348 * position, otherwise \e false.
349 */
350 inline friend bool operator<(const MovingCursor &c1, const MovingCursor &c2) {
351 return !(c1 >= c2);
352 }
353
354 /**
355 * Less than or equal to operator.
356 * \param c1 first cursor to compare
357 * \param c2 second cursor to compare
358 * \return \e true, if c1's position is lesser than or equal to c2's
359 * position, otherwise \e false.
360 */
361 inline friend bool operator<=(const MovingCursor &c1, const MovingCursor &c2) {
362 return !(c1 > c2);
363 }
364
365 /**
366 * qDebug() stream operator. Writes this cursor to the debug output in a nicely formatted way.
367 * @param s debug stream
368 * @param cursor cursor to print
369 * @return debug stream
370 */
371 inline friend QDebug operator<< (QDebug s, const MovingCursor *cursor) {
372 if (cursor) {
373 s.nospace() << "(" << cursor->line() << ", " << cursor->column() << ")";
374 } else {
375 s.nospace() << "(null cursor)";
376 }
377 return s.space();
378 }
379
380 /**
381 * qDebug() stream operator. Writes this cursor to the debug output in a nicely formatted way.
382 * @param s debug stream
383 * @param cursor cursor to print
384 * @return debug stream
385 */
386 inline friend QDebug operator<< (QDebug s, const MovingCursor &cursor) {
387 return s << &cursor;
388 }
389};
390
391}
392
393#endif
394
395