KTextEditor

movingrange.h
1/*
2 SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org>
3
4 Based on code of the SmartCursor/Range by:
5 SPDX-FileCopyrightText: 2003-2005 Hamish Rodda <rodda@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#ifndef KTEXTEDITOR_MOVINGRANGE_H
11#define KTEXTEDITOR_MOVINGRANGE_H
12
13#include <ktexteditor/attribute.h>
14#include <ktexteditor/linerange.h>
15#include <ktexteditor/movingcursor.h>
16#include <ktexteditor/range.h>
17#include <ktexteditor_export.h>
18
19class QDebug;
20
21namespace KTextEditor
22{
23class Document;
24class View;
25class MovingRangeFeedback;
26
27/**
28 * \class MovingRange movingrange.h <KTextEditor/MovingRange>
29 *
30 * \short A range that is bound to a specific Document, and maintains its
31 * position.
32 *
33 * \ingroup kte_group_moving_classes
34 *
35 * \section movingrange_intro Introduction
36 *
37 * A MovingRange is an extension of the basic Range class. It maintains its
38 * position in the document. As a result of this, MovingRange%s may not be
39 * copied, as they need to maintain a connection to the associated Document.
40 *
41 * Create a new MovingRange like this:
42 * \code
43 * KTextEditor::MovingRange* range = yourDocument->newMovingRange();
44 * \endcode
45 *
46 * The ownership of the range is passed to the user. When finished with a MovingRange,
47 * simply delete it.
48 *
49 * \section movingrange_behavior Editing Behavior
50 *
51 * The insert behavior controls how the range reacts to characters inserted
52 * at the range boundaries, i.e. at the start of the range or the end of the
53 * range. Either the range boundary moves with text insertion, or it stays.
54 * Use setInsertBehaviors() and insertBehaviors() to set and query the current
55 * insert behavior.
56 *
57 * When the start() and end() Cursor of a range equal, isEmpty() returns true.
58 * Further, the empty-behavior can be changed such that the start() and end()
59 * Cursor%s of MovingRange%s that get empty are automatically set to (-1, -1).
60 * Use setEmptyBehavior() and emptyBehavior() to control the empty behavior.
61 *
62 * \warning MovingRanges may be set to (-1, -1, -1, -1) at any time, if the
63 * user reloads a document (F5)! Use a MovingRangeFeedback to get notified
64 * if you need to catch this case, and/or listen to the signal
65 * MovingInterface::aboutToInvalidateMovingInterfaceContent().
66 *
67 * \section movingrange_feedback MovingRange Feedback
68 *
69 * With setFeedback() a feedback instance can be associated with the moving
70 * range. The MovingRangeFeedback notifies about the following events:
71 * - the text cursor (caret) entered the range,
72 * - the text cursor (caret) left the range,
73 * - the mouse cursor entered the range,
74 * - the mouse cursor left the range,
75 * - the range got empty, i.e. start() == end(),
76 * - the range got invalid, i.e. start() == end() == (-1, -1).
77 *
78 * If a feedback is not needed anymore, call setFeedback(0).
79 *
80 * \section movingrange_details Working with Ranges
81 *
82 * There are several convenience methods that make working with MovingRanges
83 * very simple. For instance, use isEmpty() to check if the start() Cursor
84 * equals the end() Cursor. Use contains(), containsLine() or containsColumn()
85 * to check whether the MovingRange contains a Range, a Cursor, a line or
86 * column. The same holds for overlaps(), overlapsLine() and overlapsColumn().
87 * Besides onSingleLine() returns whether a MovingRange spans only one line.
88 *
89 * For compatibility, a MovingRange can be explicitly converted to a simple
90 * Range by calling toRange(), or implicitly by the Range operator.
91 *
92 * \section movingrange_highlighting Arbitrary Highlighting
93 *
94 * With setAttribute() highlighting Attribute%s can be assigned to a
95 * MovingRange. By default, this highlighting is used in all views of a
96 * document. Use setView(), if the highlighting should only appear in a
97 * specific view. Further, if the additional highlighting should not be
98 * printed call setAttributeOnlyForViews() with the parameter true.
99 *
100 * \section movingrange_example MovingRange Example
101 *
102 * In the following example, we assume the KTextEditor::Document has the
103 * contents:
104 * \code
105 * void printText(const std::string & text); // this is line 3
106 * \endcode
107 * In order to highlight the function name \e printText with a yellow background
108 * color, the following code is needed:
109 * \code
110 * KTextEditor::View * view = ...;
111 * KTextEditor::Document * doc = view->document();
112 *
113 * // range is of type KTextEditor::MovingRange*
114 * auto range = doc->newMovingRange(KTextEditor::Range(3, 5, 3, 14));
115 *
116 * KTextEditor::Attribute::Ptr attrib = new KTextEditor::Attribute();
117 * attrib->setBackground(Qt::yellow);
118 *
119 * range->setAttribute(attrib);
120 * \endcode
121 *
122 * MovingRange%s are invalidated automatically when a document is cleared or closed.
123 * Therefore, to avoid invalid ranges, make sure to read the API documentation
124 * about MovingInterface::aboutToDeleteMovingInterfaceContent().
125 *
126 * \sa Cursor, MovingCursor, Range, MovingInterface, MovingRangeFeedback
127 *
128 * \author Christoph Cullmann <cullmann@kde.org>
129 *
130 * \since 4.5
131 */
132class KTEXTEDITOR_EXPORT MovingRange
133{
134 //
135 // sub types
136 //
137public:
138 /// Determine how the range reacts to characters inserted immediately outside the range.
139 /// @see InsertBehaviors
141 /// Don't expand to encapsulate new characters in either direction. This is the default.
142 DoNotExpand = 0x0,
143 /// Expand to encapsulate new characters to the left of the range.
144 ExpandLeft = 0x1,
145 /// Expand to encapsulate new characters to the right of the range.
146 ExpandRight = 0x2
147 };
148 /// Stores a combination of #InsertBehavior values.
150
151 /**
152 * Behavior of range if it becomes empty.
153 */
155 AllowEmpty = 0x0, ///< allow range to be empty
156 InvalidateIfEmpty = 0x1 ///< invalidate range, if it becomes empty
157 };
158
159 //
160 // stuff that needs to be implemented by editor part cursors
161 //
162public:
163 /**
164 * Set insert behaviors.
165 * @param insertBehaviors new insert behaviors
166 */
167 virtual void setInsertBehaviors(InsertBehaviors insertBehaviors) = 0;
168
169 /**
170 * Get current insert behaviors.
171 * @return current insert behaviors
172 */
173 virtual InsertBehaviors insertBehaviors() const = 0;
174
175 /**
176 * Set if this range will invalidate itself if it becomes empty.
177 * @param emptyBehavior behavior on becoming empty
178 */
179 virtual void setEmptyBehavior(EmptyBehavior emptyBehavior) = 0;
180
181 /**
182 * Will this range invalidate itself if it becomes empty?
183 * @return behavior on becoming empty
184 */
185 virtual EmptyBehavior emptyBehavior() const = 0;
186
187 /**
188 * Gets the document to which this range is bound.
189 * \return a pointer to the document
190 */
191 virtual Document *document() const = 0;
192
193 /**
194 * Set the range of this range.
195 *
196 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
197 * automatically invalid!
198 *
199 * @param range new range for this clever range
200 */
201 virtual void setRange(KTextEditor::Range range) = 0;
202
203 /**
204 * Set the range of this range and the connected attribute.
205 * Avoids internal overhead of separate setting that.
206 *
207 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
208 * automatically invalid!
209 *
210 * @param range new range for this clever range
211 * @param attribute Attribute to assign to this range. If null, simply removes the previous Attribute.
212 *
213 * @since 6.0
214 */
215 virtual void setRange(KTextEditor::Range range, Attribute::Ptr attribute) = 0;
216
217 /**
218 * Set the range of this range and the connected attribute and Z-depth.
219 * Avoids internal overhead of separate setting that.
220 *
221 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
222 * automatically invalid!
223 *
224 * @param range new range for this clever range
225 * @param attribute Attribute to assign to this range. If null, simply removes the previous Attribute.
226 * @param zDepth new Z-depth of this range
227 *
228 * @since 6.0
229 */
230 virtual void setRange(KTextEditor::Range range, Attribute::Ptr attribute, qreal zDepth) = 0;
231
232 /**
233 * Retrieve start cursor of this range, read-only.
234 * @return start cursor
235 */
236 virtual const MovingCursor &start() const = 0;
237
238 /**
239 * Retrieve end cursor of this range, read-only.
240 * @return end cursor
241 */
242 virtual const MovingCursor &end() const = 0;
243
244 /**
245 * Gets the active view for this range. Might be already invalid, internally only used for pointer comparisons.
246 *
247 * \return a pointer to the active view
248 */
249 virtual View *view() const = 0;
250
251 /**
252 * Sets the currently active view for this range.
253 * This will trigger update of the relevant view parts, if the view changed.
254 * Set view before the attribute, that will avoid not needed redraws.
255 *
256 * \param view View to assign to this range. If null, simply
257 * removes the previous view.
258 */
259 virtual void setView(View *view) = 0;
260
261 /**
262 * Gets the active Attribute for this range.
263 *
264 * \return a pointer to the active attribute
265 */
266 virtual const Attribute::Ptr &attribute() const = 0;
267
268 /**
269 * Sets the currently active attribute for this range.
270 * This will trigger update of the relevant view parts, if the attribute changed.
271 *
272 * \param attribute Attribute to assign to this range. If null, simply
273 * removes the previous Attribute.
274 */
275 virtual void setAttribute(Attribute::Ptr attribute) = 0;
276
277 /**
278 * Is this range's attribute only visible in views, not for example prints?
279 * Default is false.
280 * @return range visible only for views
281 */
282 virtual bool attributeOnlyForViews() const = 0;
283
284 /**
285 * Set if this range's attribute is only visible in views, not for example prints.
286 * @param onlyForViews attribute only valid for views
287 */
288 virtual void setAttributeOnlyForViews(bool onlyForViews) = 0;
289
290 /**
291 * Gets the active MovingRangeFeedback for this range.
292 *
293 * \return a pointer to the active MovingRangeFeedback
294 */
295 virtual MovingRangeFeedback *feedback() const = 0;
296
297 /**
298 * Sets the currently active MovingRangeFeedback for this range.
299 * This will trigger evaluation if feedback must be send again (for example if mouse is already inside range).
300 *
301 * \param feedback MovingRangeFeedback to assign to this range. If null, simply
302 * removes the previous MovingRangeFeedback.
303 */
304 virtual void setFeedback(MovingRangeFeedback *feedback) = 0;
305
306 /**
307 * Gets the current Z-depth of this range.
308 * Ranges with smaller Z-depth than others will win during rendering.
309 * Default is 0.0.
310 *
311 * Defined depths for common kind of ranges use in editor components implementing this interface,
312 * smaller depths are more more in the foreground and will win during rendering:
313 * - Selection == -100000.0
314 * - Search == -10000.0
315 * - Bracket Highlighting == -1000.0
316 * - Folding Hover == -100.0
317 *
318 * \return current Z-depth of this range
319 */
320 virtual qreal zDepth() const = 0;
321
322 /**
323 * Set the current Z-depth of this range.
324 * Ranges with smaller Z-depth than others will win during rendering.
325 * This will trigger update of the relevant view parts, if the depth changed.
326 * Set depth before the attribute, that will avoid not needed redraws.
327 * Default is 0.0.
328 *
329 * \param zDepth new Z-depth of this range
330 */
331 virtual void setZDepth(qreal zDepth) = 0;
332
333 /**
334 * Destruct the moving range.
335 */
336 virtual ~MovingRange();
337
338 //
339 // forbidden stuff
340 //
341protected:
342 /**
343 * For inherited class only.
344 */
346
347public:
348 /**
349 * no copy constructor, don't allow this to be copied.
350 */
351 MovingRange(const MovingRange &) = delete;
352
353 /**
354 * no assignment operator, no copying around clever ranges.
355 */
357
358 //
359 // convenience API
360 //
361public:
362 /**
363 * \overload
364 * Set the range of this range
365 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
366 * automatically invalid!
367 * @param start new start for this clever range
368 * @param end new end for this clever range
369 */
370 void setRange(Cursor start, Cursor end);
371
372 /**
373 * Convert this clever range into a dumb one.
374 * @return normal range
375 */
376 const Range toRange() const
377 {
378 return Range(start().toCursor(), end().toCursor());
379 }
380
381 /**
382 * Convert this clever range into a dumb one. Equal to toRange, allowing to use implicit conversion.
383 * @return normal range
384 */
385 operator Range() const
386 {
387 return Range(start().toCursor(), end().toCursor());
388 }
389
390 /**
391 * Convert this MovingRange to a simple LineRange.
392 * @return LineRange from the start line to the end line of this range.
393 */
394 inline LineRange toLineRange() const Q_DECL_NOEXCEPT
395 {
396 return {start().line(), end().line()};
397 }
398
399 /**
400 * Returns true if this range contains no characters, ie. the start() and
401 * end() positions are the same.
402 *
403 * \returns \e true if the range contains no characters, otherwise \e false
404 */
405 inline bool isEmpty() const
406 {
407 return start() == end();
408 }
409
410 // BEGIN comparison functions
411 /**
412 * \name Comparison
413 *
414 * The following functions perform checks against this range in comparison
415 * to other lines, columns, cursors, and ranges.
416 */
417 /**
418 * Check whether the this range wholly encompasses \e range.
419 *
420 * \param range range to check
421 *
422 * \return \e true, if this range contains \e range, otherwise \e false
423 */
424 inline bool contains(const Range &range) const
425 {
426 return range.start() >= start() && range.end() <= end();
427 }
428
429 /**
430 * Check to see if \p cursor is contained within this range, ie >= start() and < end().
431 *
432 * \param cursor the position to test for containment
433 *
434 * \return \e true if the cursor is contained within this range, otherwise \e false.
435 */
436 inline bool contains(Cursor cursor) const
437 {
438 return cursor >= start() && cursor < end();
439 }
440
441 /**
442 * Returns true if this range wholly encompasses \p line.
443 *
444 * \param line line to check
445 *
446 * \return \e true if the line is wholly encompassed by this range, otherwise \e false.
447 */
448 inline bool containsLine(int line) const
449 {
450 return (line > start().line() || (line == start().line() && !start().column())) && line < end().line();
451 }
452
453 /**
454 * Check whether the range contains \e column.
455 *
456 * \param column column to check
457 *
458 * \return \e true if the range contains \e column, otherwise \e false
459 */
460 inline bool containsColumn(int column) const
461 {
462 return column >= start().column() && column < end().column();
463 }
464
465 /**
466 * Check whether the this range overlaps with \e range.
467 *
468 * \param range range to check against
469 *
470 * \return \e true, if this range overlaps with \e range, otherwise \e false
471 */
472 bool overlaps(const Range &range) const;
473
474 /**
475 * Check whether the range overlaps at least part of \e line.
476 *
477 * \param line line to check
478 *
479 * \return \e true, if the range overlaps at least part of \e line, otherwise \e false
480 */
481 inline bool overlapsLine(int line) const
482 {
483 return line >= start().line() && line <= end().line();
484 }
485
486 /**
487 * Check to see if this range overlaps \p column; that is, if \p column is
488 * between start().column() and end().column(). This function is most likely
489 * to be useful in relation to block text editing.
490 *
491 * \param column the column to test
492 *
493 * \return \e true if the column is between the range's starting and ending
494 * columns, otherwise \e false.
495 */
496 inline bool overlapsColumn(int column) const
497 {
498 return start().column() <= column && end().column() > column;
499 }
500
501 /**
502 * Check whether the start() and end() cursors of this range
503 * are on the same line.
504 *
505 * \return \e true if both the start and end positions are on the same
506 * line, otherwise \e false
507 */
508 inline bool onSingleLine() const
509 {
510 return start().line() == end().line();
511 }
512
513 /**
514 * Returns the number of lines separating the start() and end() positions.
515 *
516 * \return the number of lines separating the start() and end() positions;
517 * 0 if the start and end lines are the same.
518 */
519 inline int numberOfLines() const Q_DECL_NOEXCEPT
520 {
521 return end().line() - start().line();
522 }
523
524 // END comparison functions
525};
526
527Q_DECLARE_OPERATORS_FOR_FLAGS(MovingRange::InsertBehaviors)
528
529/**
530 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way.
531 * @param s debug stream
532 * @param range range to print
533 * @return debug stream
534 */
535KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, const MovingRange *range);
536
537/**
538 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way.
539 * @param s debug stream
540 * @param range range to print
541 * @return debug stream
542 */
543KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, const MovingRange &range);
544}
545
546#endif
The Cursor represents a position in a Document.
Definition cursor.h:75
A KParts derived class representing a text document.
Definition document.h:284
An object representing lines from a start line to an end line.
Definition linerange.h:41
A Cursor which is bound to a specific Document, and maintains its position.
A class which provides notifications of state changes to a MovingRange.
A range that is bound to a specific Document, and maintains its position.
virtual EmptyBehavior emptyBehavior() const =0
Will this range invalidate itself if it becomes empty?
bool containsColumn(int column) const
Check whether the range contains column.
virtual void setAttribute(Attribute::Ptr attribute)=0
Sets the currently active attribute for this range.
virtual const MovingCursor & start() const =0
Retrieve start cursor of this range, read-only.
virtual void setAttributeOnlyForViews(bool onlyForViews)=0
Set if this range's attribute is only visible in views, not for example prints.
virtual const Attribute::Ptr & attribute() const =0
Gets the active Attribute for this range.
virtual void setRange(KTextEditor::Range range, Attribute::Ptr attribute, qreal zDepth)=0
Set the range of this range and the connected attribute and Z-depth.
bool isEmpty() const
Returns true if this range contains no characters, ie.
virtual void setInsertBehaviors(InsertBehaviors insertBehaviors)=0
Set insert behaviors.
bool overlapsColumn(int column) const
Check to see if this range overlaps column; that is, if column is between start()....
virtual void setView(View *view)=0
Sets the currently active view for this range.
bool containsLine(int line) const
Returns true if this range wholly encompasses line.
QFlags< InsertBehavior > InsertBehaviors
Stores a combination of InsertBehavior values.
virtual const MovingCursor & end() const =0
Retrieve end cursor of this range, read-only.
virtual MovingRangeFeedback * feedback() const =0
Gets the active MovingRangeFeedback for this range.
virtual void setRange(KTextEditor::Range range, Attribute::Ptr attribute)=0
Set the range of this range and the connected attribute.
bool overlapsLine(int line) const
Check whether the range overlaps at least part of line.
int numberOfLines() const Q_DECL_NOEXCEPT
Returns the number of lines separating the start() and end() positions.
EmptyBehavior
Behavior of range if it becomes empty.
virtual ~MovingRange()
Destruct the moving range.
const Range toRange() const
Convert this clever range into a dumb one.
LineRange toLineRange() const Q_DECL_NOEXCEPT
Convert this MovingRange to a simple LineRange.
MovingRange(const MovingRange &)=delete
no copy constructor, don't allow this to be copied.
MovingRange & operator=(const MovingRange &)=delete
no assignment operator, no copying around clever ranges.
virtual void setFeedback(MovingRangeFeedback *feedback)=0
Sets the currently active MovingRangeFeedback for this range.
virtual void setZDepth(qreal zDepth)=0
Set the current Z-depth of this range.
virtual Document * document() const =0
Gets the document to which this range is bound.
bool contains(const Range &range) const
Check whether the this range wholly encompasses range.
virtual bool attributeOnlyForViews() const =0
Is this range's attribute only visible in views, not for example prints? Default is false.
virtual void setEmptyBehavior(EmptyBehavior emptyBehavior)=0
Set if this range will invalidate itself if it becomes empty.
virtual View * view() const =0
Gets the active view for this range.
bool contains(Cursor cursor) const
Check to see if cursor is contained within this range, ie >= start() and < end().
virtual qreal zDepth() const =0
Gets the current Z-depth of this range.
virtual InsertBehaviors insertBehaviors() const =0
Get current insert behaviors.
virtual void setRange(KTextEditor::Range range)=0
Set the range of this range.
bool onSingleLine() const
Check whether the start() and end() cursors of this range are on the same line.
InsertBehavior
Determine how the range reacts to characters inserted immediately outside the range.
MovingRange()
For inherited class only.
An object representing a section of text, from one Cursor to another.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
A text widget with KXMLGUIClient that represents a Document.
Definition view.h:244
Q_SCRIPTABLE Q_NOREPLY void start()
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, const MovingCursor *cursor)
qDebug() stream operator.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:11:26 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.