KTextEditor

documentcursor.cpp
1 /* SPDX-License-Identifier: LGPL-2.0-or-later
2 
3  Copyright (C) 2010 Christoph Cullmann <[email protected]>
4  Copyright (C) 2012 Dominik Haumann <[email protected]>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "documentcursor.h"
23 
24 namespace KTextEditor
25 {
26 DocumentCursor::DocumentCursor(KTextEditor::Document *document)
27  : m_document(document)
28  , m_cursor(KTextEditor::Cursor::invalid())
29 {
30  // we require a valid document
31  Q_ASSERT(m_document);
32 }
33 
34 DocumentCursor::DocumentCursor(KTextEditor::Document *document, const KTextEditor::Cursor &position)
35  : m_document(document)
36  , m_cursor(position)
37 {
38  // we require a valid document
39  Q_ASSERT(m_document);
40 }
41 
42 DocumentCursor::DocumentCursor(KTextEditor::Document *document, int line, int column)
43  : m_document(document)
44  , m_cursor(line, column)
45 {
46  // we require a valid document
47  Q_ASSERT(m_document);
48 }
49 
50 DocumentCursor::DocumentCursor(const DocumentCursor &other)
51  : m_document(other.m_document)
52  , m_cursor(other.m_cursor)
53 {
54 }
55 
57 {
58  if (position.isValid()) {
59  m_cursor = position;
60  } else {
61  m_cursor = KTextEditor::Cursor::invalid();
62  }
63 }
64 
66 {
67  const int line = m_cursor.line();
68  const int col = m_cursor.line();
69 
70  if (line < 0) {
71  m_cursor.setPosition(0, 0);
72  } else if (line >= m_document->lines()) {
73  m_cursor = m_document->documentEnd();
74  } else if (col > m_document->lineLength(line)) {
75  m_cursor.setColumn(m_document->lineLength(line));
76  } else if (col < 0) {
77  m_cursor.setColumn(0);
78  } else if (!isValidTextPosition()) {
79  // inside a unicode surrogate (utf-32 character)
80  // -> move half one char left to the start of the utf-32 char
81  m_cursor.setColumn(col - 1);
82  }
83 
84  Q_ASSERT(isValidTextPosition());
85 }
86 
88 {
89  m_cursor.setPosition(line, column);
90 }
91 
93 {
94  setPosition(line, column());
95 }
96 
98 {
99  setPosition(line(), column);
100 }
101 
103 {
104  return isValidTextPosition() && column() == 0;
105 }
106 
108 {
109  return isValidTextPosition() && column() == document()->lineLength(line());
110 }
111 
113 {
114  return line() == 0 && column() == 0;
115 }
116 
118 {
119  // avoid costly lineLength computation if we are not in the last line
120  // this is called often e.g. during search & replace, >> 2% of the total costs
121  const auto lastLine = document()->lines() - 1;
122  return line() == lastLine && column() == document()->lineLength(lastLine);
123 }
124 
126 {
127  // only allow valid cursors
128  const bool ok = isValid() && (line() + 1 < document()->lines());
129 
130  if (ok) {
131  setPosition(Cursor(line() + 1, 0));
132  }
133 
134  return ok;
135 }
136 
138 {
139  // only allow valid cursors
140  bool ok = (line() > 0) && (column() >= 0);
141 
142  if (ok) {
143  setPosition(Cursor(line() - 1, 0));
144  }
145 
146  return ok;
147 }
148 
149 bool DocumentCursor::move(int chars, WrapBehavior wrapBehavior)
150 {
151  if (!isValid()) {
152  return false;
153  }
154 
155  // create temporary cursor to modify
156  Cursor c(m_cursor);
157 
158  // forwards?
159  if (chars > 0) {
160  // cache lineLength to minimize calls of KTextEditor::DocumentPrivate::lineLength(), as
161  // results in locating the correct block in the text buffer every time,
162  // which is relatively slow
163  int lineLength = document()->lineLength(c.line());
164 
165  // special case: cursor position is not in valid text, then the algo does
166  // not work for Wrap mode. Hence, catch this special case by setting
167  // c.column() to the lineLength()
168  if (wrapBehavior == Wrap && c.column() > lineLength) {
169  c.setColumn(lineLength);
170  }
171 
172  while (chars != 0) {
173  if (wrapBehavior == Wrap) {
174  const int advance = qMin(lineLength - c.column(), chars);
175 
176  if (chars > advance) {
177  if (c.line() + 1 >= document()->lines()) {
178  return false;
179  }
180 
181  c.setPosition(c.line() + 1, 0);
182  chars -= advance + 1; // +1 because of end-of-line wrap
183 
184  // advanced one line, so cache correct line length again
185  lineLength = document()->lineLength(c.line());
186  } else {
187  c.setColumn(c.column() + chars);
188  chars = 0;
189  }
190  } else { // NoWrap
191  c.setColumn(c.column() + chars);
192  chars = 0;
193  }
194  }
195  }
196 
197  // backwards?
198  else {
199  while (chars != 0) {
200  const int back = qMin(c.column(), -chars);
201  if (-chars > back) {
202  if (c.line() == 0) {
203  return false;
204  }
205 
206  c.setPosition(c.line() - 1, document()->lineLength(c.line() - 1));
207  chars += back + 1; // +1 because of wrap-around at start-of-line
208  } else {
209  c.setColumn(c.column() + chars);
210  chars = 0;
211  }
212  }
213  }
214 
215  if (c != m_cursor) {
216  setPosition(c);
217  }
218  return true;
219 }
220 
221 }
Document * document() const
Gets the document to which this cursor is bound.
void setPosition(const Cursor &position) Q_DECL_NOEXCEPT
Set the current cursor position to position.
Definition: cursor.h:175
virtual int lines() const =0
Get the count of lines of the document.
void makeValid()
Make sure the cursor position is at a valid text position according to the following rules...
bool isValidTextPosition() const
Check if this cursor is currently at a valid text position.
bool atStartOfDocument() const
Determine if this cursor is located at line 0 and column 0.
A Cursor which is bound to a specific Document.
virtual int lineLength(int line) const =0
Get the length of a given line in characters.
The Cursor represents a position in a Document.
Definition: cursor.h:85
bool move(int chars, WrapBehavior wrapBehavior=Wrap)
Moves the cursor chars character forward or backwards.
bool atEndOfDocument() const
Determine if this cursor is located at the end of the last line in the document.
static constexpr Cursor invalid() Q_DECL_NOEXCEPT
Returns an invalid cursor.
Definition: cursor.h:123
bool gotoNextLine()
Moves the cursor to the next line and sets the column to 0.
constexpr bool isValid() const Q_DECL_NOEXCEPT
Returns whether the current position of this cursor is a valid position (line + column must both be >...
Definition: cursor.h:113
bool gotoPreviousLine()
Moves the cursor to the previous line and sets the column to 0.
bool atStartOfLine() const
Determine if this cursor is located at column 0 of a valid text line.
A KParts derived class representing a text document.
Definition: document.h:199
bool isValid() const
Check if the current position of this cursor is a valid position, i.e.
int line() const
Retrieve the line on which this cursor is situated.
constexpr int column() const Q_DECL_NOEXCEPT
Retrieve the column on which this cursor is situated.
Definition: cursor.h:217
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
virtual Cursor documentEnd() const =0
End position of the document.
void setLine(int line)
Set the cursor line to line.
constexpr int line() const Q_DECL_NOEXCEPT
Retrieve the line on which this cursor is situated.
Definition: cursor.h:199
int column() const
Retrieve the column on which this cursor is situated.
WrapBehavior
Wrap behavior for end of line treatement used in move().
bool atEndOfLine() const
Determine if this cursor is located at the end of the current line.
void setColumn(int column)
Set the cursor column to column.
int lastLine() const
gets the last line number (lines() - 1)
Definition: katedocument.h:810
void setPosition(const KTextEditor::Cursor &position)
Set the current cursor position to position.
void setColumn(int column) Q_DECL_NOEXCEPT
Set the cursor column to column.
Definition: cursor.h:226
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 22:55:00 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.