Warning, file /frameworks/ktexteditor/src/include/ktexteditor/movingrange.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org> 0003 0004 Based on code of the SmartCursor/Range by: 0005 SPDX-FileCopyrightText: 2003-2005 Hamish Rodda <rodda@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #ifndef KTEXTEDITOR_MOVINGRANGE_H 0011 #define KTEXTEDITOR_MOVINGRANGE_H 0012 0013 #include <ktexteditor/attribute.h> 0014 #include <ktexteditor/linerange.h> 0015 #include <ktexteditor/movingcursor.h> 0016 #include <ktexteditor/range.h> 0017 #include <ktexteditor_export.h> 0018 0019 #include <QDebug> 0020 0021 namespace KTextEditor 0022 { 0023 class Document; 0024 class View; 0025 class MovingRangeFeedback; 0026 0027 /** 0028 * \class MovingRange movingrange.h <KTextEditor/MovingRange> 0029 * 0030 * \short A range that is bound to a specific Document, and maintains its 0031 * position. 0032 * 0033 * \ingroup kte_group_moving_classes 0034 * 0035 * \section movingrange_intro Introduction 0036 * 0037 * A MovingRange is an extension of the basic Range class. It maintains its 0038 * position in the document. As a result of this, MovingRange%s may not be 0039 * copied, as they need to maintain a connection to the associated Document. 0040 * 0041 * Create a new MovingRange like this: 0042 * \code 0043 * // Retrieve the MovingInterface 0044 * KTextEditor::MovingInterface* moving = 0045 * qobject_cast<KTextEditor::MovingInterface*>( yourDocument ); 0046 * 0047 * if ( moving ) { 0048 * KTextEditor::MovingRange* range = moving->newMovingRange(); 0049 * } 0050 * \endcode 0051 * 0052 * When finished with a MovingRange, simply delete it. 0053 * If the document the cursor belong to is deleted, it will get deleted 0054 * automatically. 0055 * 0056 * \section movingrange_behavior Editing Behavior 0057 * 0058 * The insert behavior controls how the range reacts to characters inserted 0059 * at the range boundaries, i.e. at the start of the range or the end of the 0060 * range. Either the range boundary moves with text insertion, or it stays. 0061 * Use setInsertBehaviors() and insertBehaviors() to set and query the current 0062 * insert behavior. 0063 * 0064 * When the start() and end() Cursor of a range equal, isEmpty() returns true. 0065 * Further, the empty-behavior can be changed such that the start() and end() 0066 * Cursor%s of MovingRange%s that get empty are automatically set to (-1, -1). 0067 * Use setEmptyBehavior() and emptyBehavior() to control the empty behavior. 0068 * 0069 * \warning MovingRanges may be set to (-1, -1, -1, -1) at any time, if the 0070 * user reloads a document (F5)! Use a MovingRangeFeedback to get notified 0071 * if you need to catch this case, and/or listen to the signal 0072 * MovingInterface::aboutToInvalidateMovingInterfaceContent(). 0073 * 0074 * \section movingrange_feedback MovingRange Feedback 0075 * 0076 * With setFeedback() a feedback instance can be associated with the moving 0077 * range. The MovingRangeFeedback notifies about the following events: 0078 * - the text cursor (caret) entered the range, 0079 * - the text cursor (caret) left the range, 0080 * - the mouse cursor entered the range, 0081 * - the mouse cursor left the range, 0082 * - the range got empty, i.e. start() == end(), 0083 * - the range got invalid, i.e. start() == end() == (-1, -1). 0084 * 0085 * If a feedback is not needed anymore, call setFeedback(0). 0086 * 0087 * \section movingrange_details Working with Ranges 0088 * 0089 * There are several convenience methods that make working with MovingRanges 0090 * very simple. For instance, use isEmpty() to check if the start() Cursor 0091 * equals the end() Cursor. Use contains(), containsLine() or containsColumn() 0092 * to check whether the MovingRange contains a Range, a Cursor, a line or 0093 * column. The same holds for overlaps(), overlapsLine() and overlapsColumn(). 0094 * Besides onSingleLine() returns whether a MovingRange spans only one line. 0095 * 0096 * For compatibility, a MovingRange can be explicitly converted to a simple 0097 * Range by calling toRange(), or implicitly by the Range operator. 0098 * 0099 * \section movingrange_highlighting Arbitrary Highlighting 0100 * 0101 * With setAttribute() highlighting Attribute%s can be assigned to a 0102 * MovingRange. By default, this highlighting is used in all views of a 0103 * document. Use setView(), if the highlighting should only appear in a 0104 * specific view. Further, if the additional highlighting should not be 0105 * printed call setAttributeOnlyForViews() with the parameter true. 0106 * 0107 * \section movingrange_example MovingRange Example 0108 * 0109 * In the following example, we assume the KTextEditor::Document has the 0110 * contents: 0111 * \code 0112 * void printText(const std::string & text); // this is line 3 0113 * \endcode 0114 * In order to highlight the function name \e printText with a yellow background 0115 * color, the following code is needed: 0116 * \code 0117 * KTextEditor::View * view = ...; 0118 * KTextEditor::Document * doc = view->document(); 0119 * 0120 * auto iface = qobject_cast<KTextEditor::MovingInterface*>(doc); 0121 * if (!iface) { 0122 * return; 0123 * } 0124 * 0125 * // range is of type KTextEditor::MovingRange* 0126 * auto range = iface->newMovingRange(KTextEditor::Range(3, 5, 3, 14)); 0127 * 0128 * KTextEditor::Attribute::Ptr attrib = new KTextEditor::Attribute(); 0129 * attrib->setBackground(Qt::yellow); 0130 * 0131 * range->setAttribute(attrib); 0132 * \endcode 0133 * 0134 * MovingRange%s are deleted automatically when a document is cleared or closed. 0135 * Therefore, to avoid dangling pointers, make sure to read the API documentation 0136 * about MovingInterface::aboutToDeleteMovingInterfaceContent(). 0137 * 0138 * \sa Cursor, MovingCursor, Range, MovingInterface, MovingRangeFeedback 0139 * 0140 * \author Christoph Cullmann \<cullmann@kde.org\> 0141 * 0142 * \since 4.5 0143 */ 0144 class KTEXTEDITOR_EXPORT MovingRange 0145 { 0146 // 0147 // sub types 0148 // 0149 public: 0150 /// Determine how the range reacts to characters inserted immediately outside the range. 0151 /// @see InsertBehaviors 0152 enum InsertBehavior { 0153 /// Don't expand to encapsulate new characters in either direction. This is the default. 0154 DoNotExpand = 0x0, 0155 /// Expand to encapsulate new characters to the left of the range. 0156 ExpandLeft = 0x1, 0157 /// Expand to encapsulate new characters to the right of the range. 0158 ExpandRight = 0x2 0159 }; 0160 /// Stores a combination of #InsertBehavior values. 0161 Q_DECLARE_FLAGS(InsertBehaviors, InsertBehavior) 0162 0163 /** 0164 * Behavior of range if it becomes empty. 0165 */ 0166 enum EmptyBehavior { 0167 AllowEmpty = 0x0, ///< allow range to be empty 0168 InvalidateIfEmpty = 0x1 ///< invalidate range, if it becomes empty 0169 }; 0170 0171 // 0172 // stuff that needs to be implemented by editor part cursors 0173 // 0174 public: 0175 /** 0176 * Set insert behaviors. 0177 * @param insertBehaviors new insert behaviors 0178 */ 0179 virtual void setInsertBehaviors(InsertBehaviors insertBehaviors) = 0; 0180 0181 /** 0182 * Get current insert behaviors. 0183 * @return current insert behaviors 0184 */ 0185 virtual InsertBehaviors insertBehaviors() const = 0; 0186 0187 /** 0188 * Set if this range will invalidate itself if it becomes empty. 0189 * @param emptyBehavior behavior on becoming empty 0190 */ 0191 virtual void setEmptyBehavior(EmptyBehavior emptyBehavior) = 0; 0192 0193 /** 0194 * Will this range invalidate itself if it becomes empty? 0195 * @return behavior on becoming empty 0196 */ 0197 virtual EmptyBehavior emptyBehavior() const = 0; 0198 0199 /** 0200 * Gets the document to which this range is bound. 0201 * \return a pointer to the document 0202 */ 0203 virtual Document *document() const = 0; 0204 0205 /** 0206 * Set the range of this range. 0207 * A TextRange is not allowed to be empty, as soon as start == end position, it will become 0208 * automatically invalid! 0209 * @param range new range for this clever range 0210 */ 0211 virtual void setRange(const KTextEditor::Range &range) = 0; 0212 0213 /** 0214 * Retrieve start cursor of this range, read-only. 0215 * @return start cursor 0216 */ 0217 virtual const MovingCursor &start() const = 0; 0218 0219 /** 0220 * Retrieve end cursor of this range, read-only. 0221 * @return end cursor 0222 */ 0223 virtual const MovingCursor &end() const = 0; 0224 0225 /** 0226 * Gets the active view for this range. Might be already invalid, internally only used for pointer comparisons. 0227 * 0228 * \return a pointer to the active view 0229 */ 0230 virtual View *view() const = 0; 0231 0232 /** 0233 * Sets the currently active view for this range. 0234 * This will trigger update of the relevant view parts, if the view changed. 0235 * Set view before the attribute, that will avoid not needed redraws. 0236 * 0237 * \param view View to assign to this range. If null, simply 0238 * removes the previous view. 0239 */ 0240 virtual void setView(View *view) = 0; 0241 0242 /** 0243 * Gets the active Attribute for this range. 0244 * 0245 * \return a pointer to the active attribute 0246 */ 0247 virtual Attribute::Ptr attribute() const = 0; 0248 0249 /** 0250 * Sets the currently active attribute for this range. 0251 * This will trigger update of the relevant view parts, if the attribute changed. 0252 * 0253 * \param attribute Attribute to assign to this range. If null, simply 0254 * removes the previous Attribute. 0255 */ 0256 virtual void setAttribute(Attribute::Ptr attribute) = 0; 0257 0258 /** 0259 * Is this range's attribute only visible in views, not for example prints? 0260 * Default is false. 0261 * @return range visible only for views 0262 */ 0263 virtual bool attributeOnlyForViews() const = 0; 0264 0265 /** 0266 * Set if this range's attribute is only visible in views, not for example prints. 0267 * @param onlyForViews attribute only valid for views 0268 */ 0269 virtual void setAttributeOnlyForViews(bool onlyForViews) = 0; 0270 0271 /** 0272 * Gets the active MovingRangeFeedback for this range. 0273 * 0274 * \return a pointer to the active MovingRangeFeedback 0275 */ 0276 virtual MovingRangeFeedback *feedback() const = 0; 0277 0278 /** 0279 * Sets the currently active MovingRangeFeedback for this range. 0280 * This will trigger evaluation if feedback must be send again (for example if mouse is already inside range). 0281 * 0282 * \param feedback MovingRangeFeedback to assign to this range. If null, simply 0283 * removes the previous MovingRangeFeedback. 0284 */ 0285 virtual void setFeedback(MovingRangeFeedback *feedback) = 0; 0286 0287 /** 0288 * Gets the current Z-depth of this range. 0289 * Ranges with smaller Z-depth than others will win during rendering. 0290 * Default is 0.0. 0291 * 0292 * Defined depths for common kind of ranges use in editor components implementing this interface, 0293 * smaller depths are more more in the foreground and will win during rendering: 0294 * - Selection == -100000.0 0295 * - Search == -10000.0 0296 * - Bracket Highlighting == -1000.0 0297 * - Folding Hover == -100.0 0298 * 0299 * \return current Z-depth of this range 0300 */ 0301 virtual qreal zDepth() const = 0; 0302 0303 /** 0304 * Set the current Z-depth of this range. 0305 * Ranges with smaller Z-depth than others will win during rendering. 0306 * This will trigger update of the relevant view parts, if the depth changed. 0307 * Set depth before the attribute, that will avoid not needed redraws. 0308 * Default is 0.0. 0309 * 0310 * \param zDepth new Z-depth of this range 0311 */ 0312 virtual void setZDepth(qreal zDepth) = 0; 0313 0314 /** 0315 * Destruct the moving range. 0316 */ 0317 virtual ~MovingRange(); 0318 0319 // 0320 // forbidden stuff 0321 // 0322 protected: 0323 /** 0324 * For inherited class only. 0325 */ 0326 MovingRange(); 0327 0328 private: 0329 /** 0330 * no copy constructor, don't allow this to be copied. 0331 */ 0332 MovingRange(const MovingRange &); 0333 0334 /** 0335 * no assignment operator, no copying around clever ranges. 0336 */ 0337 MovingRange &operator=(const MovingRange &); 0338 0339 // 0340 // convenience API 0341 // 0342 public: 0343 /** 0344 * \overload 0345 * Set the range of this range 0346 * A TextRange is not allowed to be empty, as soon as start == end position, it will become 0347 * automatically invalid! 0348 * @param start new start for this clever range 0349 * @param end new end for this clever range 0350 */ 0351 void setRange(const Cursor &start, const Cursor &end); 0352 0353 /** 0354 * Convert this clever range into a dumb one. 0355 * @return normal range 0356 */ 0357 const Range toRange() const 0358 { 0359 return Range(start().toCursor(), end().toCursor()); 0360 } 0361 0362 /** 0363 * Convert this clever range into a dumb one. Equal to toRange, allowing to use implicit conversion. 0364 * @return normal range 0365 */ 0366 operator Range() const 0367 { 0368 return Range(start().toCursor(), end().toCursor()); 0369 } 0370 0371 /** 0372 * Convert this MovingRange to a simple LineRange. 0373 * @return LineRange from the start line to the end line of this range. 0374 */ 0375 inline LineRange toLineRange() const Q_DECL_NOEXCEPT 0376 { 0377 return {start().line(), end().line()}; 0378 } 0379 0380 /** 0381 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way. 0382 * @param s debug stream 0383 * @param range range to print 0384 * @return debug stream 0385 */ 0386 inline friend QDebug operator<<(QDebug s, const MovingRange *range) 0387 { 0388 if (range) { 0389 s << "[" << range->start() << " -> " << range->end() << "]"; 0390 } else { 0391 s << "(null range)"; 0392 } 0393 return s.space(); 0394 } 0395 0396 /** 0397 * qDebug() stream operator. Writes this range to the debug output in a nicely formatted way. 0398 * @param s debug stream 0399 * @param range range to print 0400 * @return debug stream 0401 */ 0402 inline friend QDebug operator<<(QDebug s, const MovingRange &range) 0403 { 0404 return s << ⦥ 0405 } 0406 0407 /** 0408 * Returns true if this range contains no characters, ie. the start() and 0409 * end() positions are the same. 0410 * 0411 * \returns \e true if the range contains no characters, otherwise \e false 0412 */ 0413 inline bool isEmpty() const 0414 { 0415 return start() == end(); 0416 } 0417 0418 // BEGIN comparison functions 0419 /** 0420 * \name Comparison 0421 * 0422 * The following functions perform checks against this range in comparison 0423 * to other lines, columns, cursors, and ranges. 0424 */ 0425 /** 0426 * Check whether the this range wholly encompasses \e range. 0427 * 0428 * \param range range to check 0429 * 0430 * \return \e true, if this range contains \e range, otherwise \e false 0431 */ 0432 inline bool contains(const Range &range) const 0433 { 0434 return range.start() >= start() && range.end() <= end(); 0435 } 0436 0437 /** 0438 * Check to see if \p cursor is contained within this range, ie >= start() and \< end(). 0439 * 0440 * \param cursor the position to test for containment 0441 * 0442 * \return \e true if the cursor is contained within this range, otherwise \e false. 0443 */ 0444 inline bool contains(const Cursor &cursor) const 0445 { 0446 return cursor >= start() && cursor < end(); 0447 } 0448 0449 /** 0450 * Returns true if this range wholly encompasses \p line. 0451 * 0452 * \param line line to check 0453 * 0454 * \return \e true if the line is wholly encompassed by this range, otherwise \e false. 0455 */ 0456 inline bool containsLine(int line) const 0457 { 0458 return (line > start().line() || (line == start().line() && !start().column())) && line < end().line(); 0459 } 0460 0461 /** 0462 * Check whether the range contains \e column. 0463 * 0464 * \param column column to check 0465 * 0466 * \return \e true if the range contains \e column, otherwise \e false 0467 */ 0468 inline bool containsColumn(int column) const 0469 { 0470 return column >= start().column() && column < end().column(); 0471 } 0472 0473 /** 0474 * Check whether the this range overlaps with \e range. 0475 * 0476 * \param range range to check against 0477 * 0478 * \return \e true, if this range overlaps with \e range, otherwise \e false 0479 */ 0480 bool overlaps(const Range &range) const; 0481 0482 /** 0483 * Check whether the range overlaps at least part of \e line. 0484 * 0485 * \param line line to check 0486 * 0487 * \return \e true, if the range overlaps at least part of \e line, otherwise \e false 0488 */ 0489 inline bool overlapsLine(int line) const 0490 { 0491 return line >= start().line() && line <= end().line(); 0492 } 0493 0494 /** 0495 * Check to see if this range overlaps \p column; that is, if \p column is 0496 * between start().column() and end().column(). This function is most likely 0497 * to be useful in relation to block text editing. 0498 * 0499 * \param column the column to test 0500 * 0501 * \return \e true if the column is between the range's starting and ending 0502 * columns, otherwise \e false. 0503 */ 0504 inline bool overlapsColumn(int column) const 0505 { 0506 return start().column() <= column && end().column() > column; 0507 } 0508 0509 /** 0510 * Check whether the start() and end() cursors of this range 0511 * are on the same line. 0512 * 0513 * \return \e true if both the start and end positions are on the same 0514 * line, otherwise \e false 0515 */ 0516 inline bool onSingleLine() const 0517 { 0518 return start().line() == end().line(); 0519 } 0520 0521 /** 0522 * Returns the number of lines separating the start() and end() positions. 0523 * 0524 * \return the number of lines separating the start() and end() positions; 0525 * 0 if the start and end lines are the same. 0526 */ 0527 inline int numberOfLines() const Q_DECL_NOEXCEPT 0528 { 0529 return end().line() - start().line(); 0530 } 0531 0532 // END comparison functions 0533 }; 0534 0535 Q_DECLARE_OPERATORS_FOR_FLAGS(MovingRange::InsertBehaviors) 0536 0537 } 0538 0539 #endif