diff --git a/Core/GDCore/IDE/WholeProjectRefactorer.cpp b/Core/GDCore/IDE/WholeProjectRefactorer.cpp index 44b9ac81e85d..bf55de2cc52c 100644 --- a/Core/GDCore/IDE/WholeProjectRefactorer.cpp +++ b/Core/GDCore/IDE/WholeProjectRefactorer.cpp @@ -1312,6 +1312,19 @@ bool WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties( return !invalidRequiredBehaviorProblems.empty(); } +void WholeProjectRefactorer::UpdateBehaviorNameInEventsBasedBehavior( + gd::Project &project, + const gd::EventsFunctionsExtension &eventsFunctionsExtension, + gd::EventsBasedBehavior &eventsBasedBehavior, + const gd::String &sourceBehaviorName) { + const EventBasedBehaviorBrowser eventBasedBehaviorExposer( + eventsFunctionsExtension, eventsBasedBehavior); + WholeProjectRefactorer::RenameEventsBasedBehavior( + project, eventsFunctionsExtension, eventsBasedBehavior, + sourceBehaviorName, eventsBasedBehavior.GetName(), + eventBasedBehaviorExposer); +} + void WholeProjectRefactorer::RenameEventsBasedBehavior( gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension, @@ -1324,10 +1337,22 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior( return; } auto &eventsBasedBehavior = eventsBasedBehaviors.Get(oldBehaviorName); + const WholeProjectBrowser projectBrowser; + WholeProjectRefactorer::RenameEventsBasedBehavior( + project, eventsFunctionsExtension, eventsBasedBehavior, oldBehaviorName, + newBehaviorName, projectBrowser); +} +void WholeProjectRefactorer::RenameEventsBasedBehavior( + gd::Project &project, + const gd::EventsFunctionsExtension &eventsFunctionsExtension, + const gd::EventsBasedBehavior &eventsBasedBehavior, + const gd::String &oldBehaviorName, + const gd::String &newBehaviorName, + const gd::ProjectBrowser &projectBrowser) { auto renameBehaviorEventsFunction = [&project, &eventsFunctionsExtension, &oldBehaviorName, - &newBehaviorName](const gd::EventsFunction &eventsFunction) { + &newBehaviorName, &projectBrowser](const gd::EventsFunction &eventsFunction) { if (eventsFunction.IsExpression()) { // Nothing to do, expressions are not including the name of the // behavior @@ -1341,12 +1366,12 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior( gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), newBehaviorName, eventsFunction.GetName())); - gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer); + projectBrowser.ExposeEvents(project, renamer); } }; auto renameBehaviorProperty = [&project, &eventsFunctionsExtension, - &oldBehaviorName, &newBehaviorName]( + &oldBehaviorName, &newBehaviorName, &projectBrowser]( const gd::NamedPropertyDescriptor &property) { gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( @@ -1357,7 +1382,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior( gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), newBehaviorName, EventsBasedBehavior::GetPropertyActionName(property.GetName()))); - gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer); + projectBrowser.ExposeEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( project, @@ -1367,7 +1392,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior( gd::PlatformExtension::GetBehaviorEventsFunctionFullType( eventsFunctionsExtension.GetName(), newBehaviorName, EventsBasedBehavior::GetPropertyConditionName(property.GetName()))); - gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer); + projectBrowser.ExposeEvents(project, conditionRenamer); // Nothing to do for expression, expressions are not including the name of // the behavior @@ -1375,7 +1400,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior( auto renameBehaviorSharedProperty = [&project, &eventsFunctionsExtension, &oldBehaviorName, - &newBehaviorName](const gd::NamedPropertyDescriptor &property) { + &newBehaviorName, &projectBrowser](const gd::NamedPropertyDescriptor &property) { gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer( project, gd::PlatformExtension::GetBehaviorEventsFunctionFullType( @@ -1386,7 +1411,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior( eventsFunctionsExtension.GetName(), newBehaviorName, EventsBasedBehavior::GetSharedPropertyActionName( property.GetName()))); - gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer); + projectBrowser.ExposeEvents(project, actionRenamer); gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer( @@ -1399,8 +1424,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior( eventsFunctionsExtension.GetName(), newBehaviorName, EventsBasedBehavior::GetSharedPropertyConditionName( property.GetName()))); - gd::ProjectBrowserHelper::ExposeProjectEvents(project, - conditionRenamer); + projectBrowser.ExposeEvents(project, conditionRenamer); // Nothing to do for expression, expressions are not including the name // of the behavior @@ -1435,13 +1459,12 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior( renameBehaviorSharedProperty(*property); } - const WholeProjectBrowser wholeProjectExposer; DoRenameBehavior(project, gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), oldBehaviorName), gd::PlatformExtension::GetBehaviorFullType( eventsFunctionsExtension.GetName(), newBehaviorName), - wholeProjectExposer); + projectBrowser); } void WholeProjectRefactorer::RenameEventsBasedObject( diff --git a/Core/GDCore/IDE/WholeProjectRefactorer.h b/Core/GDCore/IDE/WholeProjectRefactorer.h index 3670556e421d..a48ab7a28e60 100644 --- a/Core/GDCore/IDE/WholeProjectRefactorer.h +++ b/Core/GDCore/IDE/WholeProjectRefactorer.h @@ -121,7 +121,7 @@ class GD_CORE_API WholeProjectRefactorer { const gd::String& newName); /** - * \brief Refactor behavior events after the extension was placed in a new + * \brief Refactor behavior events after the behavior was placed in a new * extension. */ static void UpdateExtensionNameInEventsBasedBehavior( @@ -324,6 +324,15 @@ class GD_CORE_API WholeProjectRefactorer { const gd::String& oldBehaviorName, const gd::String& newBehaviorName); + /** + * \brief Refactor behavior events after the behavior was duplicated. + */ + static void UpdateBehaviorNameInEventsBasedBehavior( + gd::Project &project, + const gd::EventsFunctionsExtension &eventsFunctionsExtension, + gd::EventsBasedBehavior &eventsBasedBehavior, + const gd::String &sourceBehaviorName); + /** * \brief Refactor the project **before** an object is renamed. * @@ -654,6 +663,21 @@ class GD_CORE_API WholeProjectRefactorer { const gd::String& newName, const gd::ProjectBrowser& projectBrowser); + /** + * \brief Refactor the project **before** a behavior is renamed. + * + * \warning Do the renaming of the specified behavior after calling this. + * This is because the behavior is expected to have its old name for the + * refactoring. + */ + static void RenameEventsBasedBehavior( + gd::Project &project, + const gd::EventsFunctionsExtension &eventsFunctionsExtension, + const gd::EventsBasedBehavior &eventsBasedBehavior, + const gd::String &oldBehaviorName, + const gd::String &newBehaviorName, + const gd::ProjectBrowser &projectBrowser); + static void FindDependentBehaviorNames( const gd::Project& project, const gd::Object& object, diff --git a/Core/tests/WholeProjectRefactorer.cpp b/Core/tests/WholeProjectRefactorer.cpp index 17477a50a77c..268acab8ab38 100644 --- a/Core/tests/WholeProjectRefactorer.cpp +++ b/Core/tests/WholeProjectRefactorer.cpp @@ -2030,6 +2030,43 @@ TEST_CASE("WholeProjectRefactorer", "[common]") { } } + SECTION("Events-based behavior renamed in instructions scoped to one behavior") { + gd::Project project; + gd::Platform platform; + SetupProjectWithDummyPlatform(project, platform); + auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project); + + // A behavior is copied to the same extension. + auto &copiedBehavior = + eventsExtension.GetEventsBasedBehaviors().InsertNew( + "MyDuplicatedEventsBasedBehavior", 0); + copiedBehavior.SetFullName("My events based behavior"); + copiedBehavior.SetDescription("An events based behavior for test"); + copiedBehavior.SetObjectType("MyEventsExtension::MyEventsBasedObject"); + + // Add the copied events. + auto &behaviorEventsFunctions = copiedBehavior.GetEventsFunctions(); + auto &behaviorAction = behaviorEventsFunctions.InsertNewEventsFunction( + "MyBehaviorEventsFunction", 0); + SetupEvents(behaviorAction.GetEvents()); + + gd::WholeProjectRefactorer::UpdateBehaviorNameInEventsBasedBehavior( + project, eventsExtension, copiedBehavior, "MyEventsBasedBehavior"); + + // Check that events function calls in instructions have been renamed + REQUIRE(GetEventFirstActionType( + behaviorAction.GetEvents().GetEvent(BehaviorAction)) == + "MyEventsExtension::MyDuplicatedEventsBasedBehavior::MyBehaviorEventsFunction"); + + for (auto *eventsList : GetEventsLists(project)) { + // Check that events function calls in instructions have NOT been renamed + // outside of the copied behavior. + REQUIRE( + GetEventFirstActionType(eventsList->GetEvent(BehaviorAction)) == + "MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunction"); + } + } + SECTION("Events extension renamed in parameters") { gd::Project project; gd::Platform platform; diff --git a/GDevelop.js/Bindings/Bindings.idl b/GDevelop.js/Bindings/Bindings.idl index 0bca0c2031ef..3b59c5935d3b 100644 --- a/GDevelop.js/Bindings/Bindings.idl +++ b/GDevelop.js/Bindings/Bindings.idl @@ -2511,6 +2511,11 @@ interface WholeProjectRefactorer { [Const, Ref] EventsFunctionsExtension eventsFunctionsExtension, [Const] DOMString oldName, [Const] DOMString newName); + void STATIC_UpdateBehaviorNameInEventsBasedBehavior( + [Ref] Project project, + [Const, Ref] EventsFunctionsExtension eventsFunctionsExtension, + [Ref] EventsBasedBehavior eventsBasedBehavior, + [Const] DOMString sourceBehaviorName); void STATIC_RenameEventsBasedObject( [Ref] Project project, [Const, Ref] EventsFunctionsExtension eventsFunctionsExtension, diff --git a/GDevelop.js/Bindings/Wrapper.cpp b/GDevelop.js/Bindings/Wrapper.cpp index b392e001ea77..f848e71f0f6e 100644 --- a/GDevelop.js/Bindings/Wrapper.cpp +++ b/GDevelop.js/Bindings/Wrapper.cpp @@ -731,6 +731,7 @@ typedef ExtensionAndMetadata ExtensionAndExpressionMetadata; RenameEventsBasedBehaviorSharedProperty #define STATIC_RenameEventsBasedObjectProperty RenameEventsBasedObjectProperty #define STATIC_RenameEventsBasedBehavior RenameEventsBasedBehavior +#define STATIC_UpdateBehaviorNameInEventsBasedBehavior UpdateBehaviorNameInEventsBasedBehavior #define STATIC_RenameEventsBasedObject RenameEventsBasedObject #define STATIC_RenameLayout RenameLayout #define STATIC_RenameExternalLayout RenameExternalLayout diff --git a/GDevelop.js/types.d.ts b/GDevelop.js/types.d.ts index 0796b3e59a8a..3074101c6af9 100644 --- a/GDevelop.js/types.d.ts +++ b/GDevelop.js/types.d.ts @@ -1873,6 +1873,7 @@ export class WholeProjectRefactorer extends EmscriptenObject { static renameEventsBasedBehaviorSharedProperty(project: Project, eventsFunctionsExtension: EventsFunctionsExtension, eventsBasedBehavior: EventsBasedBehavior, oldName: string, newName: string): void; static renameEventsBasedObjectProperty(project: Project, eventsFunctionsExtension: EventsFunctionsExtension, eventsBasedObject: EventsBasedObject, oldName: string, newName: string): void; static renameEventsBasedBehavior(project: Project, eventsFunctionsExtension: EventsFunctionsExtension, oldName: string, newName: string): void; + static updateBehaviorNameInEventsBasedBehavior(project: Project, eventsFunctionsExtension: EventsFunctionsExtension, eventsBasedBehavior: EventsBasedBehavior, sourceBehaviorName: string): void; static renameEventsBasedObject(project: Project, eventsFunctionsExtension: EventsFunctionsExtension, oldName: string, newName: string): void; static renameLayout(project: Project, oldName: string, newName: string): void; static renameExternalLayout(project: Project, oldName: string, newName: string): void; diff --git a/GDevelop.js/types/gdwholeprojectrefactorer.js b/GDevelop.js/types/gdwholeprojectrefactorer.js index e7fb8df2ac43..5162ab2604fe 100644 --- a/GDevelop.js/types/gdwholeprojectrefactorer.js +++ b/GDevelop.js/types/gdwholeprojectrefactorer.js @@ -15,6 +15,7 @@ declare class gdWholeProjectRefactorer { static renameEventsBasedBehaviorSharedProperty(project: gdProject, eventsFunctionsExtension: gdEventsFunctionsExtension, eventsBasedBehavior: gdEventsBasedBehavior, oldName: string, newName: string): void; static renameEventsBasedObjectProperty(project: gdProject, eventsFunctionsExtension: gdEventsFunctionsExtension, eventsBasedObject: gdEventsBasedObject, oldName: string, newName: string): void; static renameEventsBasedBehavior(project: gdProject, eventsFunctionsExtension: gdEventsFunctionsExtension, oldName: string, newName: string): void; + static updateBehaviorNameInEventsBasedBehavior(project: gdProject, eventsFunctionsExtension: gdEventsFunctionsExtension, eventsBasedBehavior: gdEventsBasedBehavior, sourceBehaviorName: string): void; static renameEventsBasedObject(project: gdProject, eventsFunctionsExtension: gdEventsFunctionsExtension, oldName: string, newName: string): void; static renameLayout(project: gdProject, oldName: string, newName: string): void; static renameExternalLayout(project: gdProject, oldName: string, newName: string): void; diff --git a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js index 450632fd9d06..711083358d96 100644 --- a/newIDE/app/src/EventsFunctionsExtensionEditor/index.js +++ b/newIDE/app/src/EventsFunctionsExtensionEditor/index.js @@ -694,18 +694,26 @@ export default class EventsFunctionsExtensionEditor extends React.Component< _onEventsBasedBehaviorPasted = ( eventsBasedBehavior: gdEventsBasedBehavior, - sourceExtensionName: string + sourceExtensionName: string, + sourceEventsBasedBehaviorName: string, ) => { const { project, eventsFunctionsExtension } = this.props; - if (eventsFunctionsExtension.getName() === sourceExtensionName) { - return; + if (eventsFunctionsExtension.getName() !== sourceExtensionName) { + gd.WholeProjectRefactorer.updateExtensionNameInEventsBasedBehavior( + project, + eventsFunctionsExtension, + eventsBasedBehavior, + sourceExtensionName + ); + } + if (eventsBasedBehavior.getName() !== sourceEventsBasedBehaviorName) { + gd.WholeProjectRefactorer.updateBehaviorNameInEventsBasedBehavior( + project, + eventsFunctionsExtension, + eventsBasedBehavior, + sourceEventsBasedBehaviorName + ); } - gd.WholeProjectRefactorer.updateExtensionNameInEventsBasedBehavior( - project, - eventsFunctionsExtension, - eventsBasedBehavior, - sourceExtensionName - ); }; _onEventsBasedBehaviorRenamed = () => { diff --git a/newIDE/app/src/EventsFunctionsList/EventsBasedBehaviorTreeViewItemContent.js b/newIDE/app/src/EventsFunctionsList/EventsBasedBehaviorTreeViewItemContent.js index 6acecc61cabd..67ccbbd0e687 100644 --- a/newIDE/app/src/EventsFunctionsList/EventsBasedBehaviorTreeViewItemContent.js +++ b/newIDE/app/src/EventsFunctionsList/EventsBasedBehaviorTreeViewItemContent.js @@ -52,7 +52,8 @@ export type EventsBasedBehaviorCallbacks = {| ) => void, onEventsBasedBehaviorPasted: ( eventsBasedBehavior: gdEventsBasedBehavior, - sourceExtensionName: string + sourceExtensionName: string, + sourceEventsBasedBehaviorName: string ) => void, |}; @@ -284,16 +285,16 @@ export class EventsBasedBehaviorTreeViewItemContent const clipboardContent = Clipboard.get( EVENTS_BASED_BEHAVIOR_CLIPBOARD_KIND ); - const copiedEventsBasedBehavior = SafeExtractor.extractObjectProperty( + const sourceEventsBasedBehavior = SafeExtractor.extractObjectProperty( clipboardContent, 'eventsBasedBehavior' ); - const name = SafeExtractor.extractStringProperty(clipboardContent, 'name'); - if (!name || !copiedEventsBasedBehavior) return; + const sourceEventsBasedBehaviorName = SafeExtractor.extractStringProperty(clipboardContent, 'name'); + if (!sourceEventsBasedBehaviorName || !sourceEventsBasedBehavior) return; const { project, eventsBasedBehaviorsList } = this.props; - const newName = newNameGenerator(name, name => + const newName = newNameGenerator(sourceEventsBasedBehaviorName, name => eventsBasedBehaviorsList.has(name) ); @@ -304,7 +305,7 @@ export class EventsBasedBehaviorTreeViewItemContent unserializeFromJSObject( newEventsBasedBehavior, - copiedEventsBasedBehavior, + sourceEventsBasedBehavior, 'unserializeFrom', project ); @@ -317,7 +318,8 @@ export class EventsBasedBehaviorTreeViewItemContent if (sourceExtensionName) { this.props.onEventsBasedBehaviorPasted( newEventsBasedBehavior, - sourceExtensionName + sourceExtensionName, + sourceEventsBasedBehaviorName ); }