1 /*
2 This file is part of the Okteta Gui library, made within the KDE community.
3
4 SPDX-FileCopyrightText: 2003, 2008-2009 Friedrich W. H. Kossebau <kossebau@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9 #include "bytearraytableranges.hpp"
10 #include "bytearraytableranges_p.hpp"
11
12 // lib
13 #include "bytearraytablelayout.hpp"
14 // Okteta core
15 #include <Okteta/ArrayChangeMetricsList>
16
17 namespace Okteta {
18
ByteArrayTableRanges(ByteArrayTableLayout * layout)19 ByteArrayTableRanges::ByteArrayTableRanges(ByteArrayTableLayout* layout)
20 : d_ptr(new ByteArrayTableRangesPrivate(layout))
21 {
22 }
23
24 ByteArrayTableRanges::~ByteArrayTableRanges() = default;
25
reset()26 void ByteArrayTableRanges::reset()
27 {
28 Q_D(ByteArrayTableRanges);
29 mSelection.cancel();
30 FirstWordSelection.unset();
31 mMarking.unset();
32 ChangedRanges.clear();
33 d->previousSelection = mSelection;
34 }
35
setMarking(const AddressRange & marking)36 void ByteArrayTableRanges::setMarking(const AddressRange& marking)
37 {
38 if (mMarking == marking) {
39 return;
40 }
41
42 const bool hadMarking = mMarking.isValid();
43 if (hadMarking) {
44 addChangedRange(mMarking);
45 }
46
47 mMarking = marking;
48
49 const bool hasNewMarking = mMarking.isValid();
50 if (hasNewMarking) {
51 addChangedRange(mMarking);
52 }
53 }
54
removeFurtherSelections()55 void ByteArrayTableRanges::removeFurtherSelections()
56 {
57 for (int i = 1; i < noOfSelections(); ++i) {
58 removeSelection(i);
59 }
60 }
61
setSelection(const AddressRange & selection)62 void ByteArrayTableRanges::setSelection(const AddressRange& selection)
63 {
64 bool Changed = mSelection.isValid();
65 if (Changed) {
66 addChangedRange(mSelection.range());
67 }
68 mSelection = selection;
69 addChangedRange(mSelection.range());
70 }
71
setSelectionStart(Address startIndex)72 void ByteArrayTableRanges::setSelectionStart(Address startIndex)
73 {
74 bool Changed = mSelection.isValid();
75 if (Changed) {
76 addChangedRange(mSelection.range());
77 }
78
79 mSelection.setStart(startIndex);
80 }
81
setSelectionEnd(Address EndIndex)82 void ByteArrayTableRanges::setSelectionEnd(Address EndIndex)
83 {
84 AddressRange OldSelection = mSelection.range();
85 mSelection.setEnd(EndIndex);
86
87 // TODO: think about rather building a diff of the sections
88 if (!OldSelection.isValid()) {
89 addChangedRange(mSelection.range());
90 return;
91 }
92 if (!mSelection.isValid()) {
93 addChangedRange(OldSelection);
94 return;
95 }
96
97 if (OldSelection == mSelection.range()) {
98 return;
99 }
100 Address CS;
101 Address CE;
102 // changes at the end?
103 if (mSelection.start() == OldSelection.start()) {
104 CS = OldSelection.nextBehindEnd();
105 CE = mSelection.end();
106 if (CE < CS) {
107 CS = mSelection.nextBehindEnd();
108 CE = OldSelection.end();
109 }
110 }
111 // changes at the start?
112 else if (mSelection.end() == OldSelection.end()) {
113 CS = OldSelection.start();
114 CE = mSelection.nextBeforeStart();
115 if (CE < CS) {
116 CS = mSelection.start();
117 CE = OldSelection.nextBeforeStart();
118 }
119 }
120 // change over the anchor
121 else {
122 CS = OldSelection.start();
123 CE = mSelection.end();
124 if (CE < CS) {
125 CS = mSelection.start();
126 CE = OldSelection.end();
127 }
128 }
129 AddressRange C(CS, CE);
130
131 bool Changed = C.isValid();
132 if (Changed) {
133 addChangedRange(C);
134 }
135 return;
136 }
137
removeSelection(int id)138 AddressRange ByteArrayTableRanges::removeSelection(int id)
139 {
140 if (id > 0) {
141 return AddressRange();
142 }
143
144 AddressRange range = mSelection.range();
145 bool Changed = range.isValid();
146 if (Changed) {
147 addChangedRange(range);
148 }
149
150 mSelection.cancel();
151 FirstWordSelection.unset();
152
153 return range;
154 }
155
overlapsSelection(Address FirstIndex,Address LastIndex,Address * startIndex,Address * endIndex) const156 bool ByteArrayTableRanges::overlapsSelection(Address FirstIndex, Address LastIndex, Address* startIndex, Address* endIndex) const
157 {
158 if (mSelection.range().overlaps(AddressRange(FirstIndex, LastIndex))) {
159 *startIndex = mSelection.start();
160 *endIndex = mSelection.end();
161 return true;
162 }
163 return false;
164 }
165
overlapsMarking(Address FirstIndex,Address LastIndex,Address * startIndex,Address * endIndex) const166 bool ByteArrayTableRanges::overlapsMarking(Address FirstIndex, Address LastIndex, Address* startIndex, Address* endIndex) const
167 {
168 if (mMarking.overlaps(AddressRange(FirstIndex, LastIndex))) {
169 *startIndex = mMarking.start();
170 *endIndex = mMarking.end();
171 return true;
172 }
173 return false;
174 }
175
firstOverlappingSelection(const AddressRange & Range) const176 const AddressRange* ByteArrayTableRanges::firstOverlappingSelection(const AddressRange& Range) const
177 {
178 return mSelection.range().overlaps(Range) ? &mSelection.range() : nullptr;
179 }
180
overlappingMarking(const AddressRange & Range) const181 const AddressRange* ByteArrayTableRanges::overlappingMarking(const AddressRange& Range) const
182 {
183 return mMarking.overlaps(Range) ? &mMarking : nullptr;
184 }
185
186 /*
187 bool ByteArrayTableRanges::overlapsChanges( Address FirstIndex, Address LastIndex, Address* startIndex, Address* endIndex ) const
188 {
189 for( CoordRangeList::const_iterator S=ChangedRanges.begin(); S!=ChangedRanges.end(); ++S )
190 {
191 if( (*S).overlaps(KBuff(FirstIndex,LastIndex)) )
192 {
193 *startIndex = (*S).start();
194 *endIndex = (*S).end();
195 return true;
196 }
197 }
198
199 return false;
200 }
201
202 bool ByteArrayTableRanges::overlapsChanges( AddressRange Indizes, AddressRange *ChangedRange ) const
203 {
204 for( AddressRangeList::const_iterator S=ChangedRanges.begin(); S!=ChangedRanges.end(); ++S )
205 {
206 if( (*S).overlaps(Indizes) )
207 {
208 *ChangedRange = *S;
209 return true;
210 }
211 }
212
213 return false;
214 }
215 */
216
overlapsChanges(const CoordRange & Range,CoordRange * ChangedRange) const217 bool ByteArrayTableRanges::overlapsChanges(const CoordRange& Range, CoordRange* ChangedRange) const
218 {
219 // TODO: add a lastusedrange pointer for quicker access
220 return std::any_of(ChangedRanges.begin(), ChangedRanges.end(),
221 [Range, ChangedRange](const CoordRange& changedRange) mutable {
222 if (changedRange.overlaps(Range)) {
223 *ChangedRange = changedRange;
224 return true;
225 }
226 return false;
227 });
228 }
229
addChangedOffsetLines(const LineRange & changedLines)230 void ByteArrayTableRanges::addChangedOffsetLines(const LineRange& changedLines)
231 {
232 if (mChangedOffsetLines.isEmpty()) {
233 mChangedOffsetLines = changedLines;
234 mModified = true;
235 } else {
236 mChangedOffsetLines.extendTo(changedLines);
237 }
238 }
239
addChangedRange(Address startIndex,Address endIndex)240 void ByteArrayTableRanges::addChangedRange(Address startIndex, Address endIndex)
241 {
242 addChangedRange(AddressRange(startIndex, endIndex));
243 }
244
addChangedRange(const AddressRange & range)245 void ByteArrayTableRanges::addChangedRange(const AddressRange& range)
246 {
247 Q_D(ByteArrayTableRanges);
248 // qCDebug(LOG_OKTETA_GUI) << "adding change range "<<S.start()<<","<<S.end();
249 addChangedRange(d->layout->coordRangeOfIndizes(range));
250 }
251
addChangedRange(const CoordRange & range)252 void ByteArrayTableRanges::addChangedRange(const CoordRange& range)
253 {
254 ChangedRanges.addCoordRange(range);
255 // qCDebug(LOG_OKTETA_GUI) << "as range "<<NewRange.start().pos()<<","<<NewRange.start().line()<<"-"
256 // <<NewRange.end().pos()<<","<<NewRange.end().line()<<endl;
257
258 mModified = true;
259 }
260
resetChangedRanges()261 void ByteArrayTableRanges::resetChangedRanges()
262 {
263 mChangedOffsetLines.unset();
264 ChangedRanges.clear();
265 mModified = false;
266 }
267
takeHasSelectionChanged(bool * hasSelectionChanged,bool * selectionChanged)268 void ByteArrayTableRanges::takeHasSelectionChanged(bool* hasSelectionChanged, bool* selectionChanged)
269 {
270 Q_D(ByteArrayTableRanges);
271
272 const bool hadSelection = d->previousSelection.isValid();
273 const bool hasSelection = mSelection.isValid();
274 *hasSelectionChanged = (hadSelection != hasSelection);
275
276 *selectionChanged = (d->previousSelection != mSelection);
277
278 if (*selectionChanged) {
279 d->previousSelection = mSelection;
280 }
281 }
282
setFirstWordSelection(const AddressRange & range)283 void ByteArrayTableRanges::setFirstWordSelection(const AddressRange& range)
284 {
285 FirstWordSelection = range;
286 setSelection(FirstWordSelection);
287 }
288
ensureWordSelectionForward(bool Forward)289 void ByteArrayTableRanges::ensureWordSelectionForward(bool Forward)
290 {
291 // in the anchor not on the right side?
292 if (mSelection.isForward() != Forward) {
293 setSelectionEnd(Forward ? FirstWordSelection.start() : FirstWordSelection.nextBehindEnd());
294
295 mSelection.setForward(Forward);
296 }
297 }
298
adaptToChanges(const ArrayChangeMetricsList & changeList,Size oldLength)299 void ByteArrayTableRanges::adaptToChanges(const ArrayChangeMetricsList& changeList, Size oldLength)
300 {
301 for (const ArrayChangeMetrics& change : changeList) {
302 // TODO: change parameters to ArrayChangeMetrics
303 switch (change.type())
304 {
305 case ArrayChangeMetrics::Replacement:
306 {
307 oldLength += change.lengthChange();
308 const Address offset = change.offset();
309 const Size diff = change.lengthChange();
310 const Address behindLast = (diff == 0) ? offset + change.insertLength() :
311 (diff < 0) ? oldLength - diff :
312 oldLength;
313 addChangedRange(offset, behindLast - 1);
314
315 if (mSelection.isValid()) {
316 mSelection.adaptToReplacement(offset, change.removeLength(), change.insertLength());
317 }
318 if (mMarking.isValid()) {
319 mMarking.adaptToReplacement(offset, change.removeLength(), change.insertLength());
320 }
321 break;
322 }
323 case ArrayChangeMetrics::Swapping:
324 addChangedRange(change.offset(), change.secondEnd());
325
326 if (mSelection.isValid()) {
327 mSelection.adaptToSwap(change.offset(), change.secondStart(), change.secondLength());
328 }
329 // TODO:
330 // if( mMarking.isValid() )
331 // mMarking.adaptToSwap( change.offset(), change.secondStart(), change.secondLength() );
332 default:
333 ;
334 }
335 }
336 }
337
338 }
339