/* * GDevelop Core * Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights * reserved. This project is released under the MIT License. */ #include "WholeProjectRefactorer.h" #include "GDCore/Extensions/Metadata/BehaviorMetadata.h" #include "GDCore/Extensions/Metadata/MetadataProvider.h" #include "GDCore/Extensions/PlatformExtension.h" #include "GDCore/IDE/DependenciesAnalyzer.h" #include "GDCore/IDE/EventBasedBehaviorBrowser.h" #include "GDCore/IDE/Events/ArbitraryEventsWorker.h" #include "GDCore/IDE/Events/BehaviorTypeRenamer.h" #include "GDCore/IDE/Events/CustomObjectTypeRenamer.h" #include "GDCore/IDE/Events/EventsBehaviorRenamer.h" #include "GDCore/IDE/Events/EventsRefactorer.h" #include "GDCore/IDE/Events/ExpressionsParameterMover.h" #include "GDCore/IDE/Events/ExpressionsRenamer.h" #include "GDCore/IDE/Events/InstructionsParameterMover.h" #include "GDCore/IDE/Events/InstructionsTypeRenamer.h" #include "GDCore/IDE/Events/LinkEventTargetRenamer.h" #include "GDCore/IDE/Events/ProjectElementRenamer.h" #include "GDCore/IDE/EventsFunctionTools.h" #include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h" #include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h" #include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h" #include "GDCore/IDE/Project/ArbitraryObjectsWorker.h" #include "GDCore/IDE/Project/BehaviorObjectTypeRenamer.h" #include "GDCore/IDE/Project/BehaviorsSharedDataBehaviorTypeRenamer.h" #include "GDCore/IDE/Project/FunctionParameterBehaviorTypeRenamer.h" #include "GDCore/IDE/Project/FunctionParameterObjectTypeRenamer.h" #include "GDCore/IDE/Project/RequiredBehaviorRenamer.h" #include "GDCore/IDE/ProjectBrowser.h" #include "GDCore/IDE/ProjectBrowserHelper.h" #include "GDCore/IDE/UnfilledRequiredBehaviorPropertyProblem.h" #include "GDCore/IDE/WholeProjectBrowser.h" #include "GDCore/Project/Behavior.h" #include "GDCore/Project/BehaviorConfigurationContainer.h" #include "GDCore/Project/EventsBasedBehavior.h" #include "GDCore/Project/EventsBasedObject.h" #include "GDCore/Project/EventsFunctionsExtension.h" #include "GDCore/Project/ExternalEvents.h" #include "GDCore/Project/ExternalLayout.h" #include "GDCore/Project/InitialInstancesContainer.h" #include "GDCore/Project/Layout.h" #include "GDCore/Project/ObjectGroup.h" #include "GDCore/Project/Project.h" #include "GDCore/String.h" #include "GDCore/Tools/Log.h" namespace gd { // By convention, the first parameter of an events based behavior method is // always called "Object". const gd::String WholeProjectRefactorer::behaviorObjectParameterName = "Object"; // By convention, the first parameter of an events based object method is // always called "Object". const gd::String WholeProjectRefactorer::parentObjectParameterName = "Object"; std::set WholeProjectRefactorer::GetAllObjectTypesUsingEventsBasedBehavior( const gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedBehavior &eventsBasedBehavior) { std::set allTypes; const gd::String behaviorType = gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName()); auto addTypesOfObjectsIn = [&allTypes, &behaviorType](const gd::ObjectsContainer &objectsContainer) { for (auto &object : objectsContainer.GetObjects()) { for (auto &behavior : object->GetAllBehaviorContents()) { if (behavior.second->GetTypeName() == behaviorType) { allTypes.insert(object->GetType()); } } } }; addTypesOfObjectsIn(project); for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) { auto &layout = project.GetLayout(s); addTypesOfObjectsIn(layout); } return allTypes; } void WholeProjectRefactorer::EnsureBehaviorEventsFunctionsProperParameters( const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedBehavior &eventsBasedBehavior) { for (auto &eventsFunction : eventsBasedBehavior.GetEventsFunctions().GetInternalVector()) { auto ¶meters = eventsFunction->GetParameters(); while (parameters.size() < 2) { gd::ParameterMetadata newParameter; parameters.push_back(newParameter); } parameters[0] .SetType("object") .SetName(behaviorObjectParameterName) .SetDescription("Object") .SetExtraInfo(eventsBasedBehavior.GetObjectType()); parameters[1] .SetType("behavior") .SetName("Behavior") .SetDescription("Behavior") .SetExtraInfo(gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName())); } } void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters( const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedObject &eventsBasedObject) { for (auto &eventsFunction : eventsBasedObject.GetEventsFunctions().GetInternalVector()) { auto ¶meters = eventsFunction->GetParameters(); while (parameters.size() < 1) { gd::ParameterMetadata newParameter; parameters.push_back(newParameter); } parameters[0] .SetType("object") .SetName(parentObjectParameterName) .SetDescription("Object") .SetExtraInfo(gd::PlatformExtension::GetObjectFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName())); } } void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, gd::EventsBasedBehavior &eventsBasedBehavior, const gd::String &sourceExtensionName) { const EventBasedBehaviorBrowser eventBasedBehaviorExposer( eventsBasedBehavior); WholeProjectRefactorer::RenameEventsFunctionsExtension( project, eventsFunctionsExtension, sourceExtensionName, eventsFunctionsExtension.GetName(), eventBasedBehaviorExposer); } void WholeProjectRefactorer::RenameEventsFunctionsExtension( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::String &oldName, const gd::String &newName) { const WholeProjectBrowser wholeProjectExposer; RenameEventsFunctionsExtension(project, eventsFunctionsExtension, oldName, newName, wholeProjectExposer); } void WholeProjectRefactorer::RenameEventsFunctionsExtension( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::String &oldName, const gd::String &newName, const gd::ProjectBrowser &projectBrowser) { auto renameEventsFunction = [&project, &oldName, &newName, &projectBrowser]( const gd::EventsFunction &eventsFunction) { DoRenameEventsFunction(project, eventsFunction, gd::PlatformExtension::GetEventsFunctionFullType( oldName, eventsFunction.GetName()), gd::PlatformExtension::GetEventsFunctionFullType( newName, eventsFunction.GetName()), projectBrowser); }; auto renameBehaviorEventsFunction = [&project, &oldName, &newName, &projectBrowser](const gd::EventsBasedBehavior &eventsBasedBehavior, const gd::EventsFunction &eventsFunction) { if (eventsFunction.IsExpression()) { // Nothing to do, expressions are not including the extension name } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( oldName, eventsBasedBehavior.GetName(), eventsFunction.GetName()), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( newName, eventsBasedBehavior.GetName(), eventsFunction.GetName())); projectBrowser.ExposeEvents(project, renamer); } }; auto renameBehaviorPropertyFunctions = [&project, &oldName, &newName, &projectBrowser](const gd::EventsBasedBehavior &eventsBasedBehavior, const gd::NamedPropertyDescriptor &property) { gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( oldName, eventsBasedBehavior.GetName(), gd::EventsBasedBehavior::GetPropertyActionName( property.GetName())), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( newName, eventsBasedBehavior.GetName(), gd::EventsBasedBehavior::GetPropertyActionName( property.GetName()))); projectBrowser.ExposeEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( oldName, eventsBasedBehavior.GetName(), gd::EventsBasedBehavior::GetPropertyConditionName( property.GetName())), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( newName, eventsBasedBehavior.GetName(), gd::EventsBasedBehavior::GetPropertyConditionName( property.GetName()))); projectBrowser.ExposeEvents(project, conditionRenamer); // Nothing to do for expressions, expressions are not including the // extension name }; auto renameBehaviorSharedPropertyFunctions = [&project, &oldName, &newName, &projectBrowser](const gd::EventsBasedBehavior &eventsBasedBehavior, const gd::NamedPropertyDescriptor &property) { gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( oldName, eventsBasedBehavior.GetName(), gd::EventsBasedBehavior::GetSharedPropertyActionName( property.GetName())), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( newName, eventsBasedBehavior.GetName(), gd::EventsBasedBehavior::GetSharedPropertyActionName( property.GetName()))); projectBrowser.ExposeEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( oldName, eventsBasedBehavior.GetName(), gd::EventsBasedBehavior::GetSharedPropertyConditionName( property.GetName())), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( newName, eventsBasedBehavior.GetName(), gd::EventsBasedBehavior::GetSharedPropertyConditionName( property.GetName()))); projectBrowser.ExposeEvents(project, conditionRenamer); // Nothing to do for expressions, expressions are not including the // extension name }; auto renameObjectEventsFunction = [&project, &oldName, &newName, &projectBrowser](const gd::EventsBasedObject &eventsBasedObject, const gd::EventsFunction &eventsFunction) { if (eventsFunction.IsExpression()) { // Nothing to do, expressions are not including the extension name } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetObjectEventsFunctionFullType( oldName, eventsBasedObject.GetName(), eventsFunction.GetName()), gd::PlatformExtension::GetObjectEventsFunctionFullType( newName, eventsBasedObject.GetName(), eventsFunction.GetName())); projectBrowser.ExposeEvents(project, renamer); } }; auto renameObjectPropertyFunctions = [&project, &oldName, &newName, &projectBrowser](const gd::EventsBasedObject &eventsBasedObject, const gd::NamedPropertyDescriptor &property) { gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetObjectEventsFunctionFullType( oldName, eventsBasedObject.GetName(), gd::EventsBasedObject::GetPropertyActionName( property.GetName())), gd::PlatformExtension::GetObjectEventsFunctionFullType( newName, eventsBasedObject.GetName(), gd::EventsBasedObject::GetPropertyActionName( property.GetName()))); projectBrowser.ExposeEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetObjectEventsFunctionFullType( oldName, eventsBasedObject.GetName(), gd::EventsBasedObject::GetPropertyConditionName( property.GetName())), gd::PlatformExtension::GetObjectEventsFunctionFullType( newName, eventsBasedObject.GetName(), gd::EventsBasedObject::GetPropertyConditionName( property.GetName()))); projectBrowser.ExposeEvents(project, conditionRenamer); // Nothing to do for expressions, expressions are not including the // extension name }; // Order is important: we first rename the expressions then the instructions, // to avoid being unable to fetch the metadata (the types of parameters) of // instructions after they are renamed. // Free expressions for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) { if (eventsFunction->IsExpression()) { renameEventsFunction(*eventsFunction); } } // Behavior expressions for (auto &&eventsBasedBehavior : eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) { auto &behaviorEventsFunctions = eventsBasedBehavior->GetEventsFunctions(); for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) { if (eventsFunction->IsExpression()) { renameBehaviorEventsFunction(*eventsBasedBehavior, *eventsFunction); } } } // Free instructions for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) { if (eventsFunction->IsAction() || eventsFunction->IsCondition()) { renameEventsFunction(*eventsFunction); } } // Behavior instructions for (auto &&eventsBasedBehavior : eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) { auto &behaviorEventsFunctions = eventsBasedBehavior->GetEventsFunctions(); for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) { if (eventsFunction->IsAction() || eventsFunction->IsCondition()) { renameBehaviorEventsFunction(*eventsBasedBehavior, *eventsFunction); } } } // Behavior properties for (auto &&eventsBasedBehavior : eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) { for (auto &&propertyDescriptor : eventsBasedBehavior->GetPropertyDescriptors().GetInternalVector()) { renameBehaviorPropertyFunctions(*eventsBasedBehavior, *propertyDescriptor); } for (auto &&propertyDescriptor : eventsBasedBehavior->GetSharedPropertyDescriptors() .GetInternalVector()) { renameBehaviorSharedPropertyFunctions(*eventsBasedBehavior, *propertyDescriptor); } } // Object instructions for (auto &&eventsBasedObject : eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) { auto &objectEventsFunctions = eventsBasedObject->GetEventsFunctions(); for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) { if (eventsFunction->IsAction() || eventsFunction->IsCondition()) { renameObjectEventsFunction(*eventsBasedObject, *eventsFunction); } } } // Object properties for (auto &&eventsBasedObject : eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) { auto &objectProperties = eventsBasedObject->GetPropertyDescriptors(); for (auto &&propertyDescriptor : objectProperties.GetInternalVector()) { renameObjectPropertyFunctions(*eventsBasedObject, *propertyDescriptor); } } // Finally, rename behaviors used in objects for (auto &&eventsBasedBehavior : eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) { DoRenameBehavior(project, gd::PlatformExtension::GetBehaviorFullType( oldName, eventsBasedBehavior->GetName()), gd::PlatformExtension::GetBehaviorFullType( newName, eventsBasedBehavior->GetName()), projectBrowser); } // Finally, rename custom objects type for (auto &&eventsBasedObject : eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) { DoRenameObject(project, gd::PlatformExtension::GetObjectFullType( oldName, eventsBasedObject->GetName()), gd::PlatformExtension::GetObjectFullType( newName, eventsBasedObject->GetName()), projectBrowser); } } void WholeProjectRefactorer::RenameEventsFunction( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::String &oldFunctionName, const gd::String &newFunctionName) { if (!eventsFunctionsExtension.HasEventsFunctionNamed(oldFunctionName)) return; const gd::EventsFunction &eventsFunction = eventsFunctionsExtension.GetEventsFunction(oldFunctionName); const WholeProjectBrowser wholeProjectExposer; DoRenameEventsFunction( project, eventsFunction, gd::PlatformExtension::GetEventsFunctionFullType( eventsFunctionsExtension.GetName(), oldFunctionName), gd::PlatformExtension::GetEventsFunctionFullType( eventsFunctionsExtension.GetName(), newFunctionName), wholeProjectExposer); if (eventsFunction.GetFunctionType() == gd::EventsFunction::ExpressionAndCondition) { for (auto &&otherFunction : eventsFunctionsExtension.GetInternalVector()) { if (otherFunction->GetFunctionType() == gd::EventsFunction::ActionWithOperator && otherFunction->GetGetterName() == oldFunctionName) { otherFunction->SetGetterName(newFunctionName); } } } } void WholeProjectRefactorer::RenameBehaviorEventsFunction( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedBehavior &eventsBasedBehavior, const gd::String &oldFunctionName, const gd::String &newFunctionName) { auto &eventsFunctions = eventsBasedBehavior.GetEventsFunctions(); if (!eventsFunctions.HasEventsFunctionNamed(oldFunctionName)) return; const gd::EventsFunction &eventsFunction = eventsFunctions.GetEventsFunction(oldFunctionName); // Order is important: we first rename the expressions then the instructions, // to avoid being unable to fetch the metadata (the types of parameters) of // instructions after they are renamed. if (eventsFunction.IsExpression()) { gd::ExpressionsRenamer renamer = gd::ExpressionsRenamer(project.GetCurrentPlatform()); renamer.SetReplacedBehaviorExpression( gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName()), oldFunctionName, newFunctionName); gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer); } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), oldFunctionName), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), newFunctionName)); gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer); } if (eventsFunction.GetFunctionType() == gd::EventsFunction::ExpressionAndCondition) { for (auto &&otherFunction : eventsBasedBehavior.GetEventsFunctions().GetInternalVector()) { if (otherFunction->GetFunctionType() == gd::EventsFunction::ActionWithOperator && otherFunction->GetGetterName() == oldFunctionName) { otherFunction->SetGetterName(newFunctionName); } } } } void WholeProjectRefactorer::RenameObjectEventsFunction( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedObject &eventsBasedObject, const gd::String &oldFunctionName, const gd::String &newFunctionName) { auto &eventsFunctions = eventsBasedObject.GetEventsFunctions(); if (!eventsFunctions.HasEventsFunctionNamed(oldFunctionName)) return; const gd::EventsFunction &eventsFunction = eventsFunctions.GetEventsFunction(oldFunctionName); if (eventsFunction.IsExpression()) { gd::ExpressionsRenamer renamer = gd::ExpressionsRenamer(project.GetCurrentPlatform()); renamer.SetReplacedObjectExpression( gd::PlatformExtension::GetObjectFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName()), oldFunctionName, newFunctionName); gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer); } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName(), oldFunctionName), gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName(), newFunctionName)); gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer); } if (eventsFunction.GetFunctionType() == gd::EventsFunction::ExpressionAndCondition) { for (auto &&otherFunction : eventsBasedObject.GetEventsFunctions().GetInternalVector()) { if (otherFunction->GetFunctionType() == gd::EventsFunction::ActionWithOperator && otherFunction->GetGetterName() == oldFunctionName) { otherFunction->SetGetterName(newFunctionName); } } } } void WholeProjectRefactorer::MoveEventsFunctionParameter( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::String &functionName, std::size_t oldIndex, std::size_t newIndex) { if (!eventsFunctionsExtension.HasEventsFunctionNamed(functionName)) return; const gd::EventsFunction &eventsFunction = eventsFunctionsExtension.GetEventsFunction(functionName); const gd::String &eventsFunctionType = gd::PlatformExtension::GetEventsFunctionFullType( eventsFunctionsExtension.GetName(), functionName); if (eventsFunction.IsExpression()) { gd::ExpressionsParameterMover mover = gd::ExpressionsParameterMover(project.GetCurrentPlatform()); mover.SetFreeExpressionMovedParameter(eventsFunctionType, oldIndex, newIndex); gd::ProjectBrowserHelper::ExposeProjectEvents(project, mover); } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { const int operatorIndexOffset = eventsFunction.IsExpression() ? 2 : 0; gd::InstructionsParameterMover mover = gd::InstructionsParameterMover( project, eventsFunctionType, oldIndex + operatorIndexOffset, newIndex + operatorIndexOffset); gd::ProjectBrowserHelper::ExposeProjectEvents(project, mover); } } void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedBehavior &eventsBasedBehavior, const gd::String &functionName, std::size_t oldIndex, std::size_t newIndex) { auto &eventsFunctions = eventsBasedBehavior.GetEventsFunctions(); if (!eventsFunctions.HasEventsFunctionNamed(functionName)) return; const gd::EventsFunction &eventsFunction = eventsFunctions.GetEventsFunction(functionName); const gd::String &eventsFunctionType = gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), functionName); if (eventsFunction.IsExpression()) { gd::ExpressionsParameterMover mover = gd::ExpressionsParameterMover(project.GetCurrentPlatform()); mover.SetBehaviorExpressionMovedParameter( gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName()), functionName, oldIndex, newIndex); gd::ProjectBrowserHelper::ExposeProjectEvents(project, mover); } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { const int operatorIndexOffset = eventsFunction.IsExpression() ? 2 : 0; gd::InstructionsParameterMover mover = gd::InstructionsParameterMover( project, eventsFunctionType, oldIndex + operatorIndexOffset, newIndex + operatorIndexOffset); gd::ProjectBrowserHelper::ExposeProjectEvents(project, mover); } } void WholeProjectRefactorer::MoveObjectEventsFunctionParameter( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedObject &eventsBasedObject, const gd::String &functionName, std::size_t oldIndex, std::size_t newIndex) { auto &eventsFunctions = eventsBasedObject.GetEventsFunctions(); if (!eventsFunctions.HasEventsFunctionNamed(functionName)) return; const gd::EventsFunction &eventsFunction = eventsFunctions.GetEventsFunction(functionName); const gd::String &eventsFunctionType = gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName(), functionName); if (eventsFunction.IsExpression()) { gd::ExpressionsParameterMover mover = gd::ExpressionsParameterMover(project.GetCurrentPlatform()); mover.SetObjectExpressionMovedParameter( gd::PlatformExtension::GetObjectFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName()), functionName, oldIndex, newIndex); gd::ProjectBrowserHelper::ExposeProjectEvents(project, mover); } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { const int operatorIndexOffset = eventsFunction.IsExpression() ? 2 : 0; gd::InstructionsParameterMover mover = gd::InstructionsParameterMover( project, eventsFunctionType, oldIndex + operatorIndexOffset, newIndex + operatorIndexOffset); gd::ProjectBrowserHelper::ExposeProjectEvents(project, mover); } } void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedBehavior &eventsBasedBehavior, const gd::String &oldPropertyName, const gd::String &newPropertyName) { auto &properties = eventsBasedBehavior.GetPropertyDescriptors(); if (!properties.Has(oldPropertyName)) return; if (properties.Get(oldPropertyName).GetType() == "Behavior") { // This is a property representing another behavior that must exist on the // object. // This other "required behavior" uses the property name, that is about to // change, as its name. // So we must change all reference to this name in the events of the // behavior functions. gd::EventsBehaviorRenamer behaviorRenamer(project.GetCurrentPlatform(), behaviorObjectParameterName, oldPropertyName, newPropertyName); gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents( project, eventsBasedBehavior, behaviorRenamer); } else { // Properties that represent primitive values will be used through // their related actions/conditions/expressions. Rename these. // Order is important: we first rename the expressions then the // instructions, to avoid being unable to fetch the metadata (the types of // parameters) of instructions after they are renamed. gd::ExpressionsRenamer expressionRenamer = gd::ExpressionsRenamer(project.GetCurrentPlatform()); expressionRenamer.SetReplacedBehaviorExpression( gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName()), EventsBasedBehavior::GetPropertyExpressionName(oldPropertyName), EventsBasedBehavior::GetPropertyExpressionName(newPropertyName)); gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer); gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), EventsBasedBehavior::GetPropertyActionName(oldPropertyName)), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), EventsBasedBehavior::GetPropertyActionName(newPropertyName))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), EventsBasedBehavior::GetPropertyConditionName(oldPropertyName)), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), EventsBasedBehavior::GetPropertyConditionName(newPropertyName))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer); } } void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedBehavior &eventsBasedBehavior, const gd::String &oldPropertyName, const gd::String &newPropertyName) { auto &properties = eventsBasedBehavior.GetPropertyDescriptors(); if (!properties.Has(oldPropertyName)) return; if (properties.Get(oldPropertyName).GetType() == "Behavior") { // This is a property representing another behavior that must exist on the // object. // This other "required behavior" uses the property name, that is about to // change, as its name. // So we must change all reference to this name in the events of the // behavior functions. gd::EventsBehaviorRenamer behaviorRenamer(project.GetCurrentPlatform(), behaviorObjectParameterName, oldPropertyName, newPropertyName); gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents( project, eventsBasedBehavior, behaviorRenamer); } else { // Properties that represent primitive values will be used through // their related actions/conditions/expressions. Rename these. // Order is important: we first rename the expressions then the // instructions, to avoid being unable to fetch the metadata (the types of // parameters) of instructions after they are renamed. gd::ExpressionsRenamer expressionRenamer = gd::ExpressionsRenamer(project.GetCurrentPlatform()); expressionRenamer.SetReplacedBehaviorExpression( gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName()), EventsBasedBehavior::GetSharedPropertyExpressionName(oldPropertyName), EventsBasedBehavior::GetSharedPropertyExpressionName(newPropertyName)); gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer); gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), EventsBasedBehavior::GetSharedPropertyActionName(oldPropertyName)), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), EventsBasedBehavior::GetSharedPropertyActionName(newPropertyName))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), EventsBasedBehavior::GetSharedPropertyConditionName( oldPropertyName)), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(), EventsBasedBehavior::GetSharedPropertyConditionName( newPropertyName))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer); } } void WholeProjectRefactorer::RenameEventsBasedObjectProperty( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::EventsBasedObject &eventsBasedObject, const gd::String &oldPropertyName, const gd::String &newPropertyName) { auto &properties = eventsBasedObject.GetPropertyDescriptors(); if (!properties.Has(oldPropertyName)) return; // Properties that represent primitive values will be used through // their related actions/conditions/expressions. Rename these. // Order is important: we first rename the expressions then the // instructions, to avoid being unable to fetch the metadata (the types of // parameters) of instructions after they are renamed. gd::ExpressionsRenamer expressionRenamer = gd::ExpressionsRenamer(project.GetCurrentPlatform()); expressionRenamer.SetReplacedObjectExpression( gd::PlatformExtension::GetObjectFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName()), EventsBasedObject::GetPropertyExpressionName(oldPropertyName), EventsBasedObject::GetPropertyExpressionName(newPropertyName)); gd::ProjectBrowserHelper::ExposeProjectEvents(project, expressionRenamer); gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName(), EventsBasedObject::GetPropertyActionName(oldPropertyName)), gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName(), EventsBasedObject::GetPropertyActionName(newPropertyName))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName(), EventsBasedObject::GetPropertyConditionName(oldPropertyName)), gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), eventsBasedObject.GetName(), EventsBasedObject::GetPropertyConditionName(newPropertyName))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer); } void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors( gd::Project &project, gd::Object &object, const gd::String &behaviorType, const gd::String &behaviorName) { if (object.AddNewBehavior(project, behaviorType, behaviorName) == nullptr) { // The behavior type/metadata can't be found. return; }; AddRequiredBehaviorsFor(project, object, behaviorName); } void WholeProjectRefactorer::AddRequiredBehaviorsFor( gd::Project &project, gd::Object &object, const gd::String &behaviorName) { if (!object.HasBehaviorNamed(behaviorName)) { return; }; gd::Behavior &behavior = object.GetBehavior(behaviorName); const gd::Platform &platform = project.GetCurrentPlatform(); const gd::BehaviorMetadata &behaviorMetadata = MetadataProvider::GetBehaviorMetadata(platform, behavior.GetTypeName()); if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) { // Should not happen because the behavior was added successfully (so its // metadata are valid) - but double check anyway and bail out if the // behavior metadata are invalid. return; } for (auto const &keyValue : behavior.GetProperties()) { const gd::String &propertyName = keyValue.first; const gd::PropertyDescriptor &property = keyValue.second; if (property.GetType().LowerCase() == "behavior") { const std::vector &extraInfo = property.GetExtraInfo(); if (extraInfo.size() == 0) { // very unlikely continue; } const gd::String &requiredBehaviorType = extraInfo.at(0); const auto behaviorNames = WholeProjectRefactorer::GetBehaviorsWithType( object, requiredBehaviorType); const gd::String *defaultBehaviorName = nullptr; if (behaviorNames.size() == 0) { const gd::BehaviorMetadata &requiredBehaviorMetadata = MetadataProvider::GetBehaviorMetadata(platform, requiredBehaviorType); const gd::String &requiredBehaviorName = requiredBehaviorMetadata.GetDefaultName(); WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors( project, object, requiredBehaviorType, requiredBehaviorName); defaultBehaviorName = &requiredBehaviorName; } else { defaultBehaviorName = &behaviorNames.at(0); } behavior.UpdateProperty(propertyName, *defaultBehaviorName); } } } std::vector WholeProjectRefactorer::GetBehaviorsWithType(const gd::Object &object, const gd::String &type) { std::vector behaviors; for (auto &behaviorName : object.GetAllBehaviorNames()) { const gd::Behavior &behavior = object.GetBehavior(behaviorName); if (behavior.GetTypeName() == type) { behaviors.push_back(behaviorName); } } return behaviors; } std::vector WholeProjectRefactorer::FindDependentBehaviorNames( const gd::Project &project, const gd::Object &object, const gd::String &behaviorName) { std::unordered_set dependentBehaviorNames; WholeProjectRefactorer::FindDependentBehaviorNames( project, object, behaviorName, dependentBehaviorNames); std::vector results; results.insert(results.end(), dependentBehaviorNames.begin(), dependentBehaviorNames.end()); return results; } void WholeProjectRefactorer::FindDependentBehaviorNames( const gd::Project &project, const gd::Object &object, const gd::String &behaviorName, std::unordered_set &dependentBehaviorNames) { const gd::Platform &platform = project.GetCurrentPlatform(); for (auto const &objectBehaviorName : object.GetAllBehaviorNames()) { const gd::Behavior &behavior = object.GetBehavior(objectBehaviorName); const auto &behaviorMetadata = MetadataProvider::GetBehaviorMetadata(platform, behavior.GetTypeName()); if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) { // Ignore this behavior as it's unknown. continue; } for (auto const &keyValue : behavior.GetProperties()) { const gd::String &propertyName = keyValue.first; const gd::PropertyDescriptor &property = keyValue.second; if (property.GetType().LowerCase() == "behavior" && property.GetValue() == behaviorName && dependentBehaviorNames.find(objectBehaviorName) == dependentBehaviorNames.end()) { dependentBehaviorNames.insert(objectBehaviorName); WholeProjectRefactorer::FindDependentBehaviorNames( project, object, objectBehaviorName, dependentBehaviorNames); } } } }; std::vector WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties( const gd::Project &project) { std::vector invalidRequiredBehaviorProperties; auto findInvalidRequiredBehaviorPropertiesInObjects = [&project, &invalidRequiredBehaviorProperties]( const std::vector> &objectsList) { for (auto &object : objectsList) { for (auto &behaviorKeyValuePair : object->GetAllBehaviorContents()) { gd::Behavior &behavior = *behaviorKeyValuePair.second; for (auto const &keyValue : behavior.GetProperties()) { const gd::String &propertyName = keyValue.first; const gd::PropertyDescriptor &property = keyValue.second; if (property.GetType().LowerCase() != "behavior") { continue; } const gd::String &requiredBehaviorName = property.GetValue(); const std::vector &extraInfo = property.GetExtraInfo(); if (extraInfo.size() == 0) { // very unlikely continue; } const gd::String &requiredBehaviorType = extraInfo.at(0); if (requiredBehaviorName == "" || !object->HasBehaviorNamed(requiredBehaviorName) || object->GetBehavior(requiredBehaviorName).GetTypeName() != requiredBehaviorType) { auto problem = UnfilledRequiredBehaviorPropertyProblem( project, *object, behavior, propertyName, requiredBehaviorType); invalidRequiredBehaviorProperties.push_back(problem); } } } } }; // Find in global objects findInvalidRequiredBehaviorPropertiesInObjects(project.GetObjects()); // Find in layout objects. for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) { const gd::Layout &layout = project.GetLayout(i); findInvalidRequiredBehaviorPropertiesInObjects(layout.GetObjects()); } return invalidRequiredBehaviorProperties; } bool WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties( gd::Project &project) { const auto &invalidRequiredBehaviorProblems = FindInvalidRequiredBehaviorProperties(project); for (const auto &problem : invalidRequiredBehaviorProblems) { auto &object = problem.GetSourceObject(); auto suggestedBehaviorNames = GetBehaviorsWithType(object, problem.GetExpectedBehaviorTypeName()); auto &behavior = problem.GetSourceBehaviorContent(); if (suggestedBehaviorNames.empty()) { // No matching behavior on the object. // Add required behaviors on the object. auto &expectedBehaviorMetadata = MetadataProvider::GetBehaviorMetadata( project.GetCurrentPlatform(), problem.GetExpectedBehaviorTypeName()); if (MetadataProvider::IsBadBehaviorMetadata(expectedBehaviorMetadata)) { continue; } const gd::String &newBehaviorName = expectedBehaviorMetadata.GetDefaultName(); AddBehaviorAndRequiredBehaviors(project, object, problem.GetExpectedBehaviorTypeName(), newBehaviorName); behavior.UpdateProperty(problem.GetSourcePropertyName(), newBehaviorName); } else { // There is a matching behavior on the object use it by default. behavior.UpdateProperty( problem.GetSourcePropertyName(), // It's unlikely the object has 2 behaviors of the same type. suggestedBehaviorNames[0]); } } return !invalidRequiredBehaviorProblems.empty(); } void WholeProjectRefactorer::RenameEventsBasedBehavior( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::String &oldBehaviorName, const gd::String &newBehaviorName) { auto &eventsBasedBehaviors = eventsFunctionsExtension.GetEventsBasedBehaviors(); if (!eventsBasedBehaviors.Has(oldBehaviorName)) { gd::LogWarning("Warning, " + oldBehaviorName + " was not found when calling RenameEventsBasedBehavior."); return; } auto &eventsBasedBehavior = eventsBasedBehaviors.Get(oldBehaviorName); auto renameBehaviorEventsFunction = [&project, &eventsFunctionsExtension, &oldBehaviorName, &newBehaviorName](const gd::EventsFunction &eventsFunction) { if (eventsFunction.IsExpression()) { // Nothing to do, expressions are not including the name of the // behavior } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), oldBehaviorName, eventsFunction.GetName()), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), newBehaviorName, eventsFunction.GetName())); gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer); } }; auto renameBehaviorProperty = [&project, &eventsFunctionsExtension, &oldBehaviorName, &newBehaviorName]( const gd::NamedPropertyDescriptor &property) { gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), oldBehaviorName, EventsBasedBehavior::GetPropertyActionName(property.GetName())), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), newBehaviorName, EventsBasedBehavior::GetPropertyActionName(property.GetName()))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), oldBehaviorName, EventsBasedBehavior::GetPropertyConditionName(property.GetName())), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), newBehaviorName, EventsBasedBehavior::GetPropertyConditionName(property.GetName()))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer); // Nothing to do for expression, expressions are not including the name of // the behavior }; auto renameBehaviorSharedProperty = [&project, &eventsFunctionsExtension, &oldBehaviorName, &newBehaviorName](const gd::NamedPropertyDescriptor &property) { gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), oldBehaviorName, EventsBasedBehavior::GetSharedPropertyActionName( property.GetName())), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), newBehaviorName, EventsBasedBehavior::GetSharedPropertyActionName( property.GetName()))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), oldBehaviorName, EventsBasedBehavior::GetSharedPropertyConditionName( property.GetName())), gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), newBehaviorName, EventsBasedBehavior::GetSharedPropertyConditionName( property.GetName()))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer); // Nothing to do for expression, expressions are not including the name // of the behavior }; // Order is important: we first rename the expressions then the instructions, // to avoid being unable to fetch the metadata (the types of parameters) of // instructions after they are renamed. auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions(); // Behavior expressions for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) { if (eventsFunction->IsExpression()) { renameBehaviorEventsFunction(*eventsFunction); } } // Behavior instructions for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) { if (eventsFunction->IsAction() || eventsFunction->IsCondition()) { renameBehaviorEventsFunction(*eventsFunction); } } // Behavior properties for (auto &&property : eventsBasedBehavior.GetPropertyDescriptors().GetInternalVector()) { renameBehaviorProperty(*property); } for (auto &&property : eventsBasedBehavior.GetSharedPropertyDescriptors().GetInternalVector()) { renameBehaviorSharedProperty(*property); } const WholeProjectBrowser wholeProjectExposer; DoRenameBehavior(project, gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), oldBehaviorName), gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), newBehaviorName), wholeProjectExposer); } void WholeProjectRefactorer::RenameEventsBasedObject( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, const gd::String &oldObjectName, const gd::String &newObjectName) { auto &eventsBasedObjects = eventsFunctionsExtension.GetEventsBasedObjects(); if (!eventsBasedObjects.Has(oldObjectName)) { gd::LogWarning("Warning, " + oldObjectName + " was not found when calling RenameEventsBasedObject."); return; } auto &eventsBasedObject = eventsBasedObjects.Get(oldObjectName); auto renameObjectEventsFunction = [&project, &eventsFunctionsExtension, &oldObjectName, &newObjectName](const gd::EventsFunction &eventsFunction) { if (eventsFunction.IsExpression()) { // Nothing to do, expressions are not including the name of the // object } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), oldObjectName, eventsFunction.GetName()), gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), newObjectName, eventsFunction.GetName())); gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer); } }; auto renameObjectProperty = [&project, &eventsFunctionsExtension, &oldObjectName, &newObjectName]( const gd::NamedPropertyDescriptor &property) { gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), oldObjectName, EventsBasedObject::GetPropertyActionName(property.GetName())), gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), newObjectName, EventsBasedObject::GetPropertyActionName(property.GetName()))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), oldObjectName, EventsBasedObject::GetPropertyConditionName(property.GetName())), gd::PlatformExtension::GetObjectEventsFunctionFullType( eventsFunctionsExtension.GetName(), newObjectName, EventsBasedObject::GetPropertyConditionName(property.GetName()))); gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer); // Nothing to do for expression, expressions are not including the name of // the object }; // Order is important: we first rename the expressions then the instructions, // to avoid being unable to fetch the metadata (the types of parameters) of // instructions after they are renamed. auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions(); // Object expressions for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) { if (eventsFunction->IsExpression()) { renameObjectEventsFunction(*eventsFunction); } } // Object instructions for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) { if (eventsFunction->IsAction() || eventsFunction->IsCondition()) { renameObjectEventsFunction(*eventsFunction); } } // Object properties auto &properties = eventsBasedObject.GetPropertyDescriptors(); for (auto &&property : properties.GetInternalVector()) { renameObjectProperty(*property); } const WholeProjectBrowser wholeProjectExposer; DoRenameObject(project, gd::PlatformExtension::GetObjectFullType( eventsFunctionsExtension.GetName(), oldObjectName), gd::PlatformExtension::GetObjectFullType( eventsFunctionsExtension.GetName(), newObjectName), wholeProjectExposer); } void WholeProjectRefactorer::DoRenameEventsFunction( gd::Project &project, const gd::EventsFunction &eventsFunction, const gd::String &oldFullType, const gd::String &newFullType, const gd::ProjectBrowser &projectBrowser) { // Order is important: we first rename the expressions then the instructions, // to avoid being unable to fetch the metadata (the types of parameters) of // instructions after they are renamed. if (eventsFunction.IsExpression()) { gd::ExpressionsRenamer renamer = gd::ExpressionsRenamer(project.GetCurrentPlatform()); renamer.SetReplacedFreeExpression(oldFullType, newFullType); projectBrowser.ExposeEvents(project, renamer); } if (eventsFunction.IsAction() || eventsFunction.IsCondition()) { gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(project, oldFullType, newFullType); projectBrowser.ExposeEvents(project, renamer); } } void WholeProjectRefactorer::DoRenameBehavior( gd::Project &project, const gd::String &oldBehaviorType, const gd::String &newBehaviorType, const gd::ProjectBrowser &projectBrowser) { // Rename behavior in required behavior properties auto requiredBehaviorRenamer = gd::RequiredBehaviorRenamer(oldBehaviorType, newBehaviorType); projectBrowser.ExposeEventBasedBehaviors(project, requiredBehaviorRenamer); // Rename behavior in objects lists. auto behaviorTypeRenamer = gd::BehaviorTypeRenamer(oldBehaviorType, newBehaviorType); projectBrowser.ExposeObjects(project, behaviorTypeRenamer); // Rename behavior in layout behavior shared data. auto sharedDataBehaviorTypeRenamer = gd::BehaviorsSharedDataBehaviorTypeRenamer(oldBehaviorType, newBehaviorType); projectBrowser.ExposeBehaviorSharedDatas(project, sharedDataBehaviorTypeRenamer); // Rename in parameters of (free/behavior) events function auto behaviorParameterRenamer = gd::FunctionParameterBehaviorTypeRenamer( oldBehaviorType, newBehaviorType); projectBrowser.ExposeFunctions(project, behaviorParameterRenamer); } void WholeProjectRefactorer::DoRenameObject( gd::Project &project, const gd::String &oldObjectType, const gd::String &newObjectType, const gd::ProjectBrowser &projectBrowser) { // Rename object type in objects lists. auto customObjectTypeRenamer = gd::CustomObjectTypeRenamer(oldObjectType, newObjectType); projectBrowser.ExposeObjects(project, customObjectTypeRenamer); // Rename in behaviors object type. auto behaviorObjectTypeRenamer = gd::BehaviorObjectTypeRenamer(oldObjectType, newObjectType); projectBrowser.ExposeEventBasedBehaviors(project, behaviorObjectTypeRenamer); // Rename in parameters of (free/behavior) events function auto objectParameterRenamer = gd::FunctionParameterObjectTypeRenamer(oldObjectType, newObjectType); projectBrowser.ExposeFunctions(project, objectParameterRenamer); } void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout( gd::Project &project, gd::Layout &layout, const gd::String &objectName, bool isObjectGroup, bool removeEventsAndGroups) { // Remove object in the current layout if (removeEventsAndGroups) { gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(), project, layout, layout.GetEvents(), objectName); } if (!isObjectGroup) { // Object groups can't have instances or be in other // groups if (removeEventsAndGroups) { for (std::size_t g = 0; g < layout.GetObjectGroups().size(); ++g) { if (layout.GetObjectGroups()[g].Find(objectName)) layout.GetObjectGroups()[g].RemoveObject(objectName); } } layout.GetInitialInstances().RemoveInitialInstancesOfObject(objectName); } // Remove object in external events if (removeEventsAndGroups) { for (auto &externalEventsName : GetAssociatedExternalEvents(project, layout.GetName())) { auto &externalEvents = project.GetExternalEvents(externalEventsName); gd::EventsRefactorer::RemoveObjectInEvents( project.GetCurrentPlatform(), project, layout, externalEvents.GetEvents(), objectName); } } // Remove object in external layouts if (!isObjectGroup) { // Object groups can't have instances std::vector externalLayoutsNames = GetAssociatedExternalLayouts(project, layout); for (gd::String name : externalLayoutsNames) { auto &externalLayout = project.GetExternalLayout(name); externalLayout.GetInitialInstances().RemoveInitialInstancesOfObject( objectName); } } } void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout( gd::Project &project, gd::Layout &layout, const gd::String &oldName, const gd::String &newName, bool isObjectGroup) { if (oldName == newName || newName.empty() || oldName.empty()) return; // Rename object in the current layout gd::EventsRefactorer::RenameObjectInEvents( project.GetCurrentPlatform(), project, layout, layout.GetEvents(), oldName, newName); if (!isObjectGroup) { // Object groups can't have instances or be in other // groups layout.GetInitialInstances().RenameInstancesOfObject(oldName, newName); for (std::size_t g = 0; g < layout.GetObjectGroups().size(); ++g) { layout.GetObjectGroups()[g].RenameObject(oldName, newName); } } // Rename object in external events for (auto &externalEventsName : GetAssociatedExternalEvents(project, layout.GetName())) { auto &externalEvents = project.GetExternalEvents(externalEventsName); gd::EventsRefactorer::RenameObjectInEvents( project.GetCurrentPlatform(), project, layout, externalEvents.GetEvents(), oldName, newName); } // Rename object in external layouts if (!isObjectGroup) { // Object groups can't have instances std::vector externalLayoutsNames = GetAssociatedExternalLayouts(project, layout); for (gd::String name : externalLayoutsNames) { auto &externalLayout = project.GetExternalLayout(name); externalLayout.GetInitialInstances().RenameInstancesOfObject(oldName, newName); } } } void WholeProjectRefactorer::RenameLayout(gd::Project &project, const gd::String &oldName, const gd::String &newName) { if (oldName == newName || newName.empty() || oldName.empty()) return; gd::ProjectElementRenamer projectElementRenamer( project.GetCurrentPlatform(), "sceneName", oldName, newName); gd::ProjectBrowserHelper::ExposeProjectEvents(project, projectElementRenamer); for (gd::String externalLayoutName : GetAssociatedExternalLayouts(project, oldName)) { auto &externalLayout = project.GetExternalLayout(externalLayoutName); externalLayout.SetAssociatedLayout(newName); } for (gd::String externalEventsName : GetAssociatedExternalEvents(project, oldName)) { auto &externalEvents = project.GetExternalEvents(externalEventsName); externalEvents.SetAssociatedLayout(newName); } gd::LinkEventTargetRenamer linkEventTargetRenamer( project.GetCurrentPlatform(), oldName, newName); gd::ProjectBrowserHelper::ExposeProjectEvents(project, linkEventTargetRenamer); } void WholeProjectRefactorer::RenameExternalLayout(gd::Project &project, const gd::String &oldName, const gd::String &newName) { if (oldName == newName || newName.empty() || oldName.empty()) return; gd::ProjectElementRenamer projectElementRenamer( project.GetCurrentPlatform(), "externalLayoutName", oldName, newName); gd::ProjectBrowserHelper::ExposeProjectEvents(project, projectElementRenamer); } void WholeProjectRefactorer::RenameExternalEvents(gd::Project &project, const gd::String &oldName, const gd::String &newName) { if (oldName == newName || newName.empty() || oldName.empty()) return; gd::LinkEventTargetRenamer linkEventTargetRenamer( project.GetCurrentPlatform(), oldName, newName); gd::ProjectBrowserHelper::ExposeProjectEvents(project, linkEventTargetRenamer); } void WholeProjectRefactorer::RenameLayer(gd::Project &project, gd::Layout &layout, const gd::String &oldName, const gd::String &newName) { if (oldName == newName || newName.empty() || oldName.empty()) return; gd::ProjectElementRenamer projectElementRenamer(project.GetCurrentPlatform(), "layer", oldName, newName); gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout, projectElementRenamer); } void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project, gd::Layout &layout, gd::Layer &layer, const gd::String &oldName, const gd::String &newName) { if (oldName == newName || newName.empty() || oldName.empty()) return; gd::ProjectElementRenamer projectElementRenamer( project.GetCurrentPlatform(), "layerEffectName", oldName, newName); projectElementRenamer.SetLayerConstraint(layer.GetName()); gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout, projectElementRenamer); } void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project, gd::Layout &layout, gd::Object &object, const gd::String &oldName, const gd::String &newName) { if (oldName == newName || newName.empty() || oldName.empty()) return; gd::ProjectElementRenamer projectElementRenamer( project.GetCurrentPlatform(), "objectAnimationName", oldName, newName); projectElementRenamer.SetObjectConstraint(object.GetName()); gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout, projectElementRenamer); } void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project, gd::Layout &layout, gd::Object &object, const gd::String &oldName, const gd::String &newName) { if (oldName == newName || newName.empty() || oldName.empty()) return; gd::ProjectElementRenamer projectElementRenamer( project.GetCurrentPlatform(), "objectPointName", oldName, newName); projectElementRenamer.SetObjectConstraint(object.GetName()); gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout, projectElementRenamer); } void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project, gd::Layout &layout, gd::Object &object, const gd::String &oldName, const gd::String &newName) { if (oldName == newName || newName.empty() || oldName.empty()) return; gd::ProjectElementRenamer projectElementRenamer( project.GetCurrentPlatform(), "objectEffectName", oldName, newName); projectElementRenamer.SetObjectConstraint(object.GetName()); gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout, projectElementRenamer); } void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsBasedObject( gd::Project &project, gd::EventsBasedObject &eventsBasedObject, gd::ObjectsContainer &globalObjectsContainer, gd::ObjectsContainer &objectsContainer, const gd::String &objectName, bool isObjectGroup, bool removeEventsAndGroups) { for (auto &functionUniquePtr : eventsBasedObject.GetEventsFunctions().GetInternalVector()) { auto function = functionUniquePtr.get(); WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction( project, *function, globalObjectsContainer, objectsContainer, objectName, isObjectGroup, isObjectGroup); } } void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction( gd::Project &project, gd::EventsFunction &eventsFunction, gd::ObjectsContainer &globalObjectsContainer, gd::ObjectsContainer &objectsContainer, const gd::String &objectName, bool isObjectGroup, bool removeEventsAndGroups) { // Remove object in the current layout if (removeEventsAndGroups) { gd::EventsRefactorer::RemoveObjectInEvents( project.GetCurrentPlatform(), globalObjectsContainer, objectsContainer, eventsFunction.GetEvents(), objectName); } if (!isObjectGroup) { // Object groups can't be in other groups if (removeEventsAndGroups) { for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size(); ++g) { if (eventsFunction.GetObjectGroups()[g].Find(objectName)) eventsFunction.GetObjectGroups()[g].RemoveObject(objectName); } } } } void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject( gd::Project &project, gd::ObjectsContainer &globalObjectsContainer, gd::EventsBasedObject &eventsBasedObject, const gd::String &oldName, const gd::String &newName, bool isObjectGroup) { for (auto &functionUniquePtr : eventsBasedObject.GetEventsFunctions().GetInternalVector()) { auto *function = functionUniquePtr.get(); WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction( project, *function, globalObjectsContainer, eventsBasedObject, oldName, newName, isObjectGroup); } } void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction( gd::Project &project, gd::EventsFunction &eventsFunction, gd::ObjectsContainer &globalObjectsContainer, gd::ObjectsContainer &objectsContainer, const gd::String &oldName, const gd::String &newName, bool isObjectGroup) { // Rename object in the current layout gd::EventsRefactorer::RenameObjectInEvents( project.GetCurrentPlatform(), globalObjectsContainer, objectsContainer, eventsFunction.GetEvents(), oldName, newName); if (!isObjectGroup) { // Object groups can't be in other groups for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size(); ++g) { eventsFunction.GetObjectGroups()[g].RenameObject(oldName, newName); } } } void WholeProjectRefactorer::GlobalObjectOrGroupRenamed( gd::Project &project, const gd::String &oldName, const gd::String &newName, bool isObjectGroup) { if (!isObjectGroup) { // Object groups can't be in other groups for (std::size_t g = 0; g < project.GetObjectGroups().size(); ++g) { project.GetObjectGroups()[g].RenameObject(oldName, newName); } } for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) { gd::Layout &layout = project.GetLayout(i); if (layout.HasObjectNamed(oldName)) continue; ObjectOrGroupRenamedInLayout(project, layout, oldName, newName, isObjectGroup); } } void WholeProjectRefactorer::GlobalObjectOrGroupRemoved( gd::Project &project, const gd::String &objectName, bool isObjectGroup, bool removeEventsAndGroups) { if (!isObjectGroup) { // Object groups can't be in other groups if (removeEventsAndGroups) { for (std::size_t g = 0; g < project.GetObjectGroups().size(); ++g) { project.GetObjectGroups()[g].RemoveObject(objectName); } } } for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) { gd::Layout &layout = project.GetLayout(i); if (layout.HasObjectNamed(objectName)) continue; ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup, removeEventsAndGroups); } } void WholeProjectRefactorer::RemoveLayer(gd::Project &project, gd::Layout &layout, const gd::String &layerName) { if (layerName.empty()) return; layout.GetInitialInstances().RemoveAllInstancesOnLayer(layerName); std::vector externalLayoutsNames = GetAssociatedExternalLayouts(project, layout); for (gd::String name : externalLayoutsNames) { auto &externalLayout = project.GetExternalLayout(name); externalLayout.GetInitialInstances().RemoveAllInstancesOnLayer(layerName); } } void WholeProjectRefactorer::MergeLayers(gd::Project &project, gd::Layout &layout, const gd::String &originLayerName, const gd::String &targetLayerName) { if (originLayerName == targetLayerName || originLayerName.empty()) return; layout.GetInitialInstances().MoveInstancesToLayer(originLayerName, targetLayerName); std::vector externalLayoutsNames = GetAssociatedExternalLayouts(project, layout); for (gd::String name : externalLayoutsNames) { auto &externalLayout = project.GetExternalLayout(name); externalLayout.GetInitialInstances().MoveInstancesToLayer(originLayerName, targetLayerName); } } size_t WholeProjectRefactorer::GetLayoutAndExternalLayoutLayerInstancesCount( gd::Project &project, gd::Layout &layout, const gd::String &layerName) { size_t count = layout.GetInitialInstances().GetLayerInstancesCount(layerName); std::vector externalLayoutsNames = GetAssociatedExternalLayouts(project, layout); for (gd::String name : externalLayoutsNames) { auto &externalLayout = project.GetExternalLayout(name); count += externalLayout.GetInitialInstances().GetLayerInstancesCount(layerName); } return count; } std::vector WholeProjectRefactorer::GetAssociatedExternalLayouts(gd::Project &project, gd::Layout &layout) { return GetAssociatedExternalLayouts(project, layout.GetName()); } std::vector WholeProjectRefactorer::GetAssociatedExternalLayouts( gd::Project &project, const gd::String &layoutName) { std::vector results; for (std::size_t i = 0; i < project.GetExternalLayoutsCount(); ++i) { auto &externalLayout = project.GetExternalLayout(i); if (externalLayout.GetAssociatedLayout() == layoutName) { results.push_back(externalLayout.GetName()); } } return results; } std::vector WholeProjectRefactorer::GetAssociatedExternalEvents( gd::Project &project, const gd::String &layoutName) { std::vector results; for (std::size_t i = 0; i < project.GetExternalEventsCount(); ++i) { auto &externalEvents = project.GetExternalEvents(i); if (externalEvents.GetAssociatedLayout() == layoutName) { results.push_back(externalEvents.GetName()); } } return results; } } // namespace gd