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();
32
33 // Add the range if it is multiline
34 if (spansMultipleBlocks()) {
35 m_buffer.addMultilineRange(this);
36 }
37}
38
40{
41 // reset feedback, don't want feedback during destruction
42 m_feedback = nullptr;
43
44 // remove range from cached multiline ranges
45 const auto lineRange = toLineRange();
46 if (lineRange.isValid() && spansMultipleBlocks()) {
47 m_buffer.removeMultilineRange(this);
48 }
49
50 // remove this range from the buffer
51 m_buffer.m_ranges.remove(this);
52
53 // trigger update, if we have attribute
54 // notify right view
55 // here we can ignore feedback, even with feedback, we want none if the range is deleted!
56 if (m_attribute) {
57 m_buffer.notifyAboutRangeChange(m_view, lineRange, true /* we have a attribute */);
58 }
59}
60
62{
63 // nothing to do?
64 if (_insertBehaviors == insertBehaviors()) {
65 return;
66 }
67
68 // modify cursors
71
72 // notify world
73 if (m_attribute || m_feedback) {
74 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), true /* we have a attribute */);
75 }
76}
77
79{
80 InsertBehaviors behaviors = DoNotExpand;
81
83 behaviors |= ExpandLeft;
84 }
85
87 behaviors |= ExpandRight;
88 }
89
90 return behaviors;
91}
92
94{
95 // nothing to do?
96 if (m_invalidateIfEmpty == (emptyBehavior == InvalidateIfEmpty)) {
97 return;
98 }
99
100 // remember value
101 m_invalidateIfEmpty = (emptyBehavior == InvalidateIfEmpty);
102
103 // invalidate range?
104 if (endInternal() <= startInternal()) {
106 }
107}
108
110{
111 // avoid work if nothing changed!
112 if (range == toRange()) {
113 return;
114 }
115
116 // remember old line range
117 const auto oldLineRange = toLineRange();
118 const bool oldSpannedMultipleBlocks = spansMultipleBlocks();
119
120 // change start and end cursor
121 m_start.setPosition(range.start());
122 m_end.setPosition(range.end());
123
124 const bool newSpansMultipleBlocks = spansMultipleBlocks();
125 if (oldSpannedMultipleBlocks != newSpansMultipleBlocks) {
126 if (oldSpannedMultipleBlocks) {
127 m_buffer.removeMultilineRange(this);
128 } else {
129 m_buffer.addMultilineRange(this);
130 }
131 }
132
133 // check if range now invalid, don't emit feedback here, will be handled below
134 // otherwise you can't delete ranges in feedback!
135 checkValidity(false);
136
137 // no attribute or feedback set, be done
138 if (!m_attribute && !m_feedback) {
139 return;
140 }
141
142 // get full range
143 int startLineMin = oldLineRange.start();
144 if (oldLineRange.start() == -1 || (m_start.lineInternal() != -1 && m_start.lineInternal() < oldLineRange.start())) {
145 startLineMin = m_start.line();
146 }
147
148 int endLineMax = oldLineRange.end();
149 if (oldLineRange.end() == -1 || m_end.lineInternal() > oldLineRange.end()) {
150 endLineMax = m_end.lineInternal();
151 }
152
153 // notify buffer about attribute change, it will propagate the changes
154 // notify right view
155 m_buffer.notifyAboutRangeChange(m_view, {startLineMin, endLineMax}, m_attribute);
156
157 // perhaps need to notify stuff!
158 if (m_feedback) {
159 // do this last: may delete this range
160 if (!toRange().isValid()) {
161 m_feedback->rangeInvalid(this);
162 } else if (toRange().isEmpty()) {
163 m_feedback->rangeEmpty(this);
164 }
165 }
166}
167
169{
170 // FIXME: optimize
171 setRange(range);
173}
174
176{
177 // FIXME: optimize
178 setRange(range);
181}
182
183void TextRange::checkValidity(bool notifyAboutChange)
184{
185 // in any case: reset the flag, to avoid multiple runs
186 m_isCheckValidityRequired = false;
187
188 // check if any cursor is invalid or the range is zero size and it should be invalidated then
189 if (!m_start.isValid() || !m_end.isValid() || (m_invalidateIfEmpty && m_end <= m_start)) {
190 m_start.setPosition(-1, -1);
191 m_end.setPosition(-1, -1);
192 }
193
194 // for ranges which are allowed to become empty, normalize them, if the end has moved to the front of the start
195 if (!m_invalidateIfEmpty && m_end < m_start) {
196 m_end.setPosition(m_start);
197 }
198
199 // fix lookup
200 // fixLookup(oldLineRange, toLineRange());
201
202 // perhaps need to notify stuff!
203 if (notifyAboutChange && m_feedback) {
204 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), false /* attribute not interesting here */);
205
206 // do this last: may delete this range
207 if (!toRange().isValid()) {
208 m_feedback->rangeInvalid(this);
209 } else if (toRange().isEmpty()) {
210 m_feedback->rangeEmpty(this);
211 }
212 }
213}
214
216{
217 // nothing changes, nop
218 if (view == m_view) {
219 return;
220 }
221
222 // remember the new attribute
223 m_view = view;
224
225 // notify buffer about attribute change, it will propagate the changes
226 // notify all views (can be optimized later)
227 if (m_attribute || m_feedback) {
228 m_buffer.notifyAboutRangeChange(nullptr, toLineRange(), m_attribute);
229 }
230}
231
233{
234 // nothing changes, nop, only pointer compare
235 if (attribute == m_attribute) {
236 return;
237 }
238
239 // remember the new attribute
240 m_attribute = attribute;
241
242 // notify buffer about attribute change, it will propagate the changes
243 // notify right view
244 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), true /* even for nullptr attribute, we had before one => repaint */);
245}
246
248{
249 // nothing changes, nop
250 if (feedback == m_feedback) {
251 return;
252 }
253
254 // remember the new feedback object
255 m_feedback = feedback;
256
257 // notify buffer about feedback change, it will propagate the changes
258 // notify right view
259 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), m_attribute);
260}
261
263{
264 // just set the value, no need to trigger updates, printing is not interruptable
265 m_attributeOnlyForViews = onlyForViews;
266}
267
268void TextRange::setZDepth(qreal zDepth)
269{
270 // nothing changes, nop
271 if (zDepth == m_zDepth) {
272 return;
273 }
274
275 // remember the new attribute
276 m_zDepth = zDepth;
277
278 // notify buffer about attribute change, it will propagate the changes
279 if (m_attribute) {
280 m_buffer.notifyAboutRangeChange(m_view, toLineRange(), m_attribute);
281 }
282}
283
285{
286 return m_buffer.document();
287}
288
289}
A KParts derived class representing a text document.
Definition document.h:284
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.
KTEXTEDITOR_NO_EXPORT void addMultilineRange(TextRange *range)
Add/Remove a multiline range that spans multiple blocks.
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::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 Fri Oct 4 2024 12:03:01 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.