Audacity  2.2.2
KeyView.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  KeyView.cpp
6 
7 *******************************************************************//*********************************************************************/
13 
14 #include "../Audacity.h"
15 
16 #include <wx/defs.h>
17 #include <wx/settings.h>
18 #include <wx/vlbox.h>
19 
20 #include "../AColor.h"
21 #include "../ShuttleGui.h"
22 #include "../commands/CommandManager.h"
23 #include "../commands/Keyboard.h"
24 #include "KeyView.h"
25 
26 #include <wx/dc.h>
27 #include "../Internat.h"
28 
29 // Various drawing constants
30 #define KV_BITMAP_SIZE 16
31 #define KV_LEFT_MARGIN 2
32 #define KV_COLUMN_SPACER 5
33 #define KV_VSCROLL_WIDTH 16 /* figure this out automatically? */
34 
35 // Define the KeyNode arrays
36 
37 // Define the event table
38 BEGIN_EVENT_TABLE(KeyView, wxVListBox)
39  EVT_LEFT_DOWN(KeyView::OnLeftDown)
40  EVT_KEY_DOWN(KeyView::OnKeyDown)
41  EVT_LISTBOX(wxID_ANY, KeyView::OnSelected)
42  EVT_SET_FOCUS(KeyView::OnSetFocus)
43  EVT_KILL_FOCUS(KeyView::OnKillFocus)
44  EVT_SIZE(KeyView::OnSize)
45  EVT_SCROLLWIN(KeyView::OnScroll)
47 
48 wxString KeyView::CommandTranslated="Command";
49 
50 
51 // ============================================================================
52 // KeyView class
53 // ============================================================================
54 KeyView::KeyView(wxWindow *parent,
55  wxWindowID id,
56  const wxPoint & pos,
57  const wxSize & size)
58 : wxVListBox(parent, id, pos, size, wxBORDER_THEME | wxHSCROLL | wxVSCROLL),
59  mScrollX(0),
60  mWidth(0)
61 {
62 #if wxUSE_ACCESSIBILITY
63  // Create and set accessibility object
64  SetAccessible(mAx = safenew KeyViewAx(this));
65 #endif
66 
67  SetMinSize({-1, 150});
68 
69  // The default view
70  mViewType = ViewByTree;
71 
72  // Calculate measurements used for columns and scrolling
73  RecalcExtents();
74 }
75 
77 {
78 }
79 
80 //
81 // Returns the index of the selected node
82 //
83 int
85 {
86  return LineToIndex(GetSelection());
87 }
88 
89 //
90 // Returns the name of the control
91 //
92 wxString
94 {
95  // Just forward request
96  return wxVListBox::GetName();
97 }
98 
99 //
100 // Returns the label for the given index
101 //
102 wxString
103 KeyView::GetLabel(int index) const
104 {
105  // Make sure index is valid
106  if (index < 0 || index >= (int) mNodes.size())
107  {
108  wxASSERT(false);
109  return wxEmptyString;
110  }
111 
112  return mNodes[index].label;
113 }
114 
115 //
116 // Returns the prefix (if available) prepended to the label for the given index
117 //
118 wxString
119 KeyView::GetFullLabel(int index) const
120 {
121  // Make sure index is valid
122  if (index < 0 || index >= (int) mNodes.size())
123  {
124  wxASSERT(false);
125  return wxEmptyString;
126  }
127 
128  // Cache the node and label
129  const KeyNode & node = mNodes[index];
130  wxString label = node.label;
131 
132  // Prepend the prefix if available
133  if (!node.prefix.IsEmpty())
134  {
135  label = node.prefix + wxT(" - ") + label;
136  }
137 
138  return label;
139 }
140 
141 //
142 // Returns the index for the given name
143 //
144 int
145 KeyView::GetIndexByName(const wxString & name) const
146 {
147  int cnt = (int) mNodes.size();
148 
149  // Search the nodes for the key
150  for (int i = 0; i < cnt; i++)
151  {
152  if (name.CmpNoCase(mNodes[i].name) == 0)
153  {
154  return mNodes[i].index;
155  }
156  }
157 
158  return wxNOT_FOUND;
159 }
160 
161 //
162 // Returns the command manager name for the given index
163 //
164 wxString
165 KeyView::GetName(int index) const
166 {
167  // Make sure index is valid
168  if (index < 0 || index >= (int) mNodes.size())
169  {
170  wxASSERT(false);
171  return wxEmptyString;
172  }
173 
174  return mNodes[index].name;
175 }
176 
177 //
178 // Returns the command manager index for the given key combination
179 //
180 wxString
181 KeyView::GetNameByKey(const wxString & key) const
182 {
183  int cnt = (int) mNodes.size();
184 
185  // Search the nodes for the key
186  for (int i = 0; i < cnt; i++)
187  {
188  if (key.CmpNoCase(mNodes[i].key) == 0)
189  {
190  return mNodes[i].name;
191  }
192  }
193 
194  return wxEmptyString;
195 }
196 
197 //
198 // Returns the index for the given key
199 //
200 int
201 KeyView::GetIndexByKey(const wxString & key) const
202 {
203  int cnt = (int) mNodes.size();
204 
205  // Search the nodes for the key
206  for (int i = 0; i < cnt; i++)
207  {
208  if (key.CmpNoCase(mNodes[i].key) == 0)
209  {
210  return mNodes[i].index;
211  }
212  }
213 
214  return wxNOT_FOUND;
215 }
216 
217 //
218 // Returns the key for the given index
219 //
220 wxString
221 KeyView::GetKey(int index) const
222 {
223  // Make sure index is valid
224  if (index < 0 || index >= (int) mNodes.size())
225  {
226  wxASSERT(false);
227  return wxEmptyString;
228  }
229 
230  return mNodes[index].key;
231 }
232 
233 //
234 // Use to determine if a key can be assigned to the given index
235 //
236 bool
237 KeyView::CanSetKey(int index) const
238 {
239  // Make sure index is valid
240  if (index < 0 || index >= (int) mNodes.size())
241  {
242  wxASSERT(false);
243  return false;
244  }
245 
246  // Parents can't be assigned keys
247  return !mNodes[index].isparent;
248 }
249 
250 //
251 // Sets the key for the given index
252 //
253 bool
254 KeyView::SetKey(int index, const wxString & key)
255 {
256  // Make sure index is valid
257  if (index < 0 || index >= (int) mNodes.size())
258  {
259  wxASSERT(false);
260  return false;
261  }
262 
263  // Cache the node
264  KeyNode & node = mNodes[index];
265 
266  // Do not allow setting keys on branches
267  if (node.isparent)
268  {
269  return false;
270  }
271 
272  // Set the NEW key
273  node.key = key;
274 
275  // Check to see if the key column needs to be expanded
276  int x, y;
277  GetTextExtent(node.key, &x, &y);
278  if (x > mKeyWidth || y > mLineHeight)
279  {
280  // New key is wider than column so recalc extents (will refresh view)
281  RecalcExtents();
282  return true;
283  }
284 
285  // Refresh the view lines
286  RefreshAll();
287 
288  return true;
289 }
290 
291 //
292 // Sets the key for the given name
293 //
294 bool
295 KeyView::SetKeyByName(const wxString & name, const wxString & key)
296 {
297  int index = GetIndexByName(name);
298 
299  // Bail is the name wasn't found
300  if (index == wxNOT_FOUND)
301  {
302  return false;
303  }
304 
305  // Go set the key
306  return SetKey(index, key);
307 }
308 
309 //
310 // Sets the view type
311 //
312 void
314 {
315  int index = LineToIndex(GetSelection());
316 
317  // Handle an existing selection
318  if (index != wxNOT_FOUND)
319  {
320  // Cache the currently selected node
321  KeyNode & node = mNodes[index];
322 
323  // Expand branches if switching to Tree view and a line
324  // is currently selected
325  if (type == ViewByTree)
326  {
327  // Cache the node's depth
328  int depth = node.depth;
329 
330  // Search for its parents, setting each one as open
331  for (int i = node.index - 1; i >= 0 && depth > 1; i--)
332  {
333  if (mNodes[i].depth < depth)
334  {
335  mNodes[i].isopen = true;
336  depth = mNodes[i].depth;
337  }
338  }
339  }
340  }
341 
342  // Unselect any currently selected line...do even if none selected
343  SelectNode(-1);
344 
345  // Save NEW type
346  mViewType = type;
347 
348  // Refresh the view lines
349  RefreshLines();
350 
351  // Reselect old node (if possible)
352  if (index != wxNOT_FOUND)
353  {
354  SelectNode(index);
355  }
356 
357 #if 0
358  // JKC: Optional code to list commants and shortcuts to debug console.
359  int nLines = mLines.GetCount();
360  int flags = 8;
361  for(int i=0;i<nLines;i++){
362  wxLogDebug("T.Add( %2i, %2i, 0, \"%s%s\" );", mLines[i]->depth-1, flags, mLines[i]->label,mLines[i]->key );
363  }
364 #endif
365 
366  return;
367 }
368 
369 //
370 // Sets the filter
371 //
372 void
373 KeyView::SetFilter(const wxString & filter)
374 {
375  int index = LineToIndex(GetSelection());
376 
377  // Unselect any currently selected line...do even if none selected
378  SelectNode(-1);
379 
380  // Save the filter
381  mFilter = filter.Lower();
382 
383  // Refresh the view lines
384  RefreshLines();
385 
386  // Reselect old node (if possible)
387  if (index != wxNOT_FOUND)
388  {
389  SelectNode(index);
390  }
391 }
392 
393 //
394 // Expand all branches
395 //
396 void
398 {
399  int cnt = (int) mNodes.size();
400 
401  // Set all parent nodes to open
402  for (int i = 0; i < cnt; i++)
403  {
404  KeyNode & node = mNodes[i];
405 
406  if (node.isparent)
407  {
408  node.isopen = true;
409  }
410  }
411 
412  RefreshLines();
413 }
414 
415 //
416 // Collapse all branches
417 //
418 void
420 {
421  int cnt = (int) mNodes.size();
422 
423  // Set all parent nodes to closed
424  for (int i = 0; i < cnt; i++)
425  {
426  KeyNode & node = mNodes[i];
427 
428  if (node.isparent)
429  {
430  node.isopen = false;
431  }
432  }
433 
434  RefreshLines();
435 }
436 
437 //
438 // Recalculate the measurements used for columns and scrolling
439 //
440 void
442 {
443  // Reset
444  mLineHeight = 0;
445  mCommandWidth = 0;
446  mKeyWidth = 0;
447 
448  // Examine all nodes
449  int cnt = (int) mNodes.size();
450  for (int i = 0; i < cnt; i++)
451  {
452  KeyNode & node = mNodes[i];
453  int x, y;
454 
455  if (node.iscat)
456  {
457  // Measure the category
458  GetTextExtent(node.category, &x, &y);
459  }
460  else if (node.ispfx)
461  {
462  // Measure the prefix
463  GetTextExtent(node.prefix, &x, &y);
464  }
465  else
466  {
467  // Measure the key
468  GetTextExtent(node.key, &x, &y);
469  mLineHeight = wxMax(mLineHeight, y);
470  mKeyWidth = wxMax(mKeyWidth, x);
471 
472  // Prepend prefix for view types other than tree
473  wxString label = node.label;
474  if (mViewType != ViewByTree && !node.prefix.IsEmpty())
475  {
476  label = node.prefix + wxT(" - ") + label;
477  }
478 
479  // Measure the label
480  GetTextExtent(label, &x, &y);
481  }
482 
483  // Finish calc for command column
484  mLineHeight = wxMax(mLineHeight, y);
485  mCommandWidth = wxMax(mCommandWidth, x);
486  }
487 
488  // Update horizontal scrollbar
489  UpdateHScroll();
490 }
491 
492 //
493 // Update the horizontal scrollbar or remove it if not needed
494 //
495 void
497 {
498  // Get the internal dimensions of the view
499  wxRect r = GetClientRect();
500 
501  // Calculate the full line width
503  mKeyWidth +
505  mCommandWidth +
507 
508  // Retrieve the current horizontal scroll amount
509  mScrollX = GetScrollPos(wxHORIZONTAL);
510 
511  if (mWidth <= r.GetWidth())
512  {
513  // Remove the scrollbar if it will fit within client width
514  SetScrollbar(wxHORIZONTAL, 0, 0, 0);
515  }
516  else
517  {
518  // Set scrollbar metrics
519  SetScrollbar(wxHORIZONTAL, mScrollX, r.GetWidth(), mWidth);
520  }
521 
522  // Refresh the entire view
523  RefreshAll();
524 }
525 
526 //
527 // Process a NEW set of bindings
528 //
529 void
530 KeyView::RefreshBindings(const wxArrayString & names,
531  const wxArrayString & categories,
532  const wxArrayString & prefixes,
533  const wxArrayString & labels,
534  const wxArrayString & keys,
535  bool bSort
536  )
537 {
538  // Start clean
539  mNodes.clear();
540 
541  // Same as in RecalcExtents() but do it inline
542  mLineHeight = 0;
543  mKeyWidth = 0;
544  mCommandWidth = 0;
545 
546  wxString lastcat;
547  wxString lastpfx;
548  int nodecnt = 0;
549  int depth = 1;
550  bool incat = false;
551  bool inpfx = false;
552 
553  // Examine all names...all arrays passed have the same indexes
554  int cnt = (int) names.GetCount();
555  for (int i = 0; i < cnt; i++)
556  {
557  wxString name = names[i];
558  int x, y;
559 
560  // Remove any menu code from the category and prefix
561  wxString cat = wxMenuItem::GetLabelText(categories[i]);
562  wxString pfx = wxMenuItem::GetLabelText(prefixes[i]);
563 
564  // Append "Menu" this node is for a menu title
565  if (cat != wxT("Command"))
566  {
567  cat.Append(wxT(" "));
568  cat += _("Menu");
569  }
570 
571  // Process a NEW category
572  if (cat != lastcat)
573  {
574  // A NEW category always finishes any current subtree
575  if (inpfx)
576  {
577  // Back to category level
578  depth--;
579  inpfx = false;
580  }
581 
582  // Only time this is not true is during the first iteration
583  if (incat)
584  {
585  // Back to root level
586  depth--;
587  incat = false;
588  }
589 
590  // Remember for next iteration
591  lastcat = cat;
592 
593  // Add a NEW category node
594  if (cat != wxEmptyString)
595  {
596  KeyNode node;
597 
598  // Fill in the node info
599  node.name = wxEmptyString; // don't associate branches with a command
600  node.category = cat;
601  node.prefix = pfx;
602  node.label = cat;
603  node.index = nodecnt++;
604  node.iscat = true;
605  node.isparent = true;
606  node.depth = depth++;
607  node.isopen = true;
608 
609  // Add it to the tree
610  mNodes.push_back(node);
611  incat = true;
612 
613  // Measure category
614  GetTextExtent(cat, &x, &y);
615  mLineHeight = wxMax(mLineHeight, y);
616  mCommandWidth = wxMax(mCommandWidth, x);
617  }
618  }
619 
620  // Process a NEW prefix
621  if (pfx != lastpfx)
622  {
623  // Done with prefix branch
624  if (inpfx)
625  {
626  depth--;
627  inpfx = false;
628  }
629 
630  // Remember for next iteration
631  lastpfx = pfx;
632 
633  // Add a NEW prefix node
634  if (pfx != wxEmptyString)
635  {
636  KeyNode node;
637 
638  // Fill in the node info
639  node.name = wxEmptyString; // don't associate branches with a command
640  node.category = cat;
641  node.prefix = pfx;
642  node.label = pfx;
643  node.index = nodecnt++;
644  node.ispfx = true;
645  node.isparent = true;
646  node.depth = depth++;
647  node.isopen = true;
648 
649  // Add it to the tree
650  mNodes.push_back(node);
651  inpfx = true;
652  }
653  }
654 
655  // Add the key entry
656  KeyNode node;
657  node.category = cat;
658  node.prefix = pfx;
659 
660  // Labels for undo and redo change according to the last command
661  // which can be undone/redone, so give them a special check in order
662  // not to confuse users
663  if (name == wxT("Undo"))
664  {
665  node.label = _("Undo");
666  }
667  else if (name == wxT("Redo"))
668  {
669  node.label = _("Redo");
670  }
671  else
672  {
673  // Strip any menu codes from label
674  node.label = wxMenuItem::GetLabelText(labels[i].BeforeFirst(wxT('\t')));
675  }
676 
677  // Fill in remaining info
678  node.name = name;
679  node.key = KeyStringDisplay(keys[i]);
680  node.index = nodecnt++;
681  node.depth = depth;
682 
683  // Add it to the tree
684  mNodes.push_back(node);
685 
686  // Measure key
687  GetTextExtent(node.key, &x, &y);
688  mLineHeight = wxMax(mLineHeight, y);
689  mKeyWidth = wxMax(mKeyWidth, x);
690 
691  // Prepend prefix for all view types to determine maximum
692  // column widths
693  wxString label = node.label;
694  if (!node.prefix.IsEmpty())
695  {
696  label = node.prefix + wxT(" - ") + label;
697  }
698 
699  // Measure label
700  GetTextExtent(label, &x, &y);
701  mLineHeight = wxMax(mLineHeight, y);
702  mCommandWidth = wxMax(mCommandWidth, x);
703  }
704 
705 #if 0
706  // For debugging
707  for (int j = 0; j < mNodes.GetCount(); j++)
708  {
709  KeyNode & node = mNodes[j];
710  wxLogDebug(wxT("NODE line %4d index %4d depth %1d open %1d parent %1d cat %1d pfx %1d name %s STR %s | %s | %s"),
711  node.line,
712  node.index,
713  node.depth,
714  node.isopen,
715  node.isparent,
716  node.iscat,
717  node.ispfx,
718  node.name,
719  node.category,
720  node.prefix,
721  node.label);
722  }
723 #endif
724 
725  // Update horizontal scrollbar
726  UpdateHScroll();
727 
728  // Refresh the view lines
729  RefreshLines(bSort);
730 
731  // Set the selected node if we've just reprepared the list and nothing was selected.
732  if ((GetSelection()==wxNOT_FOUND) && bSort )
733  {
735  }
736 }
737 
738 //
739 // Refresh the list of lines within the current view
740 //
741 void
743 {
744  int cnt = (int) mNodes.size();
745  int linecnt = 0;
746  mLines.clear();
747 
748  // Process a filter if one is set
749  if (!mFilter.IsEmpty())
750  {
751  // Examine all nodes
752  for (int i = 0; i < cnt; i++)
753  {
754  KeyNode & node = mNodes[i];
755 
756  // Reset line number
757  node.line = wxNOT_FOUND;
758 
759  // Search columns based on view type
760  wxString searchit;
761  switch (mViewType)
762  {
763  // The x"01" separator is used to prevent finding a
764  // match comprising the end of the label and beginning
765  // of the key. It was chosen since it's not very likely
766  // to appear in the filter itself.
767  case ViewByTree:
768  searchit = node.label.Lower() +
769  wxT("\01x") +
770  node.key.Lower();
771  break;
772 
773  case ViewByName:
774  searchit = node.label.Lower();
775  break;
776 
777  case ViewByKey:
778  searchit = node.key.Lower();
779  break;
780  }
781  if (searchit.Find(mFilter) == wxNOT_FOUND)
782  {
783  // Not found so continue to next node
784  continue;
785  }
786 
787  // For the Key View, if the filter is a single character,
788  // then it has to be the last character in the searchit string,
789  // and be preceded by nothing or +.
790  if ((mViewType == ViewByKey) &&
791  (mFilter.Len() == 1) &&
792  (!mFilter.IsSameAs(searchit.Last()) ||
793  ((searchit.Len() > 1) &&
794  ((wxString)(searchit.GetChar(searchit.Len() - 2)) != wxT("+")))))
795  {
796  // Not suitable so continue to next node
797  continue;
798  }
799 
800  // For tree view, we must make sure all parent nodes are included
801  // whether they match the filter or not.
802  if (mViewType == ViewByTree)
803  {
804  std::vector<KeyNode*> queue;
805  int depth = node.depth;
806 
807  // This node is a category or prefix node, so always mark them
808  // as open.
809  //
810  // What this is really doing is resolving a situation where the
811  // the filter matches a parent node and nothing underneath. In
812  // this case, the node would never be marked as open.
813  if (node.isparent)
814  {
815  node.isopen = true;
816  }
817 
818  // Examine siblings until a parent is found.
819  for (int j = node.index - 1; j >= 0 && depth > 0; j--)
820  {
821  // Found a parent
822  if (mNodes[j].depth < depth)
823  {
824  // Examine all previously added nodes to see if this nodes
825  // ancestors need to be added prior to adding this node.
826  bool found = false;
827  for (int k = (int) mLines.size() - 1; k >= 0; k--)
828  {
829  // The node indexes match, so we've found the parent of the
830  // child node.
831  if (mLines[k]->index == mNodes[j].index)
832  {
833  found = true;
834  break;
835  }
836  }
837 
838  // The parent wasn't found so remember it for later
839  // addition. Can't add directory to mLines here since
840  // they will wind up in reverse order.
841  if (!found)
842  {
843  queue.push_back(&mNodes[j]);
844  }
845 
846  // Traverse up the tree
847  depth = mNodes[j].depth;
848  }
849  }
850 
851  // Add any queues nodes to list. This will all be
852  // parent nodes, so mark them as open.
853  for (int j = (int) queue.size() - 1; j >= 0; j--)
854  {
855  queue[j]->isopen = true;
856  queue[j]->line = linecnt++;
857  mLines.push_back(queue[j]);
858  }
859  }
860 
861  // Finally add the child node
862  node.line = linecnt++;
863  mLines.push_back(&node);
864  }
865  }
866  else
867  {
868  // Examine all nodes - non-filtered
869  for (int i = 0; i < cnt; i++)
870  {
871  KeyNode & node = mNodes[i];
872 
873  // Reset line number
874  node.line = wxNOT_FOUND;
875 
876  // Node is either a category or prefix
877  if (node.isparent)
878  {
879  // Only need to do this for tree views
880  if (mViewType != ViewByTree)
881  {
882  continue;
883  }
884 
885  // Add the node
886  node.line = linecnt++;
887  mLines.push_back(&node);
888 
889  // If this node is not open, then skip all of it's decendants
890  if (!node.isopen)
891  {
892  bool iscat = node.iscat;
893  bool ispfx = node.ispfx;
894 
895  // Skip nodes until we find a node that has a different
896  // category or prefix
897  while (i < cnt)
898  {
899  KeyNode & skip = mNodes[i];
900 
901  if ((iscat && skip.category != node.category) ||
902  (ispfx && skip.prefix != node.prefix))
903  {
904  break;
905  }
906 
907  // Bump to next node
908  i++;
909  }
910 
911  // Index is pointing to the node that was different or
912  // past the end, so back off to last node of this branch.
913  i--;
914  }
915  continue;
916  }
917 
918  // Add child node to list
919  node.line = linecnt++;
920  mLines.push_back(&node);
921  }
922  }
923 
924  // Sorting is costly. If bSort is false, we do not have to sort.
925  // bSort false means we know that the list will be updated again before
926  // the user needs to see it.
927  if( bSort )
928  {
929  //To see how many lines are being sorted (and how often).
930  //wxLogDebug("Sorting %i lines for type %i", mLines.GetCount(), mViewType);
931 
932  // Speed up the comparison function used in sorting
933  // by only translating this string once.
934  CommandTranslated = _("Command");
935 
936  // Sort list based on type
937  switch (mViewType)
938  {
939  case ViewByTree:
940  std::sort(mLines.begin(), mLines.end(), CmpKeyNodeByTree);
941  break;
942 
943  case ViewByName:
944  std::sort(mLines.begin(), mLines.end(), CmpKeyNodeByName);
945  break;
946 
947  case ViewByKey:
948  std::sort(mLines.begin(), mLines.end(), CmpKeyNodeByKey);
949  break;
950  }
951  }
952 
953  // Now, reassign the line numbers
954  for (int i = 0; i < (int) mLines.size(); i++)
955  {
956  mLines[i]->line = i;
957  }
958 
959 #if 0
960  // For debugging
961  for (int j = 0; j < mLines.GetCount(); j++)
962  {
963  KeyNode & node = *mLines[j];
964  wxLogDebug(wxT("LINE line %4d index %4d depth %1d open %1d parent %1d cat %1d pfx %1d name %s STR %s | %s | %s"),
965  node.line,
966  node.index,
967  node.depth,
968  node.isopen,
969  node.isparent,
970  node.iscat,
971  node.ispfx,
972  node.name,
973  node.category,
974  node.prefix,
975  node.label);
976  }
977 #endif
978 
979  // Tell listbox the NEW count and refresh the entire view
980  SetItemCount(mLines.size());
981  RefreshAll();
982 
983 #if wxUSE_ACCESSIBILITY
984  // Let accessibility know that the list has changed
985  if( bSort )
986  mAx->ListUpdated();
987 #endif
988 }
989 
990 //
991 // Select a node
992 //
993 // Parameter can be wxNOT_FOUND to clear selection
994 //
995 void
997 {
998  int line = IndexToLine(index);
999 
1000  // Tell the listbox to select the line
1001  SetSelection(line);
1002 
1003 #if wxUSE_ACCESSIBILITY
1004  // And accessibility
1005  mAx->SetCurrentLine(line);
1006 #endif
1007 
1008  // Always send an event to let parent know of selection change
1009  //
1010  // Must do this ourselves becuase we want to send notifications
1011  // even if there isn't an item selected and SendSelectedEvent()
1012  // doesn't allow sending an event for indexes not in the listbox.
1013  wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, GetId());
1014  event.SetEventObject(this);
1015  event.SetInt(line);
1016  (void)GetEventHandler()->ProcessEvent(event);
1017 }
1018 
1019 //
1020 // Converts a line index to a node index
1021 //
1022 int
1023 KeyView::LineToIndex(int line) const
1024 {
1025  if (line < 0 || line >= (int) mLines.size())
1026  {
1027  return wxNOT_FOUND;
1028  }
1029 
1030  return mLines[line]->index;
1031 }
1032 
1033 //
1034 // Converts a node index to a line index
1035 //
1036 int
1037 KeyView::IndexToLine(int index) const
1038 {
1039  if (index < 0 || index >= (int) mNodes.size())
1040  {
1041  return wxNOT_FOUND;
1042  }
1043 
1044  return mNodes[index].line;
1045 }
1046 
1047 //
1048 // Draw the background for a given line
1049 //
1050 // This is called by the listbox when it needs to redraw the view.
1051 //
1052 void
1053 KeyView::OnDrawBackground(wxDC & dc, const wxRect & rect, size_t line) const
1054 {
1055  const KeyNode *node = mLines[line];
1056  wxRect r = rect;
1057  wxRect r2 = rect; // for just the key shortcut.
1058  wxCoord indent = 0;
1059 
1060  // When in tree view mode, each younger branch gets indented by the
1061  // width of the open/close bitmaps
1062  if (mViewType == ViewByTree)
1063  {
1064  indent += mKeyWidth + KV_COLUMN_SPACER + node->depth * KV_BITMAP_SIZE;
1065  }
1066 
1067  // Offset left side by the indentation (if any) and scroll amounts
1068  r.x = indent - mScrollX;
1069  r2.x = -mScrollX;
1070 
1071  // If the line width is less than the client width, then we want to
1072  // extend the background to the right edge of the client view. Otherwise,
1073  // go all the way to the end of the line width...this will draw past the
1074  // right edge, but that's what we want.
1075  r.width = wxMax(mWidth, r.width);
1076  r2.width = mKeyWidth;
1077 
1078  // Selected lines get a solid background
1079  if (IsSelected(line))
1080  {
1081  if (FindFocus() == this)
1082  {
1083  // Focused lines get highlighted background
1084  dc.SetPen(*wxTRANSPARENT_PEN);
1085  dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)));
1086  dc.DrawRectangle(r);
1087 
1088  // and they also get a dotted focus rect. This could just be left out.
1089  // The focus rect does very little for us, as it is the same size as the
1090  // rectangle itself. Consequently for themes that have black text it
1091  // disappears. But on HiContrast you do get a dotted green border which
1092  // may have some utility.
1093  AColor::DrawFocus(dc, r);
1094 
1095  if (mViewType == ViewByTree){
1096  dc.DrawRectangle(r2);
1097  AColor::DrawFocus(dc, r2);
1098  }
1099  }
1100  else
1101  {
1102  // Non focused lines get a light background
1103  dc.SetPen(*wxTRANSPARENT_PEN);
1104  dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)));
1105  dc.DrawRectangle(r);
1106  if (mViewType == ViewByTree)
1107  dc.DrawRectangle(r2);
1108  }
1109  }
1110  else
1111  {
1112  // Non-selected lines get a thin bottom border
1113  dc.SetPen(wxColour(240, 240, 240));
1114  dc.DrawLine(r.GetLeft(), r.GetBottom(), r.GetRight(), r.GetBottom());
1115  if (mViewType == ViewByTree )
1116  dc.DrawLine(r2.GetLeft(), r2.GetBottom(), r2.GetRight(), r2.GetBottom());
1117  }
1118 }
1119 
1120 //
1121 // Draw a line
1122 //
1123 // This is called by the listbox when it needs to redraw the view.
1124 //
1125 void
1126 KeyView::OnDrawItem(wxDC & dc, const wxRect & rect, size_t line) const
1127 {
1128  const KeyNode *node = mLines[line];
1129  wxString label = node->label;
1130 
1131  // Make sure the DC has a valid font
1132  dc.SetFont(GetFont());
1133 
1134  // Set the text color based on selection and focus
1135  if (IsSelected(line) && FindFocus() == this)
1136  {
1137  dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT));
1138  }
1139  else
1140  {
1141  dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT));
1142  }
1143 
1144  // Tree views get bitmaps
1145  if (mViewType == ViewByTree)
1146  {
1147  // Adjust left edge to account for scrolling
1148  wxCoord x = rect.x - mScrollX;
1149 
1150  if (node->iscat || node->ispfx)
1151  {
1152  wxCoord bx = x + mKeyWidth + KV_COLUMN_SPACER;
1153  wxCoord by = rect.y;
1154 
1155  if (node->ispfx)
1156  {
1157  bx += KV_BITMAP_SIZE;
1158  }
1159 
1160  dc.SetBrush(*wxTRANSPARENT_BRUSH);
1161  dc.SetPen(*wxBLACK_PEN);
1162  dc.DrawRectangle(bx + 3, by + 4, 9, 9);
1163  if (node->isopen)
1164  {
1165  AColor::Line(dc, bx + 5, by + 8, bx + 9, by + 8);
1166  }
1167  else
1168  {
1169  AColor::Line(dc, bx + 7, by + 6, bx + 7, by + 10);
1170  AColor::Line(dc, bx + 5, by + 8, bx + 9, by + 8);
1171  }
1172  }
1173 
1174  // Indent text
1175  x += KV_LEFT_MARGIN;
1176 
1177  // Draw the key and command columns
1178  dc.DrawText(node->key, x , rect.y);
1179  dc.DrawText(label, x + mKeyWidth + KV_COLUMN_SPACER + node->depth * KV_BITMAP_SIZE, rect.y);
1180  }
1181  else
1182  {
1183  // Adjust left edge by margin and account for scrolling
1184  wxCoord x = rect.x + KV_LEFT_MARGIN - mScrollX;
1185 
1186  // Prepend prefix if available
1187  if (!node->prefix.IsEmpty())
1188  {
1189  label = node->prefix + wxT(" - ") + label;
1190  }
1191 
1192  // don't swap the columns based on view type
1193  if((mViewType == ViewByName) || (mViewType == ViewByKey))
1194  {
1195  // Draw key columnd and then command column
1196  dc.DrawText(node->key, x, rect.y);
1197  dc.DrawText(label, x + mKeyWidth + KV_COLUMN_SPACER, rect.y);
1198  }
1199  }
1200 
1201  return;
1202 }
1203 
1204 //
1205 // Provide the height of the given line
1206 //
1207 // This is called by the listbox when it needs to redraw the view.
1208 //
1209 wxCoord
1210 KeyView::OnMeasureItem(size_t WXUNUSED(line)) const
1211 {
1212  // All lines are of equal height
1213  //
1214  // (add a magic 1 for decenders...looks better...not required)
1215  return mLineHeight + 1;
1216 }
1217 
1218 //
1219 // Handle the wxEVT_LISTBOX event
1220 //
1221 void
1222 KeyView::OnSelected(wxCommandEvent & event)
1223 {
1224  // Allow further processing
1225  event.Skip();
1226 
1227 #if wxUSE_ACCESSIBILITY
1228  // Tell accessibility of the change
1229  mAx->SetCurrentLine(event.GetInt());
1230 #endif
1231 }
1232 
1233 //
1234 // Handle the wxEVT_SET_FOCUS event
1235 //
1236 void
1237 KeyView::OnSetFocus(wxFocusEvent & event)
1238 {
1239  // Allow further processing
1240  event.Skip();
1241 
1242  // Refresh the selected line to pull in any changes while
1243  // focus was away...like when setting a NEW key value. This
1244  // will also refresh the visual (highlighted) state.
1245  if (GetSelection() != wxNOT_FOUND)
1246  {
1247  RefreshRow(GetSelection());
1248  }
1249 
1250 #if wxUSE_ACCESSIBILITY
1251  // Tell accessibility of the change
1252  mAx->SetCurrentLine(GetSelection());
1253 #endif
1254 }
1255 
1256 //
1257 // Handle the wxEVT_KILL_FOCUS event
1258 //
1259 void
1260 KeyView::OnKillFocus(wxFocusEvent & event)
1261 {
1262  // Allow further processing
1263  event.Skip();
1264 
1265  // Refresh the selected line to adjust visual highlighting.
1266  if (GetSelection() != wxNOT_FOUND)
1267  {
1268  RefreshRow(GetSelection());
1269  }
1270 }
1271 
1272 //
1273 // Handle the wxEVT_SIZE event
1274 //
1275 void
1276 KeyView::OnSize(wxSizeEvent & WXUNUSED(event))
1277 {
1278  // Update horizontal scrollbar
1279  UpdateHScroll();
1280 }
1281 
1282 //
1283 // Handle the wxEVT_SCROLL event
1284 //
1285 void
1286 KeyView::OnScroll(wxScrollWinEvent & event)
1287 {
1288  // We only care bout the horizontal scrollbar.
1289  if (event.GetOrientation() != wxHORIZONTAL)
1290  {
1291  // Allow further processing
1292  event.Skip();
1293  return;
1294  }
1295 
1296  // Get NEW scroll position and scroll the view
1297  mScrollX = event.GetPosition();
1298  SetScrollPos(wxHORIZONTAL, mScrollX);
1299 
1300  // Refresh the entire view
1301  RefreshAll();
1302 }
1303 
1304 //
1305 // Handle the wxEVT_KEY_DOWN event
1306 //
1307 void
1308 KeyView::OnKeyDown(wxKeyEvent & event)
1309 {
1310  int line = GetSelection();
1311 
1312  int keycode = event.GetKeyCode();
1313  switch (keycode)
1314  {
1315  // The LEFT key moves selection to parent or collapses selected
1316  // node if it is expanded.
1317  case WXK_LEFT:
1318  {
1319  // Nothing selected...nothing to do
1320  if (line == wxNOT_FOUND)
1321  {
1322  // Allow further processing
1323  event.Skip();
1324  break;
1325  }
1326 
1327  KeyNode *node = mLines[line];
1328 
1329  // Collapse the node if it is open
1330  if (node->isopen)
1331  {
1332  // No longer open
1333  node->isopen = false;
1334 
1335  // Don't want the view to scroll vertically, so remember the current
1336  // top line.
1337  size_t topline = GetVisibleBegin();
1338 
1339  // Refresh the view now that the number of lines have changed
1340  RefreshLines();
1341 
1342  // Reset the original top line
1343  ScrollToRow(topline);
1344 
1345  // And make sure current line is still selected
1346  SelectNode(LineToIndex(line));
1347  }
1348  else
1349  {
1350  // Move selection to the parent of this node
1351  for (int i = line - 1; i >= 0; i--)
1352  {
1353  // Found the parent
1354  if (mLines[i]->depth < node->depth)
1355  {
1356  // So select it
1357  SelectNode(LineToIndex(i));
1358  break;
1359  }
1360  }
1361  }
1362 
1363  // Further processing of the event is not wanted
1364  // (we didn't call event.Skip()
1365  }
1366  break;
1367 
1368  // The RIGHT key moves the selection to the first child or expands
1369  // the node if it is a parent.
1370  case WXK_RIGHT:
1371  {
1372  // Nothing selected...nothing to do
1373  if (line == wxNOT_FOUND)
1374  {
1375  // Allow further processing
1376  event.Skip();
1377  break;
1378  }
1379 
1380  KeyNode *node = mLines[line];
1381 
1382  // Only want parent nodes
1383  if (node->isparent)
1384  {
1385  // It is open so move select to first child
1386  if (node->isopen)
1387  {
1388  // But only if there is one
1389  if (line < (int) mLines.size() - 1)
1390  {
1391  SelectNode(LineToIndex(line + 1));
1392  }
1393  }
1394  else
1395  {
1396  // Node is now open
1397  node->isopen = true;
1398 
1399  // Don't want the view to scroll vertically, so remember the current
1400  // top line.
1401  size_t topline = GetVisibleBegin();
1402 
1403  // Refresh the view now that the number of lines have changed
1404  RefreshLines();
1405 
1406  // Reset the original top line
1407  ScrollToRow(topline);
1408 
1409  // And make sure current line is still selected
1410  SelectNode(LineToIndex(line));
1411  }
1412  }
1413 
1414  // Further processing of the event is not wanted
1415  // (we didn't call event.Skip()
1416  }
1417  break;
1418 
1419  // Move selection to next node whose 1st character matches
1420  // the keycode
1421  default:
1422  {
1423  int cnt = (int) mLines.size();
1424  bool found = false;
1425 
1426  // Search the entire list if none is currently selected
1427  if (line == wxNOT_FOUND)
1428  {
1429  line = cnt;
1430  }
1431  else
1432  {
1433  // Search from the node following the current one
1434  for (int i = line + 1; i < cnt; i++)
1435  {
1436  wxString label;
1437 
1438  // Get the string to search based on view type
1439  if (mViewType == ViewByTree)
1440  {
1441  label = GetLabel(LineToIndex(i));
1442  }
1443  else if (mViewType == ViewByName)
1444  {
1445  label = GetFullLabel(LineToIndex(i));
1446  }
1447  else if (mViewType == ViewByKey)
1448  {
1449  label = GetKey(LineToIndex(i));
1450  }
1451 
1452  // Move selection if they match
1453  if (label.Left(1).IsSameAs(keycode, false))
1454  {
1455  SelectNode(LineToIndex(i));
1456 
1457  found = true;
1458 
1459  break;
1460  }
1461  }
1462  }
1463 
1464  // A match wasn't found
1465  if (!found)
1466  {
1467  // So scan from the start of the list to the current node
1468  for (int i = 0; i < line; i++)
1469  {
1470  wxString label;
1471 
1472  // Get the string to search based on view type
1473  if (mViewType == ViewByTree)
1474  {
1475  label = GetLabel(LineToIndex(i));
1476  }
1477  else if (mViewType == ViewByName)
1478  {
1479  label = GetFullLabel(LineToIndex(i));
1480  }
1481  else if (mViewType == ViewByKey)
1482  {
1483  label = GetKey(LineToIndex(i));
1484  }
1485 
1486  // Move selection if they match
1487  if (label.Left(1).IsSameAs(keycode, false))
1488  {
1489  SelectNode(LineToIndex(i));
1490 
1491  found = true;
1492 
1493  break;
1494  }
1495  }
1496  }
1497 
1498  // A node wasn't found so allow further processing
1499  if (!found) {
1500  event.Skip();
1501  }
1502 
1503  // Otherwise, further processing of the event is not wanted
1504  // (we didn't call event.Skip()
1505  }
1506  }
1507 }
1508 
1509 //
1510 // Handle the wxEVT_LEFT_DOWN event
1511 //
1512 void
1513 KeyView::OnLeftDown(wxMouseEvent & event)
1514 {
1515  // Only check if for tree view
1516  if (mViewType != ViewByTree)
1517  {
1518  // Allow further processing (important for focus handling)
1519  event.Skip();
1520 
1521  return;
1522  }
1523 
1524  // Get the mouse position when the button was pressed
1525  wxPoint pos = event.GetPosition();
1526 
1527  // And see if it was on a line within the view
1528  int line = VirtualHitTest(pos.y);
1529 
1530  // It was on a line
1531  if (line != wxNOT_FOUND)
1532  {
1533  KeyNode *node = mLines[line];
1534 
1535  // Toggle the open state if this is a parent node
1536  if (node->isparent)
1537  {
1538  // Toggle state
1539  node->isopen = !node->isopen;
1540 
1541  // Don't want the view to scroll vertically, so remember the current
1542  // top line.
1543  size_t topline = GetVisibleBegin();
1544 
1545  // Refresh the view now that the number of lines have changed
1546  RefreshLines();
1547 
1548  // Reset the original top line
1549  ScrollToRow(topline);
1550 
1551  // And make sure current line is still selected
1552  SelectNode(LineToIndex(line));
1553  }
1554  }
1555 
1556  // Allow further processing (important for focus handling)
1557  event.Skip();
1558 }
1559 
1560 //
1561 // Sort compare function for tree view
1562 //
1563 // We want to leave the "menu" nodes alone as they are in the
1564 // order as they appear in the menus. But, we want to sort the
1565 // "command" nodes.
1566 //
1567 // To accomplish this, we prepend each label with it's line number
1568 // (in hex) for "menu" nodes. This ensures they will remain in
1569 // their original order.
1570 //
1571 // We prefix all "command" nodes with "ffffffff" (highest hex value)
1572 // to allow the sort to reorder them as needed.
1573 //
1574 bool
1576 {
1577  unsigned int k1UInt= 0xffffffff;
1578  unsigned int k2UInt= 0xffffffff;
1579 
1580  // This is a "command" node if its category is "Command"
1581  // and it is a child of the "Command" category. This latter
1582  // test ensures that the "Command" parent will be handled
1583  // as a "menu" node and remain at the bottom of the list.
1584  if (t1->category != CommandTranslated || t1->isparent)
1585  k1UInt = (unsigned int) t1->line;
1586 
1587  // See above for explanation
1588  if (t2->category != CommandTranslated || t2->isparent)
1589  k2UInt = (unsigned int) t2->line;
1590 
1591  if( k1UInt < k2UInt )
1592  return true;
1593  if( k1UInt > k2UInt )
1594  return false;
1595 
1596  return ( t1->label < t2->label );
1597 }
1598 
1599 //
1600 // Sort compare function for command view
1601 //
1602 // Nothing special here, just a standard ascending sort.
1603 //
1604 bool
1606 {
1607  wxString k1 = t1->label;
1608  wxString k2 = t2->label;
1609 
1610  // Prepend prefix if available
1611  if (!t1->prefix.IsEmpty())
1612  {
1613  k1 = t1->prefix + wxT(" - ") + k1;
1614  }
1615 
1616  // Prepend prefix if available
1617  if (!t2->prefix.IsEmpty())
1618  {
1619  k2 = t2->prefix + wxT(" - ") + k2;
1620  }
1621 
1622  return (k1 < k2);
1623 }
1624 
1625 //
1626 // Sort compare function for key view
1627 //
1628 // We want all nodes with key assignments to appear in ascending order
1629 // at the top of the list and all nodes without assignment to appear in
1630 // ascending order at the bottom of the list.
1631 //
1632 // We accomplish this by by prefixing all non-assigned entries with 0xff.
1633 // This will force them to the end, but still allow them to be sorted in
1634 // ascending order.
1635 //
1636 // The assigned entries simply get sorted as normal.
1637 //
1638 bool
1640 {
1641  wxString k1 = t1->key;
1642  wxString k2 = t2->key;
1643 
1644  // Left node is unassigned, so prefix it
1645  if(k1.IsEmpty())
1646  {
1647  k1 = wxT("\xff");
1648  }
1649 
1650  // Right node is unassigned, so prefix it
1651  if(k2.IsEmpty())
1652  {
1653  k2 = wxT("\xff");
1654  }
1655 
1656  // Add prefix if available
1657  if (!t1->prefix.IsEmpty())
1658  {
1659  k1 += t1->prefix + wxT(" - ");
1660  }
1661 
1662  // Add prefix if available
1663  if (!t2->prefix.IsEmpty())
1664  {
1665  k2 += t2->prefix + wxT(" - ");
1666  }
1667 
1668  // Add labels
1669  k1 += t1->label;
1670  k2 += t2->label;
1671 
1672  return (k1 < k2);
1673 }
1674 
1675 #if wxUSE_ACCESSIBILITY
1676 
1677 //
1678 // Return parenthood state of line
1679 //
1680 bool
1681 KeyView::HasChildren(int line)
1682 {
1683  // Make sure line is valid
1684  if (line < 0 || line >= (int) mLines.size())
1685  {
1686  wxASSERT(false);
1687  return false;
1688  }
1689 
1690  return mLines[line]->isparent;
1691 }
1692 
1693 //
1694 // Returns espanded/collapsed state of line
1695 //
1696 bool
1697 KeyView::IsExpanded(int line)
1698 {
1699  // Make sure line is valid
1700  if (line < 0 || line >= (int) mLines.size())
1701  {
1702  wxASSERT(false);
1703  return false;
1704  }
1705 
1706  return mLines[line]->isopen;
1707 }
1708 
1709 //
1710 // Returns the height of the line
1711 //
1712 wxCoord
1713 KeyView::GetLineHeight(int line)
1714 {
1715  // Make sure line is valid
1716  if (line < 0 || line >= (int) mLines.size())
1717  {
1718  wxASSERT(false);
1719  return 0;
1720  }
1721 
1722  return OnGetRowHeight(line);
1723 }
1724 
1725 //
1726 // Returns the value to be presented to accessibility
1727 //
1728 // Currently, the command and key are both provided.
1729 //
1730 wxString
1731 KeyView::GetValue(int line)
1732 {
1733  // Make sure line is valid
1734  if (line < 0 || line >= (int) mLines.size())
1735  {
1736  wxASSERT(false);
1737  return wxEmptyString;
1738  }
1739  int index = LineToIndex(line);
1740 
1741  // Get the label and key values
1742  wxString value;
1743  if (mViewType == ViewByTree)
1744  {
1745  value = GetLabel(index);
1746  }
1747  else
1748  {
1749  value = GetFullLabel(index);
1750  }
1751  wxString key = GetKey(index);
1752 
1753  // Add the key if it isn't empty
1754  if (!key.IsEmpty())
1755  {
1756  if (mViewType == ViewByKey)
1757  {
1758  value = key + wxT(" ") + value;
1759  }
1760  else
1761  {
1762  value = value + wxT(" ") + key;
1763  }
1764  }
1765 
1766  return value;
1767 }
1768 
1769 //
1770 // Returns the current view type
1771 //
1772 ViewByType
1773 KeyView::GetViewType()
1774 {
1775  return mViewType;
1776 }
1777 
1778 // ============================================================================
1779 // Accessibility provider for the KeyView class
1780 // ============================================================================
1781 KeyViewAx::KeyViewAx(KeyView *view)
1782 : wxWindowAccessible(view)
1783 {
1784  mView = view;
1785  mLastId = -1;
1786 }
1787 
1788 //
1789 // Send an event notification to accessibility that the view
1790 // has changed.
1791 //
1792 void
1793 KeyViewAx::ListUpdated()
1794 {
1795  NotifyEvent(wxACC_EVENT_OBJECT_REORDER,
1796  mView,
1797  wxOBJID_CLIENT,
1798  0);
1799 }
1800 
1801 //
1802 // Inform accessibility a NEW line has been selected and/or a previously
1803 // selected line is being unselected
1804 //
1805 void
1806 KeyViewAx::SetCurrentLine(int line)
1807 {
1808  // Only send selection remove notification if a line was
1809  // previously selected
1810  if (mLastId != -1)
1811  {
1812  NotifyEvent(wxACC_EVENT_OBJECT_SELECTIONREMOVE,
1813  mView,
1814  wxOBJID_CLIENT,
1815  mLastId);
1816  }
1817 
1818  // Nothing is selected now
1819  mLastId = -1;
1820 
1821  // Just clearing selection
1822  if (line != wxNOT_FOUND)
1823  {
1824  // Convert line number to childId
1825  LineToId(line, mLastId);
1826 
1827  // Send notifications that the line has focus
1828  NotifyEvent(wxACC_EVENT_OBJECT_FOCUS,
1829  mView,
1830  wxOBJID_CLIENT,
1831  mLastId);
1832 
1833  // And is selected
1834  NotifyEvent(wxACC_EVENT_OBJECT_SELECTION,
1835  mView,
1836  wxOBJID_CLIENT,
1837  mLastId);
1838  }
1839 }
1840 
1841 //
1842 // Convert the childId to a line number and return FALSE if it
1843 // represents a child or TRUE if it a line
1844 //
1845 bool
1846 KeyViewAx::IdToLine(int childId, int & line)
1847 {
1848  if (childId == wxACC_SELF)
1849  {
1850  return false;
1851  }
1852 
1853  // Convert to line
1854  line = childId - 1;
1855 
1856  // Make sure id is valid
1857  if (line < 0 || line >= (int) mView->GetItemCount())
1858  {
1859  // Indicate the control itself in this case
1860  return false;
1861  }
1862 
1863  return true;
1864 }
1865 
1866 //
1867 // Convert the line number to a childId.
1868 //
1869 bool
1870 KeyViewAx::LineToId(int line, int & childId)
1871 {
1872  // Make sure line is valid
1873  if (line < 0 || line >= (int) mView->GetItemCount())
1874  {
1875  // Indicate the control itself in this case
1876  childId = wxACC_SELF;
1877  return false;
1878  }
1879 
1880  // Convert to line
1881  childId = line + 1;
1882 
1883  return true;
1884 }
1885 
1886 // Can return either a child object, or an integer
1887 // representing the child element, starting from 1.
1888 wxAccStatus
1889 KeyViewAx::HitTest(const wxPoint & pt, int *childId, wxAccessible **childObject)
1890 {
1891  // Just to be safe
1892  *childObject = NULL;
1893 
1894  wxPoint pos = mView->ScreenToClient(pt);
1895 
1896  // See if it's on a line within the view
1897  int line = mView->HitTest(pos);
1898 
1899  // It was on a line
1900  if (line != wxNOT_FOUND)
1901  {
1902  LineToId(line, *childId);
1903  return wxACC_OK;
1904  }
1905 
1906  // Let the base class handle it
1907  return wxACC_NOT_IMPLEMENTED;
1908 }
1909 
1910 // Retrieves the address of an IDispatch interface for the specified child.
1911 // All objects must support this property.
1912 wxAccStatus
1913 KeyViewAx::GetChild(int childId, wxAccessible** child)
1914 {
1915  if (childId == wxACC_SELF)
1916  {
1917  *child = this;
1918  }
1919  else
1920  {
1921  *child = NULL;
1922  }
1923 
1924  return wxACC_OK;
1925 }
1926 
1927 // Gets the number of children.
1928 wxAccStatus
1929 KeyViewAx::GetChildCount(int *childCount)
1930 {
1931  *childCount = (int) mView->GetItemCount();
1932 
1933  return wxACC_OK;
1934 }
1935 
1936 // Gets the default action for this object (0) or > 0 (the action for a child).
1937 // Return wxACC_OK even if there is no action. actionName is the action, or the empty
1938 // string if there is no action.
1939 // The retrieved string describes the action that is performed on an object,
1940 // not what the object does as a result. For example, a toolbar button that prints
1941 // a document has a default action of "Press" rather than "Prints the current document."
1942 wxAccStatus
1943 KeyViewAx::GetDefaultAction(int WXUNUSED(childId), wxString *actionName)
1944 {
1945  actionName->Clear();
1946 
1947  return wxACC_OK;
1948 }
1949 
1950 // Returns the description for this object or a child.
1951 wxAccStatus
1952 KeyViewAx::GetDescription(int WXUNUSED(childId), wxString *description)
1953 {
1954  description->Clear();
1955 
1956  return wxACC_OK;
1957 }
1958 
1959 // Returns help text for this object or a child, similar to tooltip text.
1960 wxAccStatus
1961 KeyViewAx::GetHelpText(int WXUNUSED(childId), wxString *helpText)
1962 {
1963  helpText->Clear();
1964 
1965  return wxACC_OK;
1966 }
1967 
1968 // Returns the keyboard shortcut for this object or child.
1969 // Return e.g. ALT+K
1970 wxAccStatus
1971 KeyViewAx::GetKeyboardShortcut(int WXUNUSED(childId), wxString *shortcut)
1972 {
1973  shortcut->Clear();
1974 
1975  return wxACC_OK;
1976 }
1977 
1978 // Returns the rectangle for this object (id = 0) or a child element (id > 0).
1979 // rect is in screen coordinates.
1980 wxAccStatus
1981 KeyViewAx::GetLocation(wxRect & rect, int elementId)
1982 {
1983  int line;
1984 
1985  if (IdToLine(elementId, line))
1986  {
1987  if (!mView->IsVisible(line))
1988  {
1989  return wxACC_FAIL;
1990  }
1991 
1992  wxRect rectLine;
1993 
1994  rectLine.width = mView->GetClientSize().GetWidth();
1995 
1996  // iterate over all visible lines
1997  for (int i = (int) mView->GetVisibleBegin(); i <= line; i++)
1998  {
1999  wxCoord hLine = mView->GetLineHeight(i);
2000 
2001  rectLine.height = hLine;
2002 
2003  rect = rectLine;
2004  wxPoint margins = mView->GetMargins();
2005  rect.Deflate(margins.x, margins.y);
2006  rectLine.y += hLine;
2007  }
2008 
2009  rect.SetPosition(mView->ClientToScreen(rect.GetPosition()));
2010  }
2011  else
2012  {
2013  rect = mView->GetRect();
2014  rect.SetPosition(mView->GetParent()->ClientToScreen(rect.GetPosition()));
2015  }
2016 
2017  return wxACC_OK;
2018 }
2019 
2020 wxAccStatus
2021 KeyViewAx::Navigate(wxNavDir WXUNUSED(navDir),
2022  int WXUNUSED(fromId),
2023  int *WXUNUSED(toId),
2024  wxAccessible **WXUNUSED(toObject))
2025 {
2026  return wxACC_NOT_IMPLEMENTED;
2027 }
2028 
2029 // Gets the name of the specified object.
2030 wxAccStatus
2031 KeyViewAx::GetName(int childId, wxString *name)
2032 {
2033  int line;
2034 
2035  if (!IdToLine(childId, line))
2036  {
2037  *name = mView->GetName();
2038  }
2039  else
2040  {
2041  if (IdToLine(childId, line))
2042  {
2043  *name = mView->GetValue(line);
2044  }
2045  }
2046 
2047  return wxACC_OK;
2048 }
2049 
2050 wxAccStatus
2051 KeyViewAx::GetParent(wxAccessible ** WXUNUSED(parent))
2052 {
2053  return wxACC_NOT_IMPLEMENTED;
2054 }
2055 
2056 // Returns a role constant.
2057 wxAccStatus
2058 KeyViewAx::GetRole(int childId, wxAccRole *role)
2059 {
2060  if (childId == wxACC_SELF)
2061  {
2062 #if defined(__WXMSW__)
2063  *role = mView->GetViewType() == ViewByTree ? wxROLE_SYSTEM_OUTLINE : wxROLE_SYSTEM_LIST;
2064 #endif
2065 
2066 #if defined(__WXMAC__)
2067  *role = wxROLE_SYSTEM_GROUPING;
2068 #endif
2069  }
2070  else
2071  {
2072 #if defined(__WXMAC__)
2073  *role = wxROLE_SYSTEM_TEXT;
2074 #else
2075  *role = mView->GetViewType() == ViewByTree ? wxROLE_SYSTEM_OUTLINEITEM : wxROLE_SYSTEM_LISTITEM;
2076 #endif
2077  }
2078 
2079  return wxACC_OK;
2080 }
2081 
2082 // Gets a variant representing the selected children
2083 // of this object.
2084 // Acceptable values:
2085 // - a null variant (IsNull() returns TRUE)
2086 // - a list variant (GetType() == wxT("list"))
2087 // - an integer representing the selected child element,
2088 // or 0 if this object is selected (GetType() == wxT("long"))
2089 // - a "void*" pointer to a wxAccessible child object
2090 wxAccStatus
2091 KeyViewAx::GetSelections(wxVariant *selections)
2092 {
2093  int id;
2094 
2095  LineToId(mView->GetSelection(), id);
2096 
2097  *selections = (long) id;
2098 
2099  return wxACC_OK;
2100 }
2101 
2102 // Returns a state constant.
2103 wxAccStatus
2104 KeyViewAx::GetState(int childId, long *state)
2105 {
2106  int flag = wxACC_STATE_SYSTEM_FOCUSABLE;
2107  int line;
2108 
2109  if (!IdToLine(childId, line))
2110  {
2111  *state = wxACC_STATE_SYSTEM_FOCUSABLE; // |
2112  //mView->FindFocus() == mView ? wxACC_STATE_SYSTEM_FOCUSED : 0;
2113  return wxACC_OK;
2114  }
2115 
2116 #if defined(__WXMSW__)
2117  int selected = mView->GetSelection();
2118 
2119  flag |= wxACC_STATE_SYSTEM_SELECTABLE;
2120 
2121  if (line == selected)
2122  {
2123  flag |= wxACC_STATE_SYSTEM_FOCUSED |
2124  wxACC_STATE_SYSTEM_SELECTED;
2125  }
2126 
2127  if (mView->HasChildren(line))
2128  {
2129  flag |= mView->IsExpanded(line) ?
2130  wxACC_STATE_SYSTEM_EXPANDED :
2131  wxACC_STATE_SYSTEM_COLLAPSED;
2132  }
2133 #endif
2134 
2135 #if defined(__WXMAC__1)
2136  if (mGrid->IsInSelection(row, col))
2137  {
2138  flag |= wxACC_STATE_SYSTEM_SELECTED;
2139  }
2140 
2141  if (mGrid->GetGridCursorRow() == row && mGrid->GetGridCursorCol() == col)
2142  {
2143  flag |= wxACC_STATE_SYSTEM_FOCUSED;
2144  }
2145 
2146  if (mGrid->IsReadOnly(row, col))
2147  {
2148  flag |= wxACC_STATE_SYSTEM_UNAVAILABLE;
2149  }
2150 #endif
2151 
2152  *state = flag;
2153 
2154  return wxACC_OK;
2155 }
2156 
2157 // Returns a localized string representing the value for the object
2158 // or child.
2159 wxAccStatus
2160 KeyViewAx::GetValue(int childId, wxString *strValue)
2161 {
2162  int line;
2163 
2164  strValue->Clear();
2165 
2166  if (!IdToLine(childId, line))
2167  {
2168  return wxACC_NOT_IMPLEMENTED;
2169  }
2170 
2171 #if defined(__WXMSW__)
2172  if (mView->GetViewType() == ViewByTree)
2173  {
2174  KeyNode *node = mView->mLines[line];
2175  strValue->Printf(wxT("%d"), node->depth - 1);
2176  }
2177 
2178  // Don't set a value for the other view types
2179  return wxACC_NOT_IMPLEMENTED;
2180 #endif
2181 
2182 #if defined(__WXMAC__)
2183  return GetName(childId, strValue);
2184 #endif
2185 }
2186 
2187 #if defined(__WXMAC__)
2188 // Selects the object or child.
2189 wxAccStatus
2190 KeyViewAx::Select(int childId, wxAccSelectionFlags selectFlags)
2191 {
2192 #if 0
2193  int row;
2194  int col;
2195 
2196  if (GetRowCol(childId, row, col))
2197  {
2198 
2199  if (selectFlags & wxACC_SEL_TAKESELECTION)
2200  {
2201  mGrid->SetGridCursor(row, col);
2202  }
2203 
2204  mGrid->SelectBlock(row, col, row, col, selectFlags & wxACC_SEL_ADDSELECTION);
2205  }
2206 #endif
2207  return wxACC_OK;
2208 }
2209 #endif
2210 
2211 // Gets the window with the keyboard focus.
2212 // If childId is 0 and child is NULL, no object in
2213 // this subhierarchy has the focus.
2214 // If this object has the focus, child should be 'this'.
2215 wxAccStatus
2216 KeyViewAx::GetFocus(int * WXUNUSED(childId), wxAccessible **child)
2217 {
2218  *child = this;
2219 
2220  return wxACC_OK;
2221 }
2222 
2223 #endif // wxUSE_ACCESSIBILITY
wxString GetLabel(int index) const
Definition: KeyView.cpp:103
wxString prefix
Definition: KeyView.h:42
static wxArrayString names()
Definition: Tags.cpp:697
ViewByType
Definition: KeyView.h:57
void RecalcExtents()
Definition: KeyView.cpp:441
virtual ~KeyView()
Definition: KeyView.cpp:76
static wxString CommandTranslated
Definition: KeyView.h:134
void OnSelected(wxCommandEvent &event)
Definition: KeyView.cpp:1222
wxCoord mLineHeight
Definition: KeyView.h:160
static bool CmpKeyNodeByName(KeyNode *n1, KeyNode *n2)
Definition: KeyView.cpp:1605
wxString mFilter
Definition: KeyView.h:154
int GetIndexByKey(const wxString &key) const
Definition: KeyView.cpp:201
wxString GetNameByKey(const wxString &key) const
Definition: KeyView.cpp:181
void ExpandAll()
Definition: KeyView.cpp:397
wxString GetName() const
Definition: KeyView.cpp:93
void OnSetFocus(wxFocusEvent &event)
Definition: KeyView.cpp:1237
void SelectNode(int index)
Definition: KeyView.cpp:996
void UpdateHScroll()
Definition: KeyView.cpp:496
int index
Definition: KeyView.h:45
static bool CmpKeyNodeByKey(KeyNode *n1, KeyNode *n2)
Definition: KeyView.cpp:1639
wxString label
Definition: Tags.cpp:727
int GetSelected() const
Definition: KeyView.cpp:84
void OnKillFocus(wxFocusEvent &event)
Definition: KeyView.cpp:1260
wxCoord OnMeasureItem(size_t line) const
Definition: KeyView.cpp:1210
bool ispfx
Definition: KeyView.h:49
#define KV_BITMAP_SIZE
Definition: KeyView.cpp:30
Abstract base class for command interface. It implements Command::SetParameter() and defers all other...
Definition: Command.h:70
static void DrawFocus(wxDC &dc, wxRect &r)
Definition: AColor.cpp:171
int SetSelection(size_t n) override
bool CanSetKey(int index) const
Definition: KeyView.cpp:237
#define safenew
Definition: Audacity.h:223
wxString category
Definition: KeyView.h:41
wxString label
Definition: KeyView.h:43
std::vector< KeyNode > mNodes
Definition: KeyView.h:150
wxString name
Definition: KeyView.h:40
#define KV_LEFT_MARGIN
Definition: KeyView.cpp:31
wxString key
Definition: KeyView.h:44
bool iscat
Definition: KeyView.h:48
void SetView(ViewByType type)
Definition: KeyView.cpp:313
int depth
Definition: KeyView.h:47
void SetFilter(const wxString &filter)
Definition: KeyView.cpp:373
#define KV_VSCROLL_WIDTH
Definition: KeyView.cpp:33
bool isopen
Definition: KeyView.h:51
void RefreshLines(bool bSort=true)
Definition: KeyView.cpp:742
void RefreshBindings(const wxArrayString &names, const wxArrayString &categories, const wxArrayString &prefixes, const wxArrayString &labels, const wxArrayString &keys, bool bSort)
Definition: KeyView.cpp:530
void OnLeftDown(wxMouseEvent &event)
Definition: KeyView.cpp:1513
wxCoord mKeyWidth
Definition: KeyView.h:163
if(pTrack &&pTrack->GetDisplay()!=WaveTrack::Spectrum)
int mCommandWidth
Definition: KeyView.h:162
void OnDrawItem(wxDC &dc, const wxRect &rect, size_t line) const
Definition: KeyView.cpp:1126
wxString GetKey(int index) const
Definition: KeyView.cpp:221
wxString KeyStringDisplay(const wxString &key, bool usesSpecialChars)
Definition: Keyboard.cpp:53
int line
Definition: KeyView.h:46
ViewByType mViewType
Definition: KeyView.h:153
int LineToIndex(int line) const
Definition: KeyView.cpp:1023
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
std::vector< KeyNode * > mLines
Definition: KeyView.h:151
void OnKeyDown(wxKeyEvent &event)
Definition: KeyView.cpp:1308
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
void OnSize(wxSizeEvent &event)
Definition: KeyView.cpp:1276
wxCoord mScrollX
Definition: KeyView.h:156
int GetIndexByName(const wxString &name) const
Definition: KeyView.cpp:145
static bool CmpKeyNodeByTree(KeyNode *n1, KeyNode *n2)
Definition: KeyView.cpp:1575
bool isparent
Definition: KeyView.h:50
const wxChar * name
Definition: Distortion.cpp:94
void OnDrawBackground(wxDC &dc, const wxRect &rect, size_t line) const
Definition: KeyView.cpp:1053
END_EVENT_TABLE()
wxCoord mWidth
Definition: KeyView.h:157
bool SetKey(int index, const wxString &key)
Definition: KeyView.cpp:254
wxString GetFullLabel(int index) const
Definition: KeyView.cpp:119
int IndexToLine(int index) const
Definition: KeyView.cpp:1037
#define KV_COLUMN_SPACER
Definition: KeyView.cpp:32
void OnScroll(wxScrollWinEvent &event)
Definition: KeyView.cpp:1286
bool SetKeyByName(const wxString &name, const wxString &key)
Definition: KeyView.cpp:295
void CollapseAll()
Definition: KeyView.cpp:419
Provides multiple views of keyboard shortcuts.
Definition: KeyView.h:72