/* This file is part of the KDE project * Copyright (C) 2003-2005 Hamish Rodda * Copyright (C) 2001-2005 Christoph Cullmann * Copyright (C) 2002 Christian Couder * Copyright (C) 2001 Joseph Wenninger * Copyright (C) 1999 Jochen Wilhelmy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KDELIBS_KTEXTEDITOR_RANGE_H #define KDELIBS_KTEXTEDITOR_RANGE_H #include #include namespace KTextEditor { class SmartRange; /** * \short An object representing a section of text, from one Cursor to another. * * A Range is a basic class which represents a range of text with two Cursors, * from a start() position to an end() position. * * For simplicity and convenience, ranges always maintain their start position to * be before or equal to their end position. Attempting to set either the * start or end of the range beyond the respective end or start will result in * both values being set to the specified position. In the constructor, the * start and end will be swapped if necessary. * * If you want additional functionality such as the ability to maintain position * in a document, see SmartRange. * * \sa SmartRange * * \author Hamish Rodda \ */ class KTEXTEDITOR_EXPORT Range { friend class Cursor; public: /** * Default constructor. Creates a valid range from position (0, 0) to * position (0, 0). */ Range(); /** * Constructor which creates a range from \e start to \e end. * If start is after end, they will be swapped. * * \param start start position * \param end end position */ Range(const Cursor& start, const Cursor& end); /** * Constructor which creates a single-line range from \p start, * extending \p width characters along the same line. * * \param start start position * \param width width of this range in columns along the same line */ Range(const Cursor& start, int width); /** * Constructor which creates a range from \p start, to \p endLine, \p endColumn. * * \param start start position * \param endLine end line * \param endColumn end column */ Range(const Cursor& start, int endLine, int endColumn); /** * Constructor which creates a range from \e startLine, \e startColumn to \e endLine, \e endColumn. * * \param startLine start line * \param startColumn start column * \param endLine end line * \param endColumn end column */ Range(int startLine, int startColumn, int endLine, int endColumn); /** * Copy constructor. * * \param copy the range from which to copy the start and end position. */ Range(const Range& copy); /** * Virtual destructor. */ //Do not remove! Needed for inheritance. virtual ~Range(); /** * Validity check. In the base class, returns true unless the range starts before (0,0). */ virtual bool isValid() const; /** * Returns an invalid range. */ static Range invalid(); /** * Returns whether this range is a SmartRange. */ virtual bool isSmartRange() const; /** * Returns this range as a SmartRange, if it is one. */ virtual SmartRange* toSmartRange() const; /** * \name Position * * The following functions provide access to, and manipulation of, the range's position. * \{ */ /** * Get the start position of this range. This will always be <= end(). * * This non-const function allows direct manipulation of the start position, * while still retaining notification support. * * If start is set to a position after end, end will be moved to the * same position as start, as ranges are not allowed to have * start() > end(). * * \note If you want to change both start() and end() simultaneously, * you should use setRange(), for several reasons: * \li otherwise, the rule preventing start() > end() may alter your intended change * \li any notifications needed will be performed multiple times for no benefit * * \returns a reference to the start position of this range. */ Cursor& start(); /** * Get the start position of this range. This will always be <= end(). * * \returns a const reference to the start position of this range. * * \internal this function is virtual to allow for covariant return of SmartCursor%s. */ const Cursor& start() const; /** * Get the end position of this range. This will always be >= start(). * * This non-const function allows direct manipulation of the end position, * while still retaining notification support. * * If end is set to a position before start, start will be moved to the * same position as end, as ranges are not allowed to have * start() > end(). * * \note If you want to change both start() and end() simultaneously, * you should use setRange(), for several reasons: * \li otherwise, the rule preventing start() > end() may alter your intended change * \li any notifications needed will be performed multiple times for no benefit * * \returns a reference to the end position of this range. * * \internal this function is virtual to allow for covariant return of SmartCursor%s. */ Cursor& end(); /** * Get the end position of this range. This will always be >= start(). * * \returns a const reference to the end position of this range. * * \internal this function is virtual to allow for covariant return of SmartCursor%s. */ const Cursor& end() const; /** * Convenience function. Set the start and end lines to \p line. * * \param line the line number to assign to start() and end() */ void setBothLines(int line); /** * Convenience function. Set the start and end columns to \p column. * * \param column the column number to assign to start() and end() */ void setBothColumns(int column); /** * Set the start and end cursors to \e range.start() and \e range.end() respectively. * * \param range range to assign to this range */ virtual void setRange(const Range& range); /** * \overload * \n \n * Set the start and end cursors to \e start and \e end respectively. * * \note If \e start is after \e end, they will be reversed. * * \param start start cursor * \param end end cursor */ void setRange(const Cursor& start, const Cursor& end); /** * Expand this range if necessary to contain \p range. * * \param range range which this range should contain * * \return \e true if expansion occurred, \e false otherwise */ virtual bool expandToRange(const Range& range); /** * Confine this range if necessary to fit within \p range. * * \param range range which should contain this range * * \return \e true if confinement occurred, \e false otherwise */ virtual bool confineToRange(const Range& range); /** * Check whether this range is wholly contained within one line, ie. if * the start() and end() positions are on the same line. * * \return \e true if both the start and end positions are on the same * line, otherwise \e false */ bool onSingleLine() const; /** * Returns the number of lines separating the start() and end() positions. * * \return the number of lines separating the start() and end() positions; * 0 if the start and end lines are the same. */ int numberOfLines() const; /** * Returns the number of columns separating the start() and end() positions. * * \return the number of columns separating the start() and end() positions; * 0 if the start and end columns are the same. */ int columnWidth() const; /** * Returns true if this range contains no characters, ie. the start() and * end() positions are the same. * * \returns \e true if the range contains no characters, otherwise \e false */ bool isEmpty() const; //BEGIN comparison functions /** * \} * * \name Comparison * * The following functions perform checks against this range in comparison * to other lines, columns, cursors, and ranges. * \{ */ /** * Check whether the this range wholly encompasses \e range. * * \param range range to check * * \return \e true, if this range contains \e range, otherwise \e false */ bool contains(const Range& range) const; /** * Check to see if \p cursor is contained within this range, ie >= start() and \< end(). * * \param cursor the position to test for containment * * \return \e true if the cursor is contained within this range, otherwise \e false. */ bool contains(const Cursor& cursor) const; /** * Returns true if this range wholly encompasses \p line. * * \param line line to check * * \return \e true if the line is wholly encompassed by this range, otherwise \e false. */ bool containsLine(int line) const; /** * Check whether the range contains \e column. * * \param column column to check * * \return \e true if the range contains \e column, otherwise \e false */ bool containsColumn(int column) const; /** * Check whether the this range overlaps with \e range. * * \param range range to check against * * \return \e true, if this range overlaps with \e range, otherwise \e false */ bool overlaps(const Range& range) const; /** * Check whether the range overlaps at least part of \e line. * * \param line line to check * * \return \e true, if the range overlaps at least part of \e line, otherwise \e false */ bool overlapsLine(int line) const; /** * Check to see if this range overlaps \p column; that is, if \p column is * between start().column() and end().column(). This function is most likely * to be useful in relation to block text editing. * * \param column the column to test * * \return \e true if the column is between the range's starting and ending * columns, otherwise \e false. */ bool overlapsColumn(int column) const; /** * Determine where \p cursor is positioned in relationship to this range. * Equivalency (a return value of 0) is returned when \p cursor is \e contained * within the range, not when \e overlapped - i.e., \p cursor may be on a * line which is also partially occupied by this range, but the position * may not be eqivalent. For overlap checking, use positionRelativeToLine(). * * \param cursor position to check * * \return \e -1 if before, \e +1 if after, and \e 0 if \p cursor is contained within the range. * * \see positionRelativeToLine() */ int positionRelativeToCursor(const Cursor& cursor) const; /** * Determine where \p line is positioned in relationship to this range. * Equivalency (a return value of 0) is returned when \p line is \e overlapped * within the range, not when \e contained - i.e., this range may not cover an entire line, * but \p line's position will still be eqivalent. For containment checking, use positionRelativeToCursor(). * * \param line line to check * * \return \e -1 if before, \e +1 if after, and \e 0 if \p line is overlapped by this range. * * \see positionRelativeToCursor() */ int positionRelativeToLine(int line) const; /** * Check whether \p cursor is located at either of the start() or end() * boundaries. * * \param cursor cursor to check * * \return \e true if the cursor is equal to \p start() or \p end(), * otherwise \e false. */ bool boundaryAtCursor(const Cursor& cursor) const; /** * Check whether \p line is on the same line as either of the start() or * end() boundaries. * * \param line line to check * * \return \e true if \p line is on the same line as either of the * boundaries, otherwise \e false */ bool boundaryOnLine(int line) const; /** * Check whether \p column is on the same column as either of the start() * or end() boundaries. * * \param column column to check * * \return \e true if \p column is on the same column as either of the * boundaries, otherwise \e false */ bool boundaryOnColumn(int column) const; //!\} //END /** * Intersects this range with another, returning the shared area of * the two ranges. * * \param range other range to intersect with this * * \return the intersection of this range and the supplied \a range. */ Range intersect(const Range& range) const; /** * Returns the smallest range which encompasses this range and the * supplied \a range. * * \param range other range to encompass * * \return the smallest range which contains this range and the supplied \a range. */ Range encompass(const Range& range) const; /** * Assignment operator. Same as setRange(). * * \param rhs range to assign to this range. * * \return a reference to this range, after assignment has occurred. * * \see setRange() */ inline Range& operator=(const Range& rhs) { setRange(rhs); return *this; } /** * Addition operator. Takes two ranges and returns their summation. * * \param r1 the first range * \param r2 the second range * * \return a the summation of the two input ranges */ inline friend Range operator+(const Range& r1, const Range& r2) { return Range(r1.start() + r2.start(), r1.end() + r2.end()); } /** * Addition assignment operator. Adds \p r2 to this range. * * \param r1 the first range * \param r2 the second range * * \return a reference to the cursor which has just been added to */ inline friend Range& operator+=(Range& r1, const Range& r2) { r1.setRange(r1.start() + r2.start(), r1.end() + r2.end()); return r1; } /** * Subtraction operator. Takes two ranges and returns the subtraction * of \p r2 from \p r1. * * \param r1 the first range * \param r2 the second range * * \return a range representing the subtraction of \p r2 from \p r1 */ inline friend Range operator-(const Range& r1, const Range& r2) { return Range(r1.start() - r2.start(), r1.end() - r2.end()); } /** * Subtraction assignment operator. Subtracts \p r2 from \p r1. * * \param r1 the first range * \param r2 the second range * * \return a reference to the range which has just been subtracted from */ inline friend Range& operator-=(Range& r1, const Range& r2) { r1.setRange(r1.start() - r2.start(), r1.end() - r2.end()); return r1; } /** * Intersects \a r1 and \a r2. * * \param r1 the first range * \param r2 the second range * * \return the intersected range, invalid() if there is no overlap */ inline friend Range operator&(const Range& r1, const Range& r2) { return r1.intersect(r2); } /** * Intersects \a r1 with \a r2 and assigns the result to \a r1. * * \param r1 the range to assign the intersection to * \param r2 the range to intersect \a r1 with * * \return a reference to this range, after the intersection has taken place */ inline friend Range& operator&=(Range& r1, const Range& r2) { r1.setRange(r1.intersect(r2)); return r1; } /** * Equality operator. * * \param r1 first range to compare * \param r2 second range to compare * * \return \e true if \e r1 and \e r2 equal, otherwise \e false */ inline friend bool operator==(const Range& r1, const Range& r2) { return r1.start() == r2.start() && r1.end() == r2.end(); } /** * Inequality operator. * * \param r1 first range to compare * \param r2 second range to compare * * \return \e true if \e r1 and \e r2 do \e not equal, otherwise \e false */ inline friend bool operator!=(const Range& r1, const Range& r2) { return r1.start() != r2.start() || r1.end() != r2.end(); } /** * Greater than operator. Looks only at the position of the two ranges, * does not consider their size. * * \param r1 first range to compare * \param r2 second range to compare * * \return \e true if \e r1 starts after where \e r2 ends, otherwise \e false */ inline friend bool operator>(const Range& r1, const Range& r2) { return r1.start() > r2.end(); } /** * Less than operator. Looks only at the position of the two ranges, * does not consider their size. * * \param r1 first range to compare * \param r2 second range to compare * * \return \e true if \e r1 ends before \e r2 begins, otherwise \e false */ inline friend bool operator<(const Range& r1, const Range& r2) { return r1.end() < r2.start(); } /** * kDebug() stream operator. Writes this range to the debug output in a nicely formatted way. */ inline friend QDebug operator<< (QDebug s, const Range& range) { s << "[" << range.start() << " -> " << range.end() << "]"; return s; } protected: /** * Constructor for advanced cursor types. * Creates a range from \e start to \e end. * Takes ownership of \e start and \e end. * * \param start the start cursor. * \param end the end cursor. */ Range(Cursor* start, Cursor* end); /** * Notify this range that one or both of the cursors' position has changed directly. * * \param cursor the cursor that changed. If 0L, both cursors have changed. * \param from the previous position of this range * * \internal */ virtual void rangeChanged(Cursor* cursor, const Range& from); /** * This range's start cursor pointer. * * \internal */ Cursor* m_start; /** * This range's end cursor pointer. * * \internal */ Cursor* m_end; }; } #endif // kate: space-indent on; indent-width 2; replace-tabs on;