1
0
Fork 0

GUI: added QHexEdit class

This commit is contained in:
Mr. eXoDia 2014-07-05 03:01:40 +02:00
parent d43579ef14
commit 9424054434
8 changed files with 1521 additions and 0 deletions

View File

@ -0,0 +1,106 @@
#include "ArrayCommand.h"
CharCommand::CharCommand(XByteArray * xData, Cmd cmd, int charPos, char newChar, QUndoCommand *parent) : QUndoCommand(parent)
{
_xData = xData;
_charPos = charPos;
_newChar = newChar;
_cmd = cmd;
}
bool CharCommand::mergeWith(const QUndoCommand *command)
{
const CharCommand *nextCommand = static_cast<const CharCommand *>(command);
bool result = false;
if (_cmd != remove)
{
if (nextCommand->_cmd == replace)
if (nextCommand->_charPos == _charPos)
{
_newChar = nextCommand->_newChar;
result = true;
}
}
return result;
}
void CharCommand::undo()
{
switch (_cmd)
{
case insert:
_xData->remove(_charPos, 1);
break;
case replace:
_xData->replace(_charPos, _oldChar);
break;
case remove:
_xData->insert(_charPos, _oldChar);
break;
}
}
void CharCommand::redo()
{
switch (_cmd)
{
case insert:
_xData->insert(_charPos, _newChar);
break;
case replace:
_oldChar = _xData->data()[_charPos];
_xData->replace(_charPos, _newChar);
break;
case remove:
_oldChar = _xData->data()[_charPos];
_xData->remove(_charPos, 1);
break;
}
}
ArrayCommand::ArrayCommand(XByteArray * xData, Cmd cmd, int baPos, QByteArray newBa, int len, QUndoCommand *parent)
: QUndoCommand(parent)
{
_cmd = cmd;
_xData = xData;
_baPos = baPos;
_newBa = newBa;
_len = len;
}
void ArrayCommand::undo()
{
switch (_cmd)
{
case insert:
_xData->remove(_baPos, _newBa.length());
break;
case replace:
_xData->replace(_baPos, _oldBa);
break;
case remove:
_xData->insert(_baPos, _oldBa);
break;
}
}
void ArrayCommand::redo()
{
switch (_cmd)
{
case insert:
_xData->insert(_baPos, _newBa);
break;
case replace:
_oldBa = _xData->data().mid(_baPos, _len);
_xData->replace(_baPos, _newBa);
break;
case remove:
_oldBa = _xData->data().mid(_baPos, _len);
_xData->remove(_baPos, _len);
break;
}
}

View File

@ -0,0 +1,50 @@
#ifndef ARRAYCOMMAND_H
#define ARRAYCOMMAND_H
#include <QUndoCommand>
#include "XByteArray.h"
class CharCommand : public QUndoCommand
{
public:
enum { Id = 1234 };
enum Cmd {insert, remove, replace};
CharCommand(XByteArray * xData, Cmd cmd, int charPos, char newChar,
QUndoCommand *parent=0);
void undo();
void redo();
bool mergeWith(const QUndoCommand *command);
int id() const
{
return Id;
}
private:
XByteArray * _xData;
int _charPos;
char _newChar;
char _oldChar;
Cmd _cmd;
};
class ArrayCommand : public QUndoCommand
{
public:
enum Cmd {insert, remove, replace};
ArrayCommand(XByteArray * xData, Cmd cmd, int baPos, QByteArray newBa=QByteArray(), int len=0, QUndoCommand *parent=0);
void undo();
void redo();
private:
Cmd _cmd;
XByteArray * _xData;
int _baPos;
int _len;
QByteArray _wasChanged;
QByteArray _newBa;
QByteArray _oldBa;
};
#endif // ARRAYCOMMAND_H

View File

@ -0,0 +1,224 @@
#include <QtGui>
#include "QHexEdit.h"
QHexEdit::QHexEdit(QWidget *parent) : QScrollArea(parent)
{
qHexEdit_p = new QHexEditPrivate(this);
setWidget(qHexEdit_p);
setWidgetResizable(true);
connect(qHexEdit_p, SIGNAL(currentAddressChanged(int)), this, SIGNAL(currentAddressChanged(int)));
connect(qHexEdit_p, SIGNAL(currentSizeChanged(int)), this, SIGNAL(currentSizeChanged(int)));
connect(qHexEdit_p, SIGNAL(dataChanged()), this, SIGNAL(dataChanged()));
connect(qHexEdit_p, SIGNAL(overwriteModeChanged(bool)), this, SIGNAL(overwriteModeChanged(bool)));
setFocusPolicy(Qt::NoFocus);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
}
void QHexEdit::insert(int i, const QByteArray & ba, const QByteArray & mask)
{
qHexEdit_p->insert(i, ba, mask);
}
void QHexEdit::insert(int i, char ch, char mask)
{
qHexEdit_p->insert(i, ch, mask);
}
void QHexEdit::remove(int pos, int len)
{
qHexEdit_p->remove(pos, len);
}
void QHexEdit::replace( int pos, int len, const QByteArray & after, const QByteArray & mask)
{
qHexEdit_p->replace(pos, len, after, mask);
}
void QHexEdit::redo()
{
qHexEdit_p->redo();
}
void QHexEdit::undo()
{
qHexEdit_p->undo();
}
void QHexEdit::setCursorPosition(int cursorPos)
{
// cursorPos in QHexEditPrivate is the position of the textcoursor without
// blanks, means bytePos*2
qHexEdit_p->setCursorPos(cursorPos*2);
}
int QHexEdit::cursorPosition()
{
return qHexEdit_p->cursorPos() / 2;
}
void QHexEdit::setData(const QByteArray & data, const QByteArray & mask)
{
qHexEdit_p->setData(data, mask);
}
void QHexEdit::setData(const QByteArray & data)
{
qHexEdit_p->setData(data, QByteArray(data.size(), 0));
}
void QHexEdit::setData(const QString & pattern)
{
QString convert;
for(int i=0; i<pattern.length(); i++)
{
QChar ch = pattern[i].toLower();
if((ch >= '1' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (wildcardEnabled() && ch == '?'))
convert += ch;
}
if(convert.length()%2) //odd length
convert += "0";
QByteArray data(convert.length(), 0);
QByteArray mask(data.length(), 0);
for(int i=0; i<convert.length(); i++)
{
if(convert[i] == '?')
{
data[i]='0';
mask[i]='1';
}
else
{
data[i]=convert[i].toAscii();
mask[i]='0';
}
}
qHexEdit_p->setData(QByteArray().fromHex(data), QByteArray().fromHex(mask));
}
QByteArray QHexEdit::applyMaskedData(const QByteArray & data)
{
QByteArray ret = data.toHex();
QByteArray _data = this->data().toHex();
QByteArray _mask = this->mask().toHex();
if(ret.size() != _data.size())
ret.resize(_data.size());
for(int i=0; i<_data.size(); i++)
{
if(_mask[i]!='1')
ret[i]=_data[i];
}
return QByteArray().fromHex(ret);
}
QByteArray QHexEdit::data()
{
return qHexEdit_p->data();
}
QByteArray QHexEdit::mask()
{
return qHexEdit_p->mask();
}
QString QHexEdit::pattern(bool space)
{
QString result;
for (int i = 0; i < this->data().size(); i++)
{
QString byte = this->data().mid(i, 1).toHex();
QString mask = this->mask().mid(i, 1).toHex();
if(mask[0] == '1')
result += "?";
else
result += byte[0];
if(mask[1] == '1')
result += "?";
else
result += byte[1];
if(space)
result += " ";
}
return result.toUpper();
}
void QHexEdit::setOverwriteMode(bool overwriteMode)
{
qHexEdit_p->setOverwriteMode(overwriteMode);
}
bool QHexEdit::overwriteMode()
{
return qHexEdit_p->overwriteMode();
}
void QHexEdit::setWildcardEnabled(bool enabled)
{
qHexEdit_p->setWildcardEnabled(enabled);
}
bool QHexEdit::wildcardEnabled()
{
return qHexEdit_p->wildcardEnabled();
}
void QHexEdit::setKeepSize(bool enabled)
{
qHexEdit_p->setKeepSize(enabled);
}
bool QHexEdit::keepSize()
{
return qHexEdit_p->keepSize();
}
void QHexEdit::setTextColor(QColor color)
{
qHexEdit_p->setTextColor(color);
}
void QHexEdit::setHorizontalSpacing(int x)
{
qHexEdit_p->setHorizontalSpacing(x);
}
int QHexEdit::horizontalSpacing()
{
return qHexEdit_p->horizontalSpacing();
}
QColor QHexEdit::textColor()
{
return qHexEdit_p->textColor();
}
void QHexEdit::setWildcardColor(QColor color)
{
qHexEdit_p->setWildcardColor(color);
}
QColor QHexEdit::wildcardColor()
{
return qHexEdit_p->wildcardColor();
}
void QHexEdit::setBackgroundColor(QColor color)
{
qHexEdit_p->setBackgroundColor(color);
}
QColor QHexEdit::backgroundColor()
{
return qHexEdit_p->backgroundColor();
}
void QHexEdit::setSelectionColor(QColor color)
{
qHexEdit_p->setSelectionColor(color);
}
QColor QHexEdit::selectionColor()
{
return qHexEdit_p->selectionColor();
}

View File

@ -0,0 +1,63 @@
#ifndef QHEXEDIT_H
#define QHEXEDIT_H
#include <QtGui>
#include "QHexEditPrivate.h"
class QHexEdit : public QScrollArea
{
Q_OBJECT
public:
QHexEdit(QWidget *parent = 0);
//data management
void setData(const QByteArray & data, const QByteArray & mask);
void setData(const QByteArray & data);
void setData(const QString & pattern);
QByteArray applyMaskedData(const QByteArray & data);
QByteArray data();
QByteArray mask();
QString pattern(bool space = false);
void insert(int i, const QByteArray & ba, const QByteArray & mask);
void insert(int i, char ch, char mask);
void remove(int pos, int len=1);
void replace( int pos, int len, const QByteArray & after, const QByteArray & mask);
//properties
void setCursorPosition(int cusorPos);
int cursorPosition();
void setOverwriteMode(bool overwriteMode);
bool overwriteMode();
void setWildcardEnabled(bool enabled);
bool wildcardEnabled();
void setKeepSize(bool enabled);
bool keepSize();
void setHorizontalSpacing(int x);
int horizontalSpacing();
void setTextColor(QColor color);
QColor textColor();
void setWildcardColor(QColor color);
QColor wildcardColor();
void setBackgroundColor(QColor color);
QColor backgroundColor();
void setSelectionColor(QColor color);
QColor selectionColor();
public slots:
void redo();
void undo();
signals:
void currentAddressChanged(int address);
void currentSizeChanged(int size);
void dataChanged();
void overwriteModeChanged(bool state);
private:
QHexEditPrivate *qHexEdit_p;
QHBoxLayout *layout;
QScrollArea *scrollArea;
};
#endif

View File

@ -0,0 +1,873 @@
#include <QtGui>
#include "QHexEditPrivate.h"
#include "ArrayCommand.h"
const int HEXCHARS_IN_LINE = 47;
const int BYTES_PER_LINE = 16;
QHexEditPrivate::QHexEditPrivate(QScrollArea *parent) : QWidget(parent)
{
_undoDataStack = new QUndoStack(this);
_undoMaskStack = new QUndoStack(this);
_scrollArea = parent;
setOverwriteMode(true);
QFont font("Monospace", 8);
font.setFixedPitch(true);
font.setStyleHint(QFont::Monospace);
this->setFont(font);
_size = 0;
_horizonalSpacing = 3;
resetSelection(0);
setCursorPos(0);
setFocusPolicy(Qt::StrongFocus);
connect(&_cursorTimer, SIGNAL(timeout()), this, SLOT(updateCursor()));
_cursorTimer.setInterval(500);
_cursorTimer.start();
_textColor=QColor("#000000");
_wildcardColor=QColor("#FF0000");
_backgroundColor=QColor("#FFF8F0");
_selectionColor=QColor("#C0C0C0");
_overwriteMode=false;
_wildcardEnabled=true;
_keepSize=false;
}
void QHexEditPrivate::setData(const QByteArray & data, const QByteArray & mask)
{
_xData.setData(data);
_xMask.setData(mask);
_undoDataStack->clear();
_undoMaskStack->clear();
_initSize = _xData.size();
adjust();
setCursorPos(0);
emit dataChanged();
}
QByteArray QHexEditPrivate::data()
{
return _xData.data();
}
QByteArray QHexEditPrivate::mask()
{
return _xMask.data();
}
void QHexEditPrivate::insert(int index, const QByteArray & ba, const QByteArray & mask)
{
if (ba.length() > 0)
{
if (_overwriteMode)
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::replace, index, mask, mask.length()));
emit dataChanged();
}
else
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::insert, index, ba, ba.length()));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::insert, index, mask, mask.length()));
emit dataChanged();
}
}
}
void QHexEditPrivate::insert(int index, char ch, char mask)
{
_undoDataStack->push(new CharCommand(&_xData, CharCommand::insert, index, ch));
_undoMaskStack->push(new CharCommand(&_xMask, CharCommand::insert, index, mask));
emit dataChanged();
}
void QHexEditPrivate::remove(int index, int len)
{
if (len > 0)
{
if (len == 1)
{
if (_overwriteMode)
{
_undoDataStack->push(new CharCommand(&_xData, CharCommand::replace, index, char(0)));
_undoMaskStack->push(new CharCommand(&_xMask, CharCommand::replace, index, char(0)));
emit dataChanged();
}
else
{
_undoDataStack->push(new CharCommand(&_xData, CharCommand::remove, index, char(0)));
_undoMaskStack->push(new CharCommand(&_xMask, CharCommand::remove, index, char(0)));
emit dataChanged();
}
}
else
{
QByteArray ba = QByteArray(len, char(0));
if (_overwriteMode)
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::replace, index, ba, ba.length()));
emit dataChanged();
}
else
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::remove, index, ba, len));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::remove, index, ba, len));
emit dataChanged();
}
}
}
}
void QHexEditPrivate::replace(int index, char ch, char mask)
{
_undoDataStack->push(new CharCommand(&_xData, CharCommand::replace, index, ch));
_undoMaskStack->push(new CharCommand(&_xMask, CharCommand::replace, index, mask));
resetSelection();
emit dataChanged();
}
void QHexEditPrivate::replace(int index, const QByteArray & ba, const QByteArray & mask)
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::replace, index, ba, ba.length()));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::replace, index, mask, mask.length()));
resetSelection();
emit dataChanged();
}
void QHexEditPrivate::replace(int pos, int len, const QByteArray &after, const QByteArray & mask)
{
_undoDataStack->push(new ArrayCommand(&_xData, ArrayCommand::replace, pos, after, len));
_undoMaskStack->push(new ArrayCommand(&_xMask, ArrayCommand::replace, pos, mask, len));
resetSelection();
emit dataChanged();
}
void QHexEditPrivate::setOverwriteMode(bool overwriteMode)
{
_overwriteMode = overwriteMode;
}
bool QHexEditPrivate::overwriteMode()
{
return _overwriteMode;
}
void QHexEditPrivate::setWildcardEnabled(bool enabled)
{
_wildcardEnabled = enabled;
}
bool QHexEditPrivate::wildcardEnabled()
{
return _wildcardEnabled;
}
void QHexEditPrivate::setKeepSize(bool enabled)
{
_keepSize = enabled;
}
bool QHexEditPrivate::keepSize()
{
return _keepSize;
}
void QHexEditPrivate::setHorizontalSpacing(int x)
{
_horizonalSpacing = x;
adjust();
this->repaint();
}
int QHexEditPrivate::horizontalSpacing()
{
return _horizonalSpacing;
}
void QHexEditPrivate::setTextColor(QColor color)
{
_textColor = color;
}
QColor QHexEditPrivate::textColor()
{
return _textColor;
}
void QHexEditPrivate::setWildcardColor(QColor color)
{
_wildcardColor = color;
}
QColor QHexEditPrivate::wildcardColor()
{
return _wildcardColor;
}
void QHexEditPrivate::setBackgroundColor(QColor color)
{
_backgroundColor = color;
}
QColor QHexEditPrivate::backgroundColor()
{
return _backgroundColor;
}
void QHexEditPrivate::setSelectionColor(QColor color)
{
_selectionColor = color;
}
QColor QHexEditPrivate::selectionColor()
{
return _selectionColor;
}
void QHexEditPrivate::redo()
{
if(!_undoDataStack->canRedo() || !_undoMaskStack->canRedo())
return;
_undoDataStack->redo();
_undoMaskStack->redo();
emit dataChanged();
setCursorPos(_cursorPosition);
update();
}
void QHexEditPrivate::undo()
{
if(!_undoDataStack->canUndo() || !_undoMaskStack->canUndo())
return;
_undoDataStack->undo();
_undoMaskStack->undo();
emit dataChanged();
setCursorPos(_cursorPosition);
update();
}
void QHexEditPrivate::resizeEvent(QResizeEvent* event)
{
adjust();
QWidget::resizeEvent(event);
}
void QHexEditPrivate::keyPressEvent(QKeyEvent *event)
{
int charX = (_cursorX - _xPosHex) / _charWidth;
int posX = (charX / 3) * 2 + (charX % 3);
int posBa = (_cursorY / _charHeight) * BYTES_PER_LINE + posX / 2;
/*****************************************************************************/
/* Cursor movements */
/*****************************************************************************/
if (event->matches(QKeySequence::MoveToNextChar))
{
setCursorPos(_cursorPosition + 1);
resetSelection(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToPreviousChar))
{
setCursorPos(_cursorPosition - 1);
resetSelection(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToEndOfLine))
{
setCursorPos(_cursorPosition | (2 * BYTES_PER_LINE -1));
resetSelection(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToStartOfLine))
{
setCursorPos(_cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)));
resetSelection(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToPreviousLine))
{
setCursorPos(_cursorPosition - (2 * BYTES_PER_LINE));
resetSelection(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToNextLine))
{
setCursorPos(_cursorPosition + (2 * BYTES_PER_LINE));
resetSelection(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToNextPage))
{
setCursorPos(_cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE));
resetSelection(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToPreviousPage))
{
setCursorPos(_cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE));
resetSelection(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToEndOfDocument))
{
setCursorPos(_xData.size() * 2);
resetSelection(_cursorPosition);
}
if (event->matches(QKeySequence::MoveToStartOfDocument))
{
setCursorPos(0);
resetSelection(_cursorPosition);
}
/*****************************************************************************/
/* Select commands */
/*****************************************************************************/
if (event->matches(QKeySequence::SelectAll))
{
resetSelection(0);
setSelection(2*_xData.size() + 1);
}
if (event->matches(QKeySequence::SelectNextChar))
{
int pos = _cursorPosition + 1;
setCursorPos(pos);
setSelection(pos);
}
if (event->matches(QKeySequence::SelectPreviousChar))
{
int pos = _cursorPosition - 1;
setSelection(pos);
setCursorPos(pos);
}
if (event->matches(QKeySequence::SelectEndOfLine))
{
int pos = _cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE)) + (2 * BYTES_PER_LINE);
setCursorPos(pos);
setSelection(pos);
}
if (event->matches(QKeySequence::SelectStartOfLine))
{
int pos = _cursorPosition - (_cursorPosition % (2 * BYTES_PER_LINE));
setCursorPos(pos);
setSelection(pos);
}
if (event->matches(QKeySequence::SelectPreviousLine))
{
int pos = _cursorPosition - (2 * BYTES_PER_LINE);
setCursorPos(pos);
setSelection(pos);
}
if (event->matches(QKeySequence::SelectNextLine))
{
int pos = _cursorPosition + (2 * BYTES_PER_LINE);
setCursorPos(pos);
setSelection(pos);
}
if (event->matches(QKeySequence::SelectNextPage))
{
int pos = _cursorPosition + (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE);
setCursorPos(pos);
setSelection(pos);
}
if (event->matches(QKeySequence::SelectPreviousPage))
{
int pos = _cursorPosition - (((_scrollArea->viewport()->height() / _charHeight) - 1) * 2 * BYTES_PER_LINE);
setCursorPos(pos);
setSelection(pos);
}
if (event->matches(QKeySequence::SelectEndOfDocument))
{
int pos = _xData.size() * 2;
setCursorPos(pos);
setSelection(pos);
}
if (event->matches(QKeySequence::SelectStartOfDocument))
{
int pos = 0;
setCursorPos(pos);
setSelection(pos);
}
/*****************************************************************************/
/* Edit Commands */
/*****************************************************************************/
/* Hex input */
int key = int(event->text().toLower()[0].toAscii());
if ((key >= '0' && key <= '9') || (key>= 'a' && key <= 'f') || (_wildcardEnabled && key == '?'))
{
if (getSelectionBegin() != getSelectionEnd())
{
posBa = getSelectionBegin();
remove(posBa, getSelectionEnd() - posBa);
setCursorPos(2*posBa);
resetSelection(2*posBa);
}
// If insert mode, then insert a byte
if (_overwriteMode == false)
{
if(_keepSize && _xData.size() >= _initSize)
return;
if ((charX % 3) == 0)
insert(posBa, char(0), char(0));
}
// Change content
if (_xData.size() > 0)
{
QByteArray hexMask = _xMask.data().mid(posBa, 1).toHex();
QByteArray hexValue = _xData.data().mid(posBa, 1).toHex();
if(key == '?') //wildcard
{
if ((charX % 3) == 0)
hexMask[0] = '1';
else
hexMask[1] = '1';
}
else
{
if ((charX % 3) == 0)
{
hexValue[0] = key;
hexMask[0] = '0';
}
else
{
hexValue[1] = key;
hexMask[1] = '0';
}
}
replace(posBa, QByteArray().fromHex(hexValue)[0], QByteArray().fromHex(hexMask)[0]);
setCursorPos(_cursorPosition + 1);
resetSelection(_cursorPosition);
}
}
/* Cut & Paste */
if (event->matches(QKeySequence::Cut))
{
QString result;
for (int idx = getSelectionBegin(); idx < getSelectionEnd(); idx++)
{
QString byte = _xData.data().mid(idx, 1).toHex();
QString mask = _xMask.data().mid(idx, 1).toHex();
if(mask[0] == '1')
result += "?";
else
result += byte[0];
if(mask[1] == '1')
result += "?";
else
result += byte[1];
result += " ";
}
remove(getSelectionBegin(), getSelectionEnd() - getSelectionBegin());
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(result.toUpper());
setCursorPos(getSelectionBegin()+2);
resetSelection(getSelectionBegin()+2);
}
if (event->matches(QKeySequence::Paste))
{
QClipboard *clipboard = QApplication::clipboard();
QString convert;
QString pattern = clipboard->text();
for(int i=0; i<pattern.length(); i++)
{
QChar ch = pattern[i].toLower();
if((ch >= '1' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (_wildcardEnabled && ch == '?'))
convert += ch;
}
if(convert.length()%2) //odd length
convert += "0";
if(_keepSize && convert.length()/2 >= _initSize)
convert.truncate((_initSize-_xData.size())*2-1);
QByteArray data(convert.length(), 0);
QByteArray mask(data.length(), 0);
for(int i=0; i<convert.length(); i++)
{
if(convert[i] == '?')
{
data[i]='0';
mask[i]='1';
}
else
{
data[i]=convert[i].toAscii();
mask[i]='0';
}
}
data = QByteArray().fromHex(data);
mask = QByteArray().fromHex(mask);
insert(_cursorPosition / 2, data, mask);
setCursorPos(_cursorPosition + 2 * data.length());
resetSelection(getSelectionBegin());
}
/* Delete char */
if (event->matches(QKeySequence::Delete))
{
if (getSelectionBegin() != getSelectionEnd())
{
posBa = getSelectionBegin();
remove(posBa, getSelectionEnd() - posBa);
setCursorPos(2*posBa);
resetSelection(2*posBa);
}
else
{
if (_overwriteMode)
replace(posBa, char(0), char(0));
else
remove(posBa, 1);
}
}
/* Backspace */
if ((event->key() == Qt::Key_Backspace) && (event->modifiers() == Qt::NoModifier))
{
if (getSelectionBegin() != getSelectionEnd())
{
posBa = getSelectionBegin();
remove(posBa, getSelectionEnd() - posBa);
setCursorPos(2*posBa);
resetSelection(2*posBa);
}
else if(_cursorPosition == 1)
{
if (getSelectionBegin() != getSelectionEnd())
{
posBa = getSelectionBegin();
remove(posBa, getSelectionEnd() - posBa);
setCursorPos(2*posBa);
resetSelection(2*posBa);
}
else
{
if (_overwriteMode)
replace(posBa, char(0), char(0));
else
remove(posBa, 1);
}
setCursorPos(0);
}
else if (posBa > 0)
{
int delta = 1;
if(_cursorPosition % 2) //odd cursor position
delta = 0;
if (_overwriteMode)
replace(posBa - delta, char(0), char(0));
else
remove(posBa - delta, 1);
setCursorPos(_cursorPosition - 1 - delta);
}
}
/* undo */
if (event->matches(QKeySequence::Undo))
{
undo();
}
/* redo */
if (event->matches(QKeySequence::Redo))
{
redo();
}
if (event->matches(QKeySequence::Copy))
{
QString result;
for (int idx = getSelectionBegin(); idx < getSelectionEnd(); idx++)
{
QString byte = _xData.data().mid(idx, 1).toHex();
QString mask = _xMask.data().mid(idx, 1).toHex();
if(mask[0] == '1')
result += "?";
else
result += byte[0];
if(mask[1] == '1')
result += "?";
else
result += byte[1];
result += " ";
}
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(result.toUpper());
}
// Switch between insert/overwrite mode
if ((event->key() == Qt::Key_Insert) && (event->modifiers() == Qt::NoModifier))
{
_overwriteMode = !_overwriteMode;
setCursorPos(_cursorPosition);
overwriteModeChanged(_overwriteMode);
}
ensureVisible();
update();
}
void QHexEditPrivate::mouseMoveEvent(QMouseEvent * event)
{
_blink = false;
update();
int actPos = cursorPos(event->pos());
setCursorPos(actPos);
setSelection(actPos);
}
void QHexEditPrivate::mousePressEvent(QMouseEvent * event)
{
_blink = false;
update();
int cPos = cursorPos(event->pos());
if((event->modifiers()&Qt::ShiftModifier)==Qt::ShiftModifier)
{
setCursorPos(cPos);
setSelection(cPos);
}
else
{
resetSelection(cPos);
setCursorPos(cPos);
}
}
void QHexEditPrivate::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.fillRect(event->rect(), _backgroundColor);
// calc position
int firstLineIdx = ((event->rect().top()/ _charHeight) - _charHeight) * BYTES_PER_LINE;
if (firstLineIdx < 0)
firstLineIdx = 0;
int lastLineIdx = ((event->rect().bottom() / _charHeight) + _charHeight) * BYTES_PER_LINE;
if (lastLineIdx > _xData.size())
lastLineIdx = _xData.size();
int yPosStart = ((firstLineIdx) / BYTES_PER_LINE) * _charHeight + _charHeight;
// paint hex area
QByteArray hexBa(_xData.data().mid(firstLineIdx, lastLineIdx - firstLineIdx + 1).toHex());
if(_wildcardEnabled)
{
QByteArray hexMask(_xMask.data().mid(firstLineIdx, lastLineIdx - firstLineIdx + 1).toHex());
for(int i=0; i<hexBa.size(); i++)
if(hexMask[i]=='1')
hexBa[i]='?';
}
for (int lineIdx = firstLineIdx, yPos = yPosStart; lineIdx < lastLineIdx; lineIdx += BYTES_PER_LINE, yPos +=_charHeight)
{
QString hex;
int xPos = _xPosHex;
for (int colIdx = 0; ((lineIdx + colIdx) < _xData.size() && (colIdx < BYTES_PER_LINE)); colIdx++)
{
int posBa = lineIdx + colIdx;
if ((getSelectionBegin() <= posBa) && (getSelectionEnd() > posBa))
{
painter.setBackground(_selectionColor);
painter.setBackgroundMode(Qt::OpaqueMode);
}
else
{
painter.setBackground(_backgroundColor);
painter.setBackgroundMode(Qt::TransparentMode);
}
// render hex value
painter.setPen(_textColor);
if (colIdx == 0)
{
hex = hexBa.mid((lineIdx - firstLineIdx) * 2, 2).toUpper();
for(int i=0; i<hex.length(); i++)
{
if(hex[i]=='?') //wildcard
painter.setPen(_wildcardColor);
else
painter.setPen(_textColor);
painter.drawText(xPos + _charWidth * i, yPos, QString(hex[i]));
}
xPos += 2 * _charWidth;
}
else
{
if(getSelectionBegin() == posBa)
{
hex = hexBa.mid((lineIdx + colIdx - firstLineIdx) * 2, 2).toUpper();
xPos += _charWidth;
}
else
hex = hexBa.mid((lineIdx + colIdx - firstLineIdx) * 2, 2).prepend(" ").toUpper();
for(int i=0; i<hex.length(); i++)
{
if(hex[i]=='?') //wildcard
painter.setPen(_wildcardColor);
else
painter.setPen(_textColor);
painter.drawText(xPos + _charWidth * i, yPos, QString(hex[i]));
}
xPos += hex.length() * _charWidth;
}
}
}
painter.setBackgroundMode(Qt::TransparentMode);
painter.setPen(this->palette().color(QPalette::WindowText));
// paint cursor
if (_blink && hasFocus())
{
if (_overwriteMode)
painter.fillRect(_cursorX, _cursorY + _charHeight - 2, _charWidth, 2, this->palette().color(QPalette::WindowText));
else
painter.fillRect(_cursorX, _cursorY, 2, _charHeight, this->palette().color(QPalette::WindowText));
}
if (_size != _xData.size())
{
_size = _xData.size();
emit currentSizeChanged(_size);
}
}
void QHexEditPrivate::setCursorPos(int position)
{
// delete cursor
_blink = false;
update();
// cursor in range?
if (_overwriteMode)
{
if (position > (_xData.size() * 2 - 1))
position = _xData.size() * 2 - 1;
}
else
{
if (position > (_xData.size() * 2))
position = _xData.size() * 2;
}
if (position < 0)
position = 0;
// calc position
_cursorPosition = position;
_cursorY = (position / (2 * BYTES_PER_LINE)) * _charHeight + 4;
int x = (position % (2 * BYTES_PER_LINE));
_cursorX = (((x / 2) * 3) + (x % 2)) * _charWidth + _xPosHex;
// immiadately draw cursor
_blink = true;
update();
emit currentAddressChanged(_cursorPosition/2);
}
int QHexEditPrivate::cursorPos(QPoint pos)
{
int result = -1;
// find char under cursor
if ((pos.x() >= _xPosHex) && (pos.x() < (_xPosHex + HEXCHARS_IN_LINE * _charWidth)))
{
int x = (pos.x() - _xPosHex) / _charWidth;
if ((x % 3) == 0)
x = (x / 3) * 2;
else
x = ((x / 3) * 2) + 1;
int y = ((pos.y() - 3) / _charHeight) * 2 * BYTES_PER_LINE;
result = x + y;
}
return result;
}
int QHexEditPrivate::cursorPos()
{
return _cursorPosition;
}
void QHexEditPrivate::resetSelection()
{
_selectionBegin = _selectionInit;
_selectionEnd = _selectionInit;
}
void QHexEditPrivate::resetSelection(int pos)
{
if (pos < 0)
pos = 0;
pos++;
pos = pos / 2;
_selectionInit = pos;
_selectionBegin = pos;
_selectionEnd = pos;
}
void QHexEditPrivate::setSelection(int pos)
{
if (pos < 0)
pos = 0;
pos++;
pos = pos / 2;
if (pos >= _selectionInit)
{
_selectionEnd = pos;
_selectionBegin = _selectionInit;
}
else
{
_selectionBegin = pos;
_selectionEnd = _selectionInit;
}
}
int QHexEditPrivate::getSelectionBegin()
{
return _selectionBegin;
}
int QHexEditPrivate::getSelectionEnd()
{
return _selectionEnd;
}
void QHexEditPrivate::updateCursor()
{
if (_blink)
_blink = false;
else
_blink = true;
update(_cursorX, _cursorY, _charWidth, _charHeight);
}
void QHexEditPrivate::adjust()
{
_charWidth = fontMetrics().width(QLatin1Char('9'));
_charHeight = fontMetrics().height();
_xPosHex = _horizonalSpacing;
// tell QAbstractScollbar, how big we are
setMinimumHeight(((_xData.size()/16 + 1) * _charHeight) + 5);
setMinimumWidth(_xPosHex + HEXCHARS_IN_LINE * _charWidth);
update();
}
void QHexEditPrivate::ensureVisible()
{
// scrolls to cursorx, cusory (which are set by setCursorPos)
// x-margin is 3 pixels, y-margin is half of charHeight
_scrollArea->ensureVisible(_cursorX, _cursorY + _charHeight/2, 3, _charHeight/2 + 2);
}

