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 << &range;
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