Audacity 3.2.0
BatchCommands.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 MacroCommands.cpp
6
7 Dominic Mazzoni
8 James Crook
9
10********************************************************************//*******************************************************************/
17
18#define wxLOG_COMPONENT "MacroCommands"
19
20
21#include "BatchCommands.h"
22
23#include <wx/defs.h>
24#include <wx/datetime.h>
25#include <wx/dir.h>
26#include <wx/log.h>
27#include <wx/textfile.h>
28#include <wx/time.h>
29
30#include "Project.h"
31#include "ProjectHistory.h"
32#include "ProjectSettings.h"
33#include "ProjectWindow.h"
36#include "effects/EffectUI.h"
37#include "FileNames.h"
38#include "Menus.h"
39#include "PluginManager.h"
40#include "Prefs.h"
41#include "SelectFile.h"
42#include "SelectUtilities.h"
43#include "SettingsVisitor.h"
44#include "Track.h"
45#include "UndoManager.h"
46
47#include "AllThemeResources.h"
48
49#include "AudacityMessageBox.h"
50
53
55: mProject{ project }
56, mExporter{ project }
57{
58 ResetMacro();
59
60 auto names = GetNames();
61 auto defaults = GetNamesOfDefaultMacros();
62
63 for( size_t i = 0;i<defaults.size();i++){
64 wxString name = defaults[i];
65 if ( ! make_iterator_range( names ).contains(name) ) {
69 }
70 }
71}
72
73static const auto MP3Conversion = XO("MP3 Conversion");
74static const auto FadeEnds = XO("Fade Ends");
75
77{
78 return {
79 MP3Conversion.Translation() ,
80 FadeEnds.Translation() ,
81 };
82}
83
84void MacroCommands::RestoreMacro(const wxString & name)
85{
86// TIDY-ME: Effects change their name with localisation.
87// Commands (at least currently) don't. Messy.
88 ResetMacro();
89 if (name == MP3Conversion.Translation() ){
90 AddToMacro( wxT("Normalize") );
91 AddToMacro( wxT("ExportMP3") );
92 } else if (name == FadeEnds.Translation() ){
93 AddToMacro( wxT("Select"), wxT("Start=\"0\" End=\"1\"") );
94 AddToMacro( wxT("FadeIn") );
95 AddToMacro( wxT("Select"), wxT("Start=\"0\" End=\"1\" RelativeTo=\"ProjectEnd\"") );
96 AddToMacro( wxT("FadeOut") );
97 AddToMacro( wxT("Select"), wxT("Start=\"0\" End=\"0\"") );
98 }
99}
100
102{
103 if (index < 0 || index >= (int)mCommandMacro.size()) {
104 return wxT("");
105 }
106
107 return mCommandMacro[index];
108}
109
110wxString MacroCommands::GetParams(int index)
111{
112 if (index < 0 || index >= (int)mParamsMacro.size()) {
113 return wxT("");
114 }
115
116 return mParamsMacro[index];
117}
118
120{
121 return (int)mCommandMacro.size();
122}
123
124wxString MacroCommands::ReadMacro(const wxString & macro, wxWindow *parent)
125{
126 // Clear any previous macro
127 ResetMacro();
128
129 // Build the filename
130 wxFileName name(FileNames::MacroDir(), macro, wxT("txt"));
131
132 // But, ask the user for the real name if we're importing
133 if (parent) {
134 FilePath fn = SelectFile(FileNames::Operation::_None,
135 XO("Import Macro"),
136 wxEmptyString,
137 name.GetName(),
138 wxT("txt"),
140 wxFD_OPEN | wxRESIZE_BORDER,
141 parent);
142
143 // User canceled...
144 if (fn.empty()) {
145 return wxEmptyString;
146 }
147
148 wxFileName check(fn);
149 check.SetPath(name.GetPath());
150 if (check.FileExists())
151 {
152 int id = AudacityMessageBox(
153 XO("Macro %s already exists. Would you like to replace it?").Format(check.GetName()),
154 XO("Import Macro"),
155 wxYES_NO);
156 if (id == wxNO) {
157 return wxEmptyString;
158 }
159 }
160
161 name.Assign(fn);
162 }
163
164 // Set the file name
165 wxTextFile tf(name.GetFullPath());
166
167 // Open and check
168 tf.Open();
169 if (!tf.IsOpened()) {
170 // wxTextFile will display any errors
171 return wxEmptyString;
172 }
173
174 // Load commands from the file
175 int lines = tf.GetLineCount();
176 if (lines > 0) {
177 for (int i = 0; i < lines; i++) {
178
179 // Find the command name terminator...ignore line if not found
180 int splitAt = tf[i].Find(wxT(':'));
181 if (splitAt < 0) {
182 continue;
183 }
184
185 // Parse and clean
186 wxString cmd = tf[i].Left(splitAt).Strip(wxString::both);
187 wxString parm = tf[i].Mid(splitAt + 1).Strip(wxString::trailing);
188
189 // Add to lists
190 mCommandMacro.push_back(cmd);
191 mParamsMacro.push_back(parm);
192 }
193 }
194
195 // Done with the file
196 tf.Close();
197
198 // Write to macro directory if importing
199 if (parent) {
200 return WriteMacro(name.GetName());
201 }
202
203 return name.GetName();
204}
205
206wxString MacroCommands::WriteMacro(const wxString & macro, wxWindow *parent)
207{
208 // Build the default filename
209 wxFileName name(FileNames::MacroDir(), macro, wxT("txt"));
210
211 // But, ask the user for the real name if we're exporting
212 if (parent) {
213 FilePath fn = SelectFile(FileNames::Operation::_None,
214 XO("Export Macro"),
215 wxEmptyString,
216 name.GetName(),
217 wxT("txt"),
219 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
220 parent);
221
222 // User canceled...
223 if (fn.empty()) {
224 return wxEmptyString;
225 }
226
227 name.Assign(fn);
228 }
229
230 // Set the file name
231 wxTextFile tf(name.GetFullPath());
232
233 // Create the file (Create() doesn't leave the file open)
234 if (!tf.Exists()) {
235 tf.Create();
236 }
237
238 // Open it
239 tf.Open();
240
241 if (!tf.IsOpened()) {
242 // wxTextFile will display any errors
243 return wxEmptyString;
244 }
245
246 // Start with a clean slate
247 tf.Clear();
248
249 // Copy over the commands
250 int lines = mCommandMacro.size();
251 for (int i = 0; i < lines; i++) {
252 // using GET to serialize macro definition to a text file
253 tf.AddLine(mCommandMacro[i].GET() + wxT(":") + mParamsMacro[ i ]);
254 }
255
256 // Write the macro
257 tf.Write();
258
259 // Done with the file
260 tf.Close();
261
262 return name.GetName();
263}
264
265bool MacroCommands::AddMacro(const wxString & macro)
266{
267 // Build the filename
268 wxFileName name(FileNames::MacroDir(), macro, wxT("txt"));
269
270 // Set the file name
271 wxTextFile tf(name.GetFullPath());
272
273 // Create it..Create will display errors
274 return tf.Create();
275}
276
277bool MacroCommands::DeleteMacro(const wxString & macro)
278{
279 // Build the filename
280 wxFileName name(FileNames::MacroDir(), macro, wxT("txt"));
281
282 // Delete it...wxRemoveFile will display errors
283 auto result = wxRemoveFile(name.GetFullPath());
284
285 // Delete any legacy chain that it shadowed
286 auto oldPath = wxFileName{ FileNames::LegacyChainDir(), macro, wxT("txt") };
287 wxRemoveFile(oldPath.GetFullPath()); // Don't care about this return value
288
289 return result;
290}
291
292bool MacroCommands::RenameMacro(const wxString & oldmacro, const wxString & newmacro)
293{
294 // Build the filenames
295 wxFileName oname(FileNames::MacroDir(), oldmacro, wxT("txt"));
296 wxFileName nname(FileNames::MacroDir(), newmacro, wxT("txt"));
297
298 // Rename it...wxRenameFile will display errors
299 return wxRenameFile(oname.GetFullPath(), nname.GetFullPath());
300}
301
302// Gets all commands that are valid for this mode.
304{
305 if (!project)
306 return;
307
308 Entries commands;
309
312 {
313 for (auto &plug
315 auto command = em.GetCommandIdentifier(plug.GetID());
316 if (!command.empty())
317 commands.push_back( {
318 { command, plug.GetSymbol().Msgid() },
319 plug.GetPluginType() == PluginTypeEffect ?
320 XO("Effect") : XO("Menu Command (With Parameters)")
321 } );
322 }
323 }
324
325 auto &manager = CommandManager::Get( *project );
326 TranslatableStrings mLabels;
327 CommandIDs mNames;
328 std::vector<bool> vExcludeFromMacros;
329 mLabels.clear();
330 mNames.clear();
331 manager.GetAllCommandLabels(mLabels, vExcludeFromMacros, true);
332 manager.GetAllCommandNames(mNames, true);
333
334 const bool english = wxGetLocale()->GetCanonicalName().StartsWith(wxT("en"));
335
336 for(size_t i=0; i<mNames.size(); i++) {
337 if( !vExcludeFromMacros[i] ){
338 auto label = mLabels[i];
339 label.Strip();
340 bool suffix;
341 if (!english)
342 suffix = false;
343 else {
344 // We'll disambiguate if the squashed name is short and shorter than the internal name.
345 // Otherwise not.
346 // This means we won't have repetitive items like "Cut (Cut)"
347 // But we will show important disambiguation like "All (SelectAll)" and "By Date (SortByDate)"
348 // Disambiguation is no longer essential as the details box will show it.
349 // PRL: I think this reasoning applies only when locale is English.
350 // For other locales, show the (CamelCaseCodeName) always. Or, never?
351 wxString squashed = label.Translation();
352 squashed.Replace( " ", "" );
353
354 // uh oh, using GET for dubious comparison of (lengths of)
355 // user-visible name and internal CommandID!
356 // and doing this only for English locale!
357 suffix = squashed.length() < wxMin( 18, mNames[i].GET().length());
358 }
359
360 if( suffix )
361 // uh oh, using GET to expose CommandID to the user, as a
362 // disambiguating suffix on a name, but this is only ever done if
363 // the locale is English!
364 // PRL: In case this logic does get fixed for other locales,
365 // localize even this punctuation format. I'm told Chinese actually
366 // prefers slightly different parenthesis characters
367 label.Join( XO("(%s)").Format( mNames[i].GET() ), wxT(" ") );
368
369 // Bug 2294. The Close command pulls the rug out from under
370 // batch processing, because it destroys the project.
371 // So it is UNSAFE for scripting, and therefore excluded from
372 // the catalog.
373 if (mNames[i] == "Close")
374 continue;
375
376 commands.push_back(
377 {
378 {
379 mNames[i], // Internal name.
380 label // User readable name
381 },
382 XO("Menu Command (No Parameters)")
383 }
384 );
385 }
386 }
387
388 // Sort commands by their user-visible names.
389 // PRL: What exactly should happen if first members of pairs are not unique?
390 // I'm not sure, but at least I can sort stably for a better defined result.
391 auto less =
392 [](const Entry &a, const Entry &b)
393 { return a.name.StrippedTranslation() <
394 b.name.StrippedTranslation(); };
395 std::stable_sort(commands.begin(), commands.end(), less);
396
397 // Now uniquify by friendly name
398 auto equal =
399 [](const Entry &a, const Entry &b)
400 { return a.name.StrippedTranslation() ==
401 b.name.StrippedTranslation(); };
402 std::unique_copy(
403 commands.begin(), commands.end(), std::back_inserter(mCommands), equal);
404}
405
406// binary search
408 -> Entries::const_iterator
409{
410 const auto less = [](const Entry &entryA, const Entry &entryB)
411 { return entryA.name.StrippedTranslation() <
412 entryB.name.StrippedTranslation(); };
413 auto range = std::equal_range(
414 begin(), end(), Entry{ { {}, friendlyName }, {} }, less
415 );
416 if (range.first != range.second) {
417 wxASSERT_MSG( range.first + 1 == range.second,
418 "Non-unique user-visible command name" );
419 return range.first;
420 }
421 else
422 return end();
423}
424
425// linear search
426auto MacroCommandsCatalog::ByCommandId( const CommandID &commandId ) const
427 -> Entries::const_iterator
428{
429 // Maybe this too should have a uniqueness check?
430 return std::find_if( begin(), end(),
431 [&](const Entry &entry)
432 { return entry.name.Internal() == commandId; });
433}
434
436{
437 const PluginID & ID =
439 if (ID.empty())
440 {
441 return wxEmptyString; // effect not found.
442 }
443
445}
446
448 const CommandID & command, const wxString & params, wxWindow &parent)
449{
450 const PluginID & ID =
452 if (ID.empty())
453 return wxEmptyString; // effect not found
454
455 wxString res = params;
456 auto cleanup = EffectManager::Get().SetBatchProcessing(ID);
457 if (EffectManager::Get().SetEffectParameters(ID, params))
458 if (EffectManager::Get().PromptUser(ID, EffectUI::DialogFactory, parent))
460 return res;
461}
462
463wxString MacroCommands::PromptForPresetFor(const CommandID & command, const wxString & params, wxWindow *parent)
464{
465 const PluginID & ID =
467 if (ID.empty())
468 {
469 return wxEmptyString; // effect not found.
470 }
471
472 wxString preset = EffectManager::Get().GetPreset(ID, params, parent);
473
474 // Preset will be empty if the user cancelled the dialog, so return the original
475 // parameter value.
476 if (preset.empty())
477 {
478 return params;
479 }
480
481 return preset;
482}
483
485 const PluginID & ID, const TranslatableString &friendlyCommand,
486 const CommandID & command, const wxString & params,
487 const CommandContext & Context)
488{
489 static_cast<void>(command);//compiler food.
490
491 //Possibly end processing here, if in batch-debug
492 if( ReportAndSkip(friendlyCommand, params))
493 return true;
494
496 if (!plug)
497 return false;
498
499 AudacityProject *project = &mProject;
500
501 // IF nothing selected, THEN select everything depending
502 // on preferences setting.
503 // (most effects require that you have something selected).
505 {
507 {
509 // i18n-hint: %s will be replaced by the name of an action, such as "Remove Tracks".
510 XO("\"%s\" requires one or more tracks to be selected.").Format(friendlyCommand));
511 return false;
512 }
513 }
514
515 bool res = false;
516
517 auto cleanup = EffectManager::Get().SetBatchProcessing(ID);
518
519 // transfer the parameters to the effect...
520 if (EffectManager::Get().SetEffectParameters(ID, params))
521 {
523 // and apply the effect...
525 Context,
529 else
530 // and apply the effect...
531 res = EffectUI::DoEffect(ID,
532 Context,
536 }
537
538 return res;
539}
540
542 const CommandID & command, const wxString & params,
543 CommandContext const * pContext)
544{
545 // Test for an effect.
546 const PluginID & ID =
548 if (!ID.empty())
549 {
550 if( pContext )
551 return ApplyEffectCommand(
552 ID, friendlyCommand, command, params, *pContext);
553 const CommandContext context( mProject );
554 return ApplyEffectCommand(
555 ID, friendlyCommand, command, params, context);
556 }
557
558 AudacityProject *project = &mProject;
559 auto &manager = CommandManager::Get( *project );
560 if( pContext ){
562 manager, command, *pContext, AlwaysEnabledFlag, true ) )
563 return true;
564 pContext->Status( wxString::Format(
565 _("Your batch command of %s was not recognized."), friendlyCommand.Translation() ));
566 return false;
567 }
568 else
569 {
570 const CommandContext context( mProject );
572 manager, command, context, AlwaysEnabledFlag, true ) )
573 return true;
574 }
575
577 XO("Your batch command of %s was not recognized.")
578 .Format( friendlyCommand ) );
579
580 return false;
581}
582
584 const TranslatableString &friendlyCommand,
585 const CommandID & command, const wxString &params,
586 CommandContext const * pContext)
587{
588 AudacityProject *project = &mProject;
589 auto &settings = ProjectSettings::Get( *project );
590 // Recalc flags and enable items that may have become enabled.
591 MenuManager::Get(*project).UpdateMenus(false);
592 // enter batch mode...
593 bool prevShowMode = settings.GetShowId3Dialog();
594 project->mBatchMode++;
595 auto cleanup = finally( [&] {
596 // exit batch mode...
597 settings.SetShowId3Dialog(prevShowMode);
598 project->mBatchMode--;
599 } );
600
601 return ApplyCommand( friendlyCommand, command, params, pContext );
602}
603
604static int MacroReentryCount = 0;
605// ApplyMacro returns true on success, false otherwise.
606// Any error reporting to the user in setting up the macro
607// has already been done.
609 const MacroCommandsCatalog &catalog, const wxString & filename)
610{
611 // Check for reentrant ApplyMacro commands.
612 // We'll allow 1 level of reentry, but not more.
613 // And we treat ignoring deeper levels as a success.
614 if (MacroReentryCount > 1) {
615 return true;
616 }
617
618 // Restore the reentry counter (to zero) when we exit.
619 auto cleanup1 = valueRestorer(MacroReentryCount);
621
622 AudacityProject *proj = &mProject;
623 bool res = false;
624
625 // Only perform this group on initial entry. They should not be done
626 // while recursing.
627 if (MacroReentryCount == 1) {
628 mFileName = filename;
629
630 TranslatableString longDesc, shortDesc;
631 wxString name = gPrefs->Read(wxT("/Batch/ActiveMacro"), wxEmptyString);
632 if (name.empty()) {
633 /* i18n-hint: active verb in past tense */
634 longDesc = XO("Applied Macro");
635 shortDesc = XO("Apply Macro");
636 }
637 else {
638 /* i18n-hint: active verb in past tense */
639 longDesc = XO("Applied Macro '%s'").Format(name);
640 shortDesc = XO("Apply '%s'").Format(name);
641 }
642
643 // Save the project state before making any changes. It will be rolled
644 // back if an error occurs.
645 // It also causes any calls to ModifyState (such as by simple
646 // view-changing commands) to append changes to this state, not to the
647 // previous state in history. See Bug 2076
648 if (proj) {
649 ProjectHistory::Get(*proj).PushState(longDesc, shortDesc);
650 }
651 }
652
653 // Upon exit of the top level apply, roll back the state if an error occurs.
654 auto cleanup2 = finally([&, macroReentryCount = MacroReentryCount] {
655 if (macroReentryCount == 1 && !res && proj) {
656 // Be sure that exceptions do not escape this destructor
657 GuardedCall([&]{
658 // Macro failed or was cancelled; revert to the previous state
659 auto &history = ProjectHistory::Get(*proj);
660 history.RollbackState();
661 // The added undo state is now vacuous. Remove it (Bug 2759)
662 auto &undoManager = UndoManager::Get(*proj);
663 undoManager.Undo(
664 [&]( const UndoStackElem &elem ){
665 history.PopState( elem.state ); } );
666 undoManager.AbandonRedo();
667 });
668 }
669 });
670
671 mAbort = false;
672
673 // Is tracing enabled?
674 bool trace;
675 gPrefs->Read(wxT("/EnableMacroTracing"), &trace, false);
676
677 // If so, then block most other messages while running the macro
678 wxLogLevel prevLevel = wxLog::GetComponentLevel("");
679 if (trace) {
680 wxLog::SetComponentLevel("", wxLOG_FatalError);
681 wxLog::SetComponentLevel(wxLOG_COMPONENT, wxLOG_Info);
682 }
683
684 size_t i = 0;
685 for (; i < mCommandMacro.size(); i++) {
686 const auto &command = mCommandMacro[i];
687 auto iter = catalog.ByCommandId(command);
688 const auto friendly = (iter == catalog.end())
689 ?
690 // uh oh, using GET to expose an internal name to the user!
691 // in default of any better friendly name
692 Verbatim( command.GET() )
693 : iter->name.Msgid().Stripped();
694
695 wxTimeSpan before;
696 if (trace) {
697 before = wxTimeSpan(0, 0, 0, wxGetUTCTimeMillis());
698 }
699
700 bool success = ApplyCommandInBatchMode(friendly, command, mParamsMacro[i]);
701
702 if (trace) {
703 auto after = wxTimeSpan(0, 0, 0, wxGetUTCTimeMillis());
704 wxLogMessage(wxT("Macro line #%ld took %s : %s:%s"),
705 i + 1,
706 (after - before).Format(wxT("%H:%M:%S.%l")),
707 command.GET(),
708 mParamsMacro[i]);
709 }
710
711 if (!success || mAbort)
712 break;
713 }
714
715 // Restore message level
716 if (trace) {
717 wxLog::SetComponentLevel("", prevLevel);
718 }
719
720 res = (i == mCommandMacro.size());
721 if (!res)
722 return false;
723
724 if (MacroReentryCount == 1) {
725 mFileName.Empty();
726
727 if (proj)
728 ProjectHistory::Get(*proj).ModifyState(true);
729 }
730
731 return true;
732}
733
734// AbortBatch() allows a premature terminatation of a batch.
736{
737 mAbort = true;
738}
739
740void MacroCommands::AddToMacro(const CommandID &command, int before)
741{
742 AddToMacro(command, GetCurrentParamsFor(command), before);
743}
744
745void MacroCommands::AddToMacro(const CommandID &command, const wxString &params, int before)
746{
747 if (before == -1) {
748 before = (int)mCommandMacro.size();
749 }
750
751 mCommandMacro.insert(mCommandMacro.begin() + before, command);
752 mParamsMacro.insert(mParamsMacro.begin() + before, params);
753}
754
756{
757 if (index < 0 || index >= (int)mCommandMacro.size()) {
758 return;
759 }
760
761 mCommandMacro.erase( mCommandMacro.begin() + index );
762 mParamsMacro.erase( mParamsMacro.begin() + index );
763}
764
766{
767 mCommandMacro.clear();
768 mParamsMacro.clear();
769}
770
771// ReportAndSkip() is a diagnostic function that avoids actually
772// applying the requested effect if in batch-debug mode.
774 const TranslatableString & friendlyCommand, const wxString & params)
775{
776 int bDebug;
777 gPrefs->Read(wxT("/Batch/Debug"), &bDebug, false);
778 if( bDebug == 0 )
779 return false;
780
781 //TODO: Add a cancel button to these, and add the logic so that we can abort.
782 if( !params.empty() )
783 {
785 XO("Apply %s with parameter(s)\n\n%s")
786 .Format( friendlyCommand, params ),
787 XO("Test Mode"));
788 }
789 else
790 {
792 XO("Apply %s").Format( friendlyCommand ),
793 XO("Test Mode"));
794 }
795 return true;
796}
797
799{
800 static bool done = false;
801 if (!done) {
802 // Check once per session at most
803
804 // Copy chain files from the old Chains into the new Macros directory,
805 // but only if like-named files are not already present in Macros.
806
807 // Leave the old copies in place, in case a user wants to go back to
808 // an old Audacity version. They will have their old chains intact, but
809 // won't have any edits they made to the copy that now lives in Macros
810 // which old Audacity will not read.
811
812 const auto oldDir = FileNames::LegacyChainDir();
813 FilePaths files;
814 wxDir::GetAllFiles(oldDir, &files, wxT("*.txt"), wxDIR_FILES);
815
816 // add a dummy path component to be overwritten by SetFullName
817 wxFileName newDir{ FileNames::MacroDir(), wxT("x") };
818
819 for (const auto &file : files) {
820 auto name = wxFileName{file}.GetFullName();
821 newDir.SetFullName(name);
822 const auto newPath = newDir.GetFullPath();
823 if (!wxFileExists(newPath))
824 FileNames::DoCopyFile(file, newPath);
825 }
826 done = true;
827 }
828 // To do: use std::once
829}
830
832{
834
835 wxArrayString names;
836 FilePaths files;
837 wxDir::GetAllFiles(FileNames::MacroDir(), &files, wxT("*.txt"), wxDIR_FILES);
838 size_t i;
839
840 wxFileName ff;
841 for (i = 0; i < files.size(); i++) {
842 ff = (files[i]);
843 names.push_back(ff.GetName());
844 }
845
846 std::sort( names.begin(), names.end() );
847
848 return names;
849}
850
851bool MacroCommands::IsFixed(const wxString & name)
852{
853 auto defaults = GetNamesOfDefaultMacros();
854 if( make_iterator_range( defaults ).contains( name ) )
855 return true;
856 return false;
857}
858
859void MacroCommands::Split(const wxString & str, wxString & command, wxString & param)
860{
861 int splitAt;
862
863 command.Empty();
864 param.Empty();
865
866 if (str.empty()) {
867 return;
868 }
869
870 splitAt = str.Find(wxT(':'));
871 if (splitAt < 0) {
872 return;
873 }
874
875 command = str.Mid(0, splitAt);
876 param = str.Mid(splitAt + 1);
877
878 return;
879}
880
881wxString MacroCommands::Join(const wxString & command, const wxString & param)
882{
883 return command + wxT(": ") + param;
884}
wxT("CloseDown"))
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
static const auto MP3Conversion
static const auto FadeEnds
#define wxLOG_COMPONENT
static int MacroReentryCount
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:34
#define str(a)
EffectDistortionSettings params
Definition: Distortion.cpp:77
const TranslatableString name
Definition: Distortion.cpp:76
wxString PluginID
Definition: EffectManager.h:30
XO("Cut/Copy/Paste")
std::vector< CommandID > CommandIDs
Definition: Identifier.h:233
#define _(s)
Definition: Internat.h:73
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:251
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:448
@ PluginTypeAudacityCommand
@ PluginTypeEffect
FileConfig * gPrefs
Definition: Prefs.cpp:70
wxString FilePath
Definition: Project.h:21
static ProjectFileIORegistry::AttributeWriterEntry entry
static const AttachedProjectObjects::RegisteredFactory manager
EffectReverbSettings preset
Definition: Reverb.cpp:44
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
Definition: SelectFile.cpp:17
TranslatableString label
Definition: TagsEditor.cpp:164
static TranslatableStrings names
Definition: TagsEditor.cpp:152
declares abstract base class Track, TrackList, and iterators over TrackList
static Settings & settings()
Definition: TrackInfo.cpp:87
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
std::vector< TranslatableString > TranslatableStrings
static const auto fn
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
virtual void Status(const wxString &message, bool bFlush=false) const
static CommandManager & Get(AudacityProject &project)
const wxString StrippedTranslation() const
EffectManager is the class that handles effects and effect categories.
Definition: EffectManager.h:48
CommandID GetCommandIdentifier(const PluginID &ID)
BatchProcessingScope SetBatchProcessing(const PluginID &ID)
Begin a scope that ends when the returned object is destroyed.
static EffectManager & Get()
wxString GetPreset(const PluginID &ID, const wxString &params, wxWindow *parent)
wxString GetEffectParameters(const PluginID &ID)
const PluginID & GetEffectByIdentifier(const CommandID &strTarget)
FILES_API const FileType TextFiles
Definition: FileNames.h:73
Abstract base class used in importing a file.
Entries::const_iterator ByCommandId(const CommandID &commandId) const
Entries::const_iterator end() const
Definition: BatchCommands.h:48
std::vector< Entry > Entries
Definition: BatchCommands.h:35
MacroCommandsCatalog(const AudacityProject *project)
Entries::const_iterator ByFriendlyName(const TranslatableString &friendlyName) const
static wxArrayStringEx GetNamesOfDefaultMacros()
static wxString PromptForPresetFor(const CommandID &command, const wxString &params, wxWindow *parent)
bool IsFixed(const wxString &name)
CommandIDs mCommandMacro
void AddToMacro(const CommandID &command, int before=-1)
bool ApplyEffectCommand(const PluginID &ID, const TranslatableString &friendlyCommand, const CommandID &command, const wxString &params, const CommandContext &Context)
wxString mFileName
bool ApplyCommand(const TranslatableString &friendlyCommand, const CommandID &command, const wxString &params, CommandContext const *pContext=NULL)
wxString GetParams(int index)
void DeleteFromMacro(int index)
wxArrayString mParamsMacro
wxString Join(const wxString &command, const wxString &param)
static wxString GetCurrentParamsFor(const CommandID &command)
static void MigrateLegacyChains()
bool RenameMacro(const wxString &oldmacro, const wxString &newmacro)
CommandID GetCommand(int index)
static wxArrayString GetNames()
bool DeleteMacro(const wxString &name)
bool ReportAndSkip(const TranslatableString &friendlyCommand, const wxString &params)
void Split(const wxString &str, wxString &command, wxString &param)
wxString WriteMacro(const wxString &macro, wxWindow *parent=nullptr)
bool ApplyMacro(const MacroCommandsCatalog &catalog, const wxString &filename={})
static wxString PromptForParamsFor(const CommandID &command, const wxString &params, wxWindow &parent)
bool AddMacro(const wxString &macro)
MacroCommands(AudacityProject &project)
wxString ReadMacro(const wxString &macro, wxWindow *parent=nullptr)
void RestoreMacro(const wxString &name)
AudacityProject & mProject
bool ApplyCommandInBatchMode(const TranslatableString &friendlyCommand, const CommandID &command, const wxString &params, CommandContext const *pContext=NULL)
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:69
void UpdateMenus(bool checkActive=true)
Definition: Menus.cpp:577
PluginType GetPluginType() const
PluginManager maintains a list of all plug ins. That covers modules, effects, generators,...
Definition: PluginManager.h:47
Range PluginsOfType(int type)
const PluginDescriptor * GetPlugin(const PluginID &ID) const
static PluginManager & Get()
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
TranslatableString & Strip(unsigned options=MenuCodes) &
TranslatableString & Join(TranslatableString arg, const wxString &separator={}) &
Append another translatable string.
wxString Translation() const
TranslatableString Stripped(unsigned options=MenuCodes) const
non-mutating, constructs another TranslatableString object
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:71
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
AUDACITY_DLL_API bool DoAudacityCommand(const PluginID &ID, const CommandContext &context, unsigned flags)
AUDACITY_DLL_API bool HandleTextualCommand(CommandManager &commandManager, const CommandID &Str, const CommandContext &context, CommandFlag flags, bool alwaysEnabled)
AUDACITY_DLL_API bool DoEffect(const PluginID &ID, const CommandContext &context, unsigned flags)
'Repeat Last Effect'.
Definition: EffectUI.cpp:1263
AUDACITY_DLL_API DialogFactoryResults DialogFactory(wxWindow &parent, EffectPlugin &host, EffectUIServices &client, EffectSettingsAccess &access)
Definition: EffectUI.cpp:1224
FILES_API FilePath MacroDir()
FILES_API bool DoCopyFile(const FilePath &file1, const FilePath &file2, bool overwrite=true)
FILES_API FilePath LegacyChainDir()
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
bool SelectAllIfNoneAndAllowed(AudacityProject &project)
Definition: BatchCommands.h:31
ComponentInterfaceSymbol name
Definition: BatchCommands.h:32
Holds one item with description and time range for the UndoManager.
Definition: UndoManager.h:117
UndoState state
Definition: UndoManager.h:128