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

KDE's Doxygen guidelines are available online.