File indexing completed on 2024-04-14 05:45:55

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