Added support for renaming property archetypes. Added support for enums to override the default type name. Added the ability for enums/choices/flags with no values/flags to be edited as ints.

This commit is contained in:
Aruki
2018-10-13 16:33:31 -06:00
parent 0e5355a103
commit cf219cf17a
244 changed files with 942 additions and 460 deletions

View File

@@ -219,6 +219,73 @@ TString CGameTemplate::GetPropertyArchetypeFilePath(const TString& kTypeName)
return GetGameDirectory() + Iter->second.Path;
}
bool CGameTemplate::RenamePropertyArchetype(const TString& kTypeName, const TString& kNewTypeName)
{
if( kTypeName != kNewTypeName )
{
// Fetch the property that we are going to be renaming.
// Validate type, too, because we only support renaming struct archetypes at the moment
auto Iter = mPropertyTemplates.find(kTypeName);
if( Iter != mPropertyTemplates.end() )
{
SPropertyTemplatePath& Path = Iter->second;
IProperty* pArchetype = Path.pTemplate.get();
if( pArchetype )
{
// Attempt to move the XML to the new location.
TString OldPath = GetGameDirectory() + Path.Path;
TString NewPath = OldPath.GetFileDirectory() + kNewTypeName + ".xml";
if( FileUtil::MoveFile(OldPath, NewPath) )
{
// Update the name in the game template's internal mapping
TString RelativePath = FileUtil::MakeRelative( NewPath, GetGameDirectory() );
auto MapNode = mPropertyTemplates.extract(Iter);
MapNode.key() = kNewTypeName;
MapNode.mapped().Path = RelativePath;
mPropertyTemplates.insert( std::move(MapNode) );
mDirty = true;
// Renaming the archetype will handle updating the actual type name, and
// dirtying/invalidating property sub-instances.
TString OldTypeName = pArchetype->HashableTypeName();
pArchetype->SetName(kNewTypeName);
// For MP2 and up, we also need to update the type names stored in the property map.
if (pArchetype->Game() >= EGame::EchoesDemo)
{
NPropertyMap::ChangeTypeName(pArchetype, *OldTypeName, *kNewTypeName);
}
// MP1 has a lot of unnamed properties that just use the type name as their name.
// Update these properties so their name now refers to the updated type name.
else
{
std::list<IProperty*> SubInstances;
pArchetype->GatherAllSubInstances(SubInstances, true);
for (auto Iter = SubInstances.begin(); Iter != SubInstances.end(); Iter++)
{
IProperty* pProperty = *Iter;
if (pProperty->Name() == kTypeName)
{
pProperty->SetName(kNewTypeName);
}
}
}
return true;
}
}
}
}
return false;
}
TString CGameTemplate::GetGameDirectory() const
{
return mSourceFile.GetFileDirectory();

View File

@@ -132,6 +132,7 @@ public:
SMessage MessageByIndex(u32 Index);
IProperty* FindPropertyArchetype(const TString& kTypeName);
TString GetPropertyArchetypeFilePath(const TString& kTypeName);
bool RenamePropertyArchetype(const TString& kTypeName, const TString& kNewTypeName);
TString GetGameDirectory() const;
// Inline Accessors

View File

@@ -170,7 +170,15 @@ inline void ConditionalLoadMap()
/** Saves property names back out to the template file */
void SaveMap(bool Force /*= false*/)
{
ASSERT( gMapIsLoaded );
if( !gMapIsLoaded )
{
if (Force)
{
LoadMap();
}
else return;
}
Log::Write("Saving property map");
if( gMapIsDirty || Force )
@@ -306,31 +314,94 @@ void SetPropertyName(u32 ID, const char* pkTypeName, const char* pkNewName)
}
}
/** Change the type name associated with a property ID */
void SetTypeName(u32 ID, const char* pkOldTypeName, const char* pkNewTypeName)
/** Change a type name of a property. */
void ChangeTypeName(IProperty* pProperty, const char* pkOldTypeName, const char* pkNewTypeName)
{
u32 OldTypeHash = CCRC32::StaticHashString(pkOldTypeName);
u32 NewTypeHash = CCRC32::StaticHashString(pkNewTypeName);
SNameKey OldKey( OldTypeHash, ID );
auto MapNode = gNameMap.extract(OldKey);
if (!MapNode.empty())
if (OldTypeHash == NewTypeHash)
{
SNameKey& Key = MapNode.key();
SNameValue& Value = MapNode.mapped();
Key.TypeHash = NewTypeHash;
gHashToTypeName[NewTypeHash] = pkNewTypeName;
for (auto Iter = Value.PropertyList.begin(); Iter != Value.PropertyList.end(); Iter++)
{
IProperty* pProperty = *Iter;
pProperty->RecacheName();
}
gNameMap.insert( std::move(MapNode) );
gMapIsDirty = true;
return;
}
// Start off with a ist of all properties in the same inheritance chain as this one.
std::list<IProperty*> Properties;
IProperty* pArchetype = pProperty->RootArchetype();
pArchetype->GatherAllSubInstances(Properties, true);
for (auto Iter = Properties.begin(); Iter != Properties.end(); Iter++)
{
pProperty = *Iter;
if (pProperty->UsesNameMap())
{
SNameKey OldKey(OldTypeHash, pProperty->ID());
SNameKey NewKey(NewTypeHash, pProperty->ID());
// Disassociate this property from the old mapping.
auto Find = gNameMap.find(OldKey);
if (Find != gNameMap.end())
{
SNameValue& Value = Find->second;
NBasics::ListRemoveOne(Value.PropertyList, pProperty);
}
// Create a key for the new property and add it to the list.
Find = gNameMap.find(NewKey);
if (Find == gNameMap.end())
{
SNameValue Value;
Value.Name = pProperty->Name();
gNameMap[NewKey] = Value;
Find = gNameMap.find(NewKey);
}
ASSERT(Find != gNameMap.end());
Find->second.PropertyList.push_back(pProperty);
gMapIsDirty = true;
}
}
gHashToTypeName[NewTypeHash] = pkNewTypeName;
}
/** Change a type name. */
void ChangeTypeNameGlobally(const char* pkOldTypeName, const char* pkNewTypeName)
{
u32 OldTypeHash = CCRC32::StaticHashString(pkOldTypeName);
u32 NewTypeHash = CCRC32::StaticHashString(pkNewTypeName);
if (OldTypeHash == NewTypeHash)
{
return;
}
// The process here is basically to find all properties with a matching typename
// hash and update the hashes to the new type. Not 100% sure if this is the best
// way to go about doing it. From what I understand, insert() does not invalidate
// iterators, and extract() only invalidates the iterator being extracted. So this
// implementation should work correctly.
for (auto MapIter = gNameMap.begin(); MapIter != gNameMap.end(); MapIter++)
{
if (MapIter->first.TypeHash == OldTypeHash)
{
auto PrevIter = MapIter;
PrevIter--;
auto MapNode = gNameMap.extract(MapIter);
MapIter = PrevIter;
SNameKey& Key = MapNode.key();
Key.TypeHash = NewTypeHash;
gNameMap.insert( std::move(MapNode) );
gMapIsDirty = true;
}
}
gHashToTypeName[NewTypeHash] = pkNewTypeName;
}
/** Registers a property in the name map. Should be called on all properties that use the map */
@@ -363,16 +434,17 @@ void RegisterProperty(IProperty* pProperty)
gNameMap[Key] = Value;
MapFind = gNameMap.find(Key);
ASSERT(MapFind != gNameMap.end());
RegisterTypeName(Key.TypeHash, pProperty->HashableTypeName());
}
}
else
{
ASSERT(MapFind != gNameMap.end());
pProperty->SetName( MapFind->second.Name );
}
ASSERT(MapFind != gNameMap.end());
MapFind->second.PropertyList.push_back(pProperty);
// Update the property's Name field to match the mapped name.

