XPlor/app/fieldeditcommand.cpp
njohnson 05c70c1108 Add field editing UI with undo support and dirty state tracking
Implement infrastructure for editing parsed binary fields:

FieldEditCommand (QUndoCommand):
- Undo/redo support for field value changes
- Stores old and new values with field metadata
- Integrates with Qt's undo stack

DirtyStateManager:
- Tracks modified state per-tab
- Emits signals when dirty state changes
- Enables save prompts and tab indicators

ScriptTypeEditorWidget enhancements:
- Add recompilation debouncing (300ms) for responsive editing
- Build form layout only for fields with values (skip unexecuted branches)
- Support edit signals for modified fields
- Improved table and form layout building

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 20:54:23 -05:00

68 lines
1.8 KiB
C++

#include "fieldeditcommand.h"
// Command ID for merging consecutive edits to the same field
static const int FIELD_EDIT_COMMAND_ID = 1001;
FieldEditCommand::FieldEditCommand(int journalId,
const QString& fieldName,
const QVariant& oldValue,
const QVariant& newValue,
ApplyCallback applyCallback,
QUndoCommand* parent)
: QUndoCommand(parent)
, m_journalId(journalId)
, m_fieldName(fieldName)
, m_oldValue(oldValue)
, m_newValue(newValue)
, m_applyCallback(applyCallback)
{
setText(QString("Edit %1").arg(fieldName));
}
void FieldEditCommand::undo()
{
if (m_applyCallback) {
m_applyCallback(m_fieldName, m_oldValue);
}
}
void FieldEditCommand::redo()
{
// Skip the first redo because the value was already applied
// when the user made the edit (before command was pushed)
if (m_firstRedo) {
m_firstRedo = false;
return;
}
if (m_applyCallback) {
m_applyCallback(m_fieldName, m_newValue);
}
}
int FieldEditCommand::id() const
{
return FIELD_EDIT_COMMAND_ID;
}
bool FieldEditCommand::mergeWith(const QUndoCommand* other)
{
// Merge consecutive edits to the same field in the same journal
// This prevents creating a new undo entry for every keystroke
if (other->id() != id()) {
return false;
}
const FieldEditCommand* otherEdit = static_cast<const FieldEditCommand*>(other);
// Only merge if same journal and field
if (otherEdit->m_journalId != m_journalId ||
otherEdit->m_fieldName != m_fieldName) {
return false;
}
// Keep original old value, take new value from other command
m_newValue = otherEdit->m_newValue;
return true;
}