View File

@ -0,0 +1,108 @@
#ifndef QHEXEDITPRIVATE_H
#define QHEXEDITPRIVATE_H
#include <QtGui>
#include "XByteArray.h"
class QHexEditPrivate : public QWidget
{
Q_OBJECT
public:
QHexEditPrivate(QScrollArea *parent);
//properties
void setCursorPos(int position);
int cursorPos();
void setOverwriteMode(bool overwriteMode);
bool overwriteMode();
void setWildcardEnabled(bool enabled);
bool wildcardEnabled();
void setKeepSize(bool enabled);
bool keepSize();
void setHorizontalSpacing(int x);
int horizontalSpacing();
void setTextColor(QColor color);
QColor textColor();
void setWildcardColor(QColor color);
QColor wildcardColor();
void setBackgroundColor(QColor color);
QColor backgroundColor();
void setSelectionColor(QColor color);
QColor selectionColor();
//data management
void setData(const QByteArray & data, const QByteArray & mask);
QByteArray data();
QByteArray mask();
void insert(int index, const QByteArray & ba, const QByteArray & mask);
void insert(int index, char ch, char mask);
void remove(int index, int len=1);
void replace(int index, char ch, char mask);
void replace(int index, const QByteArray & ba, const QByteArray & mask);
void replace(int pos, int len, const QByteArray & after, const QByteArray & mask);
void undo();
void redo();
signals:
void currentAddressChanged(int address);
void currentSizeChanged(int size);
void dataChanged();
void overwriteModeChanged(bool state);
protected:
void resizeEvent(QResizeEvent* event);
void keyPressEvent(QKeyEvent * event);
void mouseMoveEvent(QMouseEvent * event);
void mousePressEvent(QMouseEvent * event);
void paintEvent(QPaintEvent *event);
int cursorPos(QPoint pos); // calc cursorpos from graphics position. DOES NOT STORE POSITION
void resetSelection(int pos); // set selectionStart && selectionEnd to pos
void resetSelection(); // set selectionEnd to selectionStart
void setSelection(int pos); // set min (if below init) || max (if greater init)
int getSelectionBegin();
int getSelectionEnd();
private slots:
void updateCursor();
private:
void adjust();
void ensureVisible();
QScrollArea *_scrollArea;
QTimer _cursorTimer;
QUndoStack *_undoDataStack;
QUndoStack *_undoMaskStack;
XByteArray _xData;
XByteArray _xMask;
QColor _textColor;
QColor _wildcardColor;
QColor _backgroundColor;
QColor _selectionColor;
bool _blink; // true: then cursor blinks
bool _overwriteMode;
bool _wildcardEnabled;
bool _keepSize;
int _charWidth, _charHeight; // char dimensions (dpendend on font)
int _cursorX, _cursorY; // graphics position of the cursor
int _cursorPosition; // character positioin in stream (on byte ends in to steps)
int _xPosHex; // graphics x-position of the areas
int _selectionBegin; // First selected char
int _selectionEnd; // Last selected char
int _selectionInit; // That's, where we pressed the mouse button
int _size;
int _initSize;
int _horizonalSpacing;
};
#endif //QHEXEDITPRIVATE_H

