From b84f5b66f0bb875116937889a1e2e4f4c20da99b Mon Sep 17 00:00:00 2001
From: Paul Licameli <paul.licameli@audacityteam.org>
Date: Fri, 14 Jun 2019 00:50:21 -0400
Subject: [PATCH] CommandManager.cpp does not depend on EffectManager...

... some code lifted into BatchCommands.cpp to realize this.

It also doesn't depend on PluginManager, but that is not important for breaking
cycles.
---
 src/BatchCommands.cpp              | 41 ++++++++++++++++++++++++++++--
 src/BatchCommands.h                |  5 ++++
 src/commands/CommandManager.cpp    | 39 +++++++---------------------
 src/commands/CommandManager.h      | 11 +++++++-
 src/commands/ScreenshotCommand.cpp |  4 ++-
 src/toolbars/EditToolBar.cpp       |  4 ++-
 6 files changed, 69 insertions(+), 35 deletions(-)

diff --git a/src/BatchCommands.cpp b/src/BatchCommands.cpp
index a6f0ad835..e748cf268 100644
--- a/src/BatchCommands.cpp
+++ b/src/BatchCommands.cpp
@@ -749,6 +749,41 @@ bool MacroCommands::ApplyEffectCommand(
    return res;
 }
 
+bool MacroCommands::HandleTextualCommand( CommandManager &commandManager,
+   const CommandID & Str,
+   const CommandContext & context, CommandFlag flags, bool alwaysEnabled)
+{
+   switch ( commandManager.HandleTextualCommand(
+      Str, context, flags, alwaysEnabled) ) {
+   case CommandManager::CommandSuccess:
+      return true;
+   case CommandManager::CommandFailure:
+      return false;
+   case CommandManager::CommandNotFound:
+   default:
+      break;
+   }
+
+   // Not one of the singleton commands.
+   // We could/should try all the list-style commands.
+   // instead we only try the effects.
+   PluginManager & pm = PluginManager::Get();
+   EffectManager & em = EffectManager::Get();
+   const PluginDescriptor *plug = pm.GetFirstPlugin(PluginTypeEffect);
+   while (plug)
+   {
+      if (em.GetCommandIdentifier(plug->GetID()) == Str)
+      {
+         return PluginActions::DoEffect(
+            plug->GetID(), context,
+            PluginActions::kConfigured);
+      }
+      plug = pm.GetNextPlugin(PluginTypeEffect);
+   }
+
+   return false;
+}
+
 bool MacroCommands::ApplyCommand( const wxString &friendlyCommand,
    const CommandID & command, const wxString & params,
    CommandContext const * pContext)
