Audacity  2.2.2
BatchProcessDialog.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  ApplyMacroDialog.cpp
6 
7  Dominic Mazzoni
8  James Crook
9 
10 *******************************************************************//*******************************************************************/
16 
17 #include "Audacity.h"
18 #include "BatchProcessDialog.h"
19 
20 #include <wx/defs.h>
21 #include <wx/checkbox.h>
22 #include <wx/choice.h>
23 #include <wx/filedlg.h>
24 #include <wx/intl.h>
25 #include <wx/sizer.h>
26 #include <wx/statbox.h>
27 #include <wx/stattext.h>
28 #include <wx/textctrl.h>
29 #include <wx/listctrl.h>
30 #include <wx/radiobut.h>
31 #include <wx/button.h>
32 #include <wx/imaglist.h>
33 #include <wx/settings.h>
34 
35 #include "AudacityException.h"
36 #include "ShuttleGui.h"
37 #include "Prefs.h"
38 #include "Project.h"
39 #include "Internat.h"
42 #include "effects/Effect.h"
43 #include "../images/Arrow.xpm"
44 #include "../images/Empty9x16.xpm"
45 #include "BatchCommands.h"
46 #include "Track.h"
47 #include "UndoManager.h"
48 
49 #include "Theme.h"
50 #include "AllThemeResources.h"
51 
52 #include "FileDialog.h"
53 #include "FileNames.h"
54 #include "import/Import.h"
55 #include "widgets/ErrorDialog.h"
56 #include "widgets/HelpSystem.h"
57 
58 #define MacrosListID 7001
59 #define CommandsListID 7002
60 #define ApplyToProjectID 7003
61 #define ApplyToFilesID 7004
62 #define ExpandID 7005
63 #define ShrinkID 7006
64 
65 BEGIN_EVENT_TABLE(ApplyMacroDialog, wxDialogWrapper)
66  EVT_BUTTON(ApplyToProjectID, ApplyMacroDialog::OnApplyToProject)
68  EVT_BUTTON(wxID_CANCEL, ApplyMacroDialog::OnCancel)
69  EVT_BUTTON(wxID_HELP, ApplyMacroDialog::OnHelp)
71 
72 ApplyMacroDialog::ApplyMacroDialog(wxWindow * parent, bool bInherited):
73  wxDialogWrapper(parent, wxID_ANY, _("Macros Palette"),
74  wxDefaultPosition, wxDefaultSize,
75  wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
76  , mCatalog( GetActiveProject() )
77 {
78  //AudacityProject * p = GetActiveProject();
79  mAbort = false;
80  mbExpanded = false;
81  if( bInherited )
82  return;
83  SetLabel(_("Macros Palette")); // Provide visual label
84  SetName(_("Macros Palette")); // Provide audible label
85  Populate();
86 
87 }
88 
90 {
91 }
92 
94 {
95  //------------------------- Main section --------------------
96  ShuttleGui S(this, eIsCreating);
98  // ----------------------- End of main section --------------
99  // Get and validate the currently active macro
100  mActiveMacro = gPrefs->Read(wxT("/Batch/ActiveMacro"), wxT(""));
101  // Go populate the macros list.
102  PopulateMacros();
103 
104  Layout();
105  Fit();
106  wxSize sz = GetSize();
107  SetSizeHints( sz );
108 
109  // Size and place window
110  SetSize(std::min(wxSystemSettings::GetMetric(wxSYS_SCREEN_X) * 3 / 4, sz.GetWidth()),
111  std::min(wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) * 4 / 5, 400));
112 
113  Center();
114 
115  // Set the column size for the macros list.
116  sz = mMacros->GetClientSize();
117  mMacros->SetColumnWidth(0, sz.x);
118 }
119 
122 {
123  /*i18n-hint: A macro is a sequence of commands that can be applied
124  * to one or more audio files.*/
125  S.StartStatic(_("&Select Macro"), 1);
126  {
127  S.SetStyle(wxSUNKEN_BORDER | wxLC_REPORT | wxLC_HRULES | wxLC_VRULES |
128  wxLC_SINGLE_SEL);
130  mMacros->InsertColumn(0, _("Macro"), wxLIST_FORMAT_LEFT);
131  }
132  S.EndStatic();
133 
134  S.StartHorizontalLay(wxEXPAND, 0);
135  {
136  S.AddPrompt( _("Apply Macro to:") );
137  S.Id(ApplyToProjectID).AddButton(_("&Project"));
138  S.Id(ApplyToFilesID).AddButton(_("&Files..."));
139  }
140  S.EndHorizontalLay();
141 
142  S.StartHorizontalLay(wxEXPAND, 0);
143  {
144  mResize = S.Id(ExpandID).AddButton(_("&Expand"));
145  S.Prop(1).AddSpace( 10 );
147  }
148  S.EndHorizontalLay();
149 }
150 
155 {
156  wxArrayString names = mMacroCommands.GetNames();
157  int i;
158 
159  int topItem = mMacros->GetTopItem();
160  mMacros->DeleteAllItems();
161  for (i = 0; i < (int)names.GetCount(); i++) {
162  mMacros->InsertItem(i, names[i]);
163  }
164 
165  int item = mMacros->FindItem(-1, mActiveMacro);
166  bool bFound = item >=0;
167  if (item == -1) {
168  item = 0;
169  mActiveMacro = mMacros->GetItemText(0);
170  }
171 
172  // Select the name in the list...this will fire an event.
173  mMacros->SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
174 
175  if( 0 <= topItem && topItem < (int)mMacros->GetItemCount())
176  {
177  // Workaround for scrolling being windows only.
178  // Try to scroll back to where we once were...
179  mMacros->EnsureVisible( (int)mMacros->GetItemCount() -1 );
180  mMacros->EnsureVisible( topItem );
181  // And then make sure whatever is selected is still visible...
182  if( bFound )
183  mMacros->EnsureVisible( item );
184  }
185 }
186 
187 void ApplyMacroDialog::OnHelp(wxCommandEvent & WXUNUSED(event))
188 {
189  wxString page = GetHelpPageName();
190  HelpSystem::ShowHelp(this, page, true);
191 }
192 
193 void ApplyMacroDialog::OnApplyToProject(wxCommandEvent & WXUNUSED(event))
194 {
195  long item = mMacros->GetNextItem(-1,
196  wxLIST_NEXT_ALL,
197  wxLIST_STATE_SELECTED);
198 
199  if (item == -1) {
200  AudacityMessageBox(_("No macro selected"));
201  return;
202  }
203  ApplyMacroToProject( item );
204 }
205 
206 wxString ApplyMacroDialog::MacroIdOfName( const wxString & MacroName )
207 {
208  wxString Temp = MacroName;
209  Temp.Replace(" ","");
210  Temp = wxString( "Macro_" ) + Temp;
211  return Temp;
212 }
213 
214 // Apply macro, given its ID.
215 // Does nothing if not found, rather than returning an error.
216 void ApplyMacroDialog::ApplyMacroToProject( const wxString & MacroID, bool bHasGui )
217 {
218  for( int i=0;i<mMacros->GetItemCount();i++){
219  wxString name = mMacros->GetItemText(i);
220  if( MacroIdOfName( name ) == MacroID ){
221  ApplyMacroToProject( i, bHasGui );
222  return;
223  }
224  }
225 }
226 
227 // Apply macro, given its number in the list.
228 void ApplyMacroDialog::ApplyMacroToProject( int iMacro, bool bHasGui )
229 {
230  wxString name = mMacros->GetItemText(iMacro);
231  if( name.IsEmpty() )
232  return;
233 
234  wxDialogWrapper activityWin( this, wxID_ANY, GetTitle());
235  activityWin.SetName(activityWin.GetTitle());
236  ShuttleGui S(&activityWin, eIsCreating);
237 
238  S.StartHorizontalLay(wxCENTER, false);
239  {
240  S.StartStatic( {}, false); // deliberately not translated (!)
241  {
242  S.SetBorder(20);
243  S.AddFixedText(wxString::Format(_("Applying '%s' to current project"),
244  name));
245  }
246  S.EndStatic();
247  }
248  S.EndHorizontalLay();
249 
250  activityWin.Layout();
251  activityWin.Fit();
252  activityWin.CenterOnScreen();
253  // Avoid overlap with progress.
254  int x,y;
255  activityWin.GetPosition( &x, &y );
256  activityWin.Move(wxMax(0,x-300), 0);
257  activityWin.Show();
258 
259  // Without this the newly created dialog may not show completely.
260  wxYield();
261 
262  //Since we intend to keep this dialog open, there is no reason to hide it
263  //and then show it again.
264  //if( bHasGui )
265  // Hide();
266 
267  gPrefs->Write(wxT("/Batch/ActiveMacro"), name);
268  gPrefs->Flush();
269 
271 
272  // The disabler must get deleted before the EndModal() call. Otherwise,
273  // the menus on OSX will remain disabled.
274  bool success;
275  {
276  wxWindowDisabler wd(&activityWin);
277  success = GuardedCall< bool >(
278  [this]{ return mMacroCommands.ApplyMacro(mCatalog); } );
279  }
280 
281  if( !bHasGui )
282  return;
283 
284  Show();
285  Raise();
286 }
287 
288 void ApplyMacroDialog::OnApplyToFiles(wxCommandEvent & WXUNUSED(event))
289 {
290  long item = mMacros->GetNextItem(-1,
291  wxLIST_NEXT_ALL,
292  wxLIST_STATE_SELECTED);
293  if (item == -1) {
294  AudacityMessageBox(_("No macro selected"));
295  return;
296  }
297 
298  wxString name = mMacros->GetItemText(item);
299  gPrefs->Write(wxT("/Batch/ActiveMacro"), name);
300  gPrefs->Flush();
301 
302  AudacityProject *project = GetActiveProject();
303  if (!project->GetIsEmpty()) {
304  AudacityMessageBox(_("Please save and close the current project first."));
305  return;
306  }
307 
308  wxString prompt = _("Select file(s) for batch processing...");
309 
310  FormatList l;
311  wxString filter;
312  wxString all;
313 
315  for (const auto &format : l) {
316  const Format *f = &format;
317 
318  wxString newfilter = f->formatName + wxT("|");
319  for (size_t i = 0; i < f->formatExtensions.size(); i++) {
320  if (!newfilter.Contains(wxT("*.") + f->formatExtensions[i] + wxT(";")))
321  newfilter += wxT("*.") + f->formatExtensions[i] + wxT(";");
322  if (!all.Contains(wxT("*.") + f->formatExtensions[i] + wxT(";")))
323  all += wxT("*.") + f->formatExtensions[i] + wxT(";");
324  }
325  newfilter.RemoveLast(1);
326  filter += newfilter;
327  filter += wxT("|");
328  }
329  all.RemoveLast(1);
330  filter.RemoveLast(1);
331 
332  wxString mask = _("All files|*|All supported files|") +
333  all + wxT("|") +
334  filter;
335 
336  wxString type = gPrefs->Read(wxT("/DefaultOpenType"),mask.BeforeFirst(wxT('|')));
337  // Convert the type to the filter index
338  int index = mask.First(type + wxT("|"));
339  if (index == wxNOT_FOUND) {
340  index = 0;
341  }
342  else {
343  index = mask.Left(index).Freq(wxT('|')) / 2;
344  if (index < 0) {
345  index = 0;
346  }
347  }
348 
350  FileDialogWrapper dlog(this,
351  prompt,
352  path,
353  wxT(""),
354  mask,
355  wxFD_OPEN | wxFD_MULTIPLE | wxRESIZE_BORDER);
356 
357  dlog.SetFilterIndex(index);
358  if (dlog.ShowModal() != wxID_OK) {
359  Raise();
360  return;
361  }
362  Raise();
363 
364  wxArrayString files;
365  dlog.GetPaths(files);
366 
367  files.Sort();
368 
369  wxDialogWrapper activityWin(this, wxID_ANY, GetTitle());
370  activityWin.SetName(activityWin.GetTitle());
371  ShuttleGui S(&activityWin, eIsCreating);
372 
373  wxListCtrl * fileList = NULL;
374 
375  S.StartVerticalLay(false);
376  {
377  S.StartStatic(_("Applying..."), 1);
378  {
379  auto imageList = std::make_unique<wxImageList>(9, 16);
380  imageList->Add(wxIcon(empty9x16_xpm));
381  imageList->Add(wxIcon(arrow_xpm));
382 
383  S.SetStyle(wxSUNKEN_BORDER | wxLC_REPORT | wxLC_HRULES | wxLC_VRULES |
384  wxLC_SINGLE_SEL);
386  // AssignImageList takes ownership
387  fileList->AssignImageList(imageList.release(), wxIMAGE_LIST_SMALL);
388  fileList->InsertColumn(0, _("File"), wxLIST_FORMAT_LEFT);
389  }
390  S.EndStatic();
391 
392  S.StartHorizontalLay(wxCENTER, false);
393  {
394  S.Id(wxID_CANCEL).AddButton(_("&Cancel"));
395  }
396  S.EndHorizontalLay();
397  }
398  S.EndVerticalLay();
399 
400  int i;
401  for (i = 0; i < (int)files.GetCount(); i++ ) {
402  fileList->InsertItem(i, files[i], i == 0);
403  }
404 
405  // Set the column size for the files list.
406  fileList->SetColumnWidth(0, wxLIST_AUTOSIZE);
407 
408  int width = fileList->GetColumnWidth(0);
409  wxSize sz = fileList->GetClientSize();
410  if (width > sz.GetWidth() && width < 500) {
411  sz.SetWidth(width);
412  fileList->SetInitialSize(sz);
413  }
414 
415  activityWin.Layout();
416  activityWin.Fit();
417  activityWin.CenterOnScreen();
418  // Avoid overlap with progress.
419  int x,y;
420  activityWin.GetPosition( &x, &y );
421  activityWin.Move(wxMax(0,x-300), 0);
422  activityWin.Show();
423 
424  // Without this the newly created dialog may not show completely.
425  wxYield();
426  // We could avoid hiding, but there are many dialogs on screen,
427  // and hiding this one temporarily has some advantages.
428  Hide();
429 
431  for (i = 0; i < (int)files.GetCount(); i++) {
432  wxWindowDisabler wd(&activityWin);
433  if (i > 0) {
434  //Clear the arrow in previous item.
435  fileList->SetItemImage(i - 1, 0, 0);
436  }
437  fileList->SetItemImage(i, 1, 1);
438  fileList->EnsureVisible(i);
439 
440  auto success = GuardedCall< bool >( [&] {
441  project->Import(files[i]);
442  project->ZoomAfterImport(nullptr);
443  project->OnSelectAll(*project);
445  return false;
446 
447  if (!activityWin.IsShown() || mAbort)
448  return false;
449 
450  return true;
451  } );
452 
453  if (!success)
454  break;
455 
456  UndoManager *um = project->GetUndoManager();
457  um->ClearStates();
458  project->OnSelectAll(*project);
459  project->OnRemoveTracks(*project);
460  }
461  project->OnRemoveTracks(*project);
462 
463  Show();
464  Raise();
465 }
466 
467 void ApplyMacroDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
468 {
469  Hide();
470 }
471 
473 #include <wx/textdlg.h>
474 #include "BatchCommandDialog.h"
475 
476 enum {
477  AddButtonID = 10000,
488 // MacrosListID 7005
489 // CommandsListID, 7002
490 // Re-Use IDs from ApplyMacroDialog.
493 };
494 
495 BEGIN_EVENT_TABLE(MacrosWindow, ApplyMacroDialog)
498  EVT_LIST_BEGIN_LABEL_EDIT(MacrosListID, MacrosWindow::OnMacrosBeginEdit)
499  EVT_LIST_END_LABEL_EDIT(MacrosListID, MacrosWindow::OnMacrosEndEdit)
503  EVT_BUTTON(ExpandID, MacrosWindow::OnExpand)
504  EVT_BUTTON(ShrinkID, MacrosWindow::OnShrink)
505 
506  EVT_SIZE(MacrosWindow::OnSize)
507 
508  EVT_LIST_ITEM_ACTIVATED(CommandsListID, MacrosWindow::OnCommandActivated)
510  EVT_BUTTON(EditButtonID, MacrosWindow::OnEditCommandParams)
515 
516  EVT_BUTTON(wxID_OK, MacrosWindow::OnOK)
517  EVT_BUTTON(wxID_CANCEL, MacrosWindow::OnCancel)
518 
519  EVT_KEY_DOWN(MacrosWindow::OnKeyDown)
521 
522 enum {
527 };
528 
530 MacrosWindow::MacrosWindow(wxWindow * parent, bool bExpanded):
531  ApplyMacroDialog(parent, true)
532 {
533  mbExpanded = bExpanded;
534  wxString Title = mbExpanded ? _("Manage Macros") : _("Macros Palette");
535  SetLabel( Title ); // Provide visual label
536  SetName( Title ); // Provide audible label
537  SetTitle( Title );
538 
539  mChanged = false;
540  mSelectedCommand = 0;
541 
542  if( mbExpanded )
543  Populate();
544  else
546 }
547 
549 {
550 }
551 
554 {
555  //------------------------- Main section --------------------
556  ShuttleGui S(this, eIsCreating);
558  // ----------------------- End of main section --------------
559 
560  // Get and validate the currently active macro
561  mActiveMacro = gPrefs->Read(wxT("/Batch/ActiveMacro"), wxT(""));
562  // Go populate the macros list.
563  PopulateMacros();
564 
565  // We have a bare list. We need to add columns and content.
566  PopulateList();
567 
568  // Layout and set minimum size of window
569  Layout();
570  Fit();
571  SetSizeHints(GetSize());
572 
573  // Size and place window
574  SetSize(std::min(wxSystemSettings::GetMetric(wxSYS_SCREEN_X) * 3 / 4, 800),
575  std::min(wxSystemSettings::GetMetric(wxSYS_SCREEN_Y) * 4 / 5, 400));
576  Center();
577 
578  // Set the column size for the macros list.
579  wxSize sz = mMacros->GetClientSize();
580  mMacros->SetColumnWidth(0, sz.x);
581 
582  // Size columns properly
583  FitColumns();
584 }
585 
588 {
589  S.StartHorizontalLay(wxEXPAND, 1);
590  {
591  S.StartStatic(_("&Select Macro"),0);
592  {
593  S.StartHorizontalLay(wxEXPAND,1);
594  {
595  S.SetStyle(wxSUNKEN_BORDER | wxLC_REPORT | wxLC_HRULES | wxLC_SINGLE_SEL |
596  wxLC_EDIT_LABELS);
598  // i18n-hint: This is the heading for a column in the edit macros dialog
599  mMacros->InsertColumn(0, _("Macro"), wxLIST_FORMAT_LEFT);
600  S.StartVerticalLay(wxALIGN_TOP, 0);
601  {
602  S.Id(AddButtonID).AddButton(_("&New"));
603  mRemove = S.Id(RemoveButtonID).AddButton(_("Remo&ve"));
604  mRename = S.Id(RenameButtonID).AddButton(_("&Rename..."));
605  S.Id(ImportButtonID).AddButton(_("I&mport..."))->Enable( false);
606  S.Id(ExportButtonID).AddButton(_("E&xport..."))->Enable( false);
607  }
608  S.EndVerticalLay();
609  }
610  S.EndHorizontalLay();
611  }
612  S.EndStatic();
613 
614  S.StartStatic(_("Edit S&teps"), true);
615  {
616  S.StartHorizontalLay(wxEXPAND,1);
617  {
618 
619  S.SetStyle(wxSUNKEN_BORDER | wxLC_REPORT | wxLC_HRULES | wxLC_VRULES |
620  wxLC_SINGLE_SEL);
622 
623  //An empty first column is a workaround - under Win98 the first column
624  //can't be right aligned.
625  mList->InsertColumn(BlankColumn, wxT(""), wxLIST_FORMAT_LEFT);
626  /* i18n-hint: This is the number of the command in the list */
627  mList->InsertColumn(ItemNumberColumn, _("Num"), wxLIST_FORMAT_RIGHT);
628  mList->InsertColumn(ActionColumn, _("Command "), wxLIST_FORMAT_RIGHT);
629  mList->InsertColumn(ParamsColumn, _("Parameters"), wxLIST_FORMAT_LEFT);
630 
631  S.StartVerticalLay(wxALIGN_TOP, 0);
632  {
633  S.Id(InsertButtonID).AddButton(_("&Insert"), wxALIGN_LEFT);
634  S.Id(EditButtonID).AddButton(_("&Edit..."), wxALIGN_LEFT);
635  S.Id(DeleteButtonID).AddButton(_("De&lete"), wxALIGN_LEFT);
636  S.Id(UpButtonID).AddButton(_("Move &Up"), wxALIGN_LEFT);
637  S.Id(DownButtonID).AddButton(_("Move &Down"), wxALIGN_LEFT);
638  mDefaults = S.Id(DefaultsButtonID).AddButton(_("De&faults"));
639  }
640  S.EndVerticalLay();
641  }
642  S.EndHorizontalLay();
643  }
644  S.EndStatic();
645  }
646  S.EndHorizontalLay();
647 
648  S.StartHorizontalLay(wxEXPAND, 0);
649  {
650  mResize = S.Id(ShrinkID).AddButton(_("Shrin&k"));
651  // Using variable text just to get the positioning options.
652  S.Prop(0).AddVariableText( _("Apply Macro to:"), false, wxALL | wxALIGN_CENTRE_VERTICAL );
653  S.Id(ApplyToProjectID).AddButton(_("&Project"));
654  S.Id(ApplyToFilesID).AddButton(_("&Files..."));
655  S.Prop(1).AddSpace( 10 );
657  }
658  S.EndHorizontalLay();
659 
660 
661  return;
662 }
663 
666 {
667  int topItem = mList->GetTopItem();
668  mList->DeleteAllItems();
669 
670  for (int i = 0; i < mMacroCommands.GetCount(); i++) {
673  }
674  /*i18n-hint: This is the last item in a list.*/
675  AddItem(_("- END -"), wxT(""));
676 
677  // Select the name in the list...this will fire an event.
678  if (mSelectedCommand >= (int)mList->GetItemCount()) {
679  mSelectedCommand = 0;
680  }
681  mList->SetItemState(mSelectedCommand, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
682  if( 0 <= topItem && topItem < (int)mList->GetItemCount())
683  {
684  // Workaround for scrolling being windows only.
685  // Try to scroll back to where we once were...
686  mList->EnsureVisible( (int)mList->GetItemCount() -1 );
687  mList->EnsureVisible( topItem );
688  // And then make sure whatever is selected is still visible...
689  if (mSelectedCommand >= 0) {
690  mList->EnsureVisible( mSelectedCommand );
691  }
692  }
693 }
694 
696 void MacrosWindow::AddItem(const wxString &Action, const wxString &Params)
697 {
698  auto entry = mCatalog.ByCommandId(Action);
699  auto friendlyName = entry != mCatalog.end()
700  ? entry->name.Translated()
701  :
702  // Expose an internal name to the user in default of any friendly name
703  // -- AVOID THIS!
704  Action;
705 
706  int i = mList->GetItemCount();
707 
708  mList->InsertItem(i, wxT(""));
709  mList->SetItem(i, ItemNumberColumn, wxString::Format(wxT(" %02i"), i + 1));
710  mList->SetItem(i, ActionColumn, friendlyName );
711  mList->SetItem(i, ParamsColumn, Params );
712 }
713 
715 {
716  // OK even on mac, as dialog is modal.
718 }
719 
720 void MacrosWindow::UpdateDisplay( bool bExpanded )
721 {
722  if( bExpanded == mbExpanded )
723  return;
724 
725  if( !SaveChanges() )
726  return;
727 
728  mbExpanded = bExpanded;
729  DestroyChildren();
730  SetSizer( nullptr );
731 
732  mChanged = false;
733  mSelectedCommand = 0;
734  SetMinSize( wxSize( 200,200 ));
735 
736  // Get and set position for optical stability.
737  // Expanded and shrunk dialogs 'stay where they were'.
738  // That's OK , and what we want, even if we exapnd off-screen.
739  // We won't shrink to being off-screen, since the shrink button
740  // was clicked, so must have been on screen.
741  wxPoint p = GetPosition( );
742  if( mbExpanded )
743  Populate();
744  else
746  SetPosition( p );
747  mResize->SetFocus();
748 
749  wxString Title = mbExpanded ? _("Manage Macros") : _("Macros Palette");
750  SetLabel( Title ); // Provide visual label
751  SetName( Title ); // Provide audible label
752  SetTitle( Title );
753 }
754 
755 void MacrosWindow::OnExpand(wxCommandEvent &WXUNUSED(event))
756 { UpdateDisplay( true );}
757 
758 void MacrosWindow::OnShrink(wxCommandEvent &WXUNUSED(event))
759 { UpdateDisplay( false );}
760 
761 
763 {
764  if (mChanged) {
765  wxString title;
766  wxString msg;
767  int id;
768 
769  title.Printf(_("%s changed"), mActiveMacro);
770  msg = _("Do you want to save the changes?");
771 
772  id = AudacityMessageBox(msg, title, wxYES_NO | wxCANCEL);
773  if (id == wxCANCEL) {
774  return false;
775  }
776 
777  if (id == wxYES) {
779  return false;
780  }
781  }
782 
783  mChanged = false;
784  }
785 
786  return true;
787 }
789 void MacrosWindow::OnMacroSelected(wxListEvent & event)
790 {
791  if (!ChangeOK()) {
792  event.Veto();
793  return;
794  }
795 
796  int item = event.GetIndex();
797 
798  mActiveMacro = mMacros->GetItemText(item);
800  if( !mbExpanded )
801  return;
802 
804  mRemove->Disable();
805  mRename->Disable();
806  mDefaults->Enable();
807  }
808  else {
809  mRemove->Enable();
810  mRename->Enable();
811  mDefaults->Disable();
812  }
813 
814  PopulateList();
815 }
816 
818 void MacrosWindow::OnListSelected(wxListEvent & WXUNUSED(event))
819 {
820  FitColumns();
821 }
822 
824 void MacrosWindow::OnSize(wxSizeEvent & WXUNUSED(event))
825 {
826  // Refrsh the layout and re-fit the columns.
827  Layout();
828  if( !mbExpanded )
829  return;
830  FitColumns();
831 }
832 
834 {
835  mList->SetColumnWidth(0, 0); // First column width is zero, to hide it.
836 
837 #if defined(__WXMAC__)
838  // wxMac uses a hard coded width of 150 when wxLIST_AUTOSIZE_USEHEADER
839  // is specified, so we calculate the width ourselves. This method may
840  // work equally well on other platforms.
841  for (size_t c = 1; c < mList->GetColumnCount(); c++) {
842  wxListItem info;
843  int width;
844 
845  mList->SetColumnWidth(c, wxLIST_AUTOSIZE);
846  info.Clear();
847  info.SetId(c);
848  info.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_WIDTH);
849  mList->GetColumn(c, info);
850 
851  mList->GetTextExtent(info.GetText(), &width, NULL);
852  width += 2 * 4; // 2 * kItemPadding - see listctrl_mac.cpp
853  width += 16; // kIconWidth - see listctrl_mac.cpp
854 
855  mList->SetColumnWidth(c, wxMax(width, mList->GetColumnWidth(c)));
856  }
857 
858  // Looks strange, but it forces the horizontal scrollbar to get
859  // drawn. If not done, strange column sizing can occur if the
860  // user attempts to resize the columns.
861  mList->SetClientSize(mList->GetClientSize());
862 #else
863  mList->SetColumnWidth(1, wxLIST_AUTOSIZE_USEHEADER);
864  mList->SetColumnWidth(2, wxLIST_AUTOSIZE_USEHEADER);
865  mList->SetColumnWidth(3, wxLIST_AUTOSIZE);
866 #endif
867 
868  int bestfit = mList->GetColumnWidth(3);
869  int clientsize = mList->GetClientSize().GetWidth();
870  int col1 = mList->GetColumnWidth(1);
871  int col2 = mList->GetColumnWidth(2);
872  bestfit = (bestfit > clientsize-col1-col2)? bestfit : clientsize-col1-col2;
873  mList->SetColumnWidth(3, bestfit);
874 
875 }
876 
878 void MacrosWindow::OnMacrosBeginEdit(wxListEvent &event)
879 {
880  int itemNo = event.GetIndex();
881 
882  wxString macro = mMacros->GetItemText(itemNo);
883 
885  wxBell();
886  event.Veto();
887  }
888 }
889 
891 void MacrosWindow::OnMacrosEndEdit(wxListEvent &event)
892 {
893  if (event.IsEditCancelled()) {
894  return;
895  }
896 
897  wxString newname = event.GetLabel();
898 
900 
901  mActiveMacro = newname;
902 
903  PopulateMacros();
904 }
905 
907 void MacrosWindow::OnAdd(wxCommandEvent & WXUNUSED(event))
908 {
909  while (true) {
911  _("Enter name of new macro"),
912  _("Name of new macro"));
913  d.SetName(d.GetTitle());
914  wxString name;
915 
916  if (d.ShowModal() == wxID_CANCEL) {
917  Raise();
918  return;
919  }
920  Raise();
921 
922  name = d.GetValue().Strip(wxString::both);
923 
924  if (name.Length() == 0) {
925  AudacityMessageBox(_("Name must not be blank"),
926  GetTitle(),
927  wxOK | wxICON_ERROR,
928  this);
929  continue;
930  }
931 
932  if (name.Contains(wxFILE_SEP_PATH) ||
933  name.Contains(wxFILE_SEP_PATH_UNIX)) {
934  /*i18n-hint: The %c will be replaced with 'forbidden characters', like '/' and '\'.*/
935  AudacityMessageBox(wxString::Format(_("Names may not contain '%c' and '%c'"),
936  wxFILE_SEP_PATH, wxFILE_SEP_PATH_UNIX),
937  GetTitle(),
938  wxOK | wxICON_ERROR,
939  this);
940  continue;
941  }
942 
943  mMacroCommands.AddMacro(name);
944 
945  mActiveMacro = name;
946 
947  PopulateMacros();
948  UpdateMenus();
949 
950  break;
951  }
952 }
953 
955 void MacrosWindow::OnRemove(wxCommandEvent & WXUNUSED(event))
956 {
957  long item = mMacros->GetNextItem(-1,
958  wxLIST_NEXT_ALL,
959  wxLIST_STATE_SELECTED);
960  if (item == -1) {
961  return;
962  }
963 
964  wxString name = mMacros->GetItemText(item);
965  AudacityMessageDialog m(this,
966  /*i18n-hint: %s will be replaced by the name of a file.*/
967  wxString::Format(_("Are you sure you want to delete %s?"), name),
968  GetTitle(),
969  wxYES_NO | wxICON_QUESTION);
970  if (m.ShowModal() == wxID_NO) {
971  Raise();
972  return;
973  }
974  Raise();
975 
977 
978  item++;
979  if (item >= (mMacros->GetItemCount() - 1) && item >= 0) {
980  item--;
981  }
982 
983  mActiveMacro = mMacros->GetItemText(item);
984 
985  PopulateMacros();
986  UpdateMenus();
987 }
988 
990 void MacrosWindow::OnRename(wxCommandEvent & WXUNUSED(event))
991 {
992  long item = mMacros->GetNextItem(-1,
993  wxLIST_NEXT_ALL,
994  wxLIST_STATE_SELECTED);
995  if (item == -1) {
996  return;
997  }
998 
999  mMacros->EditLabel(item);
1000  UpdateMenus();
1001 }
1002 
1005 void MacrosWindow::OnCommandActivated(wxListEvent & WXUNUSED(event))
1006 {
1007  wxCommandEvent dummy;
1008  OnEditCommandParams( dummy );
1009 }
1010 
1012 void MacrosWindow::OnInsert(wxCommandEvent & WXUNUSED(event))
1013 {
1014  long item = mList->GetNextItem(-1,
1015  wxLIST_NEXT_ALL,
1016  wxLIST_STATE_SELECTED);
1017  if (item == -1) {
1018  item = mList->GetItemCount()-1;
1019  }
1020  InsertCommandAt( item );
1021 }
1022 
1024 {
1025  if (item == -1) {
1026  return;
1027  }
1028 
1029  MacroCommandDialog d(this, wxID_ANY);
1030 
1031  if (!d.ShowModal()) {
1032  Raise();
1033  return;
1034  }
1035  Raise();
1036 
1037  if(d.mSelectedCommand != wxT(""))
1038  {
1041  item);
1042  mChanged = true;
1043  mSelectedCommand = item + 1;
1044  PopulateList();
1045  }
1046 
1047 }
1048 
1049 void MacrosWindow::OnEditCommandParams(wxCommandEvent & WXUNUSED(event))
1050 {
1051  int item = mList->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
1052 
1053  // LAST command in list is END.
1054  // If nothing selected, add at END.
1055  // If END selected, add at END.
1056  // When adding at end we use InsertCommandAt, so that a new command
1057  // can be chosen.
1058  int lastItem = mList->GetItemCount()-1;
1059  if( (item<0) || (item+1) == mList->GetItemCount() )
1060  {
1061  InsertCommandAt( lastItem );
1062  return;
1063  }
1064 
1065  // Just edit the parameters, and not the command.
1066  wxString command = mMacroCommands.GetCommand(item);
1067  wxString params = mMacroCommands.GetParams(item);
1068 
1069  params = MacroCommands::PromptForParamsFor(command, params, this).Trim();
1070  Raise();
1071 
1073  mMacroCommands.AddToMacro(command,
1074  params,
1075  item);
1076  mChanged = true;
1077  mSelectedCommand = item;
1078  PopulateList();
1079 }
1080 
1082 void MacrosWindow::OnDelete(wxCommandEvent & WXUNUSED(event))
1083 {
1084  long item = mList->GetNextItem(-1,
1085  wxLIST_NEXT_ALL,
1086  wxLIST_STATE_SELECTED);
1087  if (item == -1 || item + 1 == mList->GetItemCount()) {
1088  return;
1089  }
1090 
1092  mChanged = true;
1093 
1094  if (item >= (mList->GetItemCount() - 2) && item >= 0) {
1095  item--;
1096  }
1097  mSelectedCommand = item;
1098  PopulateList();
1099 }
1100 
1102 void MacrosWindow::OnUp(wxCommandEvent & WXUNUSED(event))
1103 {
1104  long item = mList->GetNextItem(-1,
1105  wxLIST_NEXT_ALL,
1106  wxLIST_STATE_SELECTED);
1107  if (item == -1 || item == 0 || item + 1 == mList->GetItemCount()) {
1108  return;
1109  }
1110 
1112  mMacroCommands.GetParams(item),
1113  item - 1);
1114  mMacroCommands.DeleteFromMacro(item + 1);
1115  mChanged = true;
1116  mSelectedCommand = item - 1;
1117  PopulateList();
1118 }
1119 
1121 void MacrosWindow::OnDown(wxCommandEvent & WXUNUSED(event))
1122 {
1123  long item = mList->GetNextItem(-1,
1124  wxLIST_NEXT_ALL,
1125  wxLIST_STATE_SELECTED);
1126  if (item == -1 || item + 2 >= mList->GetItemCount()) {
1127  return;
1128  }
1129 
1131  mMacroCommands.GetParams(item),
1132  item + 2);
1134  mChanged = true;
1135  mSelectedCommand = item + 1;
1136  PopulateList();
1137 }
1138 
1139 void MacrosWindow::OnApplyToProject(wxCommandEvent & event)
1140 {
1141  if( !SaveChanges() )
1142  return;
1144 }
1145 
1146 void MacrosWindow::OnApplyToFiles(wxCommandEvent & event)
1147 {
1148  if( !SaveChanges() )
1149  return;
1151 }
1152 
1154 void MacrosWindow::OnDefaults(wxCommandEvent & WXUNUSED(event))
1155 {
1157 
1158  mChanged = true;
1159 
1160  PopulateList();
1161 }
1162 
1164  gPrefs->Write(wxT("/Batch/ActiveMacro"), mActiveMacro);
1165  gPrefs->Flush();
1166 
1167  if (mChanged) {
1169  return false;
1170  }
1171  }
1172  mChanged = false;
1173  return true;
1174 }
1175 
1177 void MacrosWindow::OnOK(wxCommandEvent & WXUNUSED(event))
1178 {
1179  if( !SaveChanges() )
1180  return;
1181  Hide();
1182  //EndModal(true);
1183 }
1184 
1186 void MacrosWindow::OnCancel(wxCommandEvent &WXUNUSED(event))
1187 {
1188  if (!ChangeOK()) {
1189  return;
1190  }
1191  Hide();
1192 }
1193 
1195 void MacrosWindow::OnKeyDown(wxKeyEvent &event)
1196 {
1197  if (event.GetKeyCode() == WXK_DELETE) {
1198  wxLogDebug(wxT("wxKeyEvent"));
1199  }
1200 
1201  event.Skip();
1202 }
bool AddMacro(const wxString &macro)
static wxString FindDefaultPath(Operation op)
Definition: FileNames.cpp:390
void OnApplyToProject(wxCommandEvent &event) override
void AddToMacro(const wxString &command, int before=-1)
static wxArrayString names()
Definition: Tags.cpp:697
#define ExpandID
AudacityPrefs * gPrefs
Definition: Prefs.cpp:73
wxListCtrl * mMacros
wxString GetParams(int index)
#define MacrosListID
virtual void OnHelp(wxCommandEvent &event)
virtual void OnApplyToProject(wxCommandEvent &event)
MacroCommands mMacroCommands
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
Abstract base class used in importing a file.
Definition: Import.h:32
void OnDelete(wxCommandEvent &event)
virtual void OnCancel(wxCommandEvent &event)
void OnInsert(wxCommandEvent &event)
wxString GetCommand(int index)
#define CommandsListID
void OnApplyToFiles(wxCommandEvent &event) override
void OnKeyDown(wxKeyEvent &event)
static wxArrayString GetNames()
void OnUp(wxCommandEvent &event)
bool RenameMacro(const wxString &oldmacro, const wxString &newmacro)
int AudacityMessageBox(const wxString &message, const wxString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: ErrorDialog.h:92
bool ApplyMacro(const MacroCommandsCatalog &catalog, const wxString &filename=wxT(""))
void ClearStates()
void OnSelectAll(const CommandContext &context)
Definition: Menus.cpp:6248
Wrap wxTextEntryDialog so that caption IS translatable.
Definition: ErrorDialog.h:108
Wrap wxMessageDialog so that caption IS translatable.
Definition: ErrorDialog.h:129
void OnDelete(const CommandContext &context)
virtual void OnApplyToFiles(wxCommandEvent &event)
void EndHorizontalLay()
void GetSupportedImportFormats(FormatList *formatList)
Definition: Import.cpp:123
void RebuildMenuBar()
Definition: Menus.cpp:2110
void RestoreMacro(const wxString &name)
void OnAdd(wxCommandEvent &event)
void AddPrompt(const wxString &Prompt)
Right aligned text string.
Definition: ShuttleGui.cpp:239
void OnRemove(wxCommandEvent &event)
void OnMacroSelected(wxListEvent &event)
An item in the macros list has been selected.
#define ShrinkID
wxButton * mDefaults
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:176
void EndVerticalLay()
void OnListSelected(wxListEvent &event)
An item in the macros list has been selected.
#define ApplyToFilesID
bool GetIsEmpty()
Definition: Project.cpp:1500
void InsertCommandAt(int item)
void ZoomAfterImport(Track *pTrack)
Definition: Project.cpp:4360
int format
Definition: ExportPCM.cpp:56
bool Import(const wxString &fileName, WaveTrackArray *pTrackArray=NULL)
Definition: Project.cpp:4372
void StartHorizontalLay(int PositionFlags=wxALIGN_CENTRE, int iProp=1)
wxListCtrl * AddListControlReportMode()
Definition: ShuttleGui.cpp:689
ShuttleGui & Id(int id)
bool DeleteMacro(const wxString &name)
void SetStyle(int Style)
Definition: ShuttleGui.h:287
MacrosWindow(wxWindow *parent, bool bExpanded=true)
Constructor.
static void ShowHelp(wxWindow *parent, const wxString &localFileName, const wxString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
Definition: HelpSystem.cpp:194
void AddFixedText(const wxString &Str, bool bCenter=false)
Definition: ShuttleGui.cpp:397
static wxString PromptForParamsFor(const wxString &command, const wxString &params, wxWindow *parent)
void PopulateList()
This clears and updates the contents of mList, the commands for the current macro.
#define ApplyToProjectID
int min(int a, int b)
EVT_LIST_ITEM_ACTIVATED(wxID_ANY, SuccessDialog::OnItemActivated) ExportMultiple
void ApplyMacroToProject(int iMacro, bool bHasGui=true)
void AddItem(const wxString &command, wxString const &params)
Add one item into mList.
void OnEditCommandParams(wxCommandEvent &event)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
bool ReadMacro(const wxString &macro)
wxButton * mRemove
const MacroCommandsCatalog mCatalog
bool WriteMacro(const wxString &macro)
void PopulateOrExchange(ShuttleGui &S)
Defines the dialog and does data exchange with it.
virtual void SetFilterIndex(int filterIndex)
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
void OnDefaults(wxCommandEvent &event)
Select the empty Command macro.
virtual int ShowModal()
void OnSize(wxSizeEvent &event)
The window has been resized.
Entries::const_iterator ByCommandId(const wxString &commandId) const
void DeleteFromMacro(int index)
virtual wxString GetHelpPageName()
void OnCommandActivated(wxListEvent &event)
const wxChar * name
Definition: Distortion.cpp:94
UndoManager * GetUndoManager()
Definition: Project.h:195
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:308
wxStaticText * AddVariableText(const wxString &Str, bool bCenter=false, int PositionFlags=0)
Definition: ShuttleGui.cpp:414
wxStaticBox * StartStatic(const wxString &Str, int iProp=0)
Definition: ShuttleGui.cpp:763
Entries::const_iterator end() const
Definition: BatchCommands.h:44
void PopulateOrExchange(ShuttleGui &S)
Defines the dialog and does data exchange with it.
wxArrayString formatExtensions
Definition: Import.h:35
void OnMacrosBeginEdit(wxListEvent &event)
void UpdateDisplay(bool bExpanded)
void OnMacrosEndEdit(wxListEvent &event)
Works with HistoryWindow to provide the Undo functionality.
Definition: UndoManager.h:93
ShuttleGui & Prop(int iProp)
Definition: ShuttleGui.h:418
wxButton * mResize
Provides list of available commands.
void OnDown(wxCommandEvent &event)
void OnExpand(wxCommandEvent &event)
void OnShrink(wxCommandEvent &event)
void Populate()
Creates the dialog and its contents.
void OnRename(wxCommandEvent &event)
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
END_EVENT_TABLE()
wxSizerItem * AddSpace(int width, int height)
static Importer & Get()
Definition: Import.cpp:71
EffectDistortion::Params params
Definition: Distortion.cpp:95
void SetBorder(int Border)
Definition: ShuttleGui.h:286
Shows progress in executing commands in MacroCommands.
Provides a list of configurable commands for use with MacroCommands.
static wxString MacroIdOfName(const wxString &MacroName)
void OnCancel(wxCommandEvent &event) override
void OnRemoveTracks(const CommandContext &context)
Definition: Menus.cpp:8664
void OnOK(wxCommandEvent &event)
Send changed values back to Prefs, and update Audacity.
wxButton * AddButton(const wxString &Text, int PositionFlags=wxALIGN_CENTRE)
Definition: ShuttleGui.cpp:341
bool IsFixed(const wxString &name)
virtual void GetPaths(wxArrayString &paths) const
std::vector< Format > FormatList
Definition: Import.h:46
wxString formatName
Definition: Import.h:34
EVT_LIST_ITEM_SELECTED(CurvesListID, EditCurvesDialog::OnListSelectionChange) EVT_LIST_ITEM_DESELECTED(CurvesListID
Constructor.
wxButton * mRename
void StartVerticalLay(int iProp=1)