View File

@ -0,0 +1,62 @@
#include "XByteArray.h"
XByteArray::XByteArray()
{
_oldSize = -99;
}
QByteArray & XByteArray::data()
{
return _data;
}
void XByteArray::setData(QByteArray data)
{
_data = data;
}
int XByteArray::size()
{
return _data.size();
}
QByteArray & XByteArray::insert(int i, char ch)
{
_data.insert(i, ch);
return _data;
}
QByteArray & XByteArray::insert(int i, const QByteArray & ba)
{
_data.insert(i, ba);
return _data;
}
QByteArray & XByteArray::remove(int i, int len)
{
_data.remove(i, len);
return _data;
}
QByteArray & XByteArray::replace(int index, char ch)
{
_data[index] = ch;
return _data;
}
QByteArray & XByteArray::replace(int index, const QByteArray & ba)
{
int len = ba.length();
return replace(index, len, ba);
}
QByteArray & XByteArray::replace(int index, int length, const QByteArray & ba)
{
int len;
if ((index + length) > _data.length())
len = _data.length() - index;
else
len = length;
_data.replace(index, len, ba.mid(0, len));
return _data;
}

View File

@ -0,0 +1,35 @@
#ifndef XBYTEARRAY_H
#define XBYTEARRAY_H
#include <QtCore>
class XByteArray
{
public:
explicit XByteArray();
QByteArray & data();
void setData(QByteArray data);
int size();
QByteArray & insert(int i, char ch);
QByteArray & insert(int i, const QByteArray & ba);
QByteArray & remove(int pos, int len);
QByteArray & replace(int index, char ch);
QByteArray & replace(int index, const QByteArray & ba);
QByteArray & replace(int index, int length, const QByteArray & ba);
signals:
public slots:
private:
QByteArray _data; //raw byte array
QByteArray _mask; //masked byte array
int _oldSize; // size of data
};
#endif // XBYTEARRAY_H