KTextEditor

katetextrange.cpp
1/*
2 SPDX-FileCopyrightText: 2010 Christoph Cullmann <cullmann@kde.org>
3
4 Based on code of the SmartCursor/Range by:
5 SPDX-FileCopyrightText: 2003-2005 Hamish Rodda <rodda@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "katetextrange.h"
11#include "katedocument.h"
12#include "katetextbuffer.h"
13
14namespace Kate
15{
17 : m_buffer(buffer)
18 , m_start(buffer, this, range.start(), (insertBehavior & ExpandLeft) ? Kate::TextCursor::StayOnInsert : Kate::TextCursor::MoveOnInsert)
19 , m_end(buffer, this, range.end(), (insertBehavior & ExpandRight) ? Kate::TextCursor::MoveOnInsert : Kate::TextCursor::StayOnInsert)
20 , m_view(nullptr)
21 , m_feedback(nullptr)
22 , m_zDepth(0.0)
23 , m_attributeOnlyForViews(false)
24 , m_invalidateIfEmpty(emptyBehavior == InvalidateIfEmpty)
25{
26 // remember this range in buffer
27 m_buffer.m_ranges.insert(this);
28
29 // check if range now invalid, there can happen no feedback, as m_feedback == 0
30 // only place where KTextEditor::LineRange::invalid() for old range makes sense, as we were yet not registered!
31 checkValidity(KTextEditor::LineRange::invalid());
32}
33
35{
36 // reset feedback, don't want feedback during destruction
37 m_feedback = nullptr;
38
39 // remove range from m_ranges
41
42 // remove this range from the buffer
43 m_buffer.m_ranges.remove(this);
44
45 // trigger update, if we have attribute
46 // notify right view
47 // here we can ignore feedback, even with feedback, we want none if the range is deleted!
48 if (m_attribute) {
49 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), true /* we have a attribute */);
50 }
51}
52
54{
55 // nothing to do?
56 if (_insertBehaviors == insertBehaviors()) {
57 return;
58 }
59
60 // modify cursors
63
64 // notify world
65 if (m_attribute || m_feedback) {
66 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), true /* we have a attribute */);
67 }
68}
69
71{
72 InsertBehaviors behaviors = DoNotExpand;
73
75 behaviors |= ExpandLeft;
76 }
77
79 behaviors |= ExpandRight;
80 }
81
82 return behaviors;
83}
84
86{
87 // nothing to do?
88 if (m_invalidateIfEmpty == (emptyBehavior == InvalidateIfEmpty)) {
89 return;
90 }
91
92 // remember value
93 m_invalidateIfEmpty = (emptyBehavior == InvalidateIfEmpty);
94
95 // invalidate range?
96 if (endInternal() <= startInternal()) {
98 }
99}
100
102{
103 // avoid work if nothing changed!
104 if (range == toRange()) {
105 return;
106 }
107
108 // remember old line range
109 const auto oldLineRange = toLineRange();
110
111 // change start and end cursor
112 m_start.setPosition(range.start());
113 m_end.setPosition(range.end());
114
115 // check if range now invalid, don't emit feedback here, will be handled below
116 // otherwise you can't delete ranges in feedback!
117 checkValidity(oldLineRange, false);
118
119 // no attribute or feedback set, be done
120 if (!m_attribute && !m_feedback) {
121 return;
122 }
123
124 // get full range
125 int startLineMin = oldLineRange.start();
126 if (oldLineRange.start() == -1 || (m_start.lineInternal() != -1 && m_start.lineInternal() < oldLineRange.start())) {
127 startLineMin = m_start.line();
128 }
129
130 int endLineMax = oldLineRange.end();
131 if (oldLineRange.end() == -1 || m_end.lineInternal() > oldLineRange.end()) {
132 endLineMax = m_end.lineInternal();
133 }
134
135 // notify buffer about attribute change, it will propagate the changes
136 // notify right view
137 m_buffer.notifyAboutRangeChange(m_view, {startLineMin, endLineMax}, m_attribute);
138
139 // perhaps need to notify stuff!
140 if (m_feedback) {
141 // do this last: may delete this range
142 if (!toRange().isValid()) {
143 m_feedback->rangeInvalid(this);
144 } else if (toRange().isEmpty()) {
145 m_feedback->rangeEmpty(this);
146 }
147 }
148}
149
151{
152 // FIXME: optimize
153 setRange(range);
155}
156
158{
159 // FIXME: optimize
160 setRange(range);
163}
164
165void TextRange::checkValidity(KTextEditor::LineRange oldLineRange, bool notifyAboutChange)
166{
167 // in any case: reset the flag, to avoid multiple runs
168 m_isCheckValidityRequired = false;
169
170 // check if any cursor is invalid or the range is zero size and it should be invalidated then
171 if (!m_start.isValid() || !m_end.isValid() || (m_invalidateIfEmpty && m_end <= m_start)) {
172 m_start.setPosition(-1, -1);
173 m_end.setPosition(-1, -1);
174 }
175
176 // for ranges which are allowed to become empty, normalize them, if the end has moved to the front of the start
177 if (!m_invalidateIfEmpty && m_end < m_start) {
178 m_end.setPosition(m_start);
179 }
180
181 // fix lookup
182 fixLookup(oldLineRange, toLineRange());
183
184 // perhaps need to notify stuff!
185 if (notifyAboutChange && m_feedback) {
186 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), false /* attribute not interesting here */);
187
188 // do this last: may delete this range
189 if (!toRange().isValid()) {
190 m_feedback->rangeInvalid(this);
191 } else if (toRange().isEmpty()) {
192 m_feedback->rangeEmpty(this);
193 }
194 }
195}
196
197void TextRange::fixLookup(KTextEditor::LineRange oldLineRange, KTextEditor::LineRange lineRange)
198{
199 // nothing changed?
200 if (oldLineRange == lineRange) {
201 return;
202 }
203
204 // now, not both can be invalid
205 Q_ASSERT(oldLineRange.start() >= 0 || lineRange.start() >= 0);
206 Q_ASSERT(oldLineRange.end() >= 0 || lineRange.end() >= 0);
207
208 // get full range
209 int startLineMin = oldLineRange.start();
210 if (oldLineRange.start() == -1 || (lineRange.start() != -1 && lineRange.start() < oldLineRange.start())) {
211 startLineMin = lineRange.start();
212 }
213
214 int endLineMax = oldLineRange.end();
215 if (oldLineRange.end() == -1 || lineRange.end() > oldLineRange.end()) {
216 endLineMax = lineRange.end();
217 }
218
219 // get start block
220 int blockIdx = m_buffer.blockForLine(startLineMin);
221 Q_ASSERT(blockIdx >= 0);
222
223 // remove this range from m_ranges
224 auto it = m_buffer.m_blocks.begin() + blockIdx;
225 auto end = m_buffer.m_blocks.end();
226 for (; it != end; ++it) {
227 // either insert or remove range
228 TextBlock *block = *it;
229 if ((lineRange.end() < block->startLine()) || (lineRange.start() >= (block->startLine() + block->lines()))) {
230 block->removeRange(this);
231 } else {
232 block->updateRange(this);
233 }
234
235 // ok, reached end block
236 if (endLineMax < (block->startLine() + block->lines())) {
237 return;
238 }
239 }
240
241 // we should not be here, really, then endLine is wrong
242 Q_ASSERT(false);
243}
244
246{
247 // nothing changes, nop
248 if (view == m_view) {
249 return;
250 }
251
252 // remember the new attribute
253 m_view = view;
254
255 // notify buffer about attribute change, it will propagate the changes
256 // notify all views (can be optimized later)
257 if (m_attribute || m_feedback) {
258 m_buffer.notifyAboutRangeChange(nullptr, toLineRange(), m_attribute);
259 }
260}
261
263{
264 // nothing changes, nop, only pointer compare
265 if (attribute == m_attribute) {
266 return;
267 }
268
269 // remember the new attribute
270 m_attribute = attribute;
271
272 // notify buffer about attribute change, it will propagate the changes
273 // notify right view
274 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), true /* even for nullptr attribute, we had before one => repaint */);
275}
276
278{
279 // nothing changes, nop
280 if (feedback == m_feedback) {
281 return;
282 }
283
284 // remember the new feedback object
285 m_feedback = feedback;
286
287 // notify buffer about feedback change, it will propagate the changes
288 // notify right view
289 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), m_attribute);
290}
291
293{
294 // just set the value, no need to trigger updates, printing is not interruptable
295 m_attributeOnlyForViews = onlyForViews;
296}
297
298void TextRange::setZDepth(qreal zDepth)
299{
300 // nothing changes, nop
301 if (zDepth == m_zDepth) {
302 return;
303 }
304
305 // remember the new attribute
306 m_zDepth = zDepth;
307
308 // notify buffer about attribute change, it will propagate the changes
309 if (m_attribute) {
310 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), m_attribute);
311 }
312}
313
315{
316 return m_buffer.document();
317}
318
319}
A KParts derived class representing a text document.
Definition document.h:284
An object representing lines from a start line to an end line.
Definition linerange.h:41
constexpr int start() const noexcept
Get the start line of this line range.
Definition linerange.h:105
static constexpr LineRange invalid() noexcept
Returns an invalid line range.
Definition linerange.h:73
constexpr int end() const noexcept
Get the end line of this line range.
Definition linerange.h:115
bool isValid() const
Returns whether the current position of this cursor is a valid position, i.e.
@ StayOnInsert
stay on insert
@ MoveOnInsert
move on insert
A class which provides notifications of state changes to a MovingRange.
virtual void rangeInvalid(MovingRange *range)
The range is now invalid (ie.
virtual void rangeEmpty(MovingRange *range)
The range is now empty (ie.
bool isEmpty() const
Returns true if this range contains no characters, ie.
EmptyBehavior
Behavior of range if it becomes empty.
@ InvalidateIfEmpty
invalidate range, if it becomes empty
@ DoNotExpand
Don't expand to encapsulate new characters in either direction. This is the default.
@ ExpandRight
Expand to encapsulate new characters to the right of the range.
@ ExpandLeft
Expand to encapsulate new characters to the left of the range.
An object representing a section of text, from one Cursor to another.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
static constexpr Range invalid() noexcept
Returns an invalid range.
A text widget with KXMLGUIClient that represents a Document.
Definition view.h:244
Class representing a text buffer.
Class representing a 'clever' text cursor.
int lineInternal() const
Non-virtual version of line(), which is faster.
InsertBehavior insertBehavior() const override
Get current insert behavior.
void setInsertBehavior(InsertBehavior insertBehavior) override
Set insert behavior.
void setPosition(const TextCursor &position)
Fast way to set the current cursor position to position.
int line() const override
Retrieve the line on which this cursor is situated.
qreal zDepth() const override
Gets the current Z-depth of this range.
void setAttribute(KTextEditor::Attribute::Ptr attribute) override
Sets the currently active attribute for this range.
TextRange(TextBuffer &buffer, KTextEditor::Range range, InsertBehaviors insertBehavior, EmptyBehavior emptyBehavior=AllowEmpty)
Construct a text range.
~TextRange() override
Destruct the text block.
KTextEditor::MovingRangeFeedback * feedback() const override
Gets the active MovingRangeFeedback for this range.
const TextCursor & startInternal() const
Non-virtual version of start(), which is faster.
KTextEditor::Document * document() const override
Gets the document to which this range is bound.
const KTextEditor::MovingCursor & end() const override
Retrieve end cursor of this range, read-only.
const KTextEditor::Attribute::Ptr & attribute() const override
Gets the active Attribute for this range.
void setZDepth(qreal zDepth) override
Set the current Z-depth of this range.
InsertBehaviors insertBehaviors() const override
Get current insert behaviors.
void setAttributeOnlyForViews(bool onlyForViews) override
Set if this range's attribute is only visible in views, not for example prints.
KTextEditor::View * view() const override
Gets the active view for this range.
void setFeedback(KTextEditor::MovingRangeFeedback *feedback) override
Sets the currently active MovingRangeFeedback for this range.
const KTextEditor::Range toRange() const
Convert this clever range into a dumb one.
void setView(KTextEditor::View *view) override
Sets the currently active view for this range.
void setInsertBehaviors(InsertBehaviors insertBehaviors) override
Set insert behaviors.
const TextCursor & endInternal() const
Nonvirtual version of end(), which is faster.
EmptyBehavior emptyBehavior() const override
Will this range invalidate itself if it becomes empty?
KTextEditor::LineRange toLineRange() const
Hides parent's impl of toLineRange() and uses non-virtual functions internally.
void setEmptyBehavior(EmptyBehavior emptyBehavior) override
Set if this range will invalidate itself if it becomes empty.
void setRange(KTextEditor::Range range) override
Set the range of this range.
Q_SCRIPTABLE Q_NOREPLY void start()
bool isValid(QStringView ifopt)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:15:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.