Added support for enum combo boxes, and added casing combo box and property ID pools to the property name generator

This commit is contained in:
Aruki 2018-10-12 19:38:08 -06:00
parent ef6759df4a
commit 1d724b69d9
16 changed files with 352 additions and 45 deletions

View File

@ -106,6 +106,11 @@ void CCRC32::Hash(double v)
Hash(&v, 8); Hash(&v, 8);
} }
void CCRC32::Hash(char v)
{
Hash(&v, 1);
}
void CCRC32::Hash(const char* pkString) void CCRC32::Hash(const char* pkString)
{ {
while (*pkString) while (*pkString)

View File

@ -32,6 +32,7 @@ public:
void Hash(u64 v); void Hash(u64 v);
void Hash(float v); void Hash(float v);
void Hash(double v); void Hash(double v);
void Hash(char v);
void Hash(const char* pkString); void Hash(const char* pkString);
static u32 StaticHashString(const char* pkString); static u32 StaticHashString(const char* pkString);

View File

@ -83,7 +83,7 @@ bool VectorContains(std::vector<T>& Vector, const T& kElement)
template<typename T> template<typename T>
bool VectorAddUnique(std::vector<T>& Vector, const T& kElement) bool VectorAddUnique(std::vector<T>& Vector, const T& kElement)
{ {
if (!VectorContainsElement(Vector, kElement)) if (!VectorContains(Vector, kElement))
{ {
Vector.push_back(kElement); Vector.push_back(kElement);
return true; return true;

View File

@ -193,7 +193,6 @@ SMessage CGameTemplate::MessageByIndex(u32 Index)
IProperty* CGameTemplate::FindPropertyArchetype(const TString& kTypeName) IProperty* CGameTemplate::FindPropertyArchetype(const TString& kTypeName)
{ {
auto Iter = mPropertyTemplates.find(kTypeName); auto Iter = mPropertyTemplates.find(kTypeName);
ASSERT(Iter != mPropertyTemplates.end()); // Requested archetype property does not exist; missing or malformed template
if (Iter == mPropertyTemplates.end()) if (Iter == mPropertyTemplates.end())
{ {

View File

@ -28,14 +28,9 @@ void CPropertyNameGenerator::Warmup()
while (!feof(pListFile)) while (!feof(pListFile))
{ {
char WordBuffer[256]; char WordBuffer[64];
fgets(&WordBuffer[0], 256, pListFile); fgets(&WordBuffer[0], 64, pListFile);
WordBuffer[0] = TString::CharToUpper(WordBuffer[0]);
// Capitalize first letter
if (WordBuffer[0] >= 'a' && WordBuffer[0] <= 'z')
{
WordBuffer[0] -= 0x20;
}
SWord Word; SWord Word;
Word.Word = TString(WordBuffer).Trimmed(); Word.Word = TString(WordBuffer).Trimmed();
@ -53,9 +48,27 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
ASSERT(!mIsRunning); ASSERT(!mIsRunning);
ASSERT(rkParams.TypeNames.size() > 0); ASSERT(rkParams.TypeNames.size() > 0);
mGeneratedNames.clear(); mGeneratedNames.clear();
mValidTypePairMap.clear();
mIsRunning = true; mIsRunning = true;
mFinishedRunning = false; mFinishedRunning = false;
// Convert valid type pairs into hashes.
// Also, replace the normal type name list with whatever is in the ID pairs list we were given.
if (!rkParams.ValidIdPairs.empty())
{
mTypeNames.clear();
for (const SPropertyIdTypePair& kPair : rkParams.ValidIdPairs)
{
mValidTypePairMap[ kPair.ID ] = kPair.pkType;
NBasics::VectorAddUnique( mTypeNames, TString(kPair.pkType) );
}
}
else
{
mTypeNames = rkParams.TypeNames;
}
// If we haven't loaded the word list yet, load it. // If we haven't loaded the word list yet, load it.
// If we are still loading the word list, wait until we're finished. // If we are still loading the word list, wait until we're finished.
if (!mWordListLoadFinished) if (!mWordListLoadFinished)
@ -132,11 +145,22 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
{ {
int Index = WordCache[RecalcIndex].WordIndex; int Index = WordCache[RecalcIndex].WordIndex;
// Add an underscore if needed // For camelcase, hash the first letter of the first word as lowercase
if (RecalcIndex > 0 && rkParams.UseUnderscores) if (RecalcIndex == 0 && rkParams.Casing == ENameCasing::camelCase)
LastValidHash.Hash("_"); {
const char* pkWord = *mWords[Index].Word;
LastValidHash.Hash( TString::CharToLower( pkWord[0] ) );
LastValidHash.Hash( &pkWord[1] );
}
else
{
// Add an underscore for snake case
if (RecalcIndex > 0 && rkParams.Casing == ENameCasing::Snake_Case)
LastValidHash.Hash("_");
LastValidHash.Hash( *mWords[Index].Word );
}
LastValidHash.Hash( *mWords[Index].Word );
WordCache[RecalcIndex].Hash = LastValidHash; WordCache[RecalcIndex].Hash = LastValidHash;
} }
@ -144,15 +168,15 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
CCRC32 BaseHash = LastValidHash; CCRC32 BaseHash = LastValidHash;
BaseHash.Hash( *rkParams.Suffix ); BaseHash.Hash( *rkParams.Suffix );
for (int TypeIdx = 0; TypeIdx < rkParams.TypeNames.size(); TypeIdx++) for (int TypeIdx = 0; TypeIdx < mTypeNames.size(); TypeIdx++)
{ {
CCRC32 FullHash = BaseHash; CCRC32 FullHash = BaseHash;
const char* pkTypeName = *rkParams.TypeNames[TypeIdx]; const char* pkTypeName = *mTypeNames[TypeIdx];
FullHash.Hash( pkTypeName ); FullHash.Hash( pkTypeName );
u32 PropertyID = FullHash.Digest(); u32 PropertyID = FullHash.Digest();
// Check if this hash is a property ID // Check if this hash is a property ID
if (NPropertyMap::IsValidPropertyName(PropertyID, pkTypeName)) if (IsValidPropertyID(PropertyID, pkTypeName))
{ {
SGeneratedPropertyName PropertyName; SGeneratedPropertyName PropertyName;
NPropertyMap::RetrieveXMLsWithProperty(PropertyID, pkTypeName, PropertyName.XmlList); NPropertyMap::RetrieveXMLsWithProperty(PropertyID, pkTypeName, PropertyName.XmlList);
@ -164,7 +188,7 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
{ {
int Index = WordCache[WordIdx].WordIndex; int Index = WordCache[WordIdx].WordIndex;
if (WordIdx > 0 && rkParams.UseUnderscores) if (WordIdx > 0 && rkParams.Casing == ENameCasing::Snake_Case)
{ {
PropertyName.Name += "_"; PropertyName.Name += "_";
} }
@ -172,8 +196,13 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
PropertyName.Name += mWords[Index].Word; PropertyName.Name += mWords[Index].Word;
} }
if (rkParams.Casing == ENameCasing::camelCase)
{
PropertyName.Name[0] = TString::CharToLower( PropertyName.Name[0] );
}
PropertyName.Name += rkParams.Suffix; PropertyName.Name += rkParams.Suffix;
PropertyName.Type = rkParams.TypeNames[TypeIdx]; PropertyName.Type = mTypeNames[TypeIdx];
PropertyName.ID = PropertyID; PropertyName.ID = PropertyID;
if (SaveResults) if (SaveResults)
@ -184,7 +213,7 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
// If we have too many saved results, then to avoid crashing we will force enable log output. // If we have too many saved results, then to avoid crashing we will force enable log output.
if (mGeneratedNames.size() > 9999) if (mGeneratedNames.size() > 9999)
{ {
gpUIRelay->AsyncMessageBox("Warning", "There are over 10,000 results. To avoid memory issues, results will no longer print to the screen. Check the log for the rest of the output."); gpUIRelay->AsyncMessageBox("Warning", "There are over 10,000 results. Results will no longer print to the screen. Check the log for the remaining output.");
WriteToLog = true; WriteToLog = true;
SaveResults = false; SaveResults = false;
} }
@ -222,3 +251,21 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
mIsRunning = false; mIsRunning = false;
mFinishedRunning = true; mFinishedRunning = true;
} }
/** Returns whether a given property ID is valid */
bool CPropertyNameGenerator::IsValidPropertyID(u32 ID, const char* pkType)
{
if (!mValidTypePairMap.empty())
{
auto Find = mValidTypePairMap.find(ID);
if (Find != mValidTypePairMap.end())
{
return strcmp( Find->second, pkType ) == 0;
}
else
return false;
}
else
return NPropertyMap::IsValidPropertyName(ID, pkType);
}

View File

@ -4,6 +4,21 @@
#include "Core/IProgressNotifier.h" #include "Core/IProgressNotifier.h"
#include <Common/Common.h> #include <Common/Common.h>
/** Name casing parameter */
enum class ENameCasing
{
PascalCase,
Snake_Case,
camelCase,
};
/** ID/type pairing for ID pool */
struct SPropertyIdTypePair
{
u32 ID;
const char* pkType;
};
/** Parameters for using the name generator */ /** Parameters for using the name generator */
struct SPropertyNameGenerationParameters struct SPropertyNameGenerationParameters
{ {
@ -16,11 +31,14 @@ struct SPropertyNameGenerationParameters
/** Suffix to include at the end of every name */ /** Suffix to include at the end of every name */
TString Suffix; TString Suffix;
/** Name casing to use */
ENameCasing Casing;
/** List of valid type suffixes */ /** List of valid type suffixes */
std::vector<TString> TypeNames; std::vector<TString> TypeNames;
/** Whether to separate words with underscores */ /** List of ID/type pairs to check against. If empty, all properties are valid. */
bool UseUnderscores; std::vector<SPropertyIdTypePair> ValidIdPairs;
/** Whether to print the output from the generation process to the log */ /** Whether to print the output from the generation process to the log */
bool PrintToLog; bool PrintToLog;
@ -50,6 +68,12 @@ class CPropertyNameGenerator
/** Whether the generation process finished running */ /** Whether the generation process finished running */
bool mFinishedRunning; bool mFinishedRunning;
/** List of valid property types to check against */
std::vector<TString> mTypeNames;
/** Mapping of valid ID/type pairs; if empty, all property names in NPropertyMap are allowed */
std::unordered_map<u32, const char*> mValidTypePairMap;
/** List of words */ /** List of words */
struct SWord struct SWord
{ {
@ -74,6 +98,9 @@ public:
/** Run the name generation system */ /** Run the name generation system */
void Generate(const SPropertyNameGenerationParameters& rkParams, IProgressNotifier* pProgressNotifier); void Generate(const SPropertyNameGenerationParameters& rkParams, IProgressNotifier* pProgressNotifier);
/** Returns whether a given property ID is valid */
bool IsValidPropertyID(u32 ID, const char* pkType);
/** Accessors */ /** Accessors */
bool IsRunning() const bool IsRunning() const
{ {

View File

@ -20,6 +20,7 @@ CGeneratePropertyNamesDialog::CGeneratePropertyNamesDialog(QWidget* pParent)
connect( mpUI->AddSuffixButton, SIGNAL(pressed()), this, SLOT(AddSuffix()) ); connect( mpUI->AddSuffixButton, SIGNAL(pressed()), this, SLOT(AddSuffix()) );
connect( mpUI->RemoveSuffixButton, SIGNAL(pressed()), this, SLOT(DeleteSuffix()) ); connect( mpUI->RemoveSuffixButton, SIGNAL(pressed()), this, SLOT(DeleteSuffix()) );
connect( mpUI->ClearIdPoolButton, SIGNAL(pressed()), this, SLOT(ClearIdPool()) );
connect( mpUI->StartButton, SIGNAL(pressed()), this, SLOT(StartGeneration()) ); connect( mpUI->StartButton, SIGNAL(pressed()), this, SLOT(StartGeneration()) );
connect( mpUI->CancelButton, SIGNAL(pressed()), this, SLOT(CancelGeneration()) ); connect( mpUI->CancelButton, SIGNAL(pressed()), this, SLOT(CancelGeneration()) );
connect( mpUI->CheckAllButton, SIGNAL(pressed()), this, SLOT(CheckAll()) ); connect( mpUI->CheckAllButton, SIGNAL(pressed()), this, SLOT(CheckAll()) );
@ -45,6 +46,56 @@ CGeneratePropertyNamesDialog::~CGeneratePropertyNamesDialog()
delete mpUI; delete mpUI;
} }
/** Add a property to the ID pool */
void CGeneratePropertyNamesDialog::AddToIDPool(IProperty* pProperty)
{
if (!pProperty->UsesNameMap())
{
Log::Error("Failed to add property " + pProperty->IDString(false) + " to the generator ID pool because it doesn't use the name map");
return;
}
u32 ID = pProperty->ID();
const char* pkTypeName = pProperty->HashableTypeName();
mIdPairs << SPropertyIdTypePair { ID, pkTypeName };
QString ItemText = QString("%1 [%2]").arg( *TString::HexString(pProperty->ID(), 8, false) ).arg( pkTypeName );
mpUI->IdPoolList->addItem( ItemText );
// We probably don't want to call UpdateUI every single time we add a property, but
// we do need to call it somewhere to make sure the ID list shows up on the UI...
if (mpUI->IdPoolGroupBox->isHidden())
{
UpdateUI();
}
}
/** Populate the ID pool with the children of the given property */
void CGeneratePropertyNamesDialog::AddChildrenToIDPool(IProperty* pProperty, bool Recursive)
{
for (u32 ChildIdx = 0; ChildIdx < pProperty->NumChildren(); ChildIdx++)
{
IProperty* pChild = pProperty->ChildByIndex(ChildIdx);
// Skip children that already have valid property names
if (!pChild->HasAccurateName() && pChild->UsesNameMap())
{
AddToIDPool(pChild);
}
if (Recursive)
{
AddChildrenToIDPool(pChild, true);
}
}
}
/** Show event override */
void CGeneratePropertyNamesDialog::showEvent(QShowEvent*)
{
UpdateUI();
}
/** Close event override */ /** Close event override */
void CGeneratePropertyNamesDialog::closeEvent(QCloseEvent*) void CGeneratePropertyNamesDialog::closeEvent(QCloseEvent*)
{ {
@ -52,6 +103,7 @@ void CGeneratePropertyNamesDialog::closeEvent(QCloseEvent*)
{ {
CancelGeneration(); CancelGeneration();
} }
ClearIdPool();
} }
/** Add an item to the suffix list */ /** Add an item to the suffix list */
@ -75,6 +127,14 @@ void CGeneratePropertyNamesDialog::DeleteSuffix()
} }
} }
/** Clear the ID pool */
void CGeneratePropertyNamesDialog::ClearIdPool()
{
mIdPairs.clear();
mpUI->IdPoolList->clear();
UpdateUI();
}
/** Start name generation */ /** Start name generation */
void CGeneratePropertyNamesDialog::StartGeneration() void CGeneratePropertyNamesDialog::StartGeneration()
{ {
@ -100,7 +160,8 @@ void CGeneratePropertyNamesDialog::StartGeneration()
Params.MaxWords = mpUI->NumWordsSpinBox->value(); Params.MaxWords = mpUI->NumWordsSpinBox->value();
Params.Prefix = TO_TSTRING( mpUI->PrefixLineEdit->text() ); Params.Prefix = TO_TSTRING( mpUI->PrefixLineEdit->text() );
Params.Suffix = TO_TSTRING( mpUI->SuffixLineEdit->text() ); Params.Suffix = TO_TSTRING( mpUI->SuffixLineEdit->text() );
Params.UseUnderscores = mpUI->UseUnderscoresCheckBox->isChecked(); Params.Casing = mpUI->CasingComboBox->currentEnum();
Params.ValidIdPairs = mIdPairs.toStdVector();
Params.PrintToLog = mpUI->LogOutputCheckBox->isChecked(); Params.PrintToLog = mpUI->LogOutputCheckBox->isChecked();
// Run the task and configure ourselves so we can update correctly // Run the task and configure ourselves so we can update correctly
@ -287,8 +348,11 @@ void CGeneratePropertyNamesDialog::CheckForNewResults()
/** Updates the enabled status of various widgets */ /** Updates the enabled status of various widgets */
void CGeneratePropertyNamesDialog::UpdateUI() void CGeneratePropertyNamesDialog::UpdateUI()
{ {
mpUI->TypeSuffixesGroupBox->setEnabled( !mRunningNameGeneration );
mpUI->SettingsGroupBox->setEnabled( !mRunningNameGeneration ); mpUI->SettingsGroupBox->setEnabled( !mRunningNameGeneration );
mpUI->TypeSuffixesGroupBox->setEnabled( !mRunningNameGeneration );
mpUI->TypeSuffixesGroupBox->setHidden( !mIdPairs.isEmpty() );
mpUI->IdPoolGroupBox->setEnabled( !mRunningNameGeneration );
mpUI->IdPoolGroupBox->setHidden( mIdPairs.isEmpty() );
mpUI->StartButton->setEnabled( !mRunningNameGeneration ); mpUI->StartButton->setEnabled( !mRunningNameGeneration );
mpUI->CancelButton->setEnabled( mRunningNameGeneration && !mCanceledNameGeneration ); mpUI->CancelButton->setEnabled( mRunningNameGeneration && !mCanceledNameGeneration );

View File

@ -2,7 +2,10 @@
#define CGENERATEPROPERTYNAMESDIALOG_H #define CGENERATEPROPERTYNAMESDIALOG_H
#include "CProgressBarNotifier.h" #include "CProgressBarNotifier.h"
#include "Editor/Widgets/TEnumComboBox.h"
#include <Core/Resource/Script/Property/CPropertyNameGenerator.h> #include <Core/Resource/Script/Property/CPropertyNameGenerator.h>
#include <Core/Resource/Script/Property/IProperty.h>
#include <Core/Resource/Script/Property/CEnumProperty.h>
#include <QDialog> #include <QDialog>
#include <QFuture> #include <QFuture>
@ -11,6 +14,8 @@
#include <QTimer> #include <QTimer>
#include <QTreeWidgetItem> #include <QTreeWidgetItem>
using CNameCasingComboBox = TEnumComboBox<ENameCasing>;
namespace Ui { namespace Ui {
class CGeneratePropertyNamesDialog; class CGeneratePropertyNamesDialog;
} }
@ -29,6 +34,9 @@ class CGeneratePropertyNamesDialog : public QDialog
/** Progress notifier for updating the progress bar */ /** Progress notifier for updating the progress bar */
CProgressBarNotifier mNotifier; CProgressBarNotifier mNotifier;
/** List of ID/type pairs in the ID pool */
QVector<SPropertyIdTypePair> mIdPairs;
/** Future/future watcher for name generation task */ /** Future/future watcher for name generation task */
QFuture<void> mFuture; QFuture<void> mFuture;
QFutureWatcher<void> mFutureWatcher; QFutureWatcher<void> mFutureWatcher;
@ -52,7 +60,19 @@ public:
explicit CGeneratePropertyNamesDialog(QWidget *pParent = 0); explicit CGeneratePropertyNamesDialog(QWidget *pParent = 0);
~CGeneratePropertyNamesDialog(); ~CGeneratePropertyNamesDialog();
/** Add a property to the ID pool */
void AddToIDPool(IProperty* pProperty);
/** Populate the ID pool with the children of the given property */
void AddChildrenToIDPool(IProperty* pProperty, bool Recursive);
/** Populate the ID pool with enum values */
void AddEnumValuesToIDPool(CEnumProperty* pEnum);
public slots: public slots:
/** Show event override */
virtual void showEvent(QShowEvent* pEvent);
/** Close event override */ /** Close event override */
virtual void closeEvent(QCloseEvent* pEvent); virtual void closeEvent(QCloseEvent* pEvent);
@ -62,6 +82,9 @@ public slots:
/** Deletes an item from the suffix list */ /** Deletes an item from the suffix list */
void DeleteSuffix(); void DeleteSuffix();
/** Clear the ID pool */
void ClearIdPool();
/** Start name generation */ /** Start name generation */
void StartGeneration(); void StartGeneration();

View File

@ -17,7 +17,7 @@
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,3"> <layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,3">
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<widget class="QGroupBox" name="SettingsGroupBox"> <widget class="QGroupBox" name="SettingsGroupBox">
<property name="sizePolicy"> <property name="sizePolicy">
@ -66,15 +66,18 @@
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLineEdit" name="SuffixLineEdit"/> <widget class="QLineEdit" name="SuffixLineEdit"/>
</item> </item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Casing:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="CNameCasingComboBox" name="CasingComboBox"/>
</item>
</layout> </layout>
</item> </item>
<item>
<widget class="QCheckBox" name="UseUnderscoresCheckBox">
<property name="text">
<string>Use underscores</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="LogOutputCheckBox"> <widget class="QCheckBox" name="LogOutputCheckBox">
<property name="text"> <property name="text">
@ -232,6 +235,46 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="IdPoolGroupBox">
<property name="title">
<string>IDs</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QListWidget" name="IdPoolList">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="ClearIdPoolButton">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@ -382,6 +425,11 @@
<extends>QTreeWidget</extends> <extends>QTreeWidget</extends>
<header>Editor/Widgets/CCheckableTreeWidget.h</header> <header>Editor/Widgets/CCheckableTreeWidget.h</header>
</customwidget> </customwidget>
<customwidget>
<class>CNameCasingComboBox</class>
<extends>QComboBox</extends>
<header>Editor/CGeneratePropertyNamesDialog.h</header>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="Icons.qrc"/> <include location="Icons.qrc"/>

View File

@ -201,7 +201,8 @@ HEADERS += \
CProgressBarNotifier.h \ CProgressBarNotifier.h \
Widgets/CCheckableTreeWidgetItem.h \ Widgets/CCheckableTreeWidgetItem.h \
Widgets/CCheckableTreeWidget.h \ Widgets/CCheckableTreeWidget.h \
Undo/IEditPropertyCommand.h Undo/IEditPropertyCommand.h \
Widgets/TEnumComboBox.h
# Source Files # Source Files
SOURCES += \ SOURCES += \

View File

@ -28,6 +28,13 @@ CPropertyView::CPropertyView(QWidget *pParent)
mpEditTemplateAction = new QAction("Edit template", this); mpEditTemplateAction = new QAction("Edit template", this);
connect(mpEditTemplateAction, SIGNAL(triggered()), this, SLOT(EditPropertyTemplate())); connect(mpEditTemplateAction, SIGNAL(triggered()), this, SLOT(EditPropertyTemplate()));
mpGenNamesForPropertyAction = new QAction("Generate names for this property", this);
mpGenNamesForSiblingsAction = new QAction(this); // Text set in CreateContextMenu()
mpGenNamesForChildrenAction = new QAction(this); // Text set in CreateContextMenu()
connect(mpGenNamesForPropertyAction, SIGNAL(triggered(bool)), this, SLOT(GenerateNamesForProperty()));
connect(mpGenNamesForSiblingsAction, SIGNAL(triggered(bool)), this, SLOT(GenerateNamesForSiblings()));
connect(mpGenNamesForChildrenAction, SIGNAL(triggered(bool)), this, SLOT(GenerateNamesForChildren()));
connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex))); connect(this, SIGNAL(expanded(QModelIndex)), this, SLOT(SetPersistentEditors(QModelIndex)));
connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(edit(QModelIndex))); connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(edit(QModelIndex)));
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CreateContextMenu(QPoint))); connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CreateContextMenu(QPoint)));
@ -216,9 +223,9 @@ void CPropertyView::ClosePersistentEditors(const QModelIndex& rkIndex)
void CPropertyView::OnPropertyModified(const QModelIndex& rkIndex) void CPropertyView::OnPropertyModified(const QModelIndex& rkIndex)
{ {
// Check for a character resource being changed. If that's the case we need to remake the persistent editors. // Check for a character resource being changed. If that's the case we need to remake the persistent editors.
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, true); IProperty* pProperty = mpModel->PropertyForIndex(rkIndex, true);
if (pProp->Type() == EPropertyType::AnimationSet /*&& rkIndex.internalId() & 0x1*/) if (pProperty->Type() == EPropertyType::AnimationSet /*&& rkIndex.internalId() & 0x1*/)
{ {
ClosePersistentEditors(rkIndex); ClosePersistentEditors(rkIndex);
SetPersistentEditors(rkIndex); SetPersistentEditors(rkIndex);
@ -231,12 +238,12 @@ void CPropertyView::CreateContextMenu(const QPoint& rkPos)
if (Index.isValid() && Index.column() == 0) if (Index.isValid() && Index.column() == 0)
{ {
IProperty *pProp = mpModel->PropertyForIndex(Index, true); IProperty* pProperty = mpModel->PropertyForIndex(Index, true);
mpMenuProperty = pProp; mpMenuProperty = pProperty;
QMenu Menu; QMenu Menu;
if (!pProp->IsIntrinsic()) if (!pProperty->IsIntrinsic())
{ {
Menu.addAction(mpEditTemplateAction); Menu.addAction(mpEditTemplateAction);
} }
@ -246,6 +253,27 @@ void CPropertyView::CreateContextMenu(const QPoint& rkPos)
Menu.addAction(mpShowNameValidityAction); Menu.addAction(mpShowNameValidityAction);
} }
// Add options for generating property names
if (pProperty->UsesNameMap())
{
Menu.addSeparator();
Menu.addAction(mpGenNamesForPropertyAction);
if (!pProperty->IsRootParent())
{
QString TypeName = TO_QSTRING( pProperty->Parent()->RootArchetype()->Name() );
mpGenNamesForSiblingsAction->setText( QString("Generate names for %1 properties").arg(TypeName) );
Menu.addAction(mpGenNamesForSiblingsAction);
}
if (pProperty->Type() == EPropertyType::Struct && !pProperty->IsAtomic())
{
QString TypeName = TO_QSTRING( pProperty->RootArchetype()->Name() );
mpGenNamesForChildrenAction->setText( QString("Generate names for %1 properties").arg(TypeName) );
Menu.addAction(mpGenNamesForChildrenAction);
}
}
Menu.exec(viewport()->mapToGlobal(rkPos)); Menu.exec(viewport()->mapToGlobal(rkPos));
} }
} }
@ -260,3 +288,25 @@ void CPropertyView::EditPropertyTemplate()
CTemplateEditDialog Dialog(mpMenuProperty, mpEditor); CTemplateEditDialog Dialog(mpMenuProperty, mpEditor);
Dialog.exec(); Dialog.exec();
} }
void CPropertyView::GenerateNamesForProperty()
{
CGeneratePropertyNamesDialog* pDialog = mpEditor->NameGeneratorDialog();
pDialog->AddToIDPool(mpMenuProperty);
pDialog->show();
}
void CPropertyView::GenerateNamesForSiblings()
{
CGeneratePropertyNamesDialog* pDialog = mpEditor->NameGeneratorDialog();
pDialog->AddChildrenToIDPool(mpMenuProperty->Parent(), false);
pDialog->show();
}
void CPropertyView::GenerateNamesForChildren()
{
CGeneratePropertyNamesDialog* pDialog = mpEditor->NameGeneratorDialog();
pDialog->AddChildrenToIDPool(mpMenuProperty, false);
pDialog->show();
}

View File

@ -18,6 +18,9 @@ class CPropertyView : public QTreeView
IProperty *mpMenuProperty; IProperty *mpMenuProperty;
QAction *mpShowNameValidityAction; QAction *mpShowNameValidityAction;
QAction *mpEditTemplateAction; QAction *mpEditTemplateAction;
QAction *mpGenNamesForPropertyAction;
QAction *mpGenNamesForSiblingsAction;
QAction *mpGenNamesForChildrenAction;
public: public:
CPropertyView(QWidget *pParent = 0); CPropertyView(QWidget *pParent = 0);
@ -38,6 +41,10 @@ public slots:
void CreateContextMenu(const QPoint& rkPos); void CreateContextMenu(const QPoint& rkPos);
void ToggleShowNameValidity(bool ShouldShow); void ToggleShowNameValidity(bool ShouldShow);
void EditPropertyTemplate(); void EditPropertyTemplate();
void GenerateNamesForProperty();
void GenerateNamesForSiblings();
void GenerateNamesForChildren();
}; };
#endif // CPROPERTYVIEW_H #endif // CPROPERTYVIEW_H

View File

@ -0,0 +1,38 @@
#ifndef TENUMCOMBOBOX_H
#define TENUMCOMBOBOX_H
#include <QComboBox>
#include <codegen/EnumReflection.h>
/**
* Combo box subclass that auto-fills with an enum
* No custom signals because Q_OBJECT macro doesn't support templates
*/
template<typename EnumT>
class TEnumComboBox : public QComboBox
{
/** Vector forming an index -> enum mapping */
QVector<EnumT> mValueList;
public:
/** Constructor */
explicit TEnumComboBox(QWidget* pParent = 0)
: QComboBox(pParent)
{
for (TEnumReflection<EnumT>::CIterator It; It; ++It)
{
if (It.Value() != TEnumReflection<EnumT>::ErrorValue())
{
addItem( It.Name() );
mValueList << It.Value();
}
}
}
EnumT currentEnum() const
{
return mValueList[ currentIndex() ];
}
};
#endif // TENUMCOMBOBOX_H

View File

@ -91,6 +91,7 @@ public:
inline CGameArea* ActiveArea() const { return mpArea; } inline CGameArea* ActiveArea() const { return mpArea; }
inline EGame CurrentGame() const { return gpEdApp->CurrentGame(); } inline EGame CurrentGame() const { return gpEdApp->CurrentGame(); }
inline CLinkDialog* LinkDialog() const { return mpLinkDialog; } inline CLinkDialog* LinkDialog() const { return mpLinkDialog; }
inline CGeneratePropertyNamesDialog* NameGeneratorDialog() const { return mpGeneratePropertyNamesDialog; }
CResourceBrowser* ResourceBrowser() const; CResourceBrowser* ResourceBrowser() const;
CSceneViewport* Viewport() const; CSceneViewport* Viewport() const;

View File

@ -61,6 +61,9 @@
<property name="defaultDropAction"> <property name="defaultDropAction">
<enum>Qt::MoveAction</enum> <enum>Qt::MoveAction</enum>
</property> </property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior"> <property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum> <enum>QAbstractItemView::SelectItems</enum>
</property> </property>

View File

@ -74,13 +74,6 @@ public:
gpEditorStore->ConditionalSaveStore(); gpEditorStore->ConditionalSaveStore();
} }
for (int i = 0; i < (int) EGame::Max; i++)
{
CGameTemplate* pGame = NGameList::GetGameTemplate( (EGame) i );
if (pGame) pGame->Save();
}
return 0;
// Execute application // Execute application
App.InitEditor(); App.InitEditor();
return App.exec(); return App.exec();