@@ -778,7 +813,8 @@ bool MacroCommands::ApplyCommand( const wxString &friendlyCommand,
    AudacityProject *project = GetActiveProject();
    auto &manager = CommandManager::Get( *project );
    if( pContext ){
-      if( manager.HandleTextualCommand( command, *pContext, AlwaysEnabledFlag, true ) )
+      if( HandleTextualCommand(
+         manager, command, *pContext, AlwaysEnabledFlag, true ) )
          return true;
       pContext->Status( wxString::Format(
          _("Your batch command of %s was not recognized."), friendlyCommand ));
@@ -787,7 +823,8 @@ bool MacroCommands::ApplyCommand( const wxString &friendlyCommand,
    else
    {
       const CommandContext context(  *GetActiveProject() );
-      if( manager.HandleTextualCommand( command, context, AlwaysEnabledFlag, true ) )
+      if( HandleTextualCommand(
+         manager, command, context, AlwaysEnabledFlag, true ) )
          return true;
    }
 
diff --git a/src/BatchCommands.h b/src/BatchCommands.h
index 1dee0f74f..642840950 100644
--- a/src/BatchCommands.h
+++ b/src/BatchCommands.h
@@ -15,10 +15,12 @@
 #include <wx/defs.h>
 
 #include "export/Export.h"
+#include "commands/CommandFlag.h"
 
 class wxArrayString;
 class Effect;
 class CommandContext;
+class CommandManager;
 class AudacityProject;
 class wxArrayStringEx;
 
@@ -57,6 +59,9 @@ class MacroCommands final {
  public:
    bool ApplyMacro( const MacroCommandsCatalog &catalog,
       const wxString & filename = {});
+   static bool HandleTextualCommand( CommandManager &commandManager,
+      const CommandID & Str,
+      const CommandContext & context, CommandFlag flags, bool alwaysEnabled);
    bool ApplyCommand( const wxString &friendlyCommand,
       const CommandID & command, const wxString & params,
       CommandContext const * pContext=NULL );
diff --git a/src/commands/CommandManager.cpp b/src/commands/CommandManager.cpp
index babad283a..b29a65b8f 100644
--- a/src/commands/CommandManager.cpp
+++ b/src/commands/CommandManager.cpp
@@ -96,9 +96,7 @@ CommandManager.  It holds the callback for one command.
 
 #include "../Menus.h"
 
-#include "../PluginManager.h"
 #include "../Project.h"
-#include "../effects/EffectManager.h"
 #include "../widgets/LinkingHtmlWindow.h"
 #include "../widgets/AudacityMessageBox.h"
 #include "../widgets/HelpSystem.h"
@@ -1238,10 +1236,12 @@ bool CommandManager::HandleMenuID(int id, CommandFlag flags, bool alwaysEnabled)
 /// HandleTextualCommand() allows us a limitted version of script/batch
 /// behavior, since we can get from a string command name to the actual
 /// code to run.
-bool CommandManager::HandleTextualCommand(const CommandID & Str, const CommandContext & context, CommandFlag flags, bool alwaysEnabled)
+CommandManager::TextualCommandResult
+CommandManager::HandleTextualCommand(const CommandID & Str,
+   const CommandContext & context, CommandFlag flags, bool alwaysEnabled)
 {
    if( Str.empty() )
-      return false;
+      return CommandFailure;
    // Linear search for now...
    for (const auto &entry : mCommandList)
    {
@@ -1254,7 +1254,8 @@ bool CommandManager::HandleTextualCommand(const CommandID & Str, const CommandCo
             // sub-menu name)
             Str == entry->labelPrefix )
          {
-            return HandleCommandEntry( entry.get(), flags, alwaysEnabled);
+            return HandleCommandEntry( entry.get(), flags, alwaysEnabled)
+               ? CommandSuccess : CommandFailure;
          }
       }
       else
@@ -1262,34 +1263,12 @@ bool CommandManager::HandleTextualCommand(const CommandID & Str, const CommandCo
          // Handle multis too...
          if( Str == entry->name )
          {
-            return HandleCommandEntry( entry.get(), flags, alwaysEnabled);
+            return HandleCommandEntry( entry.get(), flags, alwaysEnabled)
+               ? CommandSuccess : CommandFailure;
          }
       }
    }
-   // Not one of the singleton commands.
-   // We could/should try all the list-style commands.
-   // instead we only try the effects.
-   AudacityProject * proj = GetActiveProject();
-   if( !proj )
-   {
-      return false;
-   }
-
-   PluginManager & pm = PluginManager::Get();
-   EffectManager & em = EffectManager::Get();
-   const PluginDescriptor *plug = pm.GetFirstPlugin(PluginTypeEffect);
-   while (plug)
-   {
-      if (em.GetCommandIdentifier(plug->GetID()) == Str)
-      {
-         return PluginActions::DoEffect(
-            plug->GetID(), context,
-            PluginActions::kConfigured);
-      }
-      plug = pm.GetNextPlugin(PluginTypeEffect);
-   }
-
-   return false;
+   return CommandNotFound;
 }
 
 void CommandManager::GetCategories(wxArrayString &cats)
diff --git a/src/commands/CommandManager.h b/src/commands/CommandManager.h
index 986175e35..28009f171 100644
--- a/src/commands/CommandManager.h
+++ b/src/commands/CommandManager.h
@@ -244,7 +244,16 @@ class AUDACITY_DLL_API CommandManager final
    // Lyrics and MixerTrackCluster classes use it.
    bool FilterKeyEvent(AudacityProject *project, const wxKeyEvent & evt, bool permit = false);
    bool HandleMenuID(int id, CommandFlag flags, bool alwaysEnabled);
-   bool HandleTextualCommand(const CommandID & Str, const CommandContext & context, CommandFlag flags, bool alwaysEnabled);
+
+   enum TextualCommandResult {
+      CommandFailure,
+      CommandSuccess,
+      CommandNotFound
+   };
+
+   TextualCommandResult
+   HandleTextualCommand(const CommandID & Str,
+      const CommandContext & context, CommandFlag flags, bool alwaysEnabled);
 
    //
    // Accessing
diff --git a/src/commands/ScreenshotCommand.cpp b/src/commands/ScreenshotCommand.cpp
index 51aa901a8..4706a8c7f 100644
--- a/src/commands/ScreenshotCommand.cpp
+++ b/src/commands/ScreenshotCommand.cpp
@@ -32,6 +32,7 @@ small calculations of rectangles.
 #include <wx/valgen.h>
 
 #include "../AdornedRulerPanel.h"
+#include "../BatchCommands.h"
 #include "../TrackPanel.h"
 #include "../effects/Effect.h"
 #include "../toolbars/ToolManager.h"
@@ -454,7 +455,8 @@ void ScreenshotCommand::CapturePreferences(
       gPrefs->Flush();
       CommandID Command{ wxT("Preferences") };
       const CommandContext projectContext( *pProject );
-      if( !commandManager.HandleTextualCommand( Command, projectContext, AlwaysEnabledFlag, true ) )
+      if( !MacroCommands::HandleTextualCommand( commandManager,
+         Command, projectContext, AlwaysEnabledFlag, true ) )
       {
          // using GET in a log message for devs' eyes only
          wxLogDebug("Command %s not found", Command.GET() );
diff --git a/src/toolbars/EditToolBar.cpp b/src/toolbars/EditToolBar.cpp
index 098ee19e7..3bec6f26f 100644
--- a/src/toolbars/EditToolBar.cpp
+++ b/src/toolbars/EditToolBar.cpp
@@ -49,6 +49,7 @@
 #endif
 
 #include "../AllThemeResources.h"
+#include "../BatchCommands.h"
 #include "../ImageManipulation.h"
 #include "../Menus.h"
 #include "../Prefs.h"
@@ -299,7 +300,8 @@ void EditToolBar::OnButton(wxCommandEvent &event)
 
    auto flags = MenuManager::Get(*p).GetUpdateFlags();
    const CommandContext context( *p );
-   cm.HandleTextualCommand(EditToolbarButtonList[id].commandName, context, flags, false);
+   MacroCommands::HandleTextualCommand( cm,
+      EditToolbarButtonList[id].commandName, context, flags, false);
 }
 
 static RegisteredToolbarFactory factory{ EditBarID,