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 }