File indexing completed on 2024-03-24 05:56:10
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 "bytearraytablecursor.hpp" 0010 0011 // lib 0012 #include "bytearraytablelayout.hpp" 0013 // Okteta core 0014 #include <Okteta/ArrayChangeMetricsList> 0015 0016 namespace Okteta { 0017 0018 ByteArrayTableCursor::ByteArrayTableCursor(const ByteArrayTableLayout* layout) 0019 : mLayout(layout) 0020 , mIndex(layout->byteArrayOffset()) 0021 , mCoord(layout->startCoord()) 0022 , mBehind(false) 0023 , mAppendPosEnabled(false) 0024 { 0025 } 0026 0027 ByteArrayTableCursor::~ByteArrayTableCursor() = default; 0028 0029 void ByteArrayTableCursor::setAppendPosEnabled(bool appendPosEnabled) 0030 { 0031 if (mAppendPosEnabled == appendPosEnabled) { 0032 return; 0033 } 0034 0035 mAppendPosEnabled = appendPosEnabled; 0036 // reposition Cursor 0037 if (realIndex() > mLayout->lastByteArrayOffset() 0038 && mCoord.pos() < mLayout->noOfBytesPerLine() - 1 0039 && mLayout->length() > 0) { 0040 if (mAppendPosEnabled) { 0041 ++mIndex; 0042 mCoord.goRight(); 0043 mBehind = false; 0044 } else { 0045 --mIndex; 0046 mCoord.goLeft(); 0047 mBehind = true; 0048 } 0049 } 0050 } 0051 0052 void ByteArrayTableCursor::gotoPreviousByte() 0053 { 0054 if (mBehind) { 0055 mBehind = false; 0056 } else if (mIndex > mLayout->byteArrayOffset()) { 0057 --mIndex; 0058 mCoord.goCLeft(mLayout->noOfBytesPerLine() - 1); 0059 } 0060 } 0061 0062 void ByteArrayTableCursor::gotoPreviousByte(Size indexSteps) 0063 { 0064 if (mBehind) { 0065 --indexSteps; 0066 mBehind = false; 0067 } 0068 const Address newIndex = mIndex - indexSteps; 0069 // would step before first position? 0070 const Address firstIndex = mLayout->byteArrayOffset(); 0071 if (newIndex < firstIndex) { 0072 if (mIndex > firstIndex) { 0073 gotoStart(); 0074 } 0075 } else { 0076 gotoIndex(newIndex); 0077 } 0078 } 0079 0080 void ByteArrayTableCursor::gotoNextByte() 0081 { 0082 const Address lastIndex = mLayout->lastByteArrayOffset(); 0083 0084 if (mIndex < lastIndex) { 0085 ++mIndex; 0086 mCoord.goCRight(mLayout->noOfBytesPerLine() - 1); 0087 mBehind = false; 0088 } else if (mIndex == lastIndex) { 0089 stepToEnd(); 0090 } 0091 } 0092 0093 void ByteArrayTableCursor::gotoNextByte(Size indexSteps) // TODO: think about consistency with gotoNextByte!!! 0094 { 0095 if (mBehind) { 0096 ++indexSteps; 0097 mBehind = false; 0098 } 0099 const Address newIndex = mIndex + indexSteps; 0100 // would step behind the end? 0101 if (newIndex > mLayout->lastByteArrayOffset()) { 0102 gotoEnd(); 0103 } else { 0104 gotoIndex(newIndex); 0105 } 0106 } 0107 0108 void ByteArrayTableCursor::gotoUp() 0109 { 0110 // can we even go up? 0111 if (mCoord.isBelow(mLayout->startLine())) { 0112 mCoord.goUp(); 0113 if (mCoord.isPriorInLineThan(mLayout->startCoord())) { 0114 mIndex = mLayout->byteArrayOffset(); 0115 mCoord.setPos(mLayout->firstStartLinePosition()); 0116 mBehind = false; 0117 } else { 0118 mIndex -= mLayout->noOfBytesPerLine(); 0119 if (mBehind && !atLineEnd()) { 0120 ++mIndex; 0121 mCoord.goRight(); 0122 mBehind = false; 0123 } 0124 } 0125 } 0126 } 0127 0128 void ByteArrayTableCursor::gotoDown() 0129 { 0130 if (mCoord.isAbove(mLayout->finalLine())) { 0131 mCoord.goDown(); 0132 // behind End? 0133 if (mCoord.isLaterInLineThan(mLayout->finalCoord())) { 0134 gotoEnd(); 0135 } else { 0136 mIndex += mLayout->noOfBytesPerLine(); 0137 } 0138 } 0139 } 0140 0141 void ByteArrayTableCursor::gotoLineStart() 0142 { 0143 const Address oldIndex = mIndex; 0144 mIndex = mLayout->indexAtFirstLinePosition(mCoord.line()); 0145 mCoord.goLeft(oldIndex - mIndex); 0146 mBehind = false; 0147 } 0148 0149 void ByteArrayTableCursor::gotoLineEnd() 0150 { 0151 if (mIndex <= mLayout->lastByteArrayOffset()) { 0152 const Address oldIndex = mIndex; 0153 mIndex = mLayout->indexAtLastLinePosition(mCoord.line()); 0154 mCoord.goRight(mIndex - oldIndex); 0155 0156 stepToEnd(); 0157 } 0158 } 0159 0160 void ByteArrayTableCursor::gotoStart() 0161 { 0162 mIndex = mLayout->byteArrayOffset(); 0163 mCoord = mLayout->startCoord(); 0164 mBehind = false; 0165 } 0166 0167 void ByteArrayTableCursor::gotoEnd() 0168 { 0169 const Address lastIndex = mLayout->lastByteArrayOffset(); 0170 if (lastIndex >= 0) { 0171 mIndex = lastIndex; 0172 mCoord = mLayout->finalCoord(); 0173 0174 stepToEnd(); 0175 } else { 0176 gotoStart(); 0177 } 0178 } 0179 0180 void ByteArrayTableCursor::gotoCIndex(Address index) 0181 { 0182 if (mLayout->length() > 0) { 0183 mIndex = mLayout->correctIndex(index); 0184 mCoord = mLayout->coordOfIndex(mIndex); 0185 mBehind = (index > mIndex); 0186 } else { 0187 gotoStart(); 0188 } 0189 } 0190 0191 void ByteArrayTableCursor::gotoCCoord(Coord coord) 0192 { 0193 if (mLayout->length() > 0) { 0194 mCoord = mLayout->correctCoord(coord); 0195 mIndex = mLayout->indexAtCoord(mCoord); 0196 if (coord > mCoord) { 0197 stepToEnd(); 0198 } else { 0199 mBehind = false; 0200 } 0201 } else { 0202 gotoStart(); 0203 } 0204 } 0205 0206 void ByteArrayTableCursor::stepToEnd() 0207 { 0208 if (mAppendPosEnabled && (mCoord.pos() < mLayout->noOfBytesPerLine() - 1)) { 0209 ++mIndex; 0210 mCoord.goRight(); 0211 mBehind = false; 0212 } else { 0213 mBehind = true; 0214 } 0215 } 0216 0217 void ByteArrayTableCursor::gotoIndex(Address index) 0218 { 0219 mIndex = index; 0220 mCoord = mLayout->coordOfIndex(mIndex); 0221 mBehind = false; 0222 } 0223 0224 void ByteArrayTableCursor::gotoRealIndex() 0225 { 0226 if (mBehind 0227 && (mAppendPosEnabled || (mIndex < mLayout->lastByteArrayOffset()))) { 0228 ++mIndex; 0229 mCoord.goCRight(mLayout->noOfBytesPerLine() - 1); 0230 mBehind = false; 0231 } 0232 } 0233 0234 void ByteArrayTableCursor::gotoCoord(Coord coord) 0235 { 0236 mIndex = mLayout->indexAtCoord(coord); 0237 mCoord = coord; 0238 mBehind = false; 0239 } 0240 0241 void ByteArrayTableCursor::updateCoord() 0242 { 0243 mCoord = mLayout->coordOfIndex(mIndex); 0244 } 0245 0246 // page down should be: one page minus one line 0247 // -> if in the very first line page down will put the cursor on the same page into the last line 0248 void ByteArrayTableCursor::gotoPageUp() 0249 { 0250 const LineSize noOfLinesPerPage = mLayout->noOfLinesPerPage(); 0251 const Address newIndex = mIndex - noOfLinesPerPage * mLayout->noOfBytesPerLine(); 0252 if (newIndex >= mLayout->byteArrayOffset()) { 0253 mIndex = newIndex; 0254 mCoord.goUp(noOfLinesPerPage); 0255 if (mBehind && !atLineEnd()) { 0256 ++mIndex; 0257 mCoord.goRight(); 0258 mBehind = false; 0259 } 0260 } else { 0261 gotoStart(); 0262 } 0263 } 0264 0265 void ByteArrayTableCursor::gotoPageDown() 0266 { 0267 const LineSize noOfLinesPerPage = mLayout->noOfLinesPerPage(); 0268 const Address newIndex = mIndex + noOfLinesPerPage * mLayout->noOfBytesPerLine(); 0269 if (newIndex <= mLayout->lastByteArrayOffset()) { 0270 mIndex = newIndex; 0271 mCoord.goDown(noOfLinesPerPage); 0272 } else { 0273 gotoEnd(); 0274 } 0275 } 0276 0277 Address ByteArrayTableCursor::validIndex() const 0278 { 0279 return (mLayout->byteArrayOffset() <= mIndex && mIndex <= mLayout->lastByteArrayOffset()) ? mIndex : -1; 0280 } 0281 0282 Address ByteArrayTableCursor::indexAtLineStart() const { return mLayout->indexAtFirstLinePosition(mCoord.line()); } 0283 Address ByteArrayTableCursor::indexAtLineEnd() const { return mLayout->indexAtLastLinePosition(mCoord.line()); } 0284 0285 bool ByteArrayTableCursor::atStart() const { return mIndex == mLayout->byteArrayOffset(); } 0286 bool ByteArrayTableCursor::atEnd() const { return realIndex() == mLayout->lastByteArrayOffset() + 1; } 0287 bool ByteArrayTableCursor::atAppendPos() const { return mIndex == mLayout->lastByteArrayOffset() + 1; } 0288 0289 bool ByteArrayTableCursor::atLineStart() const { return mLayout->atFirstLinePosition(mCoord); } 0290 bool ByteArrayTableCursor::atLineEnd() const { return mLayout->atLastLinePosition(mCoord); } 0291 0292 // TODO: oldLength is a hack, as DataLayout is already updated and used by e.g. gotoCIndex 0293 void ByteArrayTableCursor::adaptToChanges(const ArrayChangeMetricsList& changeList, Size oldLength) 0294 { 0295 for (const ArrayChangeMetrics& change : changeList) { 0296 // cursor affected? 0297 if (mIndex >= change.offset()) { 0298 switch (change.type()) 0299 { 0300 case ArrayChangeMetrics::Replacement: 0301 oldLength += change.lengthChange(); 0302 if (oldLength > 0) { 0303 const Address newIndex = 0304 // cursor behind the removed section? 0305 (mIndex >= change.offset() + change.removeLength()) ? mIndex + change.lengthChange() : 0306 // cursor at substituted section? 0307 (mIndex < change.offset() + change.insertLength()) ? mIndex : 0308 // cursor at unsubstituted section 0309 change.offset() + change.insertLength(); 0310 0311 // if the cursor gets behind, it will never get inside again. 0312 if (newIndex >= oldLength) { 0313 gotoEnd(); 0314 return; 0315 } 0316 mIndex = newIndex; 0317 } 0318 // if the cursor gets at the start, it will stay there 0319 else { 0320 gotoStart(); 0321 return; 0322 } 0323 break; 0324 case ArrayChangeMetrics::Swapping: 0325 if (mIndex < change.secondStart()) { 0326 mIndex += change.secondLength(); 0327 } else if (mIndex <= change.secondEnd()) { 0328 mIndex -= change.firstLength(); 0329 } 0330 break; 0331 default: 0332 ; 0333 } 0334 } 0335 } 0336 0337 const bool wasBehind = (mIndex >= oldLength); 0338 if (wasBehind) { 0339 mIndex = oldLength - 1; 0340 } 0341 updateCoord(); 0342 if (wasBehind) { 0343 stepToEnd(); 0344 } 0345 } 0346 0347 }