Support for adding/removing strings

This commit is contained in:
Aruki 2019-01-02 12:26:06 -07:00
parent eb9236bbea
commit cb262504af
8 changed files with 549 additions and 40 deletions

View File

@ -90,6 +90,86 @@ void CStringTable::SetStringName(uint StringIndex, const TString& kNewName)
mStringNames[StringIndex] = kNewName;
}
/** Move string to another position in the table */
void CStringTable::MoveString(uint StringIndex, uint NewIndex)
{
ASSERT( NumStrings() > StringIndex );
ASSERT( NumStrings() > NewIndex );
if (NewIndex == StringIndex)
return;
// Update string data
for (uint LanguageIdx = 0; LanguageIdx < StringIndex; LanguageIdx++)
{
SLanguageData& Language = mLanguages[LanguageIdx];
TString String = Language.Strings[StringIndex];
if (NewIndex > StringIndex)
{
for (uint i=StringIndex; i<NewIndex; i++)
Language.Strings[i] = Language.Strings[i+1];
}
else
{
for (uint i=StringIndex; i>NewIndex; i--)
Language.Strings[i] = Language.Strings[i-1];
}
Language.Strings[NewIndex] = String;
}
// Update string name
TString Name = mStringNames[StringIndex];
if (NewIndex > StringIndex)
{
for (uint i=StringIndex; i<NewIndex; i++)
mStringNames[i] = mStringNames[i+1];
}
else
{
for (uint i=StringIndex; i>NewIndex; i--)
mStringNames[i] = mStringNames[i-1];
}
mStringNames[NewIndex] = Name;
}
/** Add a new string to the table */
void CStringTable::AddString(uint AtIndex)
{
if (AtIndex < NumStrings())
{
if (mStringNames.size() > AtIndex)
{
mStringNames.insert( mStringNames.begin() + AtIndex, 1, "" );
}
}
else
AtIndex = NumStrings();
for (uint LanguageIdx = 0; LanguageIdx < mLanguages.size(); LanguageIdx++)
{
SLanguageData& Language = mLanguages[LanguageIdx];
Language.Strings.insert( Language.Strings.begin() + AtIndex, 1, "" );
}
}
/** Remove a string from the table */
void CStringTable::RemoveString(uint StringIndex)
{
ASSERT( StringIndex < NumStrings() );
if (mStringNames.size() > StringIndex)
mStringNames.erase( mStringNames.begin() + StringIndex );
for (uint LanguageIdx = 0; LanguageIdx < mLanguages.size(); LanguageIdx++)
{
SLanguageData& Language = mLanguages[LanguageIdx];
Language.Strings.erase( Language.Strings.begin() + StringIndex );
}
}
/** Configures the string table with default languages for the game/region pairing of the resource */
void CStringTable::ConfigureDefaultLanguages()
{

View File

@ -58,6 +58,15 @@ public:
/** Updates a string name */
void SetStringName(uint StringIndex, const TString& kNewName);
/** Move string to another position in the table */
void MoveString(uint StringIndex, uint NewIndex);
/** Add a new string to the table */
void AddString(uint AtIndex);
/** Remove a string from the table */
void RemoveString(uint StringIndex);
/** Configures the string table with default languages for the game/region pairing of the resource */
void ConfigureDefaultLanguages();

View File

@ -2,6 +2,26 @@
#include "ui_CTweakEditor.h"
#include "Editor/Undo/IUndoCommand.h"
/** Internal undo command for changing tabs */
class CSetTweakIndexCommand : public IUndoCommand
{
CTweakEditor* mpEditor;
int mOldIndex, mNewIndex;
public:
CSetTweakIndexCommand(CTweakEditor* pEditor, int OldIndex, int NewIndex)
: IUndoCommand("Change Tab")
, mpEditor(pEditor)
, mOldIndex(OldIndex)
, mNewIndex(NewIndex)
{}
virtual void undo() override { mpEditor->SetActiveTweakIndex(mOldIndex); }
virtual void redo() override { mpEditor->SetActiveTweakIndex(mNewIndex); }
virtual bool AffectsCleanState() const { return false; }
};
/** CTweakEditor functions */
CTweakEditor::CTweakEditor(QWidget* pParent)
: IEditor(pParent)
, mpUI(new Ui::CTweakEditor)
@ -73,7 +93,8 @@ void CTweakEditor::SetActiveTweakData(CTweakData* pTweakData)
{
if (mTweakAssets[TweakIdx] == pTweakData)
{
SetActiveTweakIndex(TweakIdx);
CSetTweakIndexCommand* pCommand = new CSetTweakIndexCommand(this, mCurrentTweakIndex, TweakIdx);
UndoStack().push(pCommand);
break;
}
}
@ -96,25 +117,6 @@ void CTweakEditor::SetActiveTweakIndex(int Index)
void CTweakEditor::OnTweakTabClicked(int Index)
{
/** Internal undo command for changing tabs */
class CSetTweakIndexCommand : public IUndoCommand
{
CTweakEditor* mpEditor;
int mOldIndex, mNewIndex;
public:
CSetTweakIndexCommand(CTweakEditor* pEditor, int OldIndex, int NewIndex)
: IUndoCommand("Change Tab")
, mpEditor(pEditor)
, mOldIndex(OldIndex)
, mNewIndex(NewIndex)
{}
virtual void undo() override { mpEditor->SetActiveTweakIndex(mOldIndex); }
virtual void redo() override { mpEditor->SetActiveTweakIndex(mNewIndex); }
virtual bool AffectsCleanState() const { return false; }
};
if (Index != mCurrentTweakIndex)
{
CSetTweakIndexCommand* pCommand = new CSetTweakIndexCommand(this, mCurrentTweakIndex, Index);

View File

@ -205,7 +205,8 @@ HEADERS += \
StringEditor/CStringDelegate.h \
CCustomDelegate.h \
CTweakEditor.h \
Undo/CEditIntrinsicPropertyCommand.h
Undo/CEditIntrinsicPropertyCommand.h \
Undo/TSerializeUndoCommand.h
# Source Files
SOURCES += \

View File

@ -3,12 +3,43 @@
#include "CStringDelegate.h"
#include "Editor/UICommon.h"
#include "Editor/Undo/TSerializeUndoCommand.h"
#include <QSettings>
#include <QShortcut>
/** Settings strings */
const char* gkpLanguageSetting = "StringEditor/EditLanguage";
/** Command classes */
class CSetStringIndexCommand : public IUndoCommand
{
CStringEditor* mpEditor;
int mOldIndex, mNewIndex;
public:
CSetStringIndexCommand(CStringEditor* pEditor, int OldIndex, int NewIndex)
: mpEditor(pEditor), mOldIndex(OldIndex), mNewIndex(NewIndex)
{}
virtual void undo() override { mpEditor->SetActiveString(mOldIndex); }
virtual void redo() override { mpEditor->SetActiveString(mNewIndex); }
virtual bool AffectsCleanState() const override { return false; }
};
class CSetLanguageCommand : public IUndoCommand
{
CStringEditor* mpEditor;
ELanguage mOldLanguage, mNewLanguage;
public:
CSetLanguageCommand(CStringEditor* pEditor, ELanguage OldLanguage, ELanguage NewLanguage)
: mpEditor(pEditor), mOldLanguage(OldLanguage), mNewLanguage(NewLanguage)
{}
virtual void undo() override { mpEditor->SetActiveLanguage(mOldLanguage); }
virtual void redo() override { mpEditor->SetActiveLanguage(mNewLanguage); }
virtual bool AffectsCleanState() const override { return false; }
};
/** Constructor */
CStringEditor::CStringEditor(CStringTable* pStringTable, QWidget* pParent)
: IEditor(pParent)
@ -16,12 +47,12 @@ CStringEditor::CStringEditor(CStringTable* pStringTable, QWidget* pParent)
, mpStringTable(pStringTable)
, mCurrentLanguage(ELanguage::English)
, mCurrentStringIndex(0)
, mCurrentStringCount(0)
, mIsEditingStringName(false)
, mIsEditingStringData(false)
{
mpListModel = new CStringListModel(pStringTable, this);
mpUI->setupUi(this);
InitUI();
LoadSettings();
// LoadSettings(); // Disabled for now
}
CStringEditor::~CStringEditor()
@ -29,10 +60,42 @@ CStringEditor::~CStringEditor()
delete mpUI;
}
bool CStringEditor::eventFilter(QObject* pWatched, QEvent* pEvent)
{
if (pEvent->type() == QEvent::FocusOut)
{
if (pWatched == mpUI->StringNameLineEdit && mIsEditingStringName)
{
IUndoCommand* pCommand = new TSerializeUndoCommand<CStringTable>("Edit String Name", mpStringTable, true);
UndoStack().push(pCommand);
mIsEditingStringName = false;
return true;
}
else if (pWatched == mpUI->StringTextEdit && mIsEditingStringData)
{
IUndoCommand* pCommand = new TSerializeUndoCommand<CStringTable>("Edit String", mpStringTable, true);
UndoStack().push(pCommand);
mIsEditingStringData = false;
return true;
}
}
return false;
}
void CStringEditor::InitUI()
{
mpUI->setupUi(this);
mpListModel = new CStringListModel(mpStringTable, this);
mpUI->StringNameListView->setModel(mpListModel);
mpUI->StringNameListView->setItemDelegate( new CStringDelegate(this) );
mpUI->AddStringButton->setShortcut( QKeySequence("Alt+=") );
mpUI->RemoveStringButton->setShortcut( QKeySequence("Alt+-") );
// Register shortcuts
new QShortcut( QKeySequence("Alt+Down"), this, SLOT(IncrementStringIndex()) );
new QShortcut( QKeySequence("Alt+Up"), this, SLOT(DecrementStringIndex()) );
new QShortcut( QKeySequence("Alt+Right"), this, SLOT(IncrementLanguageIndex()) );
new QShortcut( QKeySequence("Alt+Left"), this, SLOT(DecrementLanguageIndex()) );
// Set up language tabs
mpUI->EditLanguageTabBar->setExpanding(false);
@ -48,7 +111,20 @@ void CStringEditor::InitUI()
connect( mpUI->StringNameListView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this, SLOT(OnStringSelected(QModelIndex)) );
connect( mpUI->StringNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(OnStringNameEdited()) );
connect( mpUI->StringTextEdit, SIGNAL(textChanged()), this, SLOT(OnStringTextEdited()) );
connect( mpUI->EditLanguageTabBar, SIGNAL(currentChanged(int)), this, SLOT(OnLanguageChanged(int)) );
connect( mpUI->AddStringButton, SIGNAL(pressed()), this, SLOT(OnAddString()) );
connect( mpUI->RemoveStringButton, SIGNAL(pressed()), this, SLOT(OnRemoveString()) );
connect( &UndoStack(), SIGNAL(indexChanged(int)), this, SLOT(UpdateUI()) );
mpUI->ToolBar->addSeparator();
AddUndoActions(mpUI->ToolBar);
// Install event filters
mpUI->StringNameLineEdit->installEventFilter(this);
mpUI->StringTextEdit->installEventFilter(this);
// Update window title
QString WindowTitle = "%APP_FULL_NAME% - String Editor - %1[*]";
@ -60,8 +136,8 @@ void CStringEditor::InitUI()
SplitterSizes << (height() * 0.95) << (height() * 0.05);
mpUI->splitter->setSizes(SplitterSizes);
// Initialize status bar
UpdateStatusBar();
// Initialize UI
UpdateUI();
}
void CStringEditor::UpdateStatusBar()
@ -86,9 +162,8 @@ void CStringEditor::SetActiveLanguage(ELanguage Language)
if (mCurrentLanguage != Language)
{
mCurrentLanguage = Language;
// Force UI to update with the correct string for the new language
SetActiveString( mCurrentStringIndex );
mpListModel->SetPreviewLanguage(Language);
UpdateUI();
SaveSettings();
}
}
@ -96,11 +171,7 @@ void CStringEditor::SetActiveLanguage(ELanguage Language)
void CStringEditor::SetActiveString(int StringIndex)
{
mCurrentStringIndex = StringIndex;
TString StringName = mpStringTable->StringNameByIndex(mCurrentStringIndex);
TString StringData = mpStringTable->GetString(mCurrentLanguage, mCurrentStringIndex);
mpUI->StringNameLineEdit->setText( TO_QSTRING(StringName) );
mpUI->StringTextEdit->setPlainText( TO_QSTRING(StringData) );
UpdateStatusBar();
UpdateUI();
}
void CStringEditor::LoadSettings()
@ -108,12 +179,13 @@ void CStringEditor::LoadSettings()
QSettings Settings;
// Set language
mCurrentLanguage = (ELanguage) Settings.value(gkpLanguageSetting, (int) ELanguage::English).toInt();
ELanguage Language = (ELanguage) Settings.value(gkpLanguageSetting, (int) ELanguage::English).toInt();
for (uint LanguageIdx = 0; LanguageIdx < mpStringTable->NumLanguages(); LanguageIdx++)
{
if (mpStringTable->LanguageByIndex(LanguageIdx) == mCurrentLanguage)
if (mpStringTable->LanguageByIndex(LanguageIdx) == Language)
{
SetActiveLanguage(Language);
mpUI->EditLanguageTabBar->setCurrentIndex(LanguageIdx);
break;
}
@ -127,14 +199,205 @@ void CStringEditor::SaveSettings()
}
/** Slots */
void CStringEditor::UpdateUI()
{
// Update string list
if (mCurrentStringCount != mpStringTable->NumStrings())
{
mpUI->StringNameListView->model()->layoutChanged();
mCurrentStringCount = mpStringTable->NumStrings();
}
// Update selection in string list
QModelIndex OldStringIndex = mpUI->StringNameListView->selectionModel()->hasSelection() ?
mpUI->StringNameListView->currentIndex() : QModelIndex();
QModelIndex NewStringIndex = mpUI->StringNameListView->model()->index(mCurrentStringIndex,0);
if (OldStringIndex != NewStringIndex)
{
QItemSelectionModel* pSelectionModel = mpUI->StringNameListView->selectionModel();
pSelectionModel->blockSignals(true);
pSelectionModel->setCurrentIndex(NewStringIndex, QItemSelectionModel::ClearAndSelect);
pSelectionModel->blockSignals(false);
mpUI->StringNameListView->update(OldStringIndex);
}
mpUI->StringNameListView->update(NewStringIndex);
// Update language tabs
uint LanguageIndex = mpUI->EditLanguageTabBar->currentIndex();
ELanguage TabLanguage = mpStringTable->LanguageByIndex(LanguageIndex);
if (TabLanguage != mCurrentLanguage)
{
for (uint LangIdx = 0; LangIdx < mpStringTable->NumLanguages(); LangIdx++)
{
if (mpStringTable->LanguageByIndex(LangIdx) == mCurrentLanguage)
{
mpUI->EditLanguageTabBar->blockSignals(true);
mpUI->EditLanguageTabBar->setCurrentIndex(LangIdx);
mpUI->EditLanguageTabBar->blockSignals(false);
break;
}
}
}
// Update string name/data fields
QString StringName = TO_QSTRING( mpStringTable->StringNameByIndex(mCurrentStringIndex) );
QString StringData = TO_QSTRING( mpStringTable->GetString(mCurrentLanguage, mCurrentStringIndex) );
if (StringName != mpUI->StringNameLineEdit->text())
{
mpUI->StringNameLineEdit->blockSignals(true);
mpUI->StringNameLineEdit->setText( StringName );
mpUI->StringNameLineEdit->blockSignals(false);
}
if (StringData != mpUI->StringTextEdit->toPlainText())
{
mpUI->StringTextEdit->blockSignals(true);
mpUI->StringTextEdit->setPlainText( StringData );
mpUI->StringTextEdit->blockSignals(false);
}
UpdateStatusBar();
}
void CStringEditor::OnStringSelected(const QModelIndex& kIndex)
{
SetActiveString( kIndex.row() );
if (mCurrentStringIndex != kIndex.row())
{
IUndoCommand* pCommand = new CSetStringIndexCommand(this, mCurrentStringIndex, kIndex.row());
UndoStack().push(pCommand);
}
}
void CStringEditor::OnLanguageChanged(int LanguageIndex)
{
ASSERT( LanguageIndex >= 0 && LanguageIndex < (int) mpStringTable->NumLanguages() );
ELanguage Language = mpStringTable->LanguageByIndex(LanguageIndex);
SetActiveLanguage(Language);
if (Language != mCurrentLanguage)
{
IUndoCommand* pCommand = new CSetLanguageCommand(this, mCurrentLanguage, Language);
UndoStack().push(pCommand);
}
}
void CStringEditor::OnStringNameEdited()
{
TString NewName = TO_TSTRING( mpUI->StringNameLineEdit->text() );
if (mpStringTable->StringNameByIndex(mCurrentStringIndex) != NewName)
{
IUndoCommand* pCommand = new TSerializeUndoCommand<CStringTable>("Edit String Name", mpStringTable, false);
mpStringTable->SetStringName( mCurrentStringIndex, NewName );
mIsEditingStringName = true;
UndoStack().push(pCommand);
}
}
void CStringEditor::OnStringTextEdited()
{
TString NewText = TO_TSTRING( mpUI->StringTextEdit->toPlainText() );
if (mpStringTable->GetString(mCurrentLanguage, mCurrentStringIndex) != NewText)
{
IUndoCommand* pCommand = new TSerializeUndoCommand<CStringTable>("Edit String", mpStringTable, false);
mpStringTable->SetString(mCurrentLanguage, mCurrentStringIndex, NewText);
mIsEditingStringData = true;
UndoStack().push(pCommand);
}
}
void CStringEditor::OnAddString()
{
UndoStack().beginMacro("Add String");
// Add string
IUndoCommand* pCommand = new TSerializeUndoCommand<CStringTable>("Add String", mpStringTable, true);
uint Index = mCurrentStringIndex + 1;
mpStringTable->AddString(Index);
UndoStack().push(pCommand);
// Select new string
pCommand = new CSetStringIndexCommand(this, mCurrentStringIndex, Index);
UndoStack().push(pCommand);
UndoStack().endMacro();
// Give focus to the text edit so the user can edit the string
mpUI->StringTextEdit->setFocus();
}
void CStringEditor::OnRemoveString()
{
if (mpUI->StringNameListView->selectionModel()->hasSelection())
{
UndoStack().beginMacro("Remove String");
uint Index = mCurrentStringIndex;
// Change selection to a new string.
// Do this before actually removing the string so that if the action is undone, the
// editor will not attempt to re-select the string before it gets readded to the table.
uint NewStringCount = mpStringTable->NumStrings() - 1;
uint NewIndex = (Index >= NewStringCount ? NewStringCount - 1 : Index);
IUndoCommand* pCommand = new CSetStringIndexCommand(this, Index, NewIndex);
UndoStack().push(pCommand);
// Remove the string
pCommand = new TSerializeUndoCommand<CStringTable>("Remove String", mpStringTable, true);
mpStringTable->RemoveString(Index);
UndoStack().push(pCommand);
UndoStack().endMacro();
}
}
void CStringEditor::IncrementStringIndex()
{
uint NewIndex = mCurrentStringIndex + 1;
if (NewIndex < mpStringTable->NumStrings())
{
IUndoCommand* pCommand = new CSetStringIndexCommand(this, mCurrentStringIndex, NewIndex);
UndoStack().push(pCommand);
}
}
void CStringEditor::DecrementStringIndex()
{
uint NewIndex = mCurrentStringIndex - 1;
if (NewIndex != -1)
{
IUndoCommand* pCommand = new CSetStringIndexCommand(this, mCurrentStringIndex, NewIndex);
UndoStack().push(pCommand);
}
}
void CStringEditor::IncrementLanguageIndex()
{
for (uint i=0; i<mpStringTable->NumLanguages() - 1; i++)
{
if (mpStringTable->LanguageByIndex(i) == mCurrentLanguage)
{
ELanguage NewLanguage = mpStringTable->LanguageByIndex(i+1);
IUndoCommand* pCommand = new CSetLanguageCommand(this, mCurrentLanguage, NewLanguage);
UndoStack().push(pCommand);
break;
}
}
}
void CStringEditor::DecrementLanguageIndex()
{
for (uint i=mpStringTable->NumLanguages() - 1; i>0; i--)
{
if (mpStringTable->LanguageByIndex(i) == mCurrentLanguage)
{
ELanguage NewLanguage = mpStringTable->LanguageByIndex(i-1);
IUndoCommand* pCommand = new CSetLanguageCommand(this, mCurrentLanguage, NewLanguage);
UndoStack().push(pCommand);
break;
}
}
}

View File

@ -29,12 +29,22 @@ class CStringEditor : public IEditor
/** Index of the string being edited */
uint mCurrentStringIndex;
/** Current string count */
uint mCurrentStringCount;
/** Model for the string list view */
CStringListModel* mpListModel;
/** Editor state flags */
bool mIsEditingStringName;
bool mIsEditingStringData;
public:
explicit CStringEditor(CStringTable* pStringTable, QWidget* pParent = 0);
~CStringEditor();
bool eventFilter(QObject* pWatched, QEvent* pEvent);
void InitUI();
void UpdateStatusBar();
void SetActiveLanguage(ELanguage Language);
@ -43,9 +53,26 @@ public:
void LoadSettings();
void SaveSettings();
// Accessors
inline CStringTable* StringTable() const { return mpStringTable; }
public slots:
void UpdateUI();
void OnStringSelected(const QModelIndex& kIndex);
void OnLanguageChanged(int LanguageIndex);
void OnStringNameEdited();
void OnStringTextEdited();
void OnAddString();
void OnRemoveString();
void IncrementStringIndex();
void DecrementStringIndex();
void IncrementLanguageIndex();
void DecrementLanguageIndex();
signals:
void StringNameEdited();
void StringEdited();
};
#endif // CSTRINGEDITOR_H

View File

@ -44,6 +44,15 @@
<pointsize>9</pointsize>
</font>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
@ -108,7 +117,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="AddStringButton_2">
<widget class="QPushButton" name="RemoveStringButton">
<property name="text">
<string/>
</property>

View File

@ -0,0 +1,118 @@
#ifndef TSERIALIZEUNDOCOMMAND_H
#define TSERIALIZEUNDOCOMMAND_H
#include "IUndoCommand.h"
#include <Common/Common.h>
/**
* Undo command that works by restoring the full state of an object
* on undo/redo. To use, create the command object, apply the change
* you want to make to the object, and then push the command.
*
* Commands with IsActionComplete=false will be merged.
* To prevent merging, push a final command with IsActionComplete=true.
*
* The current implementatation is "dumb" and just saves and restores
* the entire object, including parameters that have not changed. Due
* to this, it could be memory-intensive and not super performant.
* As a result, it's probably not a good idea to use this on very
* large objects right now.
*/
template<typename ObjectT>
class TSerializeUndoCommand : public IUndoCommand
{
ObjectT* mpObject;
std::vector<char> mOldData;
std::vector<char> mNewData;
bool mIsActionComplete;
public:
TSerializeUndoCommand(const QString& kText, ObjectT* pObject, bool IsActionComplete)
: IUndoCommand(kText)
, mpObject(pObject)
, mIsActionComplete(IsActionComplete)
{
// Save old state of object
CVectorOutStream Out(&mOldData, EEndian::SystemEndian);
CBasicBinaryWriter Writer(&Out, 0, EGame::Invalid);
mpObject->Serialize(Writer);
}
/** IUndoCommand interface */
virtual int id() const override
{
return FOURCC('TSUC');
}
virtual void undo() override
{
// Restore old state of object
CMemoryInStream In(&mOldData[0], mOldData.size(), EEndian::SystemEndian);
CBasicBinaryReader Reader(&In, CSerialVersion(0,0,EGame::Invalid));
mpObject->Serialize(Reader);
}
virtual void redo() override
{
// First call when command is pushed - save new state of object
if (mNewData.empty())
{
CVectorOutStream Out(&mNewData, EEndian::SystemEndian);
CBasicBinaryWriter Writer(&Out, 0, EGame::Invalid);
mpObject->Serialize(Writer);
// Obsolete command if memory buffers match
if (mIsActionComplete)
{
if (mOldData.size() == mNewData.size())
{
if (memcmp(mOldData.data(), mNewData.data(), mNewData.size()) == 0)
{
setObsolete(true);
}
}
}
}
// Subsequent calls - restore new state of object
else
{
CMemoryInStream In(&mNewData[0], mNewData.size(), EEndian::SystemEndian);
CBasicBinaryReader Reader(&In, CSerialVersion(0,0,EGame::Invalid));
mpObject->Serialize(Reader);
}
}
virtual bool mergeWith(const QUndoCommand* pkOther) override
{
if (!mIsActionComplete && pkOther->id() == id())
{
const TSerializeUndoCommand* pkSerializeCommand =
static_cast<const TSerializeUndoCommand*>(pkOther);
mNewData = pkSerializeCommand->mNewData;
mIsActionComplete = pkSerializeCommand->mIsActionComplete;
// Obsolete command if memory buffers match
if (mIsActionComplete)
{
if (mOldData.size() == mNewData.size())
{
if (memcmp(mOldData.data(), mNewData.data(), mNewData.size()) == 0)
{
setObsolete(true);
}
}
}
return true;
}
return false;
}
virtual bool AffectsCleanState() const override
{
return true;
}
};
#endif // TSERIALIZEUNDOCOMMAND_H