Update of /cvsroot/audacity/audacity-src/src/commands
In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv10717/src/commands

Modified Files:
        BatchEvalCommand.h Command.h CommandBuilder.cpp 
        CommandBuilder.h CommandHandler.cpp CommandHandler.h 
        CommandMisc.h CommandTargets.h DebugPrintCommand.h 
        ResponseQueue.cpp ScreenshotCommand.cpp ScreenshotCommand.h 
        ScriptCommandRelay.cpp ScriptCommandRelay.h 
Added Files:
        BatchEvalCommand.cpp CommandDirectory.cpp CommandDirectory.h 
        ExecMenuCommand.cpp ExecMenuCommand.h GetAllMenuCommands.cpp 
        GetAllMenuCommands.h Validators.h 
Log Message:
Added a command (ExecMenuCommand) for calling menu commands.

Improved the way commands are built - there's now a command directory which
means adding new commands is much easier, and it should be more efficient
(command signature doesn't need to be rebuilt every time a command is used).

Added a command (GetAllMenuCommands) for getting a list of available menu
commands, currently output on the status channel. 

Moved command validators out into a separate header. Split out some other files
to minimise build dependencies.

Mod-script-pipe: fixed bug with long reponses.
Mod-script-pipe: adjust version to match Audacity version.

Update test script with timing and some subroutines for calling particular
commands.

Update Makefile.in with new objects.

Added files are:
commands/BatchEvalCommand.cpp
commands/CommandDirectory.cpp
commands/ExecMenuCommand.cpp
commands/GetAllMenuCommand.cpp
commands/CommandDirectory.h
commands/ExecMenuCommand.h
commands/GetAllMenuCommands.h
commands/Validators.h

Numerous miscellaneous bits of extra documentation, header pruning and
formatting changes.

Added a target for sending messages back to the script, and set it to be used
as the default target for commands received from the script.




Index: CommandTargets.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/CommandTargets.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- CommandTargets.h    3 Jul 2009 00:00:12 -0000       1.2
+++ CommandTargets.h    26 Jul 2009 21:57:03 -0000      1.3
@@ -23,6 +23,7 @@
 #include <wx/msgdlg.h>
 #include <wx/statusbr.h>
 #include "../widgets/ProgressDialog.h"
+#include "../commands/ResponseQueue.h"
 
 /// Interface for objects that can receive command progress information
 class CommandProgressTarget
@@ -97,6 +98,50 @@
    }
 };
 
+/// Adds messages to a response queue (to be sent back to a script)
+class ResponseQueueTarget : public CommandMessageTarget
+{
+private:
+   ResponseQueue &mResponseQueue;
+public:
+   ResponseQueueTarget(ResponseQueue &responseQueue)
+      : mResponseQueue(responseQueue)
+   { }
+   virtual ~ResponseQueueTarget()
+   {
+      mResponseQueue.AddResponse(wxString(wxT("\n")));
+   }
+   virtual void Update(wxString message)
+   {
+      mResponseQueue.AddResponse(message);
+   }
+};
+
+/// Sends messages to two message targets at once
+class CombinedMessageTarget : public CommandMessageTarget
+{
+private:
+   CommandMessageTarget *m1, *m2;
+public:
+   CombinedMessageTarget(CommandMessageTarget *t1, CommandMessageTarget *t2)
+      : m1(t1), m2(t2)
+   {
+      wxASSERT(t1 != NULL);
+      wxASSERT(t2 != NULL);
+   }
+   ~CombinedMessageTarget()
+   {
+      delete m1;
+      delete m2;
+   }
+   virtual void Update(wxString message)
+   {
+      m1->Update(message);
+      m2->Update(message);
+   }
+};
+
+
 // By default, we ignore progress updates but display all other messages 
directly
 class TargetFactory
 {
@@ -125,8 +170,8 @@
 
 };
 
-/// Used to aggregate the various output targets a command may have
-// Assumes responsibility for pointers passed into it
+/// Used to aggregate the various output targets a command may have.
+/// Assumes responsibility for pointers passed into it.
 class CommandOutputTarget
 {
 private:
@@ -142,7 +187,8 @@
    ~CommandOutputTarget()
    {
       delete mProgressTarget;
-      delete mStatusTarget;
+      if (mErrorTarget != mStatusTarget)
+         delete mStatusTarget;
       delete mErrorTarget;
    }
    void Progress(double completed)

Index: CommandBuilder.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/CommandBuilder.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- CommandBuilder.h    2 Jul 2009 22:03:24 -0000       1.3
+++ CommandBuilder.h    26 Jul 2009 21:57:03 -0000      1.4
@@ -16,14 +16,8 @@
 #ifndef __COMMANDBUILDER__
 #define __COMMANDBUILDER__
 
-#include <wx/string.h>
-#include <wx/variant.h>
-#include <utility>
-#include <map>
-#include "CommandMisc.h"
-
 class Command;
-class Validator;
+class wxString;
 
 // CommandBuilder has the task of validating and interpreting a command string.
 // If the string represents a valid command, it builds the command object.
@@ -39,14 +33,12 @@
       void BuildCommand(const wxString &cmdString);
    public:
       CommandBuilder(const wxString &cmdString);
-      CommandBuilder(const wxString &cmdName, const wxString &cmdParams);
+      CommandBuilder(const wxString &cmdName, 
+                     const wxString &cmdParams);
       ~CommandBuilder();
       bool WasValid();
       Command *GetCommand();
       const wxString &GetErrorMessage();
-
-      static bool LookUpCommand(wxString name, std::pair<Command*,ParamMap> 
&result);
-      static ParamMap GetSignature(wxString name);
 };
 #endif /* End of include guard: __COMMANDBUILDER__ */
 

Index: CommandBuilder.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/CommandBuilder.cpp,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- CommandBuilder.cpp  3 Jul 2009 00:00:12 -0000       1.4
+++ CommandBuilder.cpp  26 Jul 2009 21:57:03 -0000      1.5
@@ -11,8 +11,6 @@
 \file CommandBuilder.cpp
 \brief Contains definitions for CommandBuilder class.
 
-*//****************************************************************//**
-
 \class CommandBuilder
 \brief A type of factory for Commands of various sorts.
 
@@ -23,81 +21,71 @@
 
 *//*******************************************************************/
 
+#include "CommandDirectory.h"
 #include "CommandBuilder.h"
-#include <wx/log.h>
-#include <wx/wx.h>
-#include "DebugPrintCommand.h"
-#include "BatchEvalCommand.h"
-#include "ScreenshotCommand.h"
 #include "../Shuttle.h"
+#include "BatchEvalCommand.h"
+#include "Command.h"
+#include "CommandTargets.h"
+#include "ScriptCommandRelay.h"
 
 CommandBuilder::CommandBuilder(const wxString &cmdString)
-: mValid(false), mCommand(NULL)
+   : mValid(false), mCommand(NULL)
 {
    BuildCommand(cmdString);
 }
 
 CommandBuilder::CommandBuilder(const wxString &cmdName, const wxString &params)
-: mValid(false), mCommand(NULL)
+   : mValid(false), mCommand(NULL)
 {
    BuildCommand(cmdName, params);
 }
 
-CommandBuilder::~CommandBuilder() { }
-
-bool CommandBuilder::WasValid() { return mValid; }
-
-const wxString &CommandBuilder::GetErrorMessage() { return mError; }
+CommandBuilder::~CommandBuilder() 
+{ }
 
-Command *CommandBuilder::GetCommand()
+bool CommandBuilder::WasValid() 
 {
-   wxASSERT(mValid);
-   wxASSERT(NULL != mCommand);
-   return mCommand;
+   return mValid; 
 }
 
-// Short-term solution!
-bool CommandBuilder::LookUpCommand(wxString name, std::pair<Command*,ParamMap> 
&result)
+const wxString &CommandBuilder::GetErrorMessage() 
 {
-   if (name.IsSameAs(wxT("screenshot")))
-   {
-      CommandOutputTarget *output
-         = new CommandOutputTarget(new NullProgressTarget(),
-                                   new MessageBoxTarget(),
-                                   new MessageBoxTarget());
-      result = std::pair<Command*,ParamMap>(new ScreenshotCommand(output),
-                                            ScreenshotCommand::GetSignature());
-      return true;
-   } // Other cases...
-   return false;
+   return mError; 
 }
 
-// Short-term solution!
-ParamMap CommandBuilder::GetSignature(wxString name)
+Command *CommandBuilder::GetCommand()
 {
-   if(name.IsSameAs(wxT("screenshot")))
-   {
-      return ScreenshotCommand::GetSignature();
-   }
-   return Command::GetSignature();
+   wxASSERT(mValid);
+   wxASSERT(NULL != mCommand);
+   return mCommand;
 }
 
-void CommandBuilder::BuildCommand(const wxString &cmdName, const wxString 
&cmdParams)
+void CommandBuilder::BuildCommand(const wxString &cmdName,
+                                  const wxString &cmdParams)
 {
-   // Stage 1: work out what command to create
+   // Stage 1: create a Command object of the right type
 
    ParamMap signature;
 
-   std::pair<Command*,ParamMap> commandEntry;
-   if (LookUpCommand(cmdName, commandEntry))
+   CommandMessageTarget *scriptOutput = 
ScriptCommandRelay::GetResponseTarget();
+   CommandOutputTarget *output 
+      = new CommandOutputTarget(new NullProgressTarget(),
+                                scriptOutput,
+                                scriptOutput);
+
+   CommandFactory *factory = CommandDirectory::Get()->LookUp(cmdName);
+   if (factory != NULL)
    {
-      mCommand = commandEntry.first;
-      signature = commandEntry.second;
+      mCommand = factory->Create(output);
+      signature = factory->GetSignature();
    }
    else
    {
       // Fall back to hoping the Batch Command system can handle it
-      mCommand = new BatchEvalCommand();
+      wxString name = wxT("BatchEval");
+      signature = CommandDirectory::Get()->LookUp(name)->GetSignature();
+      mCommand = new BatchEvalCommand(name, signature, output);
       mCommand->SetParameter(wxT("CommandName"), cmdName);
       mCommand->SetParameter(wxT("ParamString"), cmdParams);
       mValid = true;

--- NEW FILE: CommandDirectory.h ---
/**********************************************************************

   Audacity - A Digital Audio Editor
   Copyright 1999-2009 Audacity Team
   License: wxWidgets

   Dan Horgan

******************************************************************//**

\file CommandDirectory.h
\brief Contains declarations for CommandDirectory, CommandFactory and
TypedCommandFactory<T> classes.

\class CommandDirectory
\brief Allows registration and lookup (by name) of command types.  

A singleton. This fulfills a similar purpose to CommandManager, but for general
Commands rather than menu items. Eventually they could be unified but for now
they are kept separate to make things simpler.

\class CommandFactory
\brief Interface for a class which creates Command objects

\class TypedCommandFactory<T>
\brief Template class for concrete factories which create Command objects of a
specific type.

*//*******************************************************************/

#ifndef __COMMANDDIRECTORY__
#define __COMMANDDIRECTORY__

#include "CommandMisc.h"

class Command;
class CommandOutputTarget;

class CommandFactory
{
public:
   virtual Command *Create(CommandOutputTarget *target) = 0;
   virtual const ParamMap &GetSignature() = 0;
};

template <typename T>
class TypedCommandFactory : public CommandFactory
{
private:
   ParamMap mSignature;
public:
   TypedCommandFactory()
      : mSignature(T::BuildSignature())
   { }

   Command *Create(CommandOutputTarget *target)
   {
      return new T(T::BuildName(), mSignature, target);
   }

   const ParamMap &GetSignature()
   {
      return mSignature;
   }
};

class CommandDirectory
{
private:
   static CommandDirectory *mInstance;
   CommandMap mCmdMap;
public:
   CommandDirectory();
   ~CommandDirectory();

   /// If a command with the given name has been registered in the directory,
   /// return a pointer to the factory for commands of that type.
   /// Otherwise return NULL.
   CommandFactory *LookUp(const wxString &cmdName) const;
   
   /// A convenient way to register a type of Command object with the 
   /// directory.
   ///
   /// T must be a subclass of Command which has a constructor of the form
   /// T(const wxString &cmdName,
   ///   const ParamMap &signature,
   ///   CommandOutputTarget *target)
   /// and suitable static BuildName and BuildSignature methods
   template <typename T>
   void AddCommand()
   {
      wxString cmdName = T::BuildName(); 
      wxASSERT_MSG(mCmdMap.find(cmdName) == mCmdMap.end()
                  , wxT("A command named ") + cmdName 
                    + wxT(" already exists."));

      mCmdMap[cmdName] = new TypedCommandFactory<T>();
   }

   /// Get a pointer to the singleton instance
   static CommandDirectory *Get();

   /// Manually delete the singleton instance
   static void Destroy();
};

#endif /* End of include guard: __COMMANDDIRECTORY__ */

// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
// arch-tag: TBD

--- NEW FILE: GetAllMenuCommands.cpp ---
/**********************************************************************

   Audacity - A Digital Audio Editor
   Copyright 1999-2009 Audacity Team
   License: wxWidgets

   Dan Horgan

******************************************************************//**

\file GetAllMenuCommands.cpp
\brief Contains definitions for GetAllMenuCommands class.

*//*******************************************************************/

#include "GetAllMenuCommands.h"
#include "../Project.h"
#include "CommandManager.h"

bool GetAllMenuCommands::Apply(CommandExecutionContext context)
{
   wxArrayString names;
   context.proj->GetCommandManager()->GetAllCommandNames(names, false);
   wxArrayString::iterator iter;
   for (iter = names.begin(); iter != names.end(); ++iter)
   {
      Status(*iter);
   }
   return true;
}

wxString GetAllMenuCommands::BuildName()
{
   return wxT("GetAllMenuCommands");
}

ParamMap GetAllMenuCommands::BuildSignature()
{
   return ParamMap();
}

// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
// arch-tag: TBD

Index: DebugPrintCommand.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/DebugPrintCommand.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- DebugPrintCommand.h 2 Jul 2009 22:03:24 -0000       1.3
+++ DebugPrintCommand.h 26 Jul 2009 21:57:03 -0000      1.4
@@ -16,7 +16,7 @@
 \class DebugPrintCommand
 \brief Command to tell Audacity to print out a message.
 
-   Intended for testing and debugging.
+Intended for testing and debugging.
 
 *//*******************************************************************/
 
@@ -26,26 +26,28 @@
 #include <wx/msgout.h>
 #include "Command.h"
 
-
 class DebugPrintCommand : public Command
 {
-private:
-   wxString mMessage;
-
 public:
-   DebugPrintCommand(const wxString &message)
-      : Command(wxT("DebugPrintCommand")),
-      mMessage(message) { }
+   DebugPrintCommand(const wxString &cmdName,
+                     const ParamMap &signature,
+                     CommandOutputTarget *target)
+      : Command(cmdName, signature, target) {}
    ~DebugPrintCommand() {}
 
    virtual bool Apply(CommandExecutionContext context)
    {
-      wxMessageOutputDebug().Printf(wxT("In DebugPrintCommand::Apply"));
-      wxMessageOutputDebug().Printf(mMessage);
+      wxString message = GetString(wxT("DebugString"));
+      wxMessageOutputDebug.Printf(message);
       return true;
    }
 
-   static ParamMap GetSignature()
+   static wxString BuildName()
+   {
+      return wxT("DebugMessage");
+   }
+
+   static ParamMap BuildSignature()
    {
       ParamMap signature;
       Validator stringValidator;

Index: ScreenshotCommand.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/ScreenshotCommand.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- ScreenshotCommand.cpp       3 Jul 2009 00:00:12 -0000       1.2
+++ ScreenshotCommand.cpp       26 Jul 2009 21:57:03 -0000      1.3
@@ -201,14 +201,12 @@
    Capture(fileName, win, x, y, width, height);
 }
 
-ScreenshotCommand::ScreenshotCommand(CommandOutputTarget *output,
-                                     wxWindow *ignore)
-   : Command(wxT("screenshot"), output),
-     mIgnore(ignore),
-     mBackground(false)
-{ }
+wxString ScreenshotCommand::BuildName()
+{
+   return wxT("Screenshot");
+}
 
-ParamMap ScreenshotCommand::GetSignature()
+ParamMap ScreenshotCommand::BuildSignature()
 {
    OptionValidator captureModeValidator;
    captureModeValidator.AddOption(wxT("window"));

Index: BatchEvalCommand.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/BatchEvalCommand.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- BatchEvalCommand.h  2 Jul 2009 22:03:24 -0000       1.3
+++ BatchEvalCommand.h  26 Jul 2009 21:57:03 -0000      1.4
@@ -25,34 +25,25 @@
 #include "Command.h"
 #include "../BatchCommands.h"
 
-
 class BatchEvalCommand : public Command
 {
 public:
-   BatchEvalCommand()
-      : Command(wxT("BatchEvalCommand"))
+   BatchEvalCommand(const wxString &cmdName,
+                    const ParamMap &signature,
+                    CommandOutputTarget *target)
+      : Command(cmdName, signature, target)
    { }
-   ~BatchEvalCommand() { }
 
-   virtual bool Apply(CommandExecutionContext context)
-   {
-      wxString cmdName = GetString(wxT("CommandName"));
-      wxString cmdParams = GetString(wxT("ParamString"));
+   BatchEvalCommand(CommandOutputTarget *target)
+      : Command(BuildName(), BuildSignature(), target)
+   { }
 
-      // Create a Batch that will have just one command in it...
-      BatchCommands Batch;
+   virtual ~BatchEvalCommand() { }
 
-      return Batch.ApplyCommand(cmdName, cmdParams);
-   }
+   virtual bool Apply(CommandExecutionContext context);
 
-   static ParamMap GetSignature()
-   {
-      ParamMap signature;
-      Validator paramValidator;
-      signature[wxT("ParamString")] =
-         std::pair<wxVariant, Validator>(wxT(""), paramValidator);
-      return signature;
-   }
+   static wxString BuildName();
+   static ParamMap BuildSignature();
 };
 
 #endif /* End of include guard: __BATCHEVALCOMMAND__ */

--- NEW FILE: ExecMenuCommand.h ---
/**********************************************************************

   Audacity - A Digital Audio Editor
   Copyright 1999-2009 Audacity Team
   License: wxWidgets

   Dan Horgan

******************************************************************//**

\file ExecMenuCommand.h
\brief Contains declaration of ExecMenuCommand class.

\class ExecMenuCommand
\brief A command which asks the CommandManager to execute a menu command by
name.

*//*******************************************************************/

#ifndef __EXECMENUCOMMAND__
#define __EXECMENUCOMMAND__

#include "Command.h"
#include "CommandManager.h"
#include "../Project.h"

class ExecMenuCommand : public Command
{
   public:
      ExecMenuCommand(const wxString &cmdName,
                      const ParamMap &signature,
                      CommandOutputTarget *target)
         : Command(cmdName, signature, target)
      { }
      ~ExecMenuCommand() { }

      virtual bool Apply(CommandExecutionContext context);
      static wxString BuildName();
      static ParamMap BuildSignature();
};

#endif /* End of include guard: __EXECMENUCOMMAND__ */

Index: CommandMisc.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/CommandMisc.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- CommandMisc.h       2 Jul 2009 23:44:50 -0000       1.1
+++ CommandMisc.h       26 Jul 2009 21:57:03 -0000      1.2
@@ -1,14 +1,33 @@
+/**********************************************************************
+
+   Audacity - A Digital Audio Editor
+   Copyright 1999-2009 Audacity Team
+   License: GPL v2 - see LICENSE.txt
+
+   Dan Horgan
+
+******************************************************************//**
+
+\file CommandMisc
+\brief Some typedefs which are used in various Command-related files
+
+*//*******************************************************************/
+
 #ifndef __COMMANDMISC__
 #define __COMMANDMISC__
 
 #include <map>
 #include <utility>
+#include <wx/string.h>
+#include <wx/variant.h>
 
-class wxString;
-class wxVariant;
 class Validator;
+class CommandFactory;
 
 // Map from parameter name to the value of the parameter, with a suitable 
Validator
 typedef std::map<wxString, std::pair<wxVariant, Validator> > ParamMap;
 
+// Map from command name to factory
+typedef std::map<wxString, CommandFactory*> CommandMap;
+
 #endif /* End of include guard: __COMMANDMISC__ */

Index: ScriptCommandRelay.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/ScriptCommandRelay.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- ScriptCommandRelay.h        7 Jun 2009 15:35:49 -0000       1.2
+++ ScriptCommandRelay.h        26 Jul 2009 21:57:03 -0000      1.3
@@ -22,8 +22,7 @@
 class CommandHandler;
 class ResponseQueue;
 class Response;
-
-
+class ResponseQueueTarget;
 
 typedef int (*tpExecScriptServerFunc)( wxString * pIn, wxString * pOut);
 typedef int (*tpRegScriptServerFunc)(tpExecScriptServerFunc pFn);
@@ -49,6 +48,7 @@
 
       static void SendResponse(const wxString &response);
       static Response ReceiveResponse();
+      static ResponseQueueTarget *GetResponseTarget();
 };
 
 #endif /* End of include guard: __SCRIPTCOMMANDRELAY__ */

Index: ScreenshotCommand.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/ScreenshotCommand.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- ScreenshotCommand.h 2 Jul 2009 22:03:24 -0000       1.1
+++ ScreenshotCommand.h 26 Jul 2009 21:57:03 -0000      1.2
@@ -41,9 +41,18 @@
 
 public:
    wxTopLevelWindow *GetFrontWindow(AudacityProject *project);
-   ScreenshotCommand(CommandOutputTarget *output, wxWindow *ignore = NULL);
+   ScreenshotCommand(wxString cmdName, 
+                     const ParamMap &signature,
+                     CommandOutputTarget *output)
+      : Command(cmdName, signature, output), 
+         mIgnore(NULL), mBackground(false)
+   { }
+   ScreenshotCommand(CommandOutputTarget *output, wxWindow *ignore = NULL)
+      : Command(BuildName(), BuildSignature(), output), mIgnore(ignore)
+   { }
    bool Apply(CommandExecutionContext context);
-   static ParamMap GetSignature();
+   static ParamMap BuildSignature();
+   static wxString BuildName();
 };
 
 #endif /* End of include guard: __SCREENSHOTCOMMAND__ */

--- NEW FILE: ExecMenuCommand.cpp ---
/**********************************************************************

   Audacity - A Digital Audio Editor
   Copyright 1999-2009 Audacity Team
   License: wxWidgets

   Dan Horgan

******************************************************************//**

\file ExecMenuCommand.cpp
\brief Contains definitions for ExecMenuCommand class.

*//*******************************************************************/

#include "ExecMenuCommand.h"

bool ExecMenuCommand::Apply(CommandExecutionContext context)
{
   CommandManager *cmdManager = context.proj->GetCommandManager();

   wxString cmdName = GetString(wxT("CommandName"));
   wxUint32 cmdFlags = 0; // TODO ?
   wxUint32 cmdMask = 0;
   return cmdManager->HandleTextualCommand(cmdName, cmdFlags, cmdMask);
}

wxString ExecMenuCommand::BuildName()
{
   return wxT("MenuCommand");
}

ParamMap ExecMenuCommand::BuildSignature()
{
   ParamMap signature;
   Validator menuCommandValidator;
   signature[wxT("CommandName")] =
      std::pair<wxVariant, Validator>(wxT(""), menuCommandValidator);
   return signature;
}

--- NEW FILE: BatchEvalCommand.cpp ---
/**********************************************************************

   Audacity - A Digital Audio Editor
   Copyright 1999-2009 Audacity Team
   File License: wxWidgets

   Dan Horgan

******************************************************************//**

\file BatchEvalCommand.cpp
\brief Contains definitions for the BatchEvalCommand class

*//*******************************************************************/

#include "BatchEvalCommand.h"

bool BatchEvalCommand::Apply(CommandExecutionContext context)
{
   wxString cmdName = GetString(wxT("CommandName"));
   wxString cmdParams = GetString(wxT("ParamString"));

   // Create a Batch that will have just one command in it...
   BatchCommands Batch;

   return Batch.ApplyCommand(cmdName, cmdParams);
}

wxString BatchEvalCommand::BuildName()
{
   return wxT("BatchEval");
}

ParamMap BatchEvalCommand::BuildSignature()
{
   ParamMap signature;
   Validator commandNameValidator;
   signature[wxT("CommandName")] =
      std::pair<wxVariant, Validator>(wxT(""), commandNameValidator);
   Validator paramValidator;
   signature[wxT("ParamString")] =
      std::pair<wxVariant, Validator>(wxT(""), paramValidator);
   return signature;
}

// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
// arch-tag: TBD

Index: ResponseQueue.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/ResponseQueue.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- ResponseQueue.cpp   7 Jun 2009 15:24:06 -0000       1.1
+++ ResponseQueue.cpp   26 Jul 2009 21:57:03 -0000      1.2
@@ -20,8 +20,7 @@
 
 ResponseQueue::ResponseQueue()
    : mCondition(mMutex)
-{
-}
+{ }
 
 ResponseQueue::~ResponseQueue()
 { }
@@ -36,7 +35,10 @@
 Response ResponseQueue::WaitAndGetResponse()
 {
    wxMutexLocker locker(mMutex);
-   mCondition.Wait();
+   if (mResponses.empty())
+   {
+      mCondition.Wait();
+   }
    wxASSERT(!mResponses.empty());
    Response msg = mResponses.front();
    mResponses.pop();

Index: CommandHandler.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/CommandHandler.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- CommandHandler.h    2 Jul 2009 22:03:24 -0000       1.3
+++ CommandHandler.h    26 Jul 2009 21:57:03 -0000      1.4
@@ -13,7 +13,6 @@
 
 *//******************************************************************/
 
-
 #ifndef __COMMANDHANDLER__
 #define __COMMANDHANDLER__
 
@@ -36,7 +35,6 @@
 
       // Whenever a command is recieved, process it.
       void OnReceiveCommand(AppCommandEvent &event);
-
 };
 
 #endif /* End of include guard: __COMMANDHANDLER__ */

Index: ScriptCommandRelay.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/ScriptCommandRelay.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- ScriptCommandRelay.cpp      7 Jun 2009 15:35:49 -0000       1.2
+++ ScriptCommandRelay.cpp      26 Jul 2009 21:57:03 -0000      1.3
@@ -20,15 +20,10 @@
 *//*******************************************************************/
 
 #include "ScriptCommandRelay.h"
-#include "../BatchCommands.h"
-#include "../Audacity.h"
-#include "Command.h"
+#include "CommandTargets.h"
 #include "CommandBuilder.h"
 #include "AppCommandEvent.h"
-#include "CommandHandler.h"
 #include "ResponseQueue.h"
-#include <wx/wx.h>
-
 #include "../Project.h"
 
 // Declare static class members
@@ -37,11 +32,16 @@
 ResponseQueue ScriptCommandRelay::sResponseQueue;
 
 void ScriptCommandRelay::SetRegScriptServerFunc(tpRegScriptServerFunc scriptFn)
-{ sScriptFn = scriptFn; }
+{ 
+   sScriptFn = scriptFn;
+}
 
 void ScriptCommandRelay::SetCommandHandler(CommandHandler &ch)
-{ sCmdHandler = &ch; }
+{ 
+   sCmdHandler = &ch;
+}
 
+/// Calls the script function, passing it the function for obeying commands
 void ScriptCommandRelay::Run()
 {
    wxASSERT( sScriptFn != NULL );
@@ -62,27 +62,47 @@
       AppCommandEvent ev;
       ev.SetCommand(cmd);
       GetActiveProject()->AddPendingEvent(ev);
-      Response r = ScriptCommandRelay::ReceiveResponse();
-      *pOut      = r.GetMessage();
+
+      *pOut = wxEmptyString;
+
+      // Wait until all responses from the command have been received.
+      // The last response is signalled by an empty line.
+      wxString msg = ScriptCommandRelay::ReceiveResponse().GetMessage();
+      while (msg != wxT("\n"))
+      {
+         *pOut += msg + wxT("\n");
+         msg = ScriptCommandRelay::ReceiveResponse().GetMessage();
+      }
    } else
    {
       *pOut = wxT("Syntax error!\n");
       *pOut += builder.GetErrorMessage();
+      *pOut += wxT("\n");
    }
 
    return 0;
 }
 
+/// Adds a response to the queue to be sent back to the script
 void ScriptCommandRelay::SendResponse(const wxString &response)
 {
    sResponseQueue.AddResponse(response);
 }
 
+/// Gets a response from the queue (may block)
 Response ScriptCommandRelay::ReceiveResponse()
 {
    return ScriptCommandRelay::sResponseQueue.WaitAndGetResponse();
 }
 
+/// Get a pointer to a message target which allows commands to send responses
+/// back to a script.
+ResponseQueueTarget *ScriptCommandRelay::GetResponseTarget()
+{
+   // This should be deleted by a Command destructor
+   return new ResponseQueueTarget(sResponseQueue);
+}
+
 // Indentation settings for Vim and Emacs and unique identifier for Arch, a
 // version control system. Please do not modify past this point.
 //

--- NEW FILE: CommandDirectory.cpp ---
/**********************************************************************

   Audacity - A Digital Audio Editor
   Copyright 1999-2009 Audacity Team
   License: wxWidgets

   Dan Horgan

******************************************************************//**

\file CommandDirectory.cpp
\brief Contains definitions for the CommandDirectory class

*//*******************************************************************/

#include "CommandDirectory.h"
#include "CommandMisc.h"

#include "ScreenshotCommand.h"
#include "BatchEvalCommand.h"
#include "ExecMenuCommand.h"
#include "GetAllMenuCommands.h"

CommandDirectory *CommandDirectory::mInstance = NULL;

CommandDirectory::CommandDirectory()
{
   wxASSERT(mInstance == NULL);
   mInstance = this;

   // Create the command map. 
   // Adding an entry here is the easiest way to register a Command class.
   AddCommand<ScreenshotCommand>();
   AddCommand<BatchEvalCommand>();
   AddCommand<ExecMenuCommand>();
   AddCommand<GetAllMenuCommands>();
}

CommandDirectory::~CommandDirectory()
{
   // Delete the factories
   CommandMap::iterator iter;
   for (iter = mCmdMap.begin(); iter != mCmdMap.end(); ++iter)
   {
      delete iter->second;
   }
}

CommandFactory *CommandDirectory::LookUp(const wxString &cmdName) const
{
   CommandMap::const_iterator iter = mCmdMap.find(cmdName);
   if (iter == mCmdMap.end())
   {
      return NULL;
   }
   return iter->second;
}

CommandDirectory *CommandDirectory::Get()
{
   if (mInstance == NULL)
   {
      return new CommandDirectory();
   }
   return mInstance;
}

void CommandDirectory::Destroy()
{
   if (mInstance != NULL)
   {
      delete mInstance;
   }
}

// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
// arch-tag: TBD

Index: Command.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/Command.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- Command.h   2 Jul 2009 22:03:24 -0000       1.3
+++ Command.h   26 Jul 2009 21:57:03 -0000      1.4
@@ -11,6 +11,17 @@
 \file Command.h
 \brief Contains declaration of Command base class.
 
+\class CommandExecutionContext
+\brief Represents a context to which a command may be applied.
+
+\class Command
+\brief Base class which encapsulates a process.
+
+That process may depend on certain parameters (determined by the command's
+signature) and may produce output on various channels. Any process which is to
+be controlled by a script should be separated out into its own Command class.
+(And that class should be registered with the CommandDirectory).
+
 *//*******************************************************************/
 
 #ifndef __COMMAND__
@@ -19,17 +30,17 @@
 #include <map>
 #include <utility>
 #include <wx/string.h>
-#include <wx/msgout.h>
 #include <wx/variant.h>
 #include <wx/arrstr.h>
 
+#include "Validators.h"
 #include "CommandMisc.h"
 #include "CommandBuilder.h"
 #include "CommandTargets.h"
+#include "CommandDirectory.h"
 
 class AudacityApp;
 class AudacityProject;
-class wxVariant;
 
 class CommandExecutionContext
 {
@@ -40,143 +51,14 @@
          : app(app), proj(proj) {}
 };
 
-/// A Validator is an object which checks whether a wxVariant satisfies
-//  a certain criterion. This is a base validator which allows anything.
-class Validator
-{
-public:
-   Validator() {};
-   virtual ~Validator() {};
-
-   virtual bool Validate(const wxVariant &v) const
-   {
-      return true;
-   }
-
-   // For error messages
-   virtual wxString GetDescription() const
-   {
-      return wxT("any value");
-   }
-};
-
-/// Must be one of the defined options
-class OptionValidator : public Validator
-{
-private:
-   wxArrayString mOptions;
-
-public:
-   void AddOption(const wxString &option)
-   {
-      mOptions.Add(option);
-   }
-   virtual bool Validate(const wxVariant &v) const
-   {
-      return (mOptions.Index(v.GetString()) != wxNOT_FOUND);
-   }
-   virtual wxString GetDescription()
-   {
-      wxString desc = wxT("one of: ");
-      int optionCount = mOptions.GetCount();
-      int i = 0;
-      for (i = 0; i+1 < optionCount; ++i)
-      {
-         desc += mOptions[i] + wxT(", ");
-      }
-      desc += mOptions[optionCount-1];
-      return desc;
-   }
-};
-
-/// Must be a boolean
-class BoolValidator : public Validator
-{
-public:
-   virtual bool Validate(const wxVariant &v) const
-   {
-      return v.IsType(wxT("bool"));
-   }
-   virtual wxString GetDescription() const
-   {
-      return wxT("y/n");
-   }
-};
-
-/// Must be a floating-point number
-class DoubleValidator : public Validator
-{
-public:
-   virtual bool Validate(const wxVariant &v) const
-   {
-      return v.IsType(wxT("double"));
-   }
-   virtual wxString GetDescription() const
-   {
-      return wxT("a floating-point number");
-   }
-};
-
-/// Must lie between the two given numbers
-class RangeValidator : public Validator
-{
-private:
-   double lower, upper;
-public:
-
-   virtual bool Validate(const wxVariant &v) const
-   {
-      double d = v.GetDouble();
-      return ((lower < d) && (d < upper));
-   }
-   virtual wxString GetDescription() const
-   {
-      return wxString::Format(wxT("between %d and %d"), lower, upper);
-   }
-};
-
-/// Must be integral
-class IntValidator : public Validator
-{
-public:
-   virtual bool Validate(const wxVariant &v) const
-   {
-      if (!v.IsType(wxT("double"))) return false;
-      double d = v.GetDouble();
-      return ((long)d == d);
-   }
-   virtual wxString GetDescription() const
-   {
-      return wxT("an integer");
-   }
-};
-
-/// Must pass both of the supplied validators
-class AndValidator : public Validator
-{
-   private:
-      const Validator &v1, &v2;
-   public:
-      AndValidator(const Validator &u1, const Validator &u2)
-         : v1(u1), v2(u2)
-      { }
-      virtual bool Validate(const wxVariant &v) const
-      {
-         if (!v1.Validate(v)) return false;
-         return v2.Validate(v);
-      }
-      virtual wxString GetDescription() const
-      {
-         return v1.GetDescription() + wxT(" and ") + v2.GetDescription();
-      }
-};
-
 class Command
 {
 private:
    wxString mName;
    ParamMap mParams;
 
+   /// Using the command signature, looks up a possible parameter value and
+   /// checks whether it passes the validator.
    bool Valid(wxString paramName, const wxVariant &paramValue)
    {
       return mParams[paramName].second.Validate(paramValue);
@@ -211,36 +93,41 @@
       return v.GetString();
    }
 
+   // Convenience methods for passing messages to the output target
    void Progress(double completed)
    {
-      if (mOutput)
-         mOutput->Progress(completed);
+      mOutput->Progress(completed);
    }
    void Status(wxString status)
    {
-      if (mOutput)
-         mOutput->Status(status);
+      mOutput->Status(status);
    }
    void Error(wxString message)
    {
-      if (mOutput)
-         mOutput->Error(message);
+      mOutput->Error(message);
    }
 
+
 public:
-   Command(const wxString &name, CommandOutputTarget *output = new 
CommandOutputTarget())
+   /// Constructor should not be called directly; only by a factory which
+   /// ensures name and params are set appropriately for the command.
+   Command(const wxString &name, 
+           const ParamMap &params,
+           CommandOutputTarget *output)
       : mName(name),
-        mParams(CommandBuilder::GetSignature(name)),
+        mParams(params),
         mOutput(output)
-   { }
+   { 
+      wxASSERT(output != NULL);
+   }
 
    virtual ~Command()
    {
-      if (mOutput)
-         delete mOutput;
+      delete mOutput;
    }
 
-   // Note: wxVariant is reference counted
+   /// Attempt to one of the command's parameters to a particular value.
+   /// (Note: wxVariant is reference counted)
    bool SetParameter(const wxString &paramName, wxVariant paramValue)
    {
       wxASSERT(!paramValue.IsType(wxT("null")));
@@ -256,17 +143,59 @@
       return true;
    }
 
+   /// Apply the command and send a response message on the Status channel
+   void ApplyWithResponse(CommandExecutionContext context)
+   {
+      wxString response = GetName() + wxT(" finished: ");
+      if (Apply(context))
+      {
+         response += wxT("OK");
+      } else
+      {
+         response += wxT("Failed!");
+      }
+      Status(response);
+   }
+
+   /// An instance method for getting the command name (for consistency)
+   virtual wxString GetName()
+   {
+      return BuildName();
+   }
+
+   /// Get the signature of the command without having to build it.
+   /// (Instead, it is looked up in the CommandDirectory.)
+   virtual ParamMap GetSignature()
+   {
+      CommandFactory *factory = CommandDirectory::Get()->LookUp(GetName());
+      wxASSERT_MSG(factory != NULL, 
+                   wxT("Failed to get signature for ") + GetName());
+      return factory->GetSignature();
+   }
+
    // Subclasses should override the following:
+   // =========================================
 
+   /// Actually carry out the command. Return true if successful and false
+   /// otherwise.
    virtual bool Apply(CommandExecutionContext context)
    {
       return true;
    }
 
-   static ParamMap GetSignature()
+   /// Construct a 'signature' map containing parameter names, validators and
+   /// default values.
+   static ParamMap BuildSignature()
    {
       return ParamMap();
    }
+
+   /// Construct the name of the command. (This is the name used to call the
+   /// command from a script.)
+   static wxString BuildName()
+   {
+      return wxEmptyString;
+   }
 };
 #endif /* End of include guard: __COMMAND__ */
 

--- NEW FILE: Validators.h ---
/**********************************************************************

   Audacity - A Digital Audio Editor
   Copyright 1999-2009 Audacity Team
   License: wxWidgets

   Dan Horgan

******************************************************************//**

\file Validators.h
\brief Contains declarations and definitions for Validator, OptionValidator,
BoolValidator, DoubleValidator, RangeValidator, IntValidator and AndValidator
classes.

\class Validator
\brief A Validator is an object which checks whether a wxVariant satisfies
a certain criterion. This is a base validator which allows anything.

\class OptionValidator
\brief Parameter must be one of the defined options

\class BoolValidator
\brief Parameter must be a boolean

\class DoubleValidator
\brief Parameter must be a floating-point number

\class RangeValidator
\brief Parameter must lie between the two given numbers

\class IntValidator
\brief Parameter must be integral

\class AndValidator
\brief Parameter must pass both of the supplied validators

*//*******************************************************************/

#ifndef __VALIDATORS__
#define __VALIDATORS__

class Validator
{
public:
   Validator() {};
   virtual ~Validator() {};

   /// Judge whether the passed value satisfies the Validator
   virtual bool Validate(const wxVariant &v) const
   {
      return true;
   }

   /// Return a description (for error messages)
   /// should be of the form 'v must be $description'
   virtual wxString GetDescription() const
   {
      return wxT("any value");
   }
};

class OptionValidator : public Validator
{
private:
   wxArrayString mOptions;

public:
   void AddOption(const wxString &option)
   {
      mOptions.Add(option);
   }
   void AddOptions(const wxArrayString &options)
   {
      mOptions.insert(mOptions.begin(), options.begin(), options.end());
   }
   virtual bool Validate(const wxVariant &v) const
   {
      return (mOptions.Index(v.GetString()) != wxNOT_FOUND);
   }
   virtual wxString GetDescription()
   {
      wxString desc = wxT("one of: ");
      int optionCount = mOptions.GetCount();
      int i = 0;
      for (i = 0; i+1 < optionCount; ++i)
      {
         desc += mOptions[i] + wxT(", ");
      }
      desc += mOptions[optionCount-1];
      return desc;
   }
};

class BoolValidator : public Validator
{
public:
   virtual bool Validate(const wxVariant &v) const
   {
      return v.IsType(wxT("bool"));
   }
   virtual wxString GetDescription() const
   {
      return wxT("y/n");
   }
};

class DoubleValidator : public Validator
{
public:
   virtual bool Validate(const wxVariant &v) const
   {
      return v.IsType(wxT("double"));
   }
   virtual wxString GetDescription() const
   {
      return wxT("a floating-point number");
   }
};

class RangeValidator : public Validator
{
private:
   double lower, upper;
public:

   virtual bool Validate(const wxVariant &v) const
   {
      double d = v.GetDouble();
      return ((lower < d) && (d < upper));
   }
   virtual wxString GetDescription() const
   {
      return wxString::Format(wxT("between %d and %d"), lower, upper);
   }
};

class IntValidator : public Validator
{
public:
   virtual bool Validate(const wxVariant &v) const
   {
      if (!v.IsType(wxT("double"))) return false;
      double d = v.GetDouble();
      return ((long)d == d);
   }
   virtual wxString GetDescription() const
   {
      return wxT("an integer");
   }
};

class AndValidator : public Validator
{
   private:
      const Validator &v1, &v2;
   public:
      AndValidator(const Validator &u1, const Validator &u2)
         : v1(u1), v2(u2)
      { }
      virtual bool Validate(const wxVariant &v) const
      {
         if (!v1.Validate(v)) return false;
         return v2.Validate(v);
      }
      virtual wxString GetDescription() const
      {
         return v1.GetDescription() + wxT(" and ") + v2.GetDescription();
      }
};
#endif /* End of include guard: __VALIDATORS__ */

// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
// arch-tag: TBD

Index: CommandHandler.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/commands/CommandHandler.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- CommandHandler.cpp  7 Jun 2009 15:41:24 -0000       1.2
+++ CommandHandler.cpp  26 Jul 2009 21:57:03 -0000      1.3
@@ -11,13 +11,9 @@
 \file CommandHandler.cpp
 \brief Contains definitions for the CommandHandler class.
 
-*//****************************************************************//**
-
 \class CommandHandler
 \brief Contains methods for applying commands that are passed to it.
 
-May possibly inherit from wxEvtHandler in the future...
-
 *//*******************************************************************/
 
 #include <wx/event.h>
@@ -29,8 +25,7 @@
 
 CommandHandler::CommandHandler(AudacityApp &app)
  : mCurrentContext(new CommandExecutionContext(&app, GetActiveProject()))
-{
-}
+{ }
 
 CommandHandler::~CommandHandler()
 {
@@ -50,16 +45,7 @@
    // Then apply it to current application & project.  Note that the
    // command may change the context - for example, switching to a
    // different project.
-   bool rc = cmd->Apply(*mCurrentContext);
-
-   // Rudimentary error handling
-   wxString msgOut;
-   if (rc)
-      msgOut = wxT("OK");
-   else
-      msgOut = wxT("Command FAILED!");
-
-   ScriptCommandRelay::SendResponse(msgOut);
+   cmd->ApplyWithResponse(*mCurrentContext);
 
    // Done with the command so delete it.
    delete cmd;

--- NEW FILE: GetAllMenuCommands.h ---
/**********************************************************************

   Audacity - A Digital Audio Editor
   Copyright 1999-2009 Audacity Team
   License: wxWidgets

   Dan Horgan

******************************************************************//**

\file GetAllMenuCommands.h
\brief Contains declaration of GetAllMenuCommands class.

\class GetAllMenuCommands
\brief Command which outputs a list of available menu commands on the status
channel.

*//*******************************************************************/

#ifndef __GETALLMENUCOMMANDS__
#define __GETALLMENUCOMMANDS__

#include "Command.h"

class GetAllMenuCommands : public Command
{
public:
   GetAllMenuCommands(const wxString &cmdName,
                      const ParamMap &signature,
                      CommandOutputTarget *target)
      : Command(cmdName, signature, target)
   { }

   virtual ~GetAllMenuCommands() 
   { }

   virtual bool Apply(CommandExecutionContext context);
   static wxString BuildName();
   static ParamMap BuildSignature();
};

#endif /* End of include guard: __GETALLMENUCOMMANDS__ */

// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
// arch-tag: TBD


------------------------------------------------------------------------------
_______________________________________________
Audacity-cvs mailing list
Audacity-cvs@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/audacity-cvs

Reply via email to