View File

@@ -34,8 +34,11 @@ void RetrieveXMLsWithProperty(u32 ID, const char* pkTypeName, std::set<TString>&
/** Updates the name of a given property in the map */
void SetPropertyName(u32 ID, const char* pkTypeName, const char* pkNewName);
/** Change the type name associated with a property ID */
void SetTypeName(u32 ID, const char* pkOldTypeName, const char* pkNewTypeName);
/** Change a type name of a property. */
void ChangeTypeName(IProperty* pProperty, const char* pkOldTypeName, const char* pkNewTypeName);
/** Change a type name. */
void ChangeTypeNameGlobally(const char* pkOldTypeName, const char* pkNewTypeName);
/** Registers a property in the name map. Should be called on all properties that use the map */
void RegisterProperty(IProperty* pProperty);

View File

@@ -42,16 +42,24 @@ class TEnumPropertyBase : public TSerializeableTypedProperty<s32, TypeEnum>
};
std::vector<SEnumValue> mValues;
/** If true, the archetype's name will be used as the type name instead of "enum" or "choice". */
bool mOverrideTypeName;
protected:
/** Constructor */
TEnumPropertyBase(EGame Game)
: TSerializeableTypedProperty(Game)
, mOverrideTypeName(false)
{}
public:
virtual const char* GetHashableTypeName() const
virtual const char* HashableTypeName() const
{
if (TypeEnum == EPropertyType::Enum)
if (mpArchetype)
return mpArchetype->HashableTypeName();
else if (mOverrideTypeName)
return *mName;
else if (TypeEnum == EPropertyType::Enum)
return "enum";
else
return "choice";
@@ -64,8 +72,15 @@ public:
TEnumPropertyBase* pArchetype = static_cast<TEnumPropertyBase*>(mpArchetype);
u32 DefaultValueFlags = SH_HexDisplay | (pArchetype || Game() <= EGame::Prime ? SH_Optional : 0);
rArc << SerialParameter("DefaultValue", mDefaultValue, DefaultValueFlags, pArchetype ? pArchetype->mDefaultValue : 0);
// Only serialize type name override for root archetypes.
if (!mpArchetype)
{
rArc << SerialParameter("OverrideTypeName", mOverrideTypeName, SH_Optional, false);
}
if (!pArchetype || !rArc.CanSkipParameters() || mValues != pArchetype->mValues)
{
rArc << SerialParameter("Values", mValues);
@@ -117,10 +132,33 @@ public:
bool HasValidValue(void* pPropertyData)
{
if (mValues.empty()) return true;
int ID = ValueRef(pPropertyData);
u32 Index = ValueIndex(ID);
return Index >= 0 && Index < mValues.size();
}
bool OverridesTypeName() const
{
return mpArchetype ? TPropCast<TEnumPropertyBase>(mpArchetype)->OverridesTypeName() : mOverrideTypeName;
}
void SetOverrideTypeName(bool Override)
{
if (mpArchetype)
{
TEnumPropertyBase* pArchetype = TPropCast<TEnumPropertyBase>(RootArchetype());
pArchetype->SetOverrideTypeName(Override);
}
else
{
if (mOverrideTypeName != Override)
{
mOverrideTypeName = Override;
MarkDirty();
}
}
}
};
typedef TEnumPropertyBase<EPropertyType::Choice> CChoiceProperty;

View File

@@ -43,5 +43,6 @@ void CFlagsProperty::InitFromArchetype(IProperty* pOther)
*/
u32 CFlagsProperty::HasValidValue(void* pPropertyData)
{
if (!mAllFlags) return 0;
return ValueRef(pPropertyData) & ~mAllFlags;
}

View File

@@ -153,7 +153,6 @@ void IProperty::Initialize(IProperty* pInParent, CScriptTemplate* pInTemplate, u
{
// Make sure we only get initialized once.
ASSERT( (mFlags & EPropertyFlag::IsInitialized) == 0 );
mFlags |= EPropertyFlag::IsInitialized;
mpParent = pInParent;
mOffset = InOffset;
@@ -219,6 +218,8 @@ void IProperty::Initialize(IProperty* pInParent, CScriptTemplate* pInTemplate, u
pChild->Initialize(this, pInTemplate, ChildOffset);
}
}
mFlags |= EPropertyFlag::IsInitialized;
}
void* IProperty::RawValuePtr(void* pData) const
@@ -273,6 +274,21 @@ IProperty* IProperty::ChildByIDString(const TIDString& rkIdString)
}
}
void IProperty::GatherAllSubInstances(std::list<IProperty*>& OutList, bool Recursive)
{
OutList.push_back(this);
for( u32 SubIdx = 0; SubIdx < mSubInstances.size(); SubIdx++ )
{
IProperty* pSubInstance = mSubInstances[SubIdx];
if( Recursive )
pSubInstance->GatherAllSubInstances( OutList, true );
else
OutList.push_back( pSubInstance );
}
}
TString IProperty::GetTemplateFileName()
{
// We want to return the path to the XML file that this property originally belongs to.
@@ -328,13 +344,7 @@ void IProperty::SetName(const TString& rkNewName)
{
mName = rkNewName;
mFlags.ClearFlag(EPropertyFlag::HasCachedNameCheck);
// in Echoes and on, since property names are referenced by ID, renaming a property
// doesn't directly affect the serialized data, so it doesn't need to be flagged dirty
if (mGame <= EGame::Prime)
{
MarkDirty();
}
MarkDirty();
}
}
@@ -358,7 +368,21 @@ void IProperty::SetSuffix(const TString& rkNewSuffix)
void IProperty::MarkDirty()
{
RootParent()->mFlags |= EPropertyFlag::IsDirty;
// Don't allow properties to be marked dirty before they are fully initialized.
if (IsInitialized())
{
// Mark the root parent as dirty so the template file will get resaved
RootParent()->mFlags |= EPropertyFlag::IsDirty;
// Clear property name cache in case something has been modified that affects the hash
mFlags &= ~(EPropertyFlag::HasCachedNameCheck | EPropertyFlag::HasCorrectPropertyName);
// Mark sub-instances as dirty since they may need to resave as well
for (u32 SubIdx = 0; SubIdx < mSubInstances.size(); SubIdx++)
{
mSubInstances[SubIdx]->MarkDirty();
}
}
}
void IProperty::ClearDirtyFlag()
@@ -416,11 +440,6 @@ bool IProperty::HasAccurateName()
return mFlags.HasFlag( EPropertyFlag::HasCorrectPropertyName );
}
void IProperty::RecacheName()
{
mFlags.ClearFlag( EPropertyFlag::HasCachedNameCheck | EPropertyFlag::HasCorrectPropertyName );
}
/** IPropertyNew Accessors */
EGame IProperty::Game() const
{

View File

@@ -193,6 +193,7 @@ public:
void* RawValuePtr(void* pData) const;
IProperty* ChildByID(u32 ID) const;
IProperty* ChildByIDString(const TIDString& rkIdString);
void GatherAllSubInstances(std::list<IProperty*>& OutList, bool Recursive);
TString GetTemplateFileName();
bool ShouldCook(void* pPropertyData) const;
void SetName(const TString& rkNewName);
@@ -202,7 +203,6 @@ public:
void ClearDirtyFlag();
bool UsesNameMap();
bool HasAccurateName();
void RecacheName();
/** Accessors */
EGame Game() const;
@@ -221,6 +221,7 @@ public:
inline u32 Offset() const;
inline u32 ID() const;
inline bool IsInitialized() const { return mFlags.HasFlag(EPropertyFlag::IsInitialized); }
inline bool IsArchetype() const { return mFlags.HasFlag(EPropertyFlag::IsArchetype); }
inline bool IsArrayArchetype() const { return mFlags.HasFlag(EPropertyFlag::IsArrayArchetype); }
inline bool IsAtomic() const { return mFlags.HasFlag(EPropertyFlag::IsAtomic); }

View File

@@ -1,4 +1,5 @@
#include "CPropertyNameValidator.h"
#include "UICommon.h"
#include <Common/Hash/CCRC32.h>
CPropertyNameValidator::CPropertyNameValidator(QObject* pParent)
@@ -12,14 +13,23 @@ void CPropertyNameValidator::SetProperty(IProperty* pProp)
emit changed();
}
/** Set the type name override */
void CPropertyNameValidator::SetTypeNameOverride(const QString& kNewTypeName)
{
mTypeNameOverride = kNewTypeName;
emit changed();
}
/** Perform validation */
QValidator::State CPropertyNameValidator::validate(QString& rInput, int&) const
{
if (mpProperty)
{
TString TypeName = (mTypeNameOverride.isEmpty() ? mpProperty->HashableTypeName() : TO_TSTRING(mTypeNameOverride));
CCRC32 Hash;
Hash.Hash( rInput.toStdString().c_str() );
Hash.Hash( mpProperty->HashableTypeName() );
Hash.Hash( *TypeName );
u32 PropertyID = Hash.Digest();
if (PropertyID != mpProperty->ID())

View File

@@ -12,14 +12,21 @@ class CPropertyNameValidator : public QValidator
/** The property being validated against */
IProperty* mpProperty;
/** String to use to override the type name. If empty, the property's normal type name is used. */
QString mTypeNameOverride;
public:
CPropertyNameValidator(QObject* pParent = 0);
/** Perform validation */
QValidator::State validate(QString& rInput, int& rPos) const;
public slots:
/** Set the property to validate against */
void SetProperty(IProperty* pProp);
/** Perform validation */
QValidator::State validate(QString& rInput, int& rPos) const;
/** Set the type name override */
void SetTypeNameOverride(const QString& kNewTypeName);
};
#endif // CPROPERTYNAMEVALIDATOR_H

View File

@@ -53,7 +53,9 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
if (pProp)
{
switch (pProp->Type())
EPropertyType Type = GetEffectiveFieldType(pProp);
switch (Type)
{
case EPropertyType::Bool:
@@ -166,7 +168,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
else if (rkIndex.internalId() & 0x80000000)
{
pProp = mpModel->PropertyForIndex(rkIndex, true);
EPropertyType Type = pProp->Type();
EPropertyType Type = GetEffectiveFieldType(pProp);
// Handle character
if (Type == EPropertyType::AnimationSet)
@@ -206,7 +208,9 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
{
if (!mEditInProgress)
{
switch (pProp->Type())
EPropertyType Type = pProp->Type();
switch (Type)
{
case EPropertyType::Bool:
@@ -330,11 +334,12 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
else if (rkIndex.internalId() & 0x80000000)
{
pProp = mpModel->PropertyForIndex(rkIndex, true);
EPropertyType Type = GetEffectiveFieldType(pProp);
if (pProp->Type() == EPropertyType::AnimationSet)
if (Type == EPropertyType::AnimationSet)
SetCharacterEditorData(pEditor, rkIndex);
else if (pProp->Type() == EPropertyType::Flags)
else if (Type == EPropertyType::Flags)
{
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
@@ -359,7 +364,7 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
if (pProp)
{
EPropertyType Type = pProp->Type();
EPropertyType Type = GetEffectiveFieldType(pProp);
QVector<CScriptObject*> Objects;
Objects << mpModel->GetScriptObject();
@@ -373,10 +378,10 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
// Handle sub-properties of flags and animation sets
if (rkIndex.internalId() & 0x80000000)
{
if (pProp->Type() == EPropertyType::AnimationSet)
if (Type == EPropertyType::AnimationSet)
SetCharacterModelData(pEditor, rkIndex);
else if (pProp->Type() == EPropertyType::Flags)
else if (Type == EPropertyType::Flags)
{
QCheckBox* pCheckBox = static_cast<QCheckBox*>(pEditor);
CFlagsProperty* pFlags = static_cast<CFlagsProperty*>(pProp);
@@ -391,7 +396,7 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
else
{
switch (pProp->Type())
switch (Type)
{
case EPropertyType::Bool:
@@ -670,6 +675,46 @@ EPropertyType CPropertyDelegate::DetermineCharacterPropType(EGame Game, const QM
return EPropertyType::Invalid;
}
/** Determine the effective property type to use. Allows some types to be treated as other types. */
EPropertyType CPropertyDelegate::GetEffectiveFieldType(IProperty* pProperty) const
{
EPropertyType Out = pProperty->Type();
switch (Out)
{
// Allow Choice/Enum properties to be edited as Int properties if they don't have any values set.
case EPropertyType::Choice:
case EPropertyType::Enum:
{
CChoiceProperty* pChoice = TPropCast<CChoiceProperty>(pProperty);
if (pChoice->NumPossibleValues() == 0)
{
Out = EPropertyType::Int;
}
break;
}
// Same deal with Flag properties
case EPropertyType::Flags:
{
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProperty);
if (pFlags->NumFlags() == 0)
{
Out = EPropertyType::Int;
}
break;
}
}
return Out;
}
// ************ PUBLIC SLOTS ************
void CPropertyDelegate::WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex)
{

View File

@@ -29,6 +29,7 @@ public:
void SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const;
void SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const;
EPropertyType DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const;
EPropertyType GetEffectiveFieldType(IProperty* pProperty) const;
public slots:
void WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex);

View File

@@ -15,6 +15,7 @@ CTemplateEditDialog::CTemplateEditDialog(IProperty *pProperty, QWidget *pParent)
, mGame(pProperty->Game())
, mOriginalName(pProperty->Name())
, mOriginalDescription(pProperty->Description())
, mOriginalAllowTypeNameOverride(false)
, mOriginalNameWasValid(true)
{
mpUI->setupUi(this);
@@ -24,6 +25,37 @@ CTemplateEditDialog::CTemplateEditDialog(IProperty *pProperty, QWidget *pParent)
mpUI->NameLineEdit->setText(TO_QSTRING(pProperty->Name()));
mpUI->DescriptionTextEdit->setPlainText(TO_QSTRING(pProperty->Description()));
EPropertyType Type = pProperty->Type();
// Configure type name
if (Type == EPropertyType::Struct || Type == EPropertyType::Choice || Type == EPropertyType::Enum || Type == EPropertyType::Flags)
{
connect( mpUI->TypenameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(RefreshTypeNameOverride()) );
mOriginalTypeName = pProperty->RootArchetype()->Name();
mpUI->TypenameLineEdit->setText( TO_QSTRING(mOriginalTypeName) );
}
else
{
mpUI->TypenameLabel->setHidden(true);
mpUI->TypenameLineEdit->setHidden(true);
}
// Configure type name override option
if (Type == EPropertyType::Enum || Type == EPropertyType::Choice)
{
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProperty);
mOriginalAllowTypeNameOverride = pEnum->OverridesTypeName();
mpUI->OverrideTypeNameCheckBox->setChecked( mOriginalAllowTypeNameOverride );
connect( mpUI->OverrideTypeNameCheckBox, SIGNAL(toggled(bool)), this, SLOT(RefreshTypeNameOverride()) );
}
else
{
mpUI->OverrideTypeNameCheckBox->setHidden(true);
mpUI->OverrideTypeNameCheckBox->setChecked(true);
}
RefreshTypeNameOverride();
// Hide templates list for MP1
if (mGame <= EGame::Prime)
{
mpUI->TemplatesGroupBox->hide();
@@ -83,6 +115,7 @@ void CTemplateEditDialog::ApplyChanges()
bool RenameAll = mpUI->RenameAllCheckBox->isChecked();
// Update name
TString NewName = TO_TSTRING(mpUI->NameLineEdit->text());
if (NewName.IsEmpty()) NewName = "Unknown";
@@ -95,15 +128,34 @@ void CTemplateEditDialog::ApplyChanges()
}
}
// Update description
TString NewDescription = TO_TSTRING(mpUI->DescriptionTextEdit->toPlainText());
UpdateDescription(NewDescription);
// Update type name
TString NewTypeName = TO_TSTRING(mpUI->TypenameLineEdit->text());
bool AllowTypeNameOverride = mpUI->OverrideTypeNameCheckBox->isChecked();
UpdateTypeName(NewTypeName, AllowTypeNameOverride);
// Resave templates
NGameList::SaveTemplates();
NPropertyMap::SaveMap();
close();
}
void CTemplateEditDialog::RefreshTypeNameOverride()
{
if (mpUI->OverrideTypeNameCheckBox->isChecked())
{
QString OverrideName = mpUI->TypenameLineEdit->text();
mpValidator->SetTypeNameOverride(OverrideName);
}
else
{
mpValidator->SetTypeNameOverride("");
}
}
// ************ PROTECTED ************
void CTemplateEditDialog::UpdateDescription(const TString& rkNewDesc)
{
@@ -133,6 +185,34 @@ void CTemplateEditDialog::UpdateDescription(const TString& rkNewDesc)
}
}
void CTemplateEditDialog::UpdateTypeName(const TString& kNewTypeName, bool AllowOverride)
{
if (mOriginalTypeName != kNewTypeName || mOriginalAllowTypeNameOverride != AllowOverride)
{
// Get a list of properties to update.
for (int GameIdx = 0; GameIdx < (int) EGame::Max; GameIdx++)
{
CGameTemplate* pGame = NGameList::GetGameTemplate( (EGame) GameIdx );
if (pGame)
{
IProperty* pArchetype = pGame->FindPropertyArchetype(mOriginalTypeName);
if (pArchetype)
{
pGame->RenamePropertyArchetype(mOriginalTypeName, kNewTypeName);
if (pArchetype->Type() == EPropertyType::Enum || pArchetype->Type() == EPropertyType::Choice)
{
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pArchetype);
pEnum->SetOverrideTypeName(AllowOverride);
}
}
}
}
}
}
void CTemplateEditDialog::FindEquivalentProperties(IProperty* pProperty)
{
// This function creates a list of properties in other games that are equivalent to this one.

View File

@@ -21,6 +21,8 @@ class CTemplateEditDialog : public QDialog
TString mOriginalName;
TString mOriginalDescription;
TString mOriginalTypeName;
bool mOriginalAllowTypeNameOverride;
bool mOriginalNameWasValid;
// These members help track what templates need to be updated and resaved after the user clicks OK
@@ -32,9 +34,11 @@ public:
public slots:
void ApplyChanges();
void RefreshTypeNameOverride();
protected:
void UpdateDescription(const TString& rkNewDesc);
void UpdateTypeName(const TString& kNewTypeName, bool AllowOverride);
void FindEquivalentProperties(IProperty *pProperty);
};

View File

@@ -116,14 +116,14 @@
</item>
</layout>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="DescriptionLabel">
<property name="text">
<string>Description:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QPlainTextEdit" name="DescriptionTextEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
@@ -143,11 +143,31 @@
<height>60</height>
</size>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
<property name="plainText">
<string/>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="TypenameLabel">
<property name="text">
<string>Type Name:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="TypenameLineEdit"/>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="OverrideTypeNameCheckBox">
<property name="text">
<string>Use type name for ID hashes</string>
</property>
</widget>
</item>
</layout>
</item>
<item>