298 lines
8.9 KiB
C++
298 lines
8.9 KiB
C++
/**********************************************************************
|
|
|
|
Audacity - A Digital Audio Editor
|
|
Copyright 1999-2009 Audacity Team
|
|
License: wxwidgets
|
|
|
|
Dan Horgan
|
|
|
|
******************************************************************//**
|
|
|
|
\file Command.cpp
|
|
\brief Contains definitions for Command, DecoratedCommand,
|
|
ApplyAndSendResponse, and CommandImplementation classes. These are
|
|
remnants of Dan Horgans external scripting commands. We now use
|
|
AudacityCommand and a shuttle system. This allows commands to be used
|
|
from within macros too, to have settings dialogs, using ShuttleGui and
|
|
without need for validators.
|
|
|
|
Here's the doxygen for the still-remaining going-away classes.
|
|
|
|
|
|
\class BatchEvalCommandType
|
|
\brief The <something>CommandType classes are classes which are going
|
|
away. They all provided a BuildSignature (what parameters they accept)
|
|
and Name, but that is now replaced by the AudacityCommand interface.
|
|
|
|
We in effect merge the <something>CommandType classes into the
|
|
<something>Command classes.
|
|
|
|
\class MessageCommandType
|
|
\brief The <something>CommandType classes are classes which are going
|
|
away. They all provided a BuildSignature (what parameters they accept)
|
|
and Name, but that is now replaced by the AudacityCommand interface.
|
|
|
|
We in effect merge the <something>CommandType classes into the
|
|
<something>Command classes.
|
|
|
|
\class BatchEvalCommand
|
|
\brief Command to make processing of macros available to scripting. It can either
|
|
make a one command macro, or invoke an existing macro. It will become redundant
|
|
when menu commands are integrated into scripting.
|
|
|
|
\class HelpCommand
|
|
\brief Command to get help about other commands.
|
|
|
|
\class MessageCommand
|
|
\brief Command to get a message response. Used for testing, and used internally
|
|
to create messages for forwarding.
|
|
|
|
******************************************************************//**
|
|
|
|
\class OldStyleCommand
|
|
\brief Abstract base class for command interface. This is the version
|
|
created by Dan Horgan. It was previously a factory for other command classes.
|
|
It created a separation between the type of a command and the command itself,
|
|
which is being removed. These Cmmands were managed by CommandDirectory.
|
|
|
|
\class OldStyleCommandPointer
|
|
\brief OldStyleCommandPointer is a unique_ptr to an OldStyleCommand.
|
|
|
|
\class DecoratedCommand
|
|
\brief DecoratedCommand is a decorator for command. It forwards functions
|
|
to the mCommand it holds.
|
|
|
|
\class ApplyAndSendResponse
|
|
\brief ApplyAndSendResponse is a DecoratoredCommand that performs the given
|
|
command and then outputs a status message according to the result. It
|
|
manages a CommandContext which is passed into its mCommand, so that result
|
|
messages are routed back to the right place.
|
|
|
|
\class CommandImplementation,
|
|
\brief is derived from OldStyleCommand. It validates and
|
|
applies the command. CommandImplementation::Apply() is overloaded in
|
|
classes derived from it.
|
|
|
|
*//*******************************************************************/
|
|
|
|
#include "../Audacity.h"
|
|
#include "Command.h"
|
|
#include <map>
|
|
#include <wx/string.h>
|
|
#include <wx/variant.h>
|
|
#include <wx/arrstr.h>
|
|
|
|
#include "../AudacityException.h"
|
|
#include "Validators.h"
|
|
#include "CommandType.h"
|
|
#include "CommandMisc.h"
|
|
#include "CommandBuilder.h"
|
|
#include "CommandTargets.h"
|
|
#include "CommandDirectory.h"
|
|
|
|
#include "CommandContext.h"
|
|
#include "../Project.h"
|
|
|
|
|
|
|
|
bool OldStyleCommand::SetParameter(const wxString & WXUNUSED(paramName),
|
|
const wxVariant & WXUNUSED(paramValue))
|
|
{
|
|
wxASSERT_MSG(false, wxT("Tried to set parameter for command which doesn't support parameters!"));
|
|
return false;
|
|
}
|
|
|
|
DecoratedCommand::~DecoratedCommand()
|
|
{
|
|
}
|
|
|
|
ComponentInterfaceSymbol DecoratedCommand::GetSymbol()
|
|
{
|
|
return mCommand->GetSymbol();
|
|
}
|
|
|
|
CommandSignature &DecoratedCommand::GetSignature()
|
|
{
|
|
return mCommand->GetSignature();
|
|
}
|
|
|
|
bool DecoratedCommand::SetParameter(const wxString ¶mName,
|
|
const wxVariant ¶mValue)
|
|
{
|
|
return mCommand->SetParameter(paramName, paramValue);
|
|
}
|
|
|
|
ApplyAndSendResponse::ApplyAndSendResponse(const OldStyleCommandPointer &cmd, std::unique_ptr<CommandOutputTargets> &target)
|
|
: DecoratedCommand(cmd),
|
|
mCtx( std::make_unique<CommandContext>( *GetActiveProject(), std::move(target) ) )
|
|
{
|
|
}
|
|
|
|
|
|
bool ApplyAndSendResponse::Apply(const CommandContext &WXUNUSED(context))
|
|
{
|
|
wxLogMessage( "Context was passed in, but was ignored. ApplyAndSendResponse has its own one");
|
|
return Apply();
|
|
}
|
|
|
|
|
|
bool ApplyAndSendResponse::Apply()
|
|
{
|
|
// ApplyAndSendResponse IS a command.
|
|
// It also HOLDS a command.
|
|
|
|
// Mostly its functions forward to the recipient.
|
|
// However it uses its OWN context, not the one of
|
|
// the command it holds.
|
|
auto result = GuardedCall<bool>(
|
|
[&] {
|
|
bool bResult = mCommand->Apply(*( mCtx.get()));
|
|
return bResult; }
|
|
);
|
|
wxString response = wxT( "\n" );
|
|
|
|
// PRL: it's all right to send untranslated strings to this channel
|
|
// I don't see _("") used with literal strings.
|
|
response += GetSymbol().Internal();
|
|
|
|
// These three strings are deliberately not localised.
|
|
// They are used in script responses and always happen in English.
|
|
response += wxT(" finished: ");
|
|
if (result)
|
|
{
|
|
response += wxT("OK");
|
|
}
|
|
else
|
|
{
|
|
response += wxT("Failed!");
|
|
}
|
|
mCtx->Status(response);
|
|
return result;
|
|
}
|
|
|
|
CommandImplementation::CommandImplementation(OldStyleCommandType &type)
|
|
: mType(type),
|
|
mParams(type.GetSignature().GetDefaults()),
|
|
mSetParams()
|
|
{
|
|
}
|
|
|
|
CommandImplementation::~CommandImplementation()
|
|
{
|
|
}
|
|
|
|
void CommandImplementation::TypeCheck(const wxString &typeName,
|
|
const wxString ¶mName,
|
|
const wxVariant ¶m)
|
|
{
|
|
// this macro is empty if wxWidgets is not compiled in debug mode
|
|
wxASSERT_MSG(param.IsType(typeName),
|
|
GetSymbol().Internal()
|
|
+ wxT("command tried to get '")
|
|
+ paramName
|
|
+ wxT("' parameter as a ")
|
|
+ typeName
|
|
+ wxT(", but that wasn't enforced by the command signature."));
|
|
}
|
|
|
|
void CommandImplementation::CheckParam(const wxString ¶mName)
|
|
{
|
|
// this macro is empty if wxWidgets is not compiled in debug mode
|
|
wxASSERT_MSG(mParams.find(paramName) != mParams.end(),
|
|
GetSymbol().Internal()
|
|
+ wxT("command tried to get '")
|
|
+ paramName
|
|
+ wxT("' parameter, but that parameter doesn't exist in the command signature!"));
|
|
}
|
|
|
|
bool CommandImplementation::HasParam( const wxString ¶mName)
|
|
{
|
|
// Test for not even in map...
|
|
if( mParams.count(paramName) < 1)
|
|
return false;
|
|
return mSetParams[paramName];
|
|
}
|
|
|
|
bool CommandImplementation::GetBool(const wxString ¶mName)
|
|
{
|
|
CheckParam(paramName);
|
|
const wxVariant &v = mParams[paramName];
|
|
TypeCheck(wxT("bool"), paramName, v);
|
|
return v.GetBool();
|
|
}
|
|
|
|
long CommandImplementation::GetLong(const wxString ¶mName)
|
|
{
|
|
CheckParam(paramName);
|
|
const wxVariant &v = mParams[paramName];
|
|
TypeCheck(wxT("double"), paramName, v);
|
|
return (long)v.GetDouble();
|
|
}
|
|
|
|
double CommandImplementation::GetDouble(const wxString ¶mName)
|
|
{
|
|
CheckParam(paramName);
|
|
const wxVariant &v = mParams[paramName];
|
|
TypeCheck(wxT("double"), paramName, v);
|
|
return v.GetDouble();
|
|
}
|
|
|
|
wxString CommandImplementation::GetString(const wxString ¶mName)
|
|
{
|
|
CheckParam(paramName);
|
|
const wxVariant &v = mParams[paramName];
|
|
TypeCheck(wxT("string"), paramName, v);
|
|
return v.GetString();
|
|
}
|
|
|
|
/// Get the name of the command
|
|
ComponentInterfaceSymbol CommandImplementation::GetSymbol()
|
|
{
|
|
return mType.GetSymbol();
|
|
}
|
|
|
|
/// Get the signature of the command
|
|
CommandSignature &CommandImplementation::GetSignature()
|
|
{
|
|
return mType.GetSignature();
|
|
}
|
|
|
|
bool CommandImplementation::SetParameter(const wxString ¶mName, const wxVariant ¶mValue)
|
|
{
|
|
wxASSERT(!paramValue.IsType(wxT("null")));
|
|
CommandContext context( * GetActiveProject());
|
|
ParamValueMap::iterator iter = mParams.find(paramName);
|
|
if (iter == mParams.end())
|
|
{
|
|
// Translated format, but untranslated command name substituted into it?
|
|
// Perhaps these formats that don't need translating.
|
|
context.Error( wxString::Format(
|
|
_("%s is not a parameter accepted by %s"),
|
|
paramName, GetSymbol().Internal() ) );
|
|
return false;
|
|
}
|
|
|
|
Validator &validator = mType.GetSignature().GetValidator(iter->first);
|
|
if (!validator.Validate(paramValue))
|
|
{
|
|
context.Error( wxString::Format(
|
|
_("Invalid value for parameter '%s': should be %s"),
|
|
paramName, validator.GetDescription() ) );
|
|
return false;
|
|
}
|
|
mParams[paramName] = validator.GetConverted();
|
|
mSetParams[ paramName ] = true;
|
|
|
|
// (debug)
|
|
// context.Status(wxT("Set parameter ") + paramName + wxT(" to type ") + mParams[paramName].GetType() + wxT(", value ") + mParams[paramName].MakeString());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CommandImplementation::Apply(const CommandContext & WXUNUSED(context))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|