Support for adding/removing strings
This commit is contained in:
parent
eb9236bbea
commit
cb262504af
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -205,7 +205,8 @@ HEADERS += \
|
|||
StringEditor/CStringDelegate.h \
|
||||
CCustomDelegate.h \
|
||||
CTweakEditor.h \
|
||||
Undo/CEditIntrinsicPropertyCommand.h
|
||||
Undo/CEditIntrinsicPropertyCommand.h \
|
||||
Undo/TSerializeUndoCommand.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue