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