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 *
124 * \sa Cursor, MovingCursor, Range, MovingInterface, MovingRangeFeedback
125 *
126 * \author Christoph Cullmann <cullmann@kde.org>
127 *
128 * \since 4.5
129 */
130class KTEXTEDITOR_EXPORT MovingRange
131{
132 //
133 // sub types
134 //
135public:
136 /// Determine how the range reacts to characters inserted immediately outside the range.
137 /// @see InsertBehaviors
139 /// Don't expand to encapsulate new characters in either direction. This is the default.
140 DoNotExpand = 0x0,
141 /// Expand to encapsulate new characters to the left of the range.
142 ExpandLeft = 0x1,
143 /// Expand to encapsulate new characters to the right of the range.
144 ExpandRight = 0x2
145 };
146 /// Stores a combination of #InsertBehavior values.
148
149 /**
150 * Behavior of range if it becomes empty.
151 */
153 AllowEmpty = 0x0, ///< allow range to be empty
154 InvalidateIfEmpty = 0x1 ///< invalidate range, if it becomes empty
155 };
156
157 //
158 // stuff that needs to be implemented by editor part cursors
159 //
160public:
161 /**
162 * Set insert behaviors.
163 * @param insertBehaviors new insert behaviors
164 */
165 virtual void setInsertBehaviors(InsertBehaviors insertBehaviors) = 0;
166
167 /**
168 * Get current insert behaviors.
169 * @return current insert behaviors
170 */
171 virtual InsertBehaviors insertBehaviors() const = 0;
172
173 /**
174 * Set if this range will invalidate itself if it becomes empty.
175 * @param emptyBehavior behavior on becoming empty
176 */
177 virtual void setEmptyBehavior(EmptyBehavior emptyBehavior) = 0;
178
179 /**
180 * Will this range invalidate itself if it becomes empty?
181 * @return behavior on becoming empty
182 */
183 virtual EmptyBehavior emptyBehavior() const = 0;
184
185 /**
186 * Gets the document to which this range is bound.
187 * \return a pointer to the document
188 */
189 virtual Document *document() const = 0;
190
191 /**
192 * Set the range of this range.
193 *
194 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
195 * automatically invalid!
196 *
197 * @param range new range for this clever range
198 */
199 virtual void setRange(KTextEditor::Range range) = 0;
200
201 /**
202 * Set the range of this range and the connected attribute.
203 * Avoids internal overhead of separate setting that.
204 *
205 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
206 * automatically invalid!
207 *
208 * @param range new range for this clever range
209 * @param attribute Attribute to assign to this range. If null, simply removes the previous Attribute.
210 *
211 * @since 6.0
212 */
213 virtual void setRange(KTextEditor::Range range, Attribute::Ptr attribute) = 0;
214
215 /**
216 * Set the range of this range and the connected attribute and Z-depth.
217 * Avoids internal overhead of separate setting that.
218 *
219 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
220 * automatically invalid!
221 *
222 * @param range new range for this clever range
223 * @param attribute Attribute to assign to this range. If null, simply removes the previous Attribute.
224 * @param zDepth new Z-depth of this range
225 *
226 * @since 6.0
227 */
228 virtual void setRange(KTextEditor::Range range, Attribute::Ptr attribute, qreal zDepth) = 0;
229
230 /**
231 * Retrieve start cursor of this range, read-only.
232 * @return start cursor
233 */
234 virtual const MovingCursor &start() const = 0;
235
236 /**
237 * Retrieve end cursor of this range, read-only.
238 * @return end cursor
239 */
240 virtual const MovingCursor &end() const = 0;
241
242 /**
243 * Gets the active view for this range. Might be already invalid, internally only used for pointer comparisons.
244 *
245 * \return a pointer to the active view
246 */
247 virtual View *view() const = 0;
248
249 /**
250 * Sets the currently active view for this range.
251 * This will trigger update of the relevant view parts, if the view changed.
252 * Set view before the attribute, that will avoid not needed redraws.
253 *
254 * \param view View to assign to this range. If null, simply
255 * removes the previous view.
256 */
257 virtual void setView(View *view) = 0;
258
259 /**
260 * Gets the active Attribute for this range.
261 *
262 * \return a pointer to the active attribute
263 */
264 virtual const Attribute::Ptr &attribute() const = 0;
265
266 /**
267 * Sets the currently active attribute for this range.
268 * This will trigger update of the relevant view parts, if the attribute changed.
269 *
270 * \param attribute Attribute to assign to this range. If null, simply
271 * removes the previous Attribute.
272 */
273 virtual void setAttribute(Attribute::Ptr attribute) = 0;
274
275 /**
276 * Is this range's attribute only visible in views, not for example prints?
277 * Default is false.
278 * @return range visible only for views
279 */
280 virtual bool attributeOnlyForViews() const = 0;
281
282 /**
283 * Set if this range's attribute is only visible in views, not for example prints.
284 * @param onlyForViews attribute only valid for views
285 */
286 virtual void setAttributeOnlyForViews(bool onlyForViews) = 0;
287
288 /**
289 * Gets the active MovingRangeFeedback for this range.
290 *
291 * \return a pointer to the active MovingRangeFeedback
292 */
293 virtual MovingRangeFeedback *feedback() const = 0;
294
295 /**
296 * Sets the currently active MovingRangeFeedback for this range.
297 * This will trigger evaluation if feedback must be send again (for example if mouse is already inside range).
298 *
299 * \param feedback MovingRangeFeedback to assign to this range. If null, simply
300 * removes the previous MovingRangeFeedback.
301 */
302 virtual void setFeedback(MovingRangeFeedback *feedback) = 0;
303
304 /**
305 * Gets the current Z-depth of this range.
306 * Ranges with smaller Z-depth than others will win during rendering.
307 * Default is 0.0.
308 *
309 * Defined depths for common kind of ranges use in editor components implementing this interface,
310 * smaller depths are more more in the foreground and will win during rendering:
311 * - Selection == -100000.0
312 * - Search == -10000.0
313 * - Bracket Highlighting == -1000.0
314 * - Folding Hover == -100.0
315 *
316 * \return current Z-depth of this range
317 */
318 virtual qreal zDepth() const = 0;
319
320 /**
321 * Set the current Z-depth of this range.
322 * Ranges with smaller Z-depth than others will win during rendering.
323 * This will trigger update of the relevant view parts, if the depth changed.
324 * Set depth before the attribute, that will avoid not needed redraws.
325 * Default is 0.0.
326 *
327 * \param zDepth new Z-depth of this range
328 */
329 virtual void setZDepth(qreal zDepth) = 0;
330
331 /**
332 * Destruct the moving range.
333 */
334 virtual ~MovingRange();
335
336 //
337 // forbidden stuff
338 //
339protected:
340 /**
341 * For inherited class only.
342 */
344
345public:
346 /**
347 * no copy constructor, don't allow this to be copied.
348 */
349 MovingRange(const MovingRange &) = delete;
350
351 /**
352 * no assignment operator, no copying around clever ranges.
353 */
355
356 //
357 // convenience API
358 //
359public:
360 /**
361 * \overload
362 * Set the range of this range
363 * A TextRange is not allowed to be empty, as soon as start == end position, it will become
364 * automatically invalid!
365 * @param start new start for this clever range
366 * @param end new end for this clever range
367 */
368 void setRange(Cursor start, Cursor end);
369
370 /**
371 * Convert this clever range into a dumb one.
372 * @return normal range
373 */
374 const Range toRange() const
375 {
376 return Range(start().toCursor(), end().toCursor());
377 }
378
379 /**
380 * Convert this clever range into a dumb one. Equal to toRange, allowing to use implicit conversion.
381 * @return normal range
382 */
383 operator Range() const
384 {
385 return Range(start().toCursor(), end().toCursor());
386 }
387
388 /**
389 * Convert this MovingRange to a simple LineRange.
390 * @return LineRange from the start line to the end line of this range.
391 */
392 inline LineRange toLineRange() const Q_DECL_NOEXCEPT
393 {
394 return {start().line(), end().line()};
395 }
396
397 /**
398 * Returns true if this range contains no characters, ie. the start() and
399 * end() positions are the same.
400 *
401 * \returns \e true if the range contains no characters, otherwise \e false
402 */
403 inline bool isEmpty() const
404 {
405 return start() == end();
406 }
407
408 // BEGIN comparison functions
409 /**
410 * \name Comparison
411 *
412 * The following functions perform checks against this range in comparison
413 * to other lines, columns, cursors, and ranges.
414 */
415 /**
416 * Check whether the this range wholly encompasses \e range.
417 *
418 * \param range range to check
419 *
420 * \return \e true, if this range contains \e range, otherwise \e false
421 */
422 inline bool contains(const Range &range) const
423 {
424 return range.start() >= start() && range.end() <= end();
425 }
426
427 /**
428 * Check to see if \p cursor is contained within this range, ie >= start() and < end().
429 *
430 * \param cursor the position to test for containment
431 *
432 * \return \e true if the cursor is contained within this range, otherwise \e false.
433 */
434 inline bool contains(Cursor cursor) const
435 {
436 return cursor >= start() && cursor < end();
437 }
438
439 /**
440 * Returns true if this range wholly encompasses \p line.
441 *
442 * \param line line to check
443 *
444 * \return \e true if the line is wholly encompassed by this range, otherwise \e false.
445 */
446 inline bool containsLine(int line) const
447 {
448 return (line > start().line() || (line == start().line() && !start().column())) && line < end().line();
449 }
450
451 /**
452 * Check whether the range contains \e column.
453 *
454 * \param column column to check
455 *
456 * \return \e true if the range contains \e column, otherwise \e false
457 */
458 inline bool containsColumn(int column) const
459 {
460 return column >= start().column() && column < end().column();
461 }
462
463 /**
464 * Check whether the this range overlaps with \e range.
465 *
466 * \param range range to check against
467 *
468 * \return \e true, if this range overlaps with \e range, otherwise \e false
469 */
470 bool overlaps(const Range &range) const;
471
472 /**
473 * Check whether the range overlaps at least part of \e line.
474 *
475 * \param line line to check
476 *
477 * \return \e true, if the range overlaps at least part of \e line, otherwise \e false
478 */
479 inline bool overlapsLine(int line) const
480 {
481 return line >= start().line() && line <= end().line();
482 }
483
484 /**
485 * Check to see if this range overlaps \p column; that is, if \p column is
486 * between start().column() and end().column(). This function is most likely
487 * to be useful in relation to block text editing.
488 *
489 * \param column the column to test
490 *
491 * \return \e true if the column is between the range's starting and ending
492 * columns, otherwise \e false.
493 */
494 inline bool overlapsColumn(int column) const
495 {
496 return start().column() <= column && end().column() > column;
497 }
498
499 /**
500 * Check whether the start() and end() cursors of this range
501 * are on the same line.
502 *
503 * \return \e true if both the start and end positions are on the same
504 * line, otherwise \e false
505 */
506 inline bool onSingleLine() const
507 {
508 return start().line() == end().line();
509 }
510
511 /**
512 * Returns the number of lines separating the start() and end() positions.
513 *
514 * \return the number of lines separating the start() and end() positions;
515 * 0 if the start and end lines are the same.
516 */
517 inline int numberOfLines() const Q_DECL_NOEXCEPT
518 {
519 return end().line() - start().line();
520 }
521
522 // END comparison functions
523};
524
525Q_DECLARE_OPERATORS_FOR_FLAGS(MovingRange::InsertBehaviors)
526
527/**
528 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way.
529 * @param s debug stream
530 * @param range range to print
531 * @return debug stream
532 */
533KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, const MovingRange *range);
534
535/**
536 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way.
537 * @param s debug stream
538 * @param range range to print
539 * @return debug stream
540 */
541KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, const MovingRange &range);
542}
543
544#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 Fri Dec 13 2024 11:57:04 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.