File indexing completed on 2024-04-21 16:34:02

0001 /*
0002     This file is part of the Okteta Gui library, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2003, 2008-2009 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "bytearraytableranges.hpp"
0010 #include "bytearraytableranges_p.hpp"
0011 
0012 // lib
0013 #include "bytearraytablelayout.hpp"
0014 // Okteta core
0015 #include <Okteta/ArrayChangeMetricsList>
0016 
0017 namespace Okteta {
0018 
0019 ByteArrayTableRanges::ByteArrayTableRanges(ByteArrayTableLayout* layout)
0020     : d_ptr(new ByteArrayTableRangesPrivate(layout))
0021 {
0022 }
0023 
0024 ByteArrayTableRanges::~ByteArrayTableRanges() = default;
0025 
0026 void ByteArrayTableRanges::reset()
0027 {
0028     Q_D(ByteArrayTableRanges);
0029     mSelection.cancel();
0030     FirstWordSelection.unset();
0031     mMarking.unset();
0032     ChangedRanges.clear();
0033     d->previousSelection = mSelection;
0034 }
0035 
0036 void ByteArrayTableRanges::setMarking(const AddressRange& marking)
0037 {
0038     if (mMarking == marking) {
0039         return;
0040     }
0041 
0042     const bool hadMarking = mMarking.isValid();
0043     if (hadMarking) {
0044         addChangedRange(mMarking);
0045     }
0046 
0047     mMarking = marking;
0048 
0049     const bool hasNewMarking = mMarking.isValid();
0050     if (hasNewMarking) {
0051         addChangedRange(mMarking);
0052     }
0053 }
0054 
0055 void ByteArrayTableRanges::removeFurtherSelections()
0056 {
0057     for (int i = 1; i < noOfSelections(); ++i) {
0058         removeSelection(i);
0059     }
0060 }
0061 
0062 void ByteArrayTableRanges::setSelection(const AddressRange& selection)
0063 {
0064     bool Changed = mSelection.isValid();
0065     if (Changed) {
0066         addChangedRange(mSelection.range());
0067     }
0068     mSelection = selection;
0069     addChangedRange(mSelection.range());
0070 }
0071 
0072 void ByteArrayTableRanges::setSelectionStart(Address startIndex)
0073 {
0074     bool Changed = mSelection.isValid();
0075     if (Changed) {
0076         addChangedRange(mSelection.range());
0077     }
0078 
0079     mSelection.setStart(startIndex);
0080 }
0081 
0082 void ByteArrayTableRanges::setSelectionEnd(Address EndIndex)
0083 {
0084     AddressRange OldSelection = mSelection.range();
0085     mSelection.setEnd(EndIndex);
0086 
0087     // TODO: think about rather building a diff of the sections
0088     if (!OldSelection.isValid()) {
0089         addChangedRange(mSelection.range());
0090         return;
0091     }
0092     if (!mSelection.isValid()) {
0093         addChangedRange(OldSelection);
0094         return;
0095     }
0096 
0097     if (OldSelection == mSelection.range()) {
0098         return;
0099     }
0100     Address CS;
0101     Address CE;
0102     // changes at the end?
0103     if (mSelection.start() == OldSelection.start()) {
0104         CS = OldSelection.nextBehindEnd();
0105         CE = mSelection.end();
0106         if (CE < CS) {
0107             CS = mSelection.nextBehindEnd();
0108             CE = OldSelection.end();
0109         }
0110     }
0111     // changes at the start?
0112     else if (mSelection.end() == OldSelection.end()) {
0113         CS = OldSelection.start();
0114         CE = mSelection.nextBeforeStart();
0115         if (CE < CS) {
0116             CS = mSelection.start();
0117             CE = OldSelection.nextBeforeStart();
0118         }
0119     }
0120     // change over the anchor
0121     else {
0122         CS = OldSelection.start();
0123         CE = mSelection.end();
0124         if (CE < CS) {
0125             CS = mSelection.start();
0126             CE = OldSelection.end();
0127         }
0128     }
0129     AddressRange C(CS, CE);
0130 
0131     bool Changed = C.isValid();
0132     if (Changed) {
0133         addChangedRange(C);
0134     }
0135     return;
0136 }
0137 
0138 AddressRange ByteArrayTableRanges::removeSelection(int id)
0139 {
0140     if (id > 0) {
0141         return AddressRange();
0142     }
0143 
0144     AddressRange range = mSelection.range();
0145     bool Changed = range.isValid();
0146     if (Changed) {
0147         addChangedRange(range);
0148     }
0149 
0150     mSelection.cancel();
0151     FirstWordSelection.unset();
0152 
0153     return range;
0154 }
0155 
0156 bool ByteArrayTableRanges::overlapsSelection(Address FirstIndex, Address LastIndex, Address* startIndex, Address* endIndex) const
0157 {
0158     if (mSelection.range().overlaps(AddressRange(FirstIndex, LastIndex))) {
0159         *startIndex = mSelection.start();
0160         *endIndex = mSelection.end();
0161         return true;
0162     }
0163     return false;
0164 }
0165 
0166 bool ByteArrayTableRanges::overlapsMarking(Address FirstIndex, Address LastIndex, Address* startIndex, Address* endIndex) const
0167 {
0168     if (mMarking.overlaps(AddressRange(FirstIndex, LastIndex))) {
0169         *startIndex = mMarking.start();
0170         *endIndex = mMarking.end();
0171         return true;
0172     }
0173     return false;
0174 }
0175 
0176 const AddressRange* ByteArrayTableRanges::firstOverlappingSelection(const AddressRange& Range) const
0177 {
0178     return mSelection.range().overlaps(Range) ? &mSelection.range() : nullptr;
0179 }
0180 
0181 const AddressRange* ByteArrayTableRanges::overlappingMarking(const AddressRange& Range) const
0182 {
0183     return mMarking.overlaps(Range) ? &mMarking : nullptr;
0184 }
0185 
0186 /*
0187 bool ByteArrayTableRanges::overlapsChanges( Address FirstIndex, Address LastIndex, Address* startIndex, Address* endIndex ) const
0188 {
0189     for( CoordRangeList::const_iterator S=ChangedRanges.begin(); S!=ChangedRanges.end(); ++S )
0190     {
0191         if( (*S).overlaps(KBuff(FirstIndex,LastIndex)) )
0192         {
0193             *startIndex = (*S).start();
0194             *endIndex = (*S).end();
0195             return true;
0196         }
0197     }
0198 
0199     return false;
0200 }
0201 
0202 bool ByteArrayTableRanges::overlapsChanges( AddressRange Indizes, AddressRange *ChangedRange ) const
0203 {
0204     for( AddressRangeList::const_iterator S=ChangedRanges.begin(); S!=ChangedRanges.end(); ++S )
0205     {
0206         if( (*S).overlaps(Indizes) )
0207         {
0208             *ChangedRange = *S;
0209             return true;
0210         }
0211     }
0212 
0213     return false;
0214 }
0215 */
0216 
0217 bool ByteArrayTableRanges::overlapsChanges(const CoordRange& Range, CoordRange* ChangedRange) const
0218 {
0219     // TODO: add a lastusedrange pointer for quicker access
0220     return std::any_of(ChangedRanges.begin(), ChangedRanges.end(),
0221                        [Range, ChangedRange](const CoordRange& changedRange) mutable {
0222         if (changedRange.overlaps(Range)) {
0223             *ChangedRange = changedRange;
0224             return true;
0225         }
0226         return false;
0227     });
0228 }
0229 
0230 void ByteArrayTableRanges::addChangedOffsetLines(const LineRange& changedLines)
0231 {
0232     if (mChangedOffsetLines.isEmpty()) {
0233         mChangedOffsetLines = changedLines;
0234         mModified = true;
0235     } else {
0236         mChangedOffsetLines.extendTo(changedLines);
0237     }
0238 }
0239 
0240 void ByteArrayTableRanges::addChangedRange(Address startIndex, Address endIndex)
0241 {
0242     addChangedRange(AddressRange(startIndex, endIndex));
0243 }
0244 
0245 void ByteArrayTableRanges::addChangedRange(const AddressRange& range)
0246 {
0247     Q_D(ByteArrayTableRanges);
0248 // qCDebug(LOG_OKTETA_GUI) << "adding change range "<<S.start()<<","<<S.end();
0249     addChangedRange(d->layout->coordRangeOfIndizes(range));
0250 }
0251 
0252 void ByteArrayTableRanges::addChangedRange(const CoordRange& range)
0253 {
0254     ChangedRanges.addCoordRange(range);
0255 // qCDebug(LOG_OKTETA_GUI) << "as range "<<NewRange.start().pos()<<","<<NewRange.start().line()<<"-"
0256 // <<NewRange.end().pos()<<","<<NewRange.end().line()<<endl;
0257 
0258     mModified = true;
0259 }
0260 
0261 void ByteArrayTableRanges::resetChangedRanges()
0262 {
0263     mChangedOffsetLines.unset();
0264     ChangedRanges.clear();
0265     mModified = false;
0266 }
0267 
0268 void ByteArrayTableRanges::takeHasSelectionChanged(bool* hasSelectionChanged, bool* selectionChanged)
0269 {
0270     Q_D(ByteArrayTableRanges);
0271 
0272     const bool hadSelection = d->previousSelection.isValid();
0273     const bool hasSelection = mSelection.isValid();
0274     *hasSelectionChanged = (hadSelection != hasSelection);
0275 
0276     *selectionChanged = (d->previousSelection != mSelection);
0277 
0278     if (*selectionChanged) {
0279         d->previousSelection = mSelection;
0280     }
0281 }
0282 
0283 void ByteArrayTableRanges::setFirstWordSelection(const AddressRange& range)
0284 {
0285     FirstWordSelection = range;
0286     setSelection(FirstWordSelection);
0287 }
0288 
0289 void ByteArrayTableRanges::ensureWordSelectionForward(bool Forward)
0290 {
0291     // in the anchor not on the right side?
0292     if (mSelection.isForward() != Forward) {
0293         setSelectionEnd(Forward ? FirstWordSelection.start() : FirstWordSelection.nextBehindEnd());
0294 
0295         mSelection.setForward(Forward);
0296     }
0297 }
0298 
0299 void ByteArrayTableRanges::adaptToChanges(const ArrayChangeMetricsList& changeList, Size oldLength)
0300 {
0301     for (const ArrayChangeMetrics& change : changeList) {
0302         // TODO: change parameters to ArrayChangeMetrics
0303         switch (change.type())
0304         {
0305         case ArrayChangeMetrics::Replacement:
0306         {
0307             oldLength += change.lengthChange();
0308             const Address offset = change.offset();
0309             const Size diff = change.lengthChange();
0310             const Address behindLast = (diff == 0) ? offset + change.insertLength() :
0311                                        (diff < 0) ?  oldLength - diff :
0312                                                      oldLength;
0313             addChangedRange(offset, behindLast - 1);
0314 
0315             if (mSelection.isValid()) {
0316                 mSelection.adaptToReplacement(offset, change.removeLength(), change.insertLength());
0317             }
0318             if (mMarking.isValid()) {
0319                 mMarking.adaptToReplacement(offset, change.removeLength(), change.insertLength());
0320             }
0321             break;
0322         }
0323         case ArrayChangeMetrics::Swapping:
0324             addChangedRange(change.offset(), change.secondEnd());
0325 
0326             if (mSelection.isValid()) {
0327                 mSelection.adaptToSwap(change.offset(), change.secondStart(), change.secondLength());
0328             }
0329         // TODO:
0330 //             if( mMarking.isValid() )
0331 //                 mMarking.adaptToSwap( change.offset(), change.secondStart(), change.secondLength() );
0332         default:
0333             ;
0334         }
0335     }
0336 }
0337 
0338 }