File indexing completed on 2024-04-28 05:52:37
0001 /* 0002 This file is part of the Okteta Gui library, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2004, 2008 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 "valueeditor.hpp" 0010 0011 // lib 0012 #include <bytearraytablecursor.hpp> 0013 #include <abstractbytearrayview.hpp> 0014 // Okteta core 0015 #include <Okteta/AbstractByteArrayModel> 0016 #include <Okteta/ChangesDescribable> 0017 #include <Okteta/ValueCodec> 0018 // KF 0019 #include <KLocalizedString> 0020 // Qt 0021 #include <QKeyEvent> 0022 0023 namespace Okteta { 0024 0025 ValueEditor::ValueEditor(ByteArrayTableCursor* cursor, AbstractByteArrayView* view, AbstractController* parent) 0026 : AbstractEditor(cursor, view, parent) 0027 , mInEditMode(false) 0028 , mEditModeByInsert(false) 0029 { 0030 } 0031 0032 ValueEditor::~ValueEditor() = default; 0033 0034 void ValueEditor::adaptToValueCodecChange() 0035 { 0036 const uint newCodingWidth = mView->valueCodec()->encodingWidth(); 0037 mValueString.resize(newCodingWidth); 0038 } 0039 0040 void ValueEditor::startEdit(const QString& description) 0041 { 0042 Q_ASSERT(!mInEditMode); 0043 0044 Okteta::AbstractByteArrayModel* byteArrayModel = mView->byteArrayModel(); 0045 Okteta::ChangesDescribable* changesDescribable = 0046 qobject_cast<Okteta::ChangesDescribable*>(byteArrayModel); 0047 0048 if (changesDescribable) { 0049 changesDescribable->openGroupedChange(description); 0050 } 0051 0052 mInEditMode = true; 0053 } 0054 0055 void ValueEditor::cancelEdit(bool undoChanges) 0056 { 0057 // Q_ASSERT( mInEditMode ); 0058 if (!mInEditMode) { 0059 return; 0060 } 0061 0062 mInEditMode = false; 0063 0064 if (undoChanges) { 0065 Okteta::AbstractByteArrayModel* byteArrayModel = mView->byteArrayModel(); 0066 Okteta::ChangesDescribable* changesDescribable = 0067 qobject_cast<Okteta::ChangesDescribable*>(byteArrayModel); 0068 0069 // TODO: if !changesDescribable the changes need to be undone, too 0070 if (changesDescribable) { 0071 changesDescribable->cancelGroupedChange(); 0072 } 0073 } 0074 } 0075 0076 void ValueEditor::finishEdit() 0077 { 0078 if (!mInEditMode) { 0079 return; 0080 } 0081 0082 mInEditMode = false; 0083 0084 Okteta::AbstractByteArrayModel* byteArrayModel = mView->byteArrayModel(); 0085 Okteta::ChangesDescribable* changesDescribable = 0086 qobject_cast<Okteta::ChangesDescribable*>(byteArrayModel); 0087 0088 if (changesDescribable) { 0089 changesDescribable->closeGroupedChange(); 0090 } 0091 } 0092 0093 bool ValueEditor::handleKeyPress(QKeyEvent* keyEvent) 0094 { 0095 bool keyUsed = true; 0096 0097 // TODO: for now we don't touch it if there are selections 0098 if (!mView->hasSelectedData()) { 0099 // 0100 switch (keyEvent->key()) 0101 { 0102 case Qt::Key_Plus: 0103 doValueEditAction(IncValue); 0104 break; 0105 case Qt::Key_Minus: 0106 doValueEditAction(DecValue); 0107 break; 0108 case Qt::Key_Space: 0109 if (!mInEditMode) { 0110 keyUsed = false; 0111 break; 0112 } 0113 [[fallthrough]]; 0114 case Qt::Key_Enter: 0115 case Qt::Key_Return: 0116 doValueEditAction(mInEditMode ? LeaveValue : EnterValue); 0117 break; 0118 case Qt::Key_Escape: 0119 if (mInEditMode) { 0120 cancelEdit(); 0121 } else { 0122 keyUsed = false; 0123 } 0124 break; 0125 case Qt::Key_Backspace: 0126 if (mInEditMode) { 0127 doValueEditAction(ValueBackspace); 0128 } else { 0129 keyUsed = false; 0130 } 0131 break; 0132 default: 0133 { 0134 // is plain char? 0135 const QString text = keyEvent->text(); 0136 if (text.length() > 0 0137 && (!(keyEvent->modifiers() & (Qt::CTRL | Qt::ALT | Qt::META)))) { 0138 const QChar enteredChar = text.at(0); 0139 // no usable char? 0140 if (!enteredChar.isPrint()) { 0141 keyUsed = false; 0142 break; 0143 } 0144 const int input = enteredChar.toLatin1(); 0145 0146 const Okteta::ValueCodec* valueCodec = mView->valueCodec(); 0147 if (mInEditMode) { 0148 if (mInsertedDigitsCount < valueCodec->encodingWidth()) { 0149 doValueEditAction(ValueAppend, input); 0150 } 0151 } else { 0152 Byte inputValue = 0; 0153 // valid digit? 0154 if (valueCodec->appendDigit(&inputValue, input)) { 0155 if (mView->isOverwriteMode()) { 0156 doValueEditAction(ValueEdit, inputValue); 0157 } else { 0158 const Address index = mCursor->realIndex(); 0159 0160 startEdit(i18nc("name of the change", "Insert")); 0161 if (mView->byteArrayModel()->insert(index, &inputValue, 1) > 0) { 0162 mEditModeByInsert = true; 0163 mOldValue = mEditValue = inputValue; 0164 mInsertedDigitsCount = 1; 0165 valueCodec->encode(&mValueString, 0, mEditValue); 0166 0167 mCursor->gotoIndex(index); 0168 mView->ensureCursorVisible(); 0169 // mView->updateCursors(); 0170 Q_EMIT mView->cursorPositionChanged(mCursor->realIndex()); 0171 } else { 0172 cancelEdit(); 0173 } 0174 } 0175 } 0176 } 0177 } else { 0178 keyUsed = false; 0179 } 0180 } 0181 } 0182 } else { 0183 keyUsed = false; 0184 } 0185 0186 return keyUsed ? true : AbstractEditor::handleKeyPress(keyEvent); 0187 } 0188 0189 void ValueEditor::doValueEditAction(ValueEditAction Action, int input) 0190 { 0191 const Okteta::ValueCodec* valueCodec = mView->valueCodec(); 0192 0193 // we are not yet in edit mode? 0194 if (!mInEditMode) { 0195 const Address validIndex = mCursor->validIndex(); 0196 // no valid cursor position? 0197 if (validIndex == -1 || (!mView->isOverwriteMode() && input == -1) || mCursor->isBehind()) { 0198 return; 0199 } 0200 0201 startEdit(i18nc("name of the change", "Replace")); 0202 mEditModeByInsert = false; // default, to be overwritten if so 0203 0204 // save old value 0205 mOldValue = mEditValue = (unsigned char)mView->byteArrayModel()->byte(validIndex); 0206 mInsertedDigitsCount = valueCodec->encodingWidth(); 0207 } 0208 0209 // 0210 Byte newValue = mEditValue; 0211 bool stayInEditMode = true; 0212 bool moveToNext = false; 0213 0214 switch (Action) 0215 { 0216 case ValueEdit: 0217 newValue = input; 0218 mEditValue = newValue ^ 255; // force update 0219 mEditModeByInsert = true; 0220 mInsertedDigitsCount = 1; 0221 break; 0222 case ValueBackspace: 0223 if (mInsertedDigitsCount > 0) { 0224 if (newValue > 0) { 0225 valueCodec->removeLastDigit(&newValue); 0226 } 0227 --mInsertedDigitsCount; 0228 } 0229 break; 0230 case EnterValue: 0231 mEditValue ^= 255; // force update 0232 break; 0233 case IncValue: 0234 if (newValue < 255) { 0235 ++newValue; 0236 mInsertedDigitsCount = valueCodec->encodingWidth(); 0237 } 0238 break; 0239 case DecValue: 0240 if (newValue > 0) { 0241 --newValue; 0242 mInsertedDigitsCount = valueCodec->encodingWidth(); 0243 } 0244 break; 0245 case ValueAppend: 0246 if (valueCodec->appendDigit(&newValue, input)) { 0247 ++mInsertedDigitsCount; 0248 if (mEditModeByInsert && 0249 (newValue >= valueCodec->digitsFilledLimit() || mInsertedDigitsCount == valueCodec->encodingWidth())) { 0250 stayInEditMode = false; 0251 moveToNext = true; 0252 } 0253 } 0254 break; 0255 case LeaveValue: 0256 stayInEditMode = false; 0257 moveToNext = mEditModeByInsert; 0258 break; 0259 } 0260 0261 // change happened? 0262 if (newValue != mEditValue) { 0263 // sync value 0264 mEditValue = newValue; 0265 valueCodec->encode(&mValueString, 0, mEditValue); 0266 mView->byteArrayModel()->replace(mCursor->index(), 1, &mEditValue, 1); 0267 } 0268 0269 // mView->updateCursors(); 0270 0271 if (!stayInEditMode) { 0272 mView->pauseCursor(); 0273 finishEdit(); 0274 0275 if (moveToNext) { 0276 mCursor->gotoNextByte(); 0277 } 0278 0279 mView->unpauseCursor(); 0280 if (moveToNext) { 0281 Q_EMIT mView->cursorPositionChanged(mCursor->realIndex()); 0282 } 0283 } 0284 } 0285 0286 }