Audacity  3.0.3
CommandManager.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  CommandManager.cpp
6 
7  Brian Gunlogson
8  Dominic Mazzoni
9 
10 *******************************************************************//****************************************************************//****************************************************************//****************************************************************//****************************************************************//****************************************************************//****************************************************************//****************************************************************//******************************************************************/
77 
78 
79 
80 #include "CommandManager.h"
81 
82 #include "CommandContext.h"
84 
85 #include <wx/defs.h>
86 #include <wx/evtloop.h>
87 #include <wx/frame.h>
88 #include <wx/hash.h>
89 #include <wx/intl.h>
90 #include <wx/log.h>
91 #include <wx/menu.h>
92 #include <wx/tokenzr.h>
93 
94 #include "../Menus.h"
95 
96 #include "../Project.h"
97 #include "../widgets/AudacityMessageBox.h"
98 #include "../widgets/HelpSystem.h"
99 
100 
101 // On wxGTK, there may be many many many plugins, but the menus don't automatically
102 // allow for scrolling, so we build sub-menus. If the menu gets longer than
103 // MAX_MENU_LEN, we put things in submenus that have MAX_SUBMENU_LEN items in them.
104 //
105 #ifdef __WXGTK__
106 #define MAX_MENU_LEN 20
107 #define MAX_SUBMENU_LEN 15
108 #else
109 #define MAX_MENU_LEN 1000
110 #define MAX_SUBMENU_LEN 1000
111 #endif
112 
113 #define COMMAND XO("Command")
114 
115 
117 {
118  MenuBarListEntry(const wxString &name_, wxMenuBar *menubar_);
120 
121  wxString name;
122  wxWeakRef<wxMenuBar> menubar; // This structure does not assume memory ownership!
123 };
124 
126 {
127  SubMenuListEntry( const TranslatableString &name_ );
130 
132  std::unique_ptr<wxMenu> menu;
133 };
134 
136 {
137  int id;
145  wxMenu *menu;
149 
150  // type of a function that determines checkmark state
151  using CheckFn = std::function< bool(AudacityProject&) >;
153 
154  bool multi;
155  int index;
156  int count;
157  bool enabled;
159  bool wantKeyup;
160  bool allowDup;
161  bool isGlobal;
162  bool isOccult;
163  bool isEffect;
166  bool useStrictFlags{ false };
167 };
168 
170 {
171 }
172 
174 {
175 }
176 
177 MenuBarListEntry::MenuBarListEntry(const wxString &name_, wxMenuBar *menubar_)
178  : name(name_), menubar(menubar_)
179 {
180 }
181 
183 {
184 }
185 
187  : name(name_), menu( std::make_unique< wxMenu >() )
188 {
189 }
190 
192 {
193 }
194 
197  [](AudacityProject&) {
198  return std::make_unique<CommandManager>();
199  }
200 };
201 
203 {
204  return project.AttachedObjects::Get< CommandManager >( key );
205 }
206 
208 {
209  return Get( const_cast< AudacityProject & >( project ) );
210 }
211 
213 {
214  static CommandManager::MenuHook theHook;
215  return theHook;
216 }
217 
219 {
220  auto &theHook = sMenuHook();
221  auto result = theHook;
222  theHook = hook;
223  return result;
224 }
225 
230  mCurrentID(17000),
231  mCurrentMenuName(COMMAND),
232  bMakingOccultCommands( false )
233 {
234  mbSeparatorAllowed = false;
235  SetMaxList();
236  mLastProcessId = 0;
237 }
238 
243 {
244  //WARNING: This removes menubars that could still be assigned to windows!
245  PurgeData();
246 }
247 
248 const std::vector<NormalizedKeyString> &CommandManager::ExcludedList()
249 {
250  static const auto list = [] {
251  // These short cuts are for the max list only....
252  const char *const strings[] = {
253  // "Ctrl+I",
254  "Ctrl+Alt+I",
255  "Ctrl+J",
256  "Ctrl+Alt+J",
257  "Ctrl+Alt+V",
258  "Alt+X",
259  "Alt+K",
260  "Shift+Alt+X",
261  "Shift+Alt+K",
262  "Alt+L",
263  "Shift+Alt+C",
264  "Alt+I",
265  "Alt+J",
266  "Shift+Alt+J",
267  "Ctrl+Shift+A",
268  //"Q",
269  //"Shift+J",
270  //"Shift+K",
271  //"Shift+Home",
272  //"Shift+End",
273  "Ctrl+[",
274  "Ctrl+]",
275  "1",
276  "Shift+F5",
277  "Shift+F6",
278  "Shift+F7",
279  "Shift+F8",
280  "Ctrl+Shift+F5",
281  "Ctrl+Shift+F7",
282  "Ctrl+Shift+N",
283  "Ctrl+Shift+M",
284  "Ctrl+Home",
285  "Ctrl+End",
286  "Shift+C",
287  "Alt+Shift+Up",
288  "Alt+Shift+Down",
289  "Shift+P",
290  "Alt+Shift+Left",
291  "Alt+Shift+Right",
292  "Ctrl+Shift+T",
293  //"Command+M",
294  //"Option+Command+M",
295  "Shift+H",
296  "Shift+O",
297  "Shift+I",
298  "Shift+N",
299  "D",
300  "A",
301  "Alt+Shift+F6",
302  "Alt+F6",
303  };
304 
305  std::vector<NormalizedKeyString> result(
306  std::begin(strings), std::end(strings)
307  );
308  std::sort( result.begin(), result.end() );
309  return result;
310  }();
311  return list;
312 }
313 
314 // CommandManager needs to know which defaults are standard and which are in the
315 // full (max) list.
317 {
318 
319  // This list is a DUPLICATE of the list in
320  // KeyConfigPrefs::OnImportDefaults(wxCommandEvent & event)
321 
322  // TODO: At a later date get rid of the maxList entirely and
323  // instead use flags in the menu entries to indicate whether the default
324  // shortcut is standard or full.
325 
326  mMaxListOnly.clear();
327 
328  // if the full list, don't exclude any.
329  bool bFull = gPrefs->ReadBool(wxT("/GUI/Shortcuts/FullDefaults"),false);
330  if( bFull )
331  return;
332 
334 }
335 
336 
338 {
339  // mCommandList contains pointers to CommandListEntrys
340  // mMenuBarList contains MenuBarListEntrys.
341  // mSubMenuList contains SubMenuListEntrys
342  mCommandList.clear();
343  mMenuBarList.clear();
344  mSubMenuList.clear();
345 
346  mCommandNameHash.clear();
347  mCommandKeyHash.clear();
348  mCommandNumericIDHash.clear();
349 
351  mCurrentID = 17000;
352 }
353 
354 
360 std::unique_ptr<wxMenuBar> CommandManager::AddMenuBar(const wxString & sMenu)
361 {
362  wxMenuBar *menuBar = GetMenuBar(sMenu);
363  if (menuBar) {
364  wxASSERT(false);
365  return {};
366  }
367 
368  auto result = std::make_unique<wxMenuBar>();
369  mMenuBarList.emplace_back(sMenu, result.get());
370 
371  return result;
372 }
373 
374 
378 wxMenuBar * CommandManager::GetMenuBar(const wxString & sMenu) const
379 {
380  for (const auto &entry : mMenuBarList)
381  {
382  if(entry.name == sMenu)
383  return entry.menubar;
384  }
385 
386  return NULL;
387 }
388 
389 
394 {
395  if(mMenuBarList.empty())
396  return NULL;
397 
398  return mMenuBarList.back().menubar;
399 }
400 
407 {
408  auto iter = mMenuBarList.end();
409  if ( iter != mMenuBarList.begin() )
410  mMenuBarList.erase( --iter );
411  else
412  wxASSERT( false );
413 }
414 
415 
420 {
421  if ( mCurrentMenu )
422  return BeginSubMenu( tName );
423  else
424  return BeginMainMenu( tName );
425 }
426 
427 
430 // and in all cases ends the menu
433 {
434  if ( mSubMenuList.empty() )
435  EndMainMenu();
436  else
437  EndSubMenu();
438 }
439 
440 
445 {
446  uCurrentMenu = std::make_unique<wxMenu>();
447  mCurrentMenu = uCurrentMenu.get();
448  mCurrentMenuName = tName;
449  return mCurrentMenu;
450 }
451 
452 
457 {
458  // Add the menu to the menubar after all menu items have been
459  // added to the menu to allow OSX to rearrange special menu
460  // items like Preferences, About, and Quit.
461  wxASSERT(uCurrentMenu);
462  CurrentMenuBar()->Append(
464  mCurrentMenu = nullptr;
466 }
467 
468 
473 {
474  mSubMenuList.emplace_back( tName );
475  mbSeparatorAllowed = false;
476  return mSubMenuList.back().menu.get();
477 }
478 
479 
485 {
486  //Save the submenu's information
487  SubMenuListEntry tmpSubMenu{ std::move( mSubMenuList.back() ) };
488 
489  //Pop off the NEW submenu so CurrentMenu returns the parent of the submenu
490  mSubMenuList.pop_back();
491 
492  //Add the submenu to the current menu
493  auto name = tmpSubMenu.name.Translation();
494  CurrentMenu()->Append(0, name, tmpSubMenu.menu.release(),
495  name /* help string */ );
496  mbSeparatorAllowed = true;
497 }
498 
499 
504 {
505  if(mSubMenuList.empty())
506  return NULL;
507 
508  return mSubMenuList.back().menu.get();
509 }
510 
516 {
517  if(!mCurrentMenu)
518  return NULL;
519 
520  wxMenu * tmpCurrentSubMenu = CurrentSubMenu();
521 
522  if(!tmpCurrentSubMenu)
523  {
524  return mCurrentMenu;
525  }
526 
527  return tmpCurrentSubMenu;
528 }
529 
531 {
532  for ( const auto &entry : mCommandList ) {
533  if ( entry->menu && entry->checkmarkFn && !entry->isOccult) {
534  entry->menu->Check( entry->id, entry->checkmarkFn( project ) );
535  }
536  }
537 }
538 
539 
540 
542  const CommandID &name,
543  const TranslatableString &label_in,
544  CommandHandlerFinder finder,
545  CommandFunctorPointer callback,
546  CommandFlag flags,
547  const Options &options)
548 {
549  if (options.global) {
550  //wxASSERT( flags == AlwaysEnabledFlag );
552  name, label_in, finder, callback, options );
553  return;
554  }
555 
556  wxASSERT( flags != NoFlagsSpecified );
557 
558  CommandListEntry *entry =
560  label_in,
561  CurrentMenu(), finder, callback,
562  {}, 0, 0,
563  options);
564  entry->useStrictFlags = options.useStrictFlags;
565  int ID = entry->id;
566  wxString label = FormatLabelWithDisabledAccel(entry);
567 
568  SetCommandFlags(name, flags);
569 
570 
571  auto &checker = options.checker;
572  if (checker) {
573  CurrentMenu()->AppendCheckItem(ID, label);
574  CurrentMenu()->Check(ID, checker( project ));
575  }
576  else {
577  CurrentMenu()->Append(ID, label);
578  }
579 
580  mbSeparatorAllowed = true;
581 }
582 
584  const wxString key, bool defaultValue ) -> CheckFn
585 {
586  return [=](AudacityProject&){ return gPrefs->ReadBool( key, defaultValue ); };
587 }
588 
596  const ComponentInterfaceSymbol items[],
597  size_t nItems,
598  CommandHandlerFinder finder,
599  CommandFunctorPointer callback,
600  CommandFlag flags,
601  bool bIsEffect)
602 {
603  for (size_t i = 0, cnt = nItems; i < cnt; i++) {
604  CommandListEntry *entry =
606  items[i].Msgid(),
607  CurrentMenu(),
608  finder,
609  callback,
610  items[i].Internal(),
611  i,
612  cnt,
613  Options{}
614  .IsEffect(bIsEffect));
615  entry->flags = flags;
616  CurrentMenu()->Append(entry->id, FormatLabelForMenu(entry));
617  mbSeparatorAllowed = true;
618  }
619 }
620 
622  const TranslatableString &label_in,
623  CommandHandlerFinder finder,
624  CommandFunctorPointer callback,
625  const Options &options)
626 {
627  CommandListEntry *entry =
628  NewIdentifier(name, label_in, NULL, finder, callback,
629  {}, 0, 0, options);
630 
631  entry->enabled = false;
632  entry->isGlobal = true;
633  entry->flags = AlwaysEnabledFlag;
634 }
635 
637 {
638  if( mbSeparatorAllowed )
639  CurrentMenu()->AppendSeparator();
640  mbSeparatorAllowed = false; // boolean to prevent too many separators.
641 }
642 
644 {
645  ID++;
646 
647  //Skip the reserved identifiers used by wxWidgets
648  if((ID >= wxID_LOWEST) && (ID <= wxID_HIGHEST))
649  ID = wxID_HIGHEST+1;
650 
651  return ID;
652 }
653 
660  const TranslatableString & label,
661  wxMenu *menu,
662  CommandHandlerFinder finder,
663  CommandFunctorPointer callback,
664  const CommandID &nameSuffix,
665  int index,
666  int count,
667  const Options &options)
668 {
669  bool excludeFromMacros =
670  (options.allowInMacros == 0) ||
671  ((options.allowInMacros == -1) && label.MSGID().GET().Contains("..."));
672 
673  const wxString & accel = options.accel;
674  bool bIsEffect = options.bIsEffect;
675  CommandID parameter = options.parameter == "" ? nameIn : options.parameter;
676 
677  // if empty, new identifier's long label will be same as label, below:
678  const auto &longLabel = options.longName;
679 
680  const bool multi = !nameSuffix.empty();
681  auto name = nameIn;
682 
683  // If we have the identifier already, reuse it.
685  if (!prev);
686  else if( prev->label != label );
687  else if( multi );
688  else
689  return prev;
690 
691  {
692  auto entry = std::make_unique<CommandListEntry>();
693 
694  TranslatableString labelPrefix;
695  if (!mSubMenuList.empty())
696  labelPrefix = mSubMenuList.back().name.Stripped();
697 
698  // For key bindings for commands with a list, such as align,
699  // the name in prefs is the category name plus the effect name.
700  // This feature is not used for built-in effects.
701  if (multi)
702  name = CommandID{ { name, nameSuffix }, wxT('_') };
703 
704  // wxMac 2.5 and higher will do special things with the
705  // Preferences, Exit (Quit), and About menu items,
706  // if we give them the right IDs.
707  // Otherwise we just pick increasing ID numbers for each NEW
708  // command. Note that the name string we are comparing
709  // ("About", "Preferences") is the internal command name
710  // (untranslated), not the label that actually appears in the
711  // menu (which might be translated).
712 
714  entry->id = mCurrentID;
715  entry->parameter = parameter;
716 
717 #if defined(__WXMAC__)
718  // See bug #2642 for some history as to why these items
719  // on Mac have their IDs set explicitly and not others.
720  if (name == wxT("Preferences"))
721  entry->id = wxID_PREFERENCES;
722  else if (name == wxT("Exit"))
723  entry->id = wxID_EXIT;
724  else if (name == wxT("About"))
725  entry->id = wxID_ABOUT;
726 #endif
727 
728  entry->name = name;
729  entry->label = label;
730 
731  // long label is the same as label unless options specified otherwise:
732  entry->longLabel = longLabel.empty() ? label : longLabel;
733 
734  entry->excludeFromMacros = excludeFromMacros;
735  entry->key = NormalizedKeyString{ accel.BeforeFirst(wxT('\t')) };
736  entry->defaultKey = entry->key;
737  entry->labelPrefix = labelPrefix;
738  entry->labelTop = mCurrentMenuName.Stripped();
739  entry->menu = menu;
740  entry->finder = finder;
741  entry->callback = callback;
742  entry->isEffect = bIsEffect;
743  entry->multi = multi;
744  entry->index = index;
745  entry->count = count;
746  entry->flags = AlwaysEnabledFlag;
747  entry->enabled = true;
748  entry->skipKeydown = options.skipKeyDown;
749  entry->wantKeyup = options.wantKeyUp || entry->skipKeydown;
750  entry->allowDup = options.allowDup;
751  entry->isGlobal = false;
752  entry->isOccult = bMakingOccultCommands;
753  entry->checkmarkFn = options.checker;
754 
755  // Exclude accelerators that are in the MaxList.
756  // Note that the default is unaffected, intentionally so.
757  // There are effectively two levels of default, the full (max) list
758  // and the normal reduced list.
759  if( std::binary_search( mMaxListOnly.begin(), mMaxListOnly.end(),
760  entry->key ) )
761  entry->key = {};
762 
763  // Key from preferences overrides the default key given
764  gPrefs->SetPath(wxT("/NewKeys"));
765  // using GET to interpret CommandID as a config path component
766  const auto &path = entry->name.GET();
767  if (gPrefs->HasEntry(path)) {
768  entry->key =
769  NormalizedKeyString{ gPrefs->ReadObject(path, entry->key) };
770  }
771  gPrefs->SetPath(wxT("/"));
772 
773  mCommandList.push_back(std::move(entry));
774  // Don't use the variable entry eny more!
775  }
776 
777  // New variable
778  CommandListEntry *entry = &*mCommandList.back();
779  mCommandNumericIDHash[entry->id] = entry;
780 
781 #if defined(_DEBUG)
782  prev = mCommandNameHash[entry->name];
783  if (prev) {
784  // Under Linux it looks as if we may ask for a newID for the same command
785  // more than once. So it's only an error if two different commands
786  // have the exact same name.
787  if( prev->label != entry->label )
788  {
789  wxLogDebug(wxT("Command '%s' defined by '%s' and '%s'"),
790  // using GET in a log message for devs' eyes only
791  entry->name.GET(),
792  prev->label.Debug(),
793  entry->label.Debug());
794  wxFAIL_MSG(wxString::Format(wxT("Command '%s' defined by '%s' and '%s'"),
795  // using GET in an assertion violation message for devs'
796  // eyes only
797  entry->name.GET(),
798  prev->label.Debug(),
799  entry->label.Debug()));
800  }
801  }
802 #endif
803  mCommandNameHash[entry->name] = entry;
804 
805  if (!entry->key.empty()) {
806  mCommandKeyHash[entry->key] = entry;
807  }
808 
809  return entry;
810 }
811 
813 {
814  auto label = entry->label.Translation();
815  if (!entry->key.empty())
816  {
817  // using GET to compose menu item name for wxWidgets
818  label += wxT("\t") + entry->key.GET();
819  }
820 
821  return label;
822 }
823 
824 // A label that may have its accelerator disabled.
825 // The problem is that as soon as we show accelerators in the menu, the menu might
826 // catch them in normal wxWidgets processing, rather than passing the key presses on
827 // to the controls that had the focus. We would like all the menu accelerators to be
828 // disabled, in fact.
830 {
831  auto label = entry->label.Translation();
832 #if 1
833  wxString Accel;
834  do{
835  if (!entry->key.empty())
836  {
837  // Dummy accelerator that looks Ok in menus but is non functional.
838  // Note the space before the key.
839 #ifdef __WXMSW__
840  // using GET to compose menu item name for wxWidgets
841  auto key = entry->key.GET();
842  Accel = wxString("\t ") + key;
843  if( key.StartsWith("Left" )) break;
844  if( key.StartsWith("Right")) break;
845  if( key.StartsWith("Up" )) break;
846  if( key.StartsWith("Down")) break;
847  if( key.StartsWith("Return")) break;
848  if( key.StartsWith("Tab")) break;
849  if( key.StartsWith("Shift+Tab")) break;
850  if( key.StartsWith("0")) break;
851  if( key.StartsWith("1")) break;
852  if( key.StartsWith("2")) break;
853  if( key.StartsWith("3")) break;
854  if( key.StartsWith("4")) break;
855  if( key.StartsWith("5")) break;
856  if( key.StartsWith("6")) break;
857  if( key.StartsWith("7")) break;
858  if( key.StartsWith("8")) break;
859  if( key.StartsWith("9")) break;
860  // Uncomment the below so as not to add the illegal accelerators.
861  // Accel = "";
862  //if( entry->key.StartsWith("Space" )) break;
863  // These ones appear to be illegal already and mess up accelerator processing.
864  if( key.StartsWith("NUMPAD_ENTER" )) break;
865  if( key.StartsWith("Backspace" )) break;
866  if( key.StartsWith("Delete" )) break;
867 #endif
868  //wxLogDebug("Added Accel:[%s][%s]", entry->label, entry->key );
869  // Normal accelerator.
870  // using GET to compose menu item name for wxWidgets
871  Accel = wxString("\t") + entry->key.GET();
872  }
873  } while (false );
874  label += Accel;
875 #endif
876  return label;
877 }
883 void CommandManager::Enable(CommandListEntry *entry, bool enabled)
884 {
885  if (!entry->menu) {
886  entry->enabled = enabled;
887  return;
888  }
889 
890  // LL: Refresh from real state as we can get out of sync on the
891  // Mac due to its reluctance to enable menus when in a modal
892  // state.
893  entry->enabled = entry->menu->IsEnabled(entry->id);
894 
895  // Only enabled if needed
896  if (entry->enabled != enabled) {
897  entry->menu->Enable(entry->id, enabled);
898  entry->enabled = entry->menu->IsEnabled(entry->id);
899  }
900 
901  if (entry->multi) {
902  int i;
903  int ID = entry->id;
904 
905  for(i=1; i<entry->count; i++) {
906  ID = NextIdentifier(ID);
907 
908  // This menu item is not necessarily in the same menu, because
909  // multi-items can be spread across multiple sub menus
910  CommandListEntry *multiEntry = mCommandNumericIDHash[ID];
911  if (multiEntry) {
912  wxMenuItem *item = multiEntry->menu->FindItem(ID);
913 
914  if (item) {
915  item->Enable(enabled);
916  } else {
917  // using GET in a log message for devs' eyes only
918  wxLogDebug(wxT("Warning: Menu entry with id %i in %s not found"),
919  ID, entry->name.GET());
920  }
921  } else {
922  wxLogDebug(wxT("Warning: Menu entry with id %i not in hash"), ID);
923  }
924  }
925  }
926 }
927 
928 void CommandManager::Enable(const wxString &name, bool enabled)
929 {
931  if (!entry || !entry->menu) {
932  wxLogDebug(wxT("Warning: Unknown command enabled: '%s'"),
933  (const wxChar*)name);
934  return;
935  }
936 
937  Enable(entry, enabled);
938 }
939 
941  CommandFlag flags, CommandFlag strictFlags)
942 {
943  // strictFlags are a subset of flags. strictFlags represent the real
944  // conditions now, but flags are the conditions that could be made true.
945  // Some commands use strict flags only, refusing the chance to fix
946  // conditions
947  wxASSERT( (strictFlags & ~flags).none() );
948 
949  for(const auto &entry : mCommandList) {
950  if (entry->multi && entry->index != 0)
951  continue;
952  if( entry->isOccult )
953  continue;
954 
955  auto useFlags = entry->useStrictFlags ? strictFlags : flags;
956 
957  if (entry->flags.any()) {
958  bool enable = ((useFlags & entry->flags) == entry->flags);
959  Enable(entry.get(), enable);
960  }
961  }
962 }
963 
965 {
967  if (!entry || !entry->menu) {
968  // using GET in a log message for devs' eyes only
969  wxLogDebug(wxT("Warning: command doesn't exist: '%s'"),
970  name.GET());
971  return false;
972  }
973  return entry->enabled;
974 }
975 
977 {
978  return mXMLKeysRead;
979 }
980 
981 void CommandManager::Check(const CommandID &name, bool checked)
982 {
984  if (!entry || !entry->menu || entry->isOccult) {
985  return;
986  }
987  entry->menu->Check(entry->id, checked);
988 }
989 
991 void CommandManager::Modify(const wxString &name, const TranslatableString &newLabel)
992 {
994  if (entry && entry->menu) {
995  entry->label = newLabel;
996  entry->menu->SetLabel(entry->id, FormatLabelForMenu(entry));
997  }
998 }
999 
1001  const NormalizedKeyString &key)
1002 {
1004  if (entry) {
1005  entry->key = key;
1006  }
1007 }
1008 
1010 {
1011  const auto &entry = mCommandList[i];
1012  entry->key = key;
1013 }
1014 
1016  const ComponentInterfaceSymbol commands[], size_t nCommands) const
1017 {
1018  wxString mark;
1019  // This depends on the language setting and may change in-session after
1020  // change of preferences:
1021  bool rtl = (wxLayout_RightToLeft == wxTheApp->GetLayoutDirection());
1022  if (rtl)
1023  mark = wxT("\u200f");
1024 
1025  static const wxString &separatorFormat = wxT("%s / %s");
1026  TranslatableString result;
1027  for (size_t ii = 0; ii < nCommands; ++ii) {
1028  const auto &pair = commands[ii];
1029  // If RTL, then the control character forces right-to-left sequencing of
1030  // "/" -separated command names, and puts any "(...)" shortcuts to the
1031  // left, consistently with accelerators in menus (assuming matching
1032  // operating system preferences for language), even if the command name
1033  // was missing from the translation file and defaulted to the English.
1034 
1035  // Note: not putting this and other short format strings in the
1036  // translation catalogs
1037  auto piece = Verbatim( wxT("%s%s") )
1038  .Format( mark, pair.Msgid().Stripped() );
1039 
1040  auto name = pair.Internal();
1041  if (!name.empty()) {
1042  auto keyStr = GetKeyFromName(name);
1043  if (!keyStr.empty()){
1044  auto keyString = keyStr.Display(true);
1045  auto format = wxT("%s %s(%s)");
1046 #ifdef __WXMAC__
1047  // The unicode controls push and pop left-to-right embedding.
1048  // This keeps the directionally weak characters, such as uparrow
1049  // for Shift, left of the key name,
1050  // consistently with how menu accelerators appear, even when the
1051  // system language is RTL.
1052  format = wxT("%s %s(\u202a%s\u202c)");
1053 #endif
1054  // The mark makes correctly placed parentheses for RTL, even
1055  // in the case that the piece is untranslated.
1056  piece = Verbatim( format ).Format( piece, mark, keyString );
1057  }
1058  }
1059 
1060  if (result.empty())
1061  result = piece;
1062  else
1063  result = Verbatim( separatorFormat ).Format( result, piece );
1064  }
1065  return result;
1066 }
1067 
1071 bool CommandManager::FilterKeyEvent(AudacityProject *project, const wxKeyEvent & evt, bool permit)
1072 {
1073  if (!project)
1074  return false;
1075 
1076  auto pWindow = FindProjectFrame( project );
1078  if (entry == NULL)
1079  {
1080  return false;
1081  }
1082 
1083  int type = evt.GetEventType();
1084 
1085  // Global commands aren't tied to any specific project
1086  if (entry->isGlobal && type == wxEVT_KEY_DOWN)
1087  {
1088  // Global commands are always disabled so they do not interfere with the
1089  // rest of the command handling. But, to use the common handler, we
1090  // enable them temporarily and then disable them again after handling.
1091  // LL: Why do they need to be disabled???
1092  entry->enabled = false;
1093  auto cleanup = valueRestorer( entry->enabled, true );
1094  return HandleCommandEntry(*project, entry, NoFlagsSpecified, false, &evt);
1095  }
1096 
1097  wxWindow * pFocus = wxWindow::FindFocus();
1098  wxWindow * pParent = wxGetTopLevelParent( pFocus );
1099  bool validTarget = pParent == pWindow;
1100  // Bug 1557. MixerBoard should count as 'destined for project'
1101  // MixerBoard IS a TopLevelWindow, and its parent is the project.
1102  if( pParent && pParent->GetParent() == pWindow ){
1103  if( dynamic_cast< TopLevelKeystrokeHandlingWindow* >( pParent ) != NULL )
1104  validTarget = true;
1105  }
1106  validTarget = validTarget && wxEventLoop::GetActive()->IsMain();
1107 
1108  // Any other keypresses must be destined for this project window
1109  if (!permit && !validTarget )
1110  {
1111  return false;
1112  }
1113 
1114  auto flags = MenuManager::Get(*project).GetUpdateFlags();
1115 
1116  wxKeyEvent temp = evt;
1117 
1118  // Possibly let wxWidgets do its normal key handling IF it is one of
1119  // the standard navigation keys.
1120  if((type == wxEVT_KEY_DOWN) || (type == wxEVT_KEY_UP ))
1121  {
1122  wxWindow * pWnd = wxWindow::FindFocus();
1123  bool bIntercept =
1124  pWnd && !dynamic_cast< NonKeystrokeInterceptingWindow * >( pWnd );
1125 
1126  //wxLogDebug("Focus: %p TrackPanel: %p", pWnd, pTrackPanel );
1127  // We allow the keystrokes below to be handled by wxWidgets controls IF we are
1128  // in some sub window rather than in the TrackPanel itself.
1129  // Otherwise they will go to our command handler and if it handles them
1130  // they will NOT be available to wxWidgets.
1131  if( bIntercept ){
1132  switch( evt.GetKeyCode() ){
1133  case WXK_LEFT:
1134  case WXK_RIGHT:
1135  case WXK_UP:
1136  case WXK_DOWN:
1137  // Don't trap WXK_SPACE (Bug 1727 - SPACE not starting/stopping playback
1138  // when cursor is in a time control)
1139  // case WXK_SPACE:
1140  case WXK_TAB:
1141  case WXK_BACK:
1142  case WXK_HOME:
1143  case WXK_END:
1144  case WXK_RETURN:
1145  case WXK_NUMPAD_ENTER:
1146  case WXK_DELETE:
1147  case '0':
1148  case '1':
1149  case '2':
1150  case '3':
1151  case '4':
1152  case '5':
1153  case '6':
1154  case '7':
1155  case '8':
1156  case '9':
1157  return false;
1158  }
1159  }
1160  }
1161 
1162  if (type == wxEVT_KEY_DOWN)
1163  {
1164  if (entry->skipKeydown)
1165  {
1166  return true;
1167  }
1168  return HandleCommandEntry(*project, entry, flags, false, &temp);
1169  }
1170 
1171  if (type == wxEVT_KEY_UP && entry->wantKeyup)
1172  {
1173  return HandleCommandEntry(*project, entry, flags, false, &temp);
1174  }
1175 
1176  return false;
1177 }
1178 
1179 
1185  const CommandListEntry * entry,
1186  CommandFlag flags, bool alwaysEnabled, const wxEvent * evt)
1187 {
1188  if (!entry )
1189  return false;
1190 
1191  if (flags != AlwaysEnabledFlag && !entry->enabled)
1192  return false;
1193 
1194  if (!alwaysEnabled && entry->flags.any()) {
1195 
1196  const auto NiceName = entry->label.Stripped(
1198  // NB: The call may have the side effect of changing flags.
1199  bool allowed =
1201  NiceName, flags, entry->flags );
1202  // If the function was disallowed, it STILL should count as having been
1203  // handled (by doing nothing or by telling the user of the problem).
1204  // Otherwise we may get other handlers having a go at obeying the command.
1205  if (!allowed)
1206  return true;
1207  mNiceName = NiceName;
1208  }
1209  else {
1210  mNiceName = XO("");
1211  }
1212 
1213  const CommandContext context{ project, evt, entry->index, entry->parameter };
1214  auto &handler = entry->finder(project);
1215  (handler.*(entry->callback))(context);
1216  mLastProcessId = 0;
1217  return true;
1218 }
1219 
1220 // Called by Contrast and Plot Spectrum Plug-ins to mark them as Last Analzers.
1221 // Note that Repeat data has previously been collected
1223  if (mLastProcessId != 0) {
1224  auto& menuManager = MenuManager::Get(context.project);
1225  menuManager.mLastAnalyzerRegistration = MenuCreator::repeattypeunique;
1226  menuManager.mLastAnalyzerRegisteredId = mLastProcessId;
1227  auto lastEffectDesc = XO("Repeat %s").Format(mNiceName);
1228  Modify(wxT("RepeatLastAnalyzer"), lastEffectDesc);
1229  }
1230  return;
1231 }
1232 
1233 // Called by Selected Tools to mark them as Last Tools.
1234 // Note that Repeat data has previously been collected
1236  if (mLastProcessId != 0) {
1237  auto& menuManager = MenuManager::Get(context.project);
1238  menuManager.mLastToolRegistration = MenuCreator::repeattypeunique;
1239  menuManager.mLastToolRegisteredId = mLastProcessId;
1240  auto lastEffectDesc = XO("Repeat %s").Format(mNiceName);
1241  Modify(wxT("RepeatLastTool"), lastEffectDesc);
1242  }
1243  return;
1244 }
1245 
1246 // Used to invoke Repeat Last Analyzer Process for built-in, non-nyquist plug-ins.
1247 void CommandManager::DoRepeatProcess(const CommandContext& context, int id) {
1248  mLastProcessId = 0; //Don't Process this as repeat
1250  auto& handler = entry->finder(context.project);
1251  (handler.*(entry->callback))(context);
1252 }
1253 
1254 
1261  AudacityProject &project, int id, CommandFlag flags, bool alwaysEnabled)
1262 {
1263  mLastProcessId = id;
1265 
1266  auto hook = sMenuHook();
1267  if (hook && hook(entry->name))
1268  return true;
1269 
1270  return HandleCommandEntry( project, entry, flags, alwaysEnabled );
1271 }
1272 
1278  const CommandContext & context, CommandFlag flags, bool alwaysEnabled)
1279 {
1280  if( Str.empty() )
1281  return CommandFailure;
1282  // Linear search for now...
1283  for (const auto &entry : mCommandList)
1284  {
1285  if (!entry->multi)
1286  {
1287  // Testing against labelPrefix too allows us to call Nyquist functions by name.
1288  if( Str == entry->name ||
1289  // PRL: uh oh, mixing internal string (Str) with user-visible
1290  // (labelPrefix, which was initialized from a user-visible
1291  // sub-menu name)
1292  Str == entry->labelPrefix.Translation() )
1293  {
1294  return HandleCommandEntry(
1295  context.project, entry.get(), flags, alwaysEnabled)
1297  }
1298  }
1299  else
1300  {
1301  // Handle multis too...
1302  if( Str == entry->name )
1303  {
1304  return HandleCommandEntry(
1305  context.project, entry.get(), flags, alwaysEnabled)
1307  }
1308  }
1309  }
1310  return CommandNotFound;
1311 }
1312 
1314 {
1315  TranslatableStrings cats;
1316 
1317  for (const auto &entry : mCommandList) {
1318  auto &cat = entry->labelTop;
1319  if ( ! make_iterator_range( cats ).contains(cat) ) {
1320  cats.push_back(cat);
1321  }
1322  }
1323 #if 0
1324  mCommandList.size(); i++) {
1325  if (includeMultis || !mCommandList[i]->multi)
1326  names.push_back(mCommandList[i]->name);
1327  }
1328 
1329  if (p == NULL) {
1330  return;
1331  }
1332 
1333  wxMenuBar *bar = p->GetMenuBar();
1334  size_t cnt = bar->GetMenuCount();
1335  for (size_t i = 0; i < cnt; i++) {
1336  cats.push_back(bar->GetMenuLabelText(i));
1337  }
1338 
1339  cats.push_back(COMMAND);
1340 #endif
1341 
1342  return cats;
1343 }
1344 
1346  bool includeMultis) const
1347 {
1348  for(const auto &entry : mCommandList) {
1349  if ( entry->isEffect )
1350  continue;
1351  if (!entry->multi)
1352  names.push_back(entry->name);
1353  else if( includeMultis )
1354  names.push_back(entry->name );// + wxT(":")/*+ mCommandList[i]->label*/);
1355  }
1356 }
1357 
1359  std::vector<bool> &vExcludeFromMacros,
1360  bool includeMultis) const
1361 {
1362  vExcludeFromMacros.clear();
1363  for(const auto &entry : mCommandList) {
1364  // This is fetching commands from the menus, for use as batch commands.
1365  // Until we have properly merged EffectManager and CommandManager
1366  // we explicitly exclude effects, as they are already handled by the
1367  // effects Manager.
1368  if ( entry->isEffect )
1369  continue;
1370  if (!entry->multi)
1371  names.push_back(entry->longLabel), vExcludeFromMacros.push_back(entry->excludeFromMacros);
1372  else if( includeMultis )
1373  names.push_back(entry->longLabel), vExcludeFromMacros.push_back(entry->excludeFromMacros);
1374  }
1375 }
1376 
1378  CommandIDs &names,
1379  std::vector<NormalizedKeyString> &keys,
1380  std::vector<NormalizedKeyString> &default_keys,
1381  TranslatableStrings &labels,
1382  TranslatableStrings &categories,
1383 #if defined(EXPERIMENTAL_KEY_VIEW)
1384  TranslatableStrings &prefixes,
1385 #endif
1386  bool includeMultis)
1387 {
1388  for(const auto &entry : mCommandList) {
1389  // GetAllCommandData is used by KeyConfigPrefs.
1390  // It does need the effects.
1391  //if ( entry->isEffect )
1392  // continue;
1393  if ( !entry->multi || includeMultis )
1394  {
1395  names.push_back(entry->name);
1396  keys.push_back(entry->key);
1397  default_keys.push_back(entry->defaultKey);
1398  labels.push_back(entry->label);
1399  categories.push_back(entry->labelTop);
1400 #if defined(EXPERIMENTAL_KEY_VIEW)
1401  prefixes.push_back(entry->labelPrefix);
1402 #endif
1403  }
1404  }
1405 }
1406 
1408 {
1410  if (!entry)
1411  return {};
1412  return entry->name;
1413 }
1414 
1416 {
1418  if (!entry)
1419  return {};
1420 
1421  return entry->longLabel;
1422 }
1423 
1425 {
1427  if (!entry)
1428  return {};
1429 
1430  if (!entry->labelPrefix.empty())
1431  return Verbatim( wxT("%s - %s") )
1432  .Format(entry->labelPrefix, entry->label)
1433  .Stripped();
1434  else
1435  return entry->label.Stripped();
1436 }
1437 
1439 {
1441  if (!entry)
1442  return {};
1443 
1444  return entry->labelTop;
1445 }
1446 
1448 {
1449  CommandListEntry *entry =
1450  // May create a NULL entry
1451  const_cast<CommandManager*>(this)->mCommandNameHash[name];
1452  if (!entry)
1453  return {};
1454 
1455  return entry->key;
1456 }
1457 
1459 {
1461  if (!entry)
1462  return {};
1463 
1464  return entry->defaultKey;
1465 }
1466 
1467 bool CommandManager::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
1468 {
1469  if (!wxStrcmp(tag, wxT("audacitykeyboard"))) {
1470  mXMLKeysRead = 0;
1471  }
1472 
1473  if (!wxStrcmp(tag, wxT("command"))) {
1474  wxString name;
1476 
1477  while(*attrs) {
1478  const wxChar *attr = *attrs++;
1479  const wxChar *value = *attrs++;
1480 
1481  if (!value)
1482  break;
1483 
1484  if (!wxStrcmp(attr, wxT("name")) && XMLValueChecker::IsGoodString(value))
1485  name = value;
1486  if (!wxStrcmp(attr, wxT("key")) && XMLValueChecker::IsGoodString(value))
1487  key = NormalizedKeyString{ value };
1488  }
1489 
1490  if (mCommandNameHash[name]) {
1491  mCommandNameHash[name]->key = key;
1492  mXMLKeysRead++;
1493  }
1494  }
1495 
1496  return true;
1497 }
1498 
1499 // This message is displayed now in KeyConfigPrefs::OnImport()
1500 void CommandManager::HandleXMLEndTag(const wxChar *tag)
1501 {
1502  /*
1503  if (!wxStrcmp(tag, wxT("audacitykeyboard"))) {
1504  AudacityMessageBox(
1505  XO("Loaded %d keyboard shortcuts\n")
1506  .Format( mXMLKeysRead ),
1507  XO("Loading Keyboard Shortcuts"),
1508  wxOK | wxCENTRE);
1509  }
1510  */
1511 }
1512 
1513 XMLTagHandler *CommandManager::HandleXMLChild(const wxChar * WXUNUSED(tag))
1514 {
1515  return this;
1516 }
1517 
1519 // may throw
1520 {
1521  xmlFile.StartTag(wxT("audacitykeyboard"));
1522  xmlFile.WriteAttr(wxT("audacityversion"), AUDACITY_VERSION_STRING);
1523 
1524  for(const auto &entry : mCommandList) {
1525 
1526  xmlFile.StartTag(wxT("command"));
1527  xmlFile.WriteAttr(wxT("name"), entry->name);
1528  xmlFile.WriteAttr(wxT("key"), entry->key);
1529  xmlFile.EndTag(wxT("command"));
1530  }
1531 
1532  xmlFile.EndTag(wxT("audacitykeyboard"));
1533 }
1534 
1536 {
1537  // To do: perhaps allow occult item switching at lower levels of the
1538  // menu tree.
1539  wxASSERT( !CurrentMenu() );
1540 
1541  // Make a temporary menu bar collecting items added after.
1542  // This bar will be discarded but other side effects on the command
1543  // manager persist.
1544  mTempMenuBar = AddMenuBar(wxT("ext-menu"));
1545  bMakingOccultCommands = true;
1546 }
1547 
1549 {
1550  PopMenuBar();
1551  bMakingOccultCommands = false;
1552  mTempMenuBar.reset();
1553 }
1554 
1556  CommandFlag flags)
1557 {
1559  if (entry)
1560  entry->flags = flags;
1561 }
1562 
1563 #if defined(_DEBUG)
1564 void CommandManager::CheckDups()
1565 {
1566  int cnt = mCommandList.size();
1567  for (size_t j = 0; (int)j < cnt; j++) {
1568  if (mCommandList[j]->key.empty()) {
1569  continue;
1570  }
1571 
1572  if (mCommandList[j]->allowDup)
1573  continue;
1574 
1575  for (size_t i = 0; (int)i < cnt; i++) {
1576  if (i == j) {
1577  continue;
1578  }
1579 
1580  if (mCommandList[i]->key == mCommandList[j]->key) {
1581  wxString msg;
1582  msg.Printf(wxT("key combo '%s' assigned to '%s' and '%s'"),
1583  // using GET to form debug message
1584  mCommandList[i]->key.GET(),
1585  mCommandList[i]->label.Debug(),
1586  mCommandList[j]->label.Debug());
1587  wxASSERT_MSG(mCommandList[i]->key != mCommandList[j]->key, msg);
1588  }
1589  }
1590  }
1591 }
1592 
1593 #endif
1594 
1595 // If a default shortcut of a command is introduced or changed, then this
1596 // shortcut may be the same shortcut a user has previously assigned to another
1597 // command. This function removes such duplicates by removing the shortcut
1598 // from the command whose default has changed.
1599 // Note that two commands may have the same shortcut if their default shortcuts
1600 // are the same. However, in this function default shortcuts are checked against
1601 // user assigned shortcuts. Two such commands with the same shortcut
1602 // must both be in either the first or the second group, so there is no need
1603 // to test for this case.
1604 // Note that if a user is using the full set of default shortcuts, and one
1605 // of these is changed, then if /GUI/Shortcuts/FullDefaults is not set in audacity.cfg,
1606 // because the defaults appear as user assigned shortcuts in audacity.cfg,
1607 // the previous default overrides the changed default, and no duplicate can
1608 // be introduced.
1610 {
1611  TranslatableString disabledShortcuts;
1612 
1613  for (auto& entry : mCommandList) {
1614  if (!entry->key.empty() && entry->key != entry->defaultKey) { // user assigned
1615  for (auto& entry2 : mCommandList) {
1616  if (!entry2->key.empty() && entry2->key == entry2->defaultKey) { // default
1617  if (entry2->key == entry->key) {
1618  auto name = wxT("/NewKeys/") + entry2->name.GET();
1619  gPrefs->Write(name, NormalizedKeyString{});
1620 
1621  disabledShortcuts +=
1622  XO("\n* %s, because you have assigned the shortcut %s to %s")
1623  .Format(entry2->label.Strip(), entry->key.GET(), entry->label.Strip());
1624  }
1625  }
1626  }
1627  }
1628  }
1629 
1630  if (!disabledShortcuts.Translation().empty()) {
1631  TranslatableString message = XO("The following commands have had their shortcuts removed,"
1632  " because their default shortcut is new or changed, and is the same shortcut"
1633  " that you have assigned to another command.")
1634  + disabledShortcuts;
1635  AudacityMessageBox(message, XO("Shortcuts have been removed"), wxOK | wxCENTRE);
1636 
1637  gPrefs->Flush();
1639  }
1640 }
1641 
1642 #include "../KeyboardCapture.h"
1643 
1644 static struct InstallHandlers
1645 {
1647  {
1648  KeyboardCapture::SetPreFilter( []( wxKeyEvent & ) {
1649  // We must have a project since we will be working with the
1650  // CommandManager, which is tied to individual projects.
1651  AudacityProject *project = GetActiveProject();
1652  return project && GetProjectFrame( *project ).IsEnabled();
1653  } );
1654  KeyboardCapture::SetPostFilter( []( wxKeyEvent &key ) {
1655  // Capture handler window didn't want it, so ask the CommandManager.
1656  AudacityProject *project = GetActiveProject();
1657  auto &manager = CommandManager::Get( *project );
1658  return manager.FilterKeyEvent(project, key);
1659  } );
1660  }
1662 
XMLWriter
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:23
CommandManager::CommandManager
CommandManager()
Definition: CommandManager.cpp:229
KeyboardCapture::SetPostFilter
FilterFunction SetPostFilter(const FilterFunction &function)
Install a post-filter, returning the previously installed one Post-filter is called if the captured w...
Definition: KeyboardCapture.cpp:87
CommandManager::mCommandList
CommandList mCommandList
Definition: CommandManager.h:350
FileConfig::SetPath
virtual void SetPath(const wxString &strPath) wxOVERRIDE
Definition: FileConfig.cpp:101
CommandManager::GetAllCommandData
void GetAllCommandData(CommandIDs &names, std::vector< NormalizedKeyString > &keys, std::vector< NormalizedKeyString > &default_keys, TranslatableStrings &labels, TranslatableStrings &categories, bool includeMultis)
Definition: CommandManager.cpp:1377
TranslatableString
Definition: Types.h:290
CommandListEntry::labelPrefix
TranslatableString labelPrefix
Definition: CommandManager.cpp:143
CommandManager::CommandFailure
@ CommandFailure
Definition: CommandManager.h:215
CommandManager::GetAllCommandLabels
void GetAllCommandLabels(TranslatableStrings &labels, std::vector< bool > &vExcludeFromMacros, bool includeMultis) const
Definition: CommandManager.cpp:1358
CommandManager::SetKeyFromIndex
void SetKeyFromIndex(int i, const NormalizedKeyString &key)
Definition: CommandManager.cpp:1009
CommandManager::BeginSubMenu
wxMenu * BeginSubMenu(const TranslatableString &tName)
Definition: CommandManager.cpp:472
TranslatableString::empty
bool empty() const
Definition: Types.h:329
valueRestorer
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:430
CommandManager::GetLabelFromName
TranslatableString GetLabelFromName(const CommandID &name)
Definition: CommandManager.cpp:1415
CommandManager::Options::allowDup
bool allowDup
Definition: CommandManager.h:152
CommandListEntry::count
int count
Definition: CommandManager.cpp:156
CommandListEntry::key
NormalizedKeyString key
Definition: CommandManager.cpp:140
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:625
SubMenuListEntry::name
TranslatableString name
Definition: CommandManager.cpp:131
CommandManager::Options::wantKeyUp
bool wantKeyUp
Definition: CommandManager.h:150
CommandListEntry::name
CommandID name
Definition: CommandManager.cpp:138
CommandManager::BeginMainMenu
wxMenu * BeginMainMenu(const TranslatableString &tName)
Definition: CommandManager.cpp:444
SubMenuListEntry::menu
std::unique_ptr< wxMenu > menu
Definition: CommandManager.cpp:132
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:67
CommandManager::EndMainMenu
void EndMainMenu()
Definition: CommandManager.cpp:456
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption=AudacityMessageBoxCaptionStr(), long style=wxOK|wxCENTRE, wxWindow *parent=NULL, int x=wxDefaultCoord, int y=wxDefaultCoord)
Definition: AudacityMessageBox.h:20
TranslatableString::Ellipses
@ Ellipses
Definition: Types.h:450
CommandManager::CurrentMenuBar
wxMenuBar * CurrentMenuBar() const
Definition: CommandManager.cpp:393
FileConfig::HasEntry
virtual bool HasEntry(const wxString &strName) const wxOVERRIDE
Definition: FileConfig.cpp:146
CommandListEntry::labelTop
TranslatableString labelTop
Definition: CommandManager.cpp:144
CommandManager::CommandNotFound
@ CommandNotFound
Definition: CommandManager.h:217
CommandManager::Options
Definition: CommandManager.h:98
CommandManager::SetCommandFlags
void SetCommandFlags(const CommandID &name, CommandFlag flags)
Definition: CommandManager.cpp:1555
CommandManager::GetPrefixedLabelFromName
TranslatableString GetPrefixedLabelFromName(const CommandID &name)
Definition: CommandManager.cpp:1424
CommandManager::mMaxListOnly
std::vector< NormalizedKeyString > mMaxListOnly
Definition: CommandManager.h:346
GetActiveProject
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:107
CommandManager::TextualCommandResult
TextualCommandResult
Definition: CommandManager.h:214
CommandManager::HandleXMLChild
XMLTagHandler * HandleXMLChild(const wxChar *tag) override
Definition: CommandManager.cpp:1513
CommandManager.h
InstallHandlers
Definition: CommandManager.cpp:1645
XO
#define XO(s)
Definition: Internat.h:32
CommandManager::CommandSuccess
@ CommandSuccess
Definition: CommandManager.h:216
CommandListEntry::allowDup
bool allowDup
Definition: CommandManager.cpp:160
CommandManager::ExcludedList
static const std::vector< NormalizedKeyString > & ExcludedList()
Definition: CommandManager.cpp:248
CommandManager::SetMaxList
void SetMaxList()
Definition: CommandManager.cpp:316
CommandManager::HandleTextualCommand
TextualCommandResult HandleTextualCommand(const CommandID &Str, const CommandContext &context, CommandFlag flags, bool alwaysEnabled)
Definition: CommandManager.cpp:1277
CommandListEntry::defaultKey
NormalizedKeyString defaultKey
Definition: CommandManager.cpp:141
CommandManager::FormatLabelWithDisabledAccel
wxString FormatLabelWithDisabledAccel(const CommandListEntry *entry) const
Definition: CommandManager.cpp:829
AlwaysEnabledFlag
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:35
TranslatableString::Debug
wxString Debug() const
Definition: Types.h:341
CommandManager::GetCategoryFromName
TranslatableString GetCategoryFromName(const CommandID &name)
Definition: CommandManager.cpp:1438
CommandFlag
std::bitset< NCommandFlags > CommandFlag
Definition: CommandFlag.h:31
CommandManager::AddItem
void AddItem(AudacityProject &project, const CommandID &name, const TranslatableString &label_in, CommandHandlerFinder finder, CommandFunctorPointer callback, CommandFlag flags, const Options &options={})
Definition: CommandManager.cpp:541
CommandManager::mLastProcessId
int mLastProcessId
Definition: CommandManager.h:361
CommandListEntry::label
TranslatableString label
Definition: CommandManager.cpp:142
CommandManager::EndMenu
void EndMenu()
This attaches a menu, if it's main, to the menubar.
Definition: CommandManager.cpp:432
CommandManager::GetEnabled
bool GetEnabled(const CommandID &name)
Definition: CommandManager.cpp:964
CommandManager::GetNumberOfKeysRead
int GetNumberOfKeysRead() const
Definition: CommandManager.cpp:976
CommandManager::Enable
void Enable(const wxString &name, bool enabled)
Definition: CommandManager.cpp:928
ClientData::Site::RegisteredFactory
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:266
ComponentInterfaceSymbol
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Definition: ComponentInterface.h:60
MenuCreator::RebuildAllMenuBars
static void RebuildAllMenuBars()
Definition: Menus.cpp:678
XMLValueChecker::IsGoodString
static bool IsGoodString(const wxString &str)
Definition: XMLTagHandler.cpp:39
CommandListEntry::wantKeyup
bool wantKeyup
Definition: CommandManager.cpp:159
CommandListEntry::excludeFromMacros
bool excludeFromMacros
Definition: CommandManager.cpp:164
MenuBarListEntry::~MenuBarListEntry
~MenuBarListEntry()
Definition: CommandManager.cpp:182
CommandHandlerFinder
std::function< CommandHandlerObject &(AudacityProject &) > CommandHandlerFinder
Definition: CommandFunctors.h:33
CommandListEntry::finder
CommandHandlerFinder finder
Definition: CommandManager.cpp:146
CommandManager::HandleCommandEntry
bool HandleCommandEntry(AudacityProject &project, const CommandListEntry *entry, CommandFlag flags, bool alwaysEnabled, const wxEvent *evt=NULL)
Definition: CommandManager.cpp:1184
CommandManager::MenuHook
std::function< bool(const CommandID &) > MenuHook
Definition: CommandManager.h:66
KeyboardCapture::SetPreFilter
FilterFunction SetPreFilter(const FilterFunction &function)
Install a pre-filter, returning the previously installed one Pre-filter is called before passing the ...
Definition: KeyboardCapture.cpp:80
CommandManager::RemoveDuplicateShortcuts
void RemoveDuplicateShortcuts()
Definition: CommandManager.cpp:1609
CommandManager::DescribeCommandsAndShortcuts
TranslatableString DescribeCommandsAndShortcuts(const ComponentInterfaceSymbol commands[], size_t nCommands) const
Definition: CommandManager.cpp:1015
COMMAND
#define COMMAND
Definition: CommandManager.cpp:113
CommandManager::Options::useStrictFlags
bool useStrictFlags
Definition: CommandManager.h:149
CommandListEntry::isEffect
bool isEffect
Definition: CommandManager.cpp:163
CommandManager::mNiceName
TranslatableString mNiceName
Definition: CommandManager.h:360
TranslatableStrings
std::vector< TranslatableString > TranslatableStrings
Definition: Types.h:555
CommandContext.h
CommandManager::FilterKeyEvent
bool FilterKeyEvent(AudacityProject *project, const wxKeyEvent &evt, bool permit=false)
Definition: CommandManager.cpp:1071
CommandManager::HandleXMLEndTag
void HandleXMLEndTag(const wxChar *tag) override
Definition: CommandManager.cpp:1500
CommandManager::mCurrentID
int mCurrentID
Definition: CommandManager.h:354
CommandManager::Options::parameter
CommandParameter parameter
Definition: CommandManager.h:146
TopLevelKeystrokeHandlingWindow::~TopLevelKeystrokeHandlingWindow
virtual ~TopLevelKeystrokeHandlingWindow()
Definition: CommandManager.cpp:173
CommandContext
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
Definition: CommandContext.h:22
label
TranslatableString label
Definition: Tags.cpp:755
SubMenuListEntry::~SubMenuListEntry
~SubMenuListEntry()
Definition: CommandManager.cpp:191
MenuBarListEntry::name
wxString name
Definition: CommandManager.cpp:121
CommandListEntry::longLabel
TranslatableString longLabel
Definition: CommandManager.cpp:139
CommandManager::uCurrentMenu
std::unique_ptr< wxMenu > uCurrentMenu
Definition: CommandManager.h:362
CommandManager::BeginMenu
wxMenu * BeginMenu(const TranslatableString &tName)
Definition: CommandManager.cpp:419
CommandManager::GetKeyFromName
NormalizedKeyString GetKeyFromName(const CommandID &name) const
Definition: CommandManager.cpp:1447
TopLevelKeystrokeHandlingWindow
Definition: CommandManagerWindowClasses.h:29
GetProjectFrame
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
Definition: Project.cpp:186
FindProjectFrame
wxFrame * FindProjectFrame(AudacityProject *project)
Get a pointer to the window associated with a project, or null if the given pointer is null.
Definition: Project.h:172
none
@ none
Definition: Dither.h:20
CommandManager::DoRepeatProcess
void DoRepeatProcess(const CommandContext &context, int)
Definition: CommandManager.cpp:1247
CommandManager::Options::accel
const wxChar * accel
Definition: CommandManager.h:143
InstallHandlers::InstallHandlers
InstallHandlers()
Definition: CommandManager.cpp:1646
MenuBarListEntry::menubar
wxWeakRef< wxMenuBar > menubar
Definition: CommandManager.cpp:122
name
const TranslatableString name
Definition: Distortion.cpp:98
CommandManager::RegisterLastAnalyzer
void RegisterLastAnalyzer(const CommandContext &context)
Definition: CommandManager.cpp:1222
CommandListEntry::CheckFn
std::function< bool(AudacityProject &) > CheckFn
Definition: CommandManager.cpp:151
CommandManager::Options::skipKeyDown
bool skipKeyDown
Definition: CommandManager.h:151
format
int format
Definition: ExportPCM.cpp:54
CommandListEntry::menu
wxMenu * menu
Definition: CommandManager.cpp:145
CommandListEntry::useStrictFlags
bool useStrictFlags
Definition: CommandManager.cpp:166
sMenuHook
static CommandManager::MenuHook & sMenuHook()
Definition: CommandManager.cpp:212
CommandManager::HandleMenuID
bool HandleMenuID(AudacityProject &project, int id, CommandFlag flags, bool alwaysEnabled)
Definition: CommandManager.cpp:1260
CommandListEntry::parameter
CommandParameter parameter
Definition: CommandManager.cpp:148
CommandListEntry::flags
CommandFlag flags
Definition: CommandManager.cpp:165
CommandManager::Options::global
bool global
Definition: CommandManager.h:148
CommandManager::UpdateCheckmarks
void UpdateCheckmarks(AudacityProject &project)
Definition: CommandManager.cpp:530
NonKeystrokeInterceptingWindow::~NonKeystrokeInterceptingWindow
virtual ~NonKeystrokeInterceptingWindow()
Definition: CommandManager.cpp:169
CommandManager::CheckFn
std::function< bool(AudacityProject &) > CheckFn
Definition: CommandManager.h:94
CommandManager::AddItemList
void AddItemList(const CommandID &name, const ComponentInterfaceSymbol items[], size_t nItems, CommandHandlerFinder finder, CommandFunctorPointer callback, CommandFlag flags, bool bIsEffect=false)
Definition: CommandManager.cpp:595
CommandManager::bMakingOccultCommands
bool bMakingOccultCommands
Definition: CommandManager.h:365
CommandListEntry::isGlobal
bool isGlobal
Definition: CommandManager.cpp:161
CommandManager::mCommandNumericIDHash
CommandNumericIDHash mCommandNumericIDHash
Definition: CommandManager.h:353
CommandManager::EndSubMenu
void EndSubMenu()
Definition: CommandManager.cpp:484
CommandListEntry::index
int index
Definition: CommandManager.cpp:155
XMLTagHandler
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:80
installHandlers
static struct InstallHandlers installHandlers
Identifier::GET
const wxString & GET() const
Definition: Types.h:110
NormalizedKeyString
Definition: Keyboard.h:25
CommandManager::SetKeyFromName
void SetKeyFromName(const CommandID &name, const NormalizedKeyString &key)
Definition: CommandManager.cpp:1000
CommandManager::Options::longName
TranslatableString longName
Definition: CommandManager.h:147
CommandManager::NewIdentifier
CommandListEntry * NewIdentifier(const CommandID &name, const TranslatableString &label, wxMenu *menu, CommandHandlerFinder finder, CommandFunctorPointer callback, const CommandID &nameSuffix, int index, int count, const Options &options)
Definition: CommandManager.cpp:659
CommandManager::Options::IsEffect
Options && IsEffect(bool value=true) &&
Definition: CommandManager.h:111
CommandManager::PopMenuBar
void PopMenuBar()
Definition: CommandManager.cpp:406
CommandManager::CurrentMenu
wxMenu * CurrentMenu() const
Definition: CommandManager.cpp:515
CommandManager::GetCategories
TranslatableStrings GetCategories(AudacityProject &)
Definition: CommandManager.cpp:1313
id
int id
Definition: WaveTrackControls.cpp:589
NonKeystrokeInterceptingWindow
Definition: CommandManagerWindowClasses.h:20
CommandManager::mCurrentMenuName
TranslatableString mCurrentMenuName
Definition: CommandManager.h:359
CommandManager::EndOccultCommands
void EndOccultCommands()
Definition: CommandManager.cpp:1548
CommandManager::RegisterLastTool
void RegisterLastTool(const CommandContext &context)
Definition: CommandManager.cpp:1235
CommandManager::mCommandKeyHash
CommandKeyHash mCommandKeyHash
Definition: CommandManager.h:352
CommandManager::WriteXML
void WriteXML(XMLWriter &xmlFile) const
Definition: CommandManager.cpp:1518
CommandManager::GetDefaultKeyFromName
NormalizedKeyString GetDefaultKeyFromName(const CommandID &name)
Definition: CommandManager.cpp:1458
FileConfig::Flush
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:151
key
static const AudacityProject::AttachedObjects::RegisteredFactory key
Definition: CommandManager.cpp:196
MenuManager::ReportIfActionNotAllowed
bool ReportIfActionNotAllowed(const TranslatableString &Name, CommandFlag &flags, CommandFlag flagsRqd)
Definition: Menus.cpp:696
CommandListEntry::callback
CommandFunctorPointer callback
Definition: CommandManager.cpp:147
CommandManager::mCommandNameHash
CommandNameHash mCommandNameHash
Definition: CommandManager.h:351
TaggedIdentifier
Definition: Types.h:158
names
static TranslatableStrings names
Definition: Tags.cpp:743
TranslatableString::MenuCodes
@ MenuCodes
Definition: Types.h:449
CommandManager::EnableUsingFlags
void EnableUsingFlags(CommandFlag flags, CommandFlag strictFlags)
Definition: CommandManager.cpp:940
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:112
CommandManager::Options::bIsEffect
bool bIsEffect
Definition: CommandManager.h:145
CommandManager::HandleXMLTag
bool HandleXMLTag(const wxChar *tag, const wxChar **attrs) override
Definition: CommandManager.cpp:1467
Verbatim
TranslatableString Verbatim(wxString str)
Definition: Types.h:581
CommandManager::Options::allowInMacros
int allowInMacros
Definition: CommandManager.h:153
CommandManager::SetMenuHook
static MenuHook SetMenuHook(const MenuHook &hook)
Definition: CommandManager.cpp:218
CommandListEntry::isOccult
bool isOccult
Definition: CommandManager.cpp:162
CommandManager::AddGlobalCommand
void AddGlobalCommand(const CommandID &name, const TranslatableString &label, CommandHandlerFinder finder, CommandFunctorPointer callback, const Options &options={})
Definition: CommandManager.cpp:621
CommandListEntry::skipKeydown
bool skipKeydown
Definition: CommandManager.cpp:158
MenuManager::Get
static MenuManager & Get(AudacityProject &project)
Definition: Menus.cpp:69
CommandManager
CommandManager implements a system for organizing all user-callable commands.
Definition: CommandManager.h:59
CommandManager::Modify
void Modify(const wxString &name, const TranslatableString &newLabel)
Changes the label text of a menu item.
Definition: CommandManager.cpp:991
CommandManagerWindowClasses.h
CommandManager::AddSeparator
void AddSeparator()
Definition: CommandManager.cpp:636
SubMenuListEntry::SubMenuListEntry
SubMenuListEntry(const TranslatableString &name_)
Definition: CommandManager.cpp:186
CommandListEntry
CommandListEntry is a structure used by CommandManager.
Definition: CommandManager.cpp:136
CommandManager::Options::MakeCheckFn
static CheckFn MakeCheckFn(const wxString key, bool defaultValue)
Definition: CommandManager.cpp:583
CommandManager::GetMenuBar
wxMenuBar * GetMenuBar(const wxString &sMenu) const
Definition: CommandManager.cpp:378
CommandIDs
std::vector< CommandID > CommandIDs
Definition: Types.h:277
TranslatableString::MSGID
Identifier MSGID() const
Definition: Types.h:335
KeyEventToKeyString
NormalizedKeyString KeyEventToKeyString(const wxKeyEvent &event)
Definition: Keyboard.cpp:83
CommandListEntry::id
int id
Definition: CommandManager.cpp:137
CommandManager::mSubMenuList
SubMenuList mSubMenuList
Definition: CommandManager.h:349
SubMenuListEntry::SubMenuListEntry
SubMenuListEntry(SubMenuListEntry &&)=default
MenuBarListEntry
MenuBarListEntry is a structure used by CommandManager.
Definition: CommandManager.cpp:117
CommandManager::mMenuBarList
MenuBarList mMenuBarList
Definition: CommandManager.h:348
CommandManager::mbSeparatorAllowed
bool mbSeparatorAllowed
Definition: CommandManager.h:357
TranslatableString::Translation
wxString Translation() const
Definition: Types.h:337
CommandManager::Check
void Check(const CommandID &name, bool checked)
Definition: CommandManager.cpp:981
SubMenuListEntry
SubMenuListEntry is a structure used by CommandManager.
Definition: CommandManager.cpp:126
CommandManager::~CommandManager
virtual ~CommandManager()
Definition: CommandManager.cpp:242
CommandManager::CurrentSubMenu
wxMenu * CurrentSubMenu() const
Definition: CommandManager.cpp:503
TranslatableString::Format
TranslatableString & Format(Args &&...args) &
Definition: Types.h:363
CommandManager::Get
static CommandManager & Get(AudacityProject &project)
Definition: CommandManager.cpp:202
TranslatableString::Stripped
TranslatableString Stripped(unsigned options=MenuCodes) const
Definition: Types.h:457
CommandManager::PurgeData
void PurgeData()
Definition: CommandManager.cpp:337
CommandManager::AddMenuBar
std::unique_ptr< wxMenuBar > AddMenuBar(const wxString &sMenu)
Definition: CommandManager.cpp:360
CommandListEntry::enabled
bool enabled
Definition: CommandManager.cpp:157
CommandContext::project
AudacityProject & project
Definition: CommandContext.h:52
CommandFunctorPointer
void(CommandHandlerObject::*)(const CommandContext &context) CommandFunctorPointer
Definition: CommandFunctors.h:38
MenuManager::GetUpdateFlags
CommandFlag GetUpdateFlags(bool checkActive=false) const
Definition: Menus.cpp:544
CommandManager::GetAllCommandNames
void GetAllCommandNames(CommandIDs &names, bool includeMultis) const
Definition: CommandManager.cpp:1345
Identifier::empty
bool empty() const
Definition: Types.h:104
NoFlagsSpecified
constexpr CommandFlag NoFlagsSpecified
Definition: CommandFlag.h:36
MenuBarListEntry::MenuBarListEntry
MenuBarListEntry(const wxString &name_, wxMenuBar *menubar_)
Definition: CommandManager.cpp:177
CommandManager::mTempMenuBar
std::unique_ptr< wxMenuBar > mTempMenuBar
Definition: CommandManager.h:366
CommandManager::FormatLabelForMenu
wxString FormatLabelForMenu(const CommandListEntry *entry) const
Definition: CommandManager.cpp:812
CommandListEntry::multi
bool multi
Definition: CommandManager.cpp:154
CommandManager::NextIdentifier
int NextIdentifier(int ID)
Definition: CommandManager.cpp:643
CommandListEntry::checkmarkFn
CheckFn checkmarkFn
Definition: CommandManager.cpp:152
CommandManager::mCurrentMenu
wxMenu * mCurrentMenu
Definition: CommandManager.h:363
CommandManager::GetNameFromNumericID
CommandID GetNameFromNumericID(int id)
Definition: CommandManager.cpp:1407
CommandManager::Options::checker
CheckFn checker
Definition: CommandManager.h:144
CommandManager::mXMLKeysRead
int mXMLKeysRead
Definition: CommandManager.h:355
MenuCreator::repeattypeunique
@ repeattypeunique
Definition: Menus.h:63
CommandManager::BeginOccultCommands
void BeginOccultCommands()
Definition: CommandManager.cpp:1535