File indexing completed on 2024-05-12 15:45:40

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_MOVINGCURSOR_H
0011 #define KTEXTEDITOR_MOVINGCURSOR_H
0012 
0013 #include <ktexteditor/cursor.h>
0014 #include <ktexteditor/document.h>
0015 #include <ktexteditor_export.h>
0016 
0017 #include <QDebug>
0018 
0019 namespace KTextEditor
0020 {
0021 class MovingRange;
0022 
0023 /**
0024  * \class MovingCursor movingcursor.h <KTextEditor/MovingCursor>
0025  *
0026  * \short A Cursor which is bound to a specific Document, and maintains its position.
0027  *
0028  * \ingroup kte_group_moving_classes
0029  *
0030  * A MovingCursor is an extension of the basic Cursor class. It maintains its
0031  * position in the document. As a result of this, MovingCursor%s may not be copied, as they need
0032  * to maintain a connection to the associated Document.
0033  *
0034  * Create a new MovingCursor like this:
0035  * \code
0036  * // Retrieve the MovingInterface
0037  * KTextEditor::MovingInterface* moving =
0038  *     qobject_cast<KTextEditor::MovingInterface*>( yourDocument );
0039  *
0040  * if ( moving ) {
0041  *     KTextEditor::MovingCursor* cursor = moving->newMovingCursor();
0042  * }
0043  * \endcode
0044  *
0045  * When finished with a MovingCursor, simply delete it.
0046  * If the document the cursor belong to is deleted, it will get deleted automatically.
0047  *
0048  * \sa Cursor, Range, MovingRange and MovingInterface.
0049  *
0050  * \author Christoph Cullmann \<cullmann@kde.org\>
0051  *
0052  * \since 4.5
0053  */
0054 class KTEXTEDITOR_EXPORT MovingCursor
0055 {
0056     //
0057     // sub types
0058     //
0059 public:
0060     /**
0061      * Insert behavior of this cursor, should it stay if text is insert at its position
0062      * or should it move.
0063      */
0064     enum InsertBehavior {
0065         StayOnInsert = 0x0, ///< stay on insert
0066         MoveOnInsert = 0x1 ///< move on insert
0067     };
0068 
0069     /**
0070      * Wrap behavior for end of line treatement used in move().
0071      */
0072     enum WrapBehavior {
0073         Wrap = 0x0, ///< wrap at end of line
0074         NoWrap = 0x1 ///< do not wrap at end of line
0075     };
0076 
0077     //
0078     // stuff that needs to be implemented by editor part cursors
0079     //
0080 public:
0081     /**
0082      * Set insert behavior.
0083      * @param insertBehavior new insert behavior
0084      */
0085     virtual void setInsertBehavior(InsertBehavior insertBehavior) = 0;
0086 
0087     /**
0088      * Get current insert behavior.
0089      * @return current insert behavior
0090      */
0091     virtual InsertBehavior insertBehavior() const = 0;
0092 
0093     /**
0094      * Gets the document to which this cursor is bound.
0095      * \return a pointer to the document
0096      */
0097     virtual Document *document() const = 0;
0098 
0099     /**
0100      * Get range this cursor belongs to, if any
0101      * @return range this pointer is part of, else 0
0102      */
0103     virtual MovingRange *range() const = 0;
0104 
0105     /**
0106      * Set the current cursor position to \e position.
0107      *
0108      * \param position new cursor position
0109      */
0110     virtual void setPosition(const KTextEditor::Cursor &position) = 0;
0111 
0112     /**
0113      * Retrieve the line on which this cursor is situated.
0114      * \return line number, where 0 is the first line.
0115      */
0116     virtual int line() const = 0;
0117 
0118     /**
0119      * Retrieve the column on which this cursor is situated.
0120      * \return column number, where 0 is the first column.
0121      */
0122     virtual int column() const = 0;
0123 
0124     /**
0125      * Destruct the moving cursor.
0126      */
0127     virtual ~MovingCursor();
0128 
0129     //
0130     // forbidden stuff
0131     //
0132 protected:
0133     /**
0134      * For inherited class only.
0135      */
0136     MovingCursor();
0137 
0138 private:
0139     /**
0140      * no copy constructor, don't allow this to be copied.
0141      */
0142     MovingCursor(const MovingCursor &);
0143 
0144     /**
0145      * no assignment operator, no copying around clever cursors.
0146      */
0147     MovingCursor &operator=(const MovingCursor &);
0148 
0149     //
0150     // convenience API
0151     //
0152 public:
0153     /**
0154      * Returns whether the current position of this cursor is a valid position,
0155      * i.e. whether line() >= 0 and column() >= 0.
0156      *
0157      * \return \e true , if the cursor position is valid, otherwise \e false
0158      */
0159     inline bool isValid() const
0160     {
0161         return line() >= 0 && column() >= 0;
0162     }
0163 
0164     /**
0165      * Check whether this MovingCursor is located at a valid text position.
0166      * A cursor position at (line, column) is valid, if
0167      * - line >= 0 and line < document()->lines() holds, and
0168      * - column >= 0 and column <= lineLength(column).
0169      *
0170      * Further, the text position is also invalid if it is inside a Unicode
0171      * surrogate (utf-32 character).
0172      *
0173      * \return \e true, if the cursor is a valid text position, otherwise \e false
0174      *
0175      * \see Document::isValidTextPosition()
0176      */
0177     inline bool isValidTextPosition() const
0178     {
0179         return document()->isValidTextPosition(toCursor());
0180     }
0181 
0182     /**
0183      * \overload
0184      *
0185      * Set the cursor position to \e line and \e column.
0186      *
0187      * \param line new cursor line
0188      * \param column new cursor column
0189      */
0190     void setPosition(int line, int column);
0191 
0192     /**
0193      * Set the cursor line to \e line.
0194      * \param line new cursor line
0195      */
0196     void setLine(int line);
0197 
0198     /**
0199      * Set the cursor column to \e column.
0200      * \param column new cursor column
0201      */
0202     void setColumn(int column);
0203 
0204     /**
0205      * Determine if this cursor is located at column 0 of a valid text line.
0206      *
0207      * \return \e true if cursor is a valid text position and column()=0, otherwise \e false.
0208      */
0209     bool atStartOfLine() const;
0210 
0211     /**
0212      * Determine if this cursor is located at the end of the current line.
0213      *
0214      * \return \e true if the cursor is situated at the end of the line, otherwise \e false.
0215      */
0216     bool atEndOfLine() const;
0217 
0218     /**
0219      * Determine if this cursor is located at line 0 and column 0.
0220      *
0221      * \return \e true if the cursor is at start of the document, otherwise \e false.
0222      */
0223     bool atStartOfDocument() const;
0224 
0225     /**
0226      * Determine if this cursor is located at the end of the last line in the
0227      * document.
0228      *
0229      * \return \e true if the cursor is at the end of the document, otherwise \e false.
0230      */
0231     bool atEndOfDocument() const;
0232 
0233     /**
0234      * Moves the cursor to the next line and sets the column to 0. If the cursor
0235      * position is already in the last line of the document, the cursor position
0236      * remains unchanged and the return value is \e false.
0237      *
0238      * \return \e true on success, otherwise \e false
0239      */
0240     bool gotoNextLine();
0241 
0242     /**
0243      * Moves the cursor to the previous line and sets the column to 0. If the
0244      * cursor position is already in line 0, the cursor position remains
0245      * unchanged and the return value is \e false.
0246      *
0247      * \return \e true on success, otherwise \e false
0248      */
0249     bool gotoPreviousLine();
0250 
0251     /**
0252      * Moves the cursor \p chars character forward or backwards. If \e wrapBehavior
0253      * equals WrapBehavior::Wrap, the cursor is automatically wrapped to the
0254      * next line at the end of a line.
0255      *
0256      * When moving backwards, the WrapBehavior does not have any effect.
0257      * \note If the cursor could not be moved the amount of chars requested,
0258      *       the cursor is not moved at all!
0259      *
0260      * \return \e true on success, otherwise \e false
0261      */
0262     bool move(int chars, WrapBehavior wrapBehavior = Wrap);
0263 
0264     /**
0265      * Convert this clever cursor into a dumb one.
0266      * Even if this cursor belongs to a range, the created one not.
0267      * @return normal cursor
0268      */
0269     const Cursor toCursor() const
0270     {
0271         return Cursor(line(), column());
0272     }
0273 
0274     /**
0275      * Convert this clever cursor into a dumb one. Equal to toCursor, allowing to use implicit conversion.
0276      * Even if this cursor belongs to a range, the created one not.
0277      * @return normal cursor
0278      */
0279     operator Cursor() const
0280     {
0281         return Cursor(line(), column());
0282     }
0283 
0284     //
0285     // operators for: MovingCursor <-> MovingCursor
0286     //
0287     /**
0288      * Equality operator.
0289      *
0290      * \note comparison between two invalid cursors is undefined.
0291      *       comparison between an invalid and a valid cursor will always be \e false.
0292      *
0293      * \param c1 first cursor to compare
0294      * \param c2 second cursor to compare
0295      * \return \e true, if c1's and c2's line and column are \e equal.
0296      */
0297     inline friend bool operator==(const MovingCursor &c1, const MovingCursor &c2)
0298     {
0299         return c1.line() == c2.line() && c1.column() == c2.column();
0300     }
0301 
0302     /**
0303      * Inequality operator.
0304      * \param c1 first cursor to compare
0305      * \param c2 second cursor to compare
0306      * \return \e true, if c1's and c2's line and column are \e not equal.
0307      */
0308     inline friend bool operator!=(const MovingCursor &c1, const MovingCursor &c2)
0309     {
0310         return !(c1 == c2);
0311     }
0312 
0313     /**
0314      * Greater than operator.
0315      * \param c1 first cursor to compare
0316      * \param c2 second cursor to compare
0317      * \return \e true, if c1's position is greater than c2's position,
0318      *         otherwise \e false.
0319      */
0320     inline friend bool operator>(const MovingCursor &c1, const MovingCursor &c2)
0321     {
0322         return c1.line() > c2.line() || (c1.line() == c2.line() && c1.column() > c2.column());
0323     }
0324 
0325     /**
0326      * Greater than or equal to operator.
0327      * \param c1 first cursor to compare
0328      * \param c2 second cursor to compare
0329      * \return \e true, if c1's position is greater than or equal to c2's
0330      *         position, otherwise \e false.
0331      */
0332     inline friend bool operator>=(const MovingCursor &c1, const MovingCursor &c2)
0333     {
0334         return c1.line() > c2.line() || (c1.line() == c2.line() && c1.column() >= c2.column());
0335     }
0336 
0337     /**
0338      * Less than operator.
0339      * \param c1 first cursor to compare
0340      * \param c2 second cursor to compare
0341      * \return \e true, if c1's position is greater than or equal to c2's
0342      *         position, otherwise \e false.
0343      */
0344     inline friend bool operator<(const MovingCursor &c1, const MovingCursor &c2)
0345     {
0346         return !(c1 >= c2);
0347     }
0348 
0349     /**
0350      * Less than or equal to operator.
0351      * \param c1 first cursor to compare
0352      * \param c2 second cursor to compare
0353      * \return \e true, if c1's position is lesser than or equal to c2's
0354      *         position, otherwise \e false.
0355      */
0356     inline friend bool operator<=(const MovingCursor &c1, const MovingCursor &c2)
0357     {
0358         return !(c1 > c2);
0359     }
0360 
0361     /**
0362      * qDebug() stream operator. Writes this cursor to the debug output in a nicely formatted way.
0363      * @param s debug stream
0364      * @param cursor cursor to print
0365      * @return debug stream
0366      */
0367     inline friend QDebug operator<<(QDebug s, const MovingCursor *cursor)
0368     {
0369         if (cursor) {
0370             s.nospace() << "(" << cursor->line() << ", " << cursor->column() << ")";
0371         } else {
0372             s.nospace() << "(null cursor)";
0373         }
0374         return s.space();
0375     }
0376 
0377     /**
0378      * qDebug() stream operator. Writes this cursor to the debug output in a nicely formatted way.
0379      * @param s debug stream
0380      * @param cursor cursor to print
0381      * @return debug stream
0382      */
0383     inline friend QDebug operator<<(QDebug s, const MovingCursor &cursor)
0384     {
0385         return s << &cursor;
0386     }
0387 };
0388 
0389 }
0390 
0391 #endif