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