1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        menuutils.cpp
3 // Purpose:     wxMenuCmd, wxMenuWalker, wxMenuTreeWalker,
4 //              wxMenuShortcutWalker...
5 // Author:      Francesco Montorsi
6 // Created:     2004/02/19
7 // Copyright:   (c) Francesco Montorsi
8 // Licence:     wxWidgets licence
9 /////////////////////////////////////////////////////////////////////////////
10 // RCS-ID:      $Id: menuutils.cpp 11980 2020-03-12 18:24:19Z fuscated $
11 
12 // menuutils for KeyBinder v2.0 2019/04/8
13 #ifdef __GNUG__
14 #pragma implementation "menuutils.h"
15 #endif
16 
17 // For compilers that support precompilation, includes "wx/wx.h".
18 #include "wx/wxprec.h"
19 
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23 
24 #ifndef WX_PRECOMP
25 #include "wx/wx.h"
26 #endif
27 
28 //#if defined(CB_PRECOMP) //(2019/03/1)-
29 //#include "sdk.h"
30 //#else
31 //    #include <wx/event.h>
32 //    #include <wx/frame.h> // Manager::Get()->GetAppWindow()
33 //    #include <wx/intl.h>
34 //    #include <wx/menu.h>
35 //    #include <wx/menuitem.h>
36 //    #include <wx/string.h>
37 //    #include "sdk_events.h"
38 //    #include "manager.h"
39 //    #include "projectmanager.h"
40 //    #include "editormanager.h"
41 //    #include "cbworkspace.h"
42 //    #include "cbproject.h"
43 //    #include "logmanager.h"
44 //#endif
45 
46 // includes
47 //-#include "debugging.h"
48 #include "menuutils.h"
49 
50 
51 // static
52 wxMenuBar* wxMenuCmd::m_pMenuBar = NULL;
53 // ----------------------------------------------------------------------------
54 namespace
55 // ----------------------------------------------------------------------------
56 {
wxFound(int result)57     bool wxFound(int result){return result != wxNOT_FOUND;}
58 }
59 // ----------------------------------------------------------------------------
60 // Global utility functions
61 // ----------------------------------------------------------------------------
62 
63 // ----------------------------------------------------------------------------
wxFindMenuItem(wxMenuBar * p,const wxString & str)64 int wxFindMenuItem(wxMenuBar *p, const wxString &str)
65 // ----------------------------------------------------------------------------
66 {
67     int id = wxNOT_FOUND;
68 
69     for (int i=0; i < (int)p->GetMenuCount(); i++) {
70 
71         id = p->GetMenu(i)->FindItem(str);
72         if (id != wxNOT_FOUND)
73             break;
74     }
75 
76     return id;
77 }
78 
79 namespace
80 {
81 //// ----------------------------------------------------------------------------
82 //int FindMenuDuplicateCount(wxMenuBar *p, wxString &str)
83 //// ----------------------------------------------------------------------------
84 //{
85 //    //int id = wxNOT_FOUND;
86 //    int count = 0;
87 //
88 //    for (int i = 0; i < (int)p->GetMenuCount(); ++i) {
89 //
90 //        //id = p->GetMenu(i)->FindItem(str);
91 //        //if (id != wxNOT_FOUND)
92 //        //  count++;
93 //        FindMenuDuplicateItems( p->GetMenu(i), str, count);
94 //    }
95 //
96 //    return count;
97 //}
98 }
99 // ----------------------------------------------------------------------------
FindMenuDuplicateItems(wxMenu * pMenu,wxString & rStr,int & rCount)100 int FindMenuDuplicateItems(wxMenu* pMenu, wxString& rStr, int& rCount)
101 // ----------------------------------------------------------------------------
102 {
103     // Recursively scan & count submenu items with name rStr
104 
105     size_t itemKnt = pMenu->GetMenuItemCount();
106     for (size_t j=0; j<itemKnt; j++ )
107     {
108         // check each item on this subMenu
109         wxMenuItem* pMenuItem = pMenu->FindItemByPosition(j);
110         // recursively walk down to deepest submenu
111         if ( pMenuItem->GetSubMenu() )
112             FindMenuDuplicateItems( pMenuItem->GetSubMenu(), rStr, rCount );
113         //---------------------------
114         // Now at deepest menu items
115         //---------------------------
116         // skip separater menu items
117         if (pMenuItem->GetKind() == wxITEM_SEPARATOR) continue;
118         //int nMenuItemID = pMenuItem->GetId();
119 
120         // Skip any menu items beginning with numerics
121         if (wxMenuCmd::IsNumericMenuItem(pMenuItem)) continue;
122 
123         // Find matching menu item in keybinder array of commands
124         wxString menuItemLabel = pMenuItem->GetItemLabelText().Trim();
125         if (rStr == pMenuItem->GetItemLabelText().Trim() )
126         {    rCount++;
127             #if defined(LOGGING)
128              wxLogMessage( _T("Duplicate menu item [%d][%s]"), pMenuItem->GetId(), pMenuItem->GetItemLabelText().GetData()  );
129             #endif
130         }
131     }//for
132     return rCount;
133 }//mergeSubmenu
134 
135 // ----------------------------------------------------------------------------
GetFullMenuPath(int id)136 wxString GetFullMenuPath(int id)
137 // ----------------------------------------------------------------------------
138 {
139     // fetch the full menu path from menu structure via a menu id
140     // It will look like "File\\Open\\Recent Files"
141     // or "" on failure
142 
143     wxString fullMenuPath = wxEmptyString;
144     wxMenuBar* pbar = wxMenuCmd::m_pMenuBar;
145     wxMenu* pMenu = 0;
146 
147     // try to find the menu item
148     wxMenuItem* pMenuItem = pbar->FindItem(id, &pMenu);
149     if ( pMenuItem == NULL ) return fullMenuPath;
150 
151     // fetch wxMenuItem label
152     fullMenuPath = pMenuItem->GetItemLabelText().Trim();
153 
154     //wxLogMessage( _T("fullMenuPath[%s]"), fullMenuPath.c_str() );
155     // get parent menu of the wxMenuItem
156     wxMenu* pParentMenu = pMenu->GetParent();
157 
158     // prepend menu labels by iterating upwards through the menu structure
159     while (pParentMenu)
160     {    for (int i=0; i < (int)pParentMenu->GetMenuItemCount(); i++)
161         {
162             wxMenuItem* pitem = pParentMenu->GetMenuItems().Item(i)->GetData();
163             if (pitem->GetSubMenu() && (pitem->GetSubMenu()== pMenu ))
164             {
165                 fullMenuPath.Prepend( pitem->GetItemLabelText().Trim() + wxT("\\"));
166                 //wxLogMessage( _T("ParentMenu[%s]"),pitem->GetLabel().c_str() );
167                 break;
168             }
169         }
170         pMenu = pParentMenu;
171         pParentMenu = pParentMenu->GetParent();
172     }//while
173 
174     // prepend last parent from menu bar
175     for (int i=0; i<(int)pbar->GetMenuCount() ;++i )
176     {
177         wxMenu* pBarMenu = pbar->GetMenu(i);
178         if ( pBarMenu == pMenu)
179         {
180             #if wxCHECK_VERSION(3, 0, 0)
181             fullMenuPath.Prepend( pbar->GetMenuLabel(i) + wxT("\\"));
182             #else
183             fullMenuPath.Prepend( pbar->GetLabelTop(i) + wxT("\\"));
184             #endif
185             //wxLogMessage( _T("ParentMenu[%s]"),pbar->GetLabelTop(i).c_str() );
186         }
187     }
188 
189     //wxLogMessage( _T("fullPath[%s]"), fullMenuPath.c_str() );
190 
191     return fullMenuPath;
192 }
193 
194 namespace
195 {
196 
197 // ----------------------------------------------------------------------------
FindMenuIdUsingFullMenuPath(const wxString & sFullMenuPath)198 int FindMenuIdUsingFullMenuPath( const wxString& sFullMenuPath )
199 // ----------------------------------------------------------------------------
200 {
201     // verify sFullMenuPath and return the menuitem id of its last level
202     // the path is in the form "File\Open\Recent Files\File01" etc.
203     // like a file path.
204 
205     if ( sFullMenuPath.IsEmpty() ) return wxNOT_FOUND;
206     #if defined(LOGGING)
207     wxLogMessage( _T("FindMenuIdUsingFullMenuPath[%s]"), sFullMenuPath.c_str() );
208     #endif
209     wxMenuBar* pMenuBar = wxMenuCmd::m_pMenuBar;
210     int id = wxNOT_FOUND;
211     int menuIndex = wxNOT_FOUND;
212 
213     wxString fullMenuPath = sFullMenuPath;
214     int levelCount = fullMenuPath.Freq(wxT('\\'))+1;
215     wxArrayString levels;
216 
217     // break the full menu path string into levels
218     for ( int i=0; i < levelCount; ++i )
219     {
220         levels.Add( fullMenuPath.BeforeFirst(wxT('\\')) );
221         fullMenuPath.Remove(0, levels[i].Length()+1 );
222         levels[i].Trim();
223         //wxLogMessage( _T("level[%d][%s]"), i, levels[i].c_str() );
224     }
225     // start searching from the menubar level
226     if ( wxNOT_FOUND == (menuIndex = pMenuBar->FindMenu( levels[0]) ))
227         return wxNOT_FOUND;
228     wxMenu* pMenu = pMenuBar->GetMenu(menuIndex);
229     wxMenuItem* pMenuItem = 0;
230     bool found = false;
231 
232     // find and compare file key path levels to each level of the actual menu
233     for (int i=1; i < (int)levels.GetCount(); ++i)
234     {
235         #if defined(LOGGING)
236         wxLogMessage( _T("Searching for Level[%d][%s]"), i, levels[i].wx_str() );
237         #endif
238         if (not pMenu) return wxNOT_FOUND;
239         found = false;
240         for (int j=0; j < (int)pMenu->GetMenuItemCount(); ++j )
241         {
242             pMenuItem = pMenu->FindItemByPosition(j);
243             //wxLogMessage( _T("MenuItem[%d][%s]"), j, pMenuItem->GetLabel().c_str() );
244             if ( pMenuItem->GetItemLabelText().Trim() == levels[i])
245             {   menuIndex = j;
246                 pMenu = pMenuItem->GetSubMenu();
247                 found = true;
248                 #if defined(LOGGING)
249                     wxLogMessage( _T("Found menuItem [%s]"), pMenuItem->GetItemLabelText().c_str() );
250                 #endif
251                 break;
252             }
253         }//for j
254         // if menu entry found, look at next level
255         if ( found) continue;
256         else return wxNOT_FOUND;
257     }//for i
258 
259     if (found) id = pMenuItem->GetId();
260     else id = wxNOT_FOUND;
261 
262     return id;
263 
264 }//FindMenuIdUsingFullMenuPath
265 }
266 // ----------------------------------------------------------------------------
267 
268 /*
269 #ifdef __WXGTK__
270 
271     #include "wx/gtk/private.h"
272     #include <gdk/gdkkeysyms.h>
273 
274 #endif
275 */
276 
277 
278 // ----------------------------------------------------------------------------
279 // wxMenuCmd
280 // ----------------------------------------------------------------------------
281 
282 #if defined( __WXGTK__) || defined(__WXMAC__)
283 // ----------------------------------------------------------------------------
Update(wxMenuItem * pSpecificMenuItem)284 void wxMenuCmd::Update(wxMenuItem* pSpecificMenuItem) //for __WXGTK__
285 // ----------------------------------------------------------------------------
286 {
287 //    //+v0.4.11
288 //    // verify menu item has not changed its id or disappeared
289 //    if (m_pMenuBar->FindItem(m_nId) != m_pItem)
290 //        return;
291     //v0.4.17
292     // Test if caller wants a different menu item other than in keybinder array
293     wxMenuItem* pLclMnuItem = m_pItem;
294     if (pSpecificMenuItem) pLclMnuItem = pSpecificMenuItem;
295     //+v0.4
296     // verify menu item has not changed its id or disappeared
297     if (not pSpecificMenuItem)
298         if (m_pMenuBar->FindItem(m_nId) != pLclMnuItem)
299             return;
300 
301 
302     //+v0.4.11
303     // leave numeric menu items alone. They get replaced by CodeBlocks
304     if (IsNumericMenuItem(pLclMnuItem))
305       return;
306 
307 #if wxCHECK_VERSION(3, 0, 0)
308     wxString strText = pLclMnuItem->GetItemLabel();
309 #else
310     wxString strText = pLclMnuItem->GetText();
311 #endif
312 
313     // *bug* 2007/01/19 v1.0.15
314     // Dont use  GetLabel to re-establish the menu text. It doesn't
315     // contain the underlined mnemonic. Use GetText()
316     //-wxString str = pLclMnuItem->GetLabel()
317 
318     wxString str = strText.BeforeFirst('\t');
319      // GTK is substituting '&' with an underscore
320     int idx = 0;
321     // change the first underscore to an & mnemonic, all others to blank
322     if ( -1 != (idx = str.Find('_'))) str[idx] = '&';
323     for ( size_t i=0; i<str.Length(); ++i)
324         if ( str[i]=='_'){ str[i] = ' ';}
325     #if defined(LOGGING)
326      wxLogMessage( _T("Updating menu item Label[%s]Text[%s]id[%d]"), str.wx_str(), strText.wx_str(), pLclMnuItem->GetId() );
327     #endif
328 
329 
330     // on GTK, an optimization in wxMenu::SetText checks
331     // if the new label is identical to the old and in this
332     // case, it returns without doing anything... :-(
333     // to solve the problem, a space is added or removed
334     // from the label to override this optimization check
335     str.Trim();
336     if (m_nShortcuts <= 0)
337     {
338         #if defined(LOGGING)
339         wxLogMessage(_("wxMenuCmd::Update - no shortcuts defined for [%s]"), str.c_str());
340         #endif
341 
342         // no more shortcuts for this menuitem: SetText()
343         // will delete the hotkeys associated...
344 #if wxCHECK_VERSION(3, 0, 0)
345         pLclMnuItem->SetItemLabel(str);
346 #else
347         pLclMnuItem->SetText(str);
348 #endif
349         return;
350     }
351 
352     wxString newtext = str+wxT("\t")+GetShortcut(0)->GetStr();
353     #if defined(LOGGING)
354     wxLogMessage(_("wxMenuCmd::Update - setting the new text to [%s]"), newtext.c_str());
355     #endif
356 
357 
358     // on GTK, the SetAccel() function doesn't have any effect...
359 #if wxCHECK_VERSION(3, 0, 0)
360     pLclMnuItem->SetItemLabel(newtext);
361 #else
362     pLclMnuItem->SetText(newtext);
363 #endif
364 
365 #ifdef __WXGTK20__
366 
367     //   gtk_menu_item_set_accel_path(GTK_MENU_ITEM(m_pItem), wxGTK_CONV(newtext));
368 
369 #endif
370 }
371 #endif //update for __WXGTK__
372 // ----------------------------------------------------------------------------
373 
374 #if defined( __WXMSW__ )
375 // ----------------------------------------------------------------------------
Update(wxMenuItem * pSpecificMenuItem)376 void wxMenuCmd::Update(wxMenuItem* pSpecificMenuItem) // for __WXMSW__
377 // ----------------------------------------------------------------------------
378 {
379     wxMenuItem* pLclMnuItem = m_pItem;
380 
381     // Test if caller wants a different menu item than in wxCmd item
382     if (pSpecificMenuItem)
383         pLclMnuItem = pSpecificMenuItem;
384 
385     // verify menu item has not changed its id or disappeared
386     if ( NULL == m_pMenuBar->FindItem(m_nId) )
387         return;
388     // if using wxCmd item, and its not a program menu item, punt
389     // this happens when a plugin deletes a menu item
390     if (not pSpecificMenuItem)
391         if (m_pMenuBar->FindItem(m_nId) != pLclMnuItem)
392             return;
393 
394     // leave numeric menu items alone. They get replaced by CodeBlocks
395     if (IsNumericMenuItem(pLclMnuItem))
396       return;
397 
398     #if wxCHECK_VERSION(3, 0, 0)
399     wxString strText = pLclMnuItem->GetItemLabel();
400     #else
401     wxString strText = pLclMnuItem->GetText();
402     #endif
403     //use full text to get label in order to preserve mnemonics/accelerators
404     wxString strLabel = strText.BeforeFirst(_T('\t'));
405     wxString newtext = strLabel; //no accel, contains mnemonic
406 
407     wxAcceleratorEntry* pItemAccel = pLclMnuItem->GetAccel();
408     // clearing previous shortcuts if none now assigned
409     if (m_nShortcuts <= 0) {
410         if ( ! pItemAccel) return;
411         #if LOGGING
412          wxLogMessage(_("wxMenuCmd::Update - Removing shortcuts [%d][%s] for [%d][%s]"),pLclMnuItem->GetId(), strText.wx_str(), m_nId, newtext.wx_str());
413         #endif
414         // set "non bitmapped" text to preserve menu width
415         #if wxCHECK_VERSION(3, 0, 0)
416         pLclMnuItem->SetItemLabel(newtext);
417         #else
418         pLclMnuItem->SetText(newtext);
419         #endif
420          //now rebuild the menuitem if bitmapped
421          if (pLclMnuItem->GetBitmap().GetWidth())
422              pLclMnuItem = RebuildMenuitem(pLclMnuItem); //+v0.4.6
423         return;
424     }
425 
426     //make new Label+Accelerator string
427     newtext = strLabel+wxT("\t")+GetShortcut(0)->GetStr();
428 
429     // change the accelerator...but only if it has changed
430     wxAcceleratorEntry* pPrfAccel = wxAcceleratorEntry::Create(newtext);
431     if ( ! pPrfAccel) return;
432     if ( pItemAccel
433          && ( pItemAccel->GetFlags() == pPrfAccel->GetFlags() )
434          && ( pItemAccel->GetKeyCode() == pPrfAccel->GetKeyCode() ) )
435          return;
436     #if LOGGING
437      wxLogMessage(_("wxMenuCmd::Update - Setting shortcuts for [%d][%s]"), pLclMnuItem->GetId(), newtext.wx_str());
438     #endif
439     #if wxCHECK_VERSION(3, 0, 0)
440     pLclMnuItem->SetItemLabel(newtext);
441     #else
442     pLclMnuItem->SetText(newtext);
443     #endif
444     //now rebuild the menuitem if bitmapped
445     if (pLclMnuItem->GetBitmap().GetWidth())
446         pLclMnuItem = RebuildMenuitem(pLclMnuItem); //+v0.4.6
447 
448 }//Update
449 //// ----------------------------------------------------------------------------
450 //// RebuildMenuitem
451 //// ----------------------------------------------------------------------------
452 ////wxMenuItem* wxMenuCmd::RebuildMenuitem(wxMenuItem* pMnuItem)
453 ////{//+v0.4.25 WXMSW
454 ////   // Since wxWidgets 2.6.3, we don't have to rebuild the menuitem
455 ////   // to preserve the bitmapped menu icon.
456 ////    return pMnuItem;
457 ////
458 ////}//RebuildMenuitem
459 
460 // ----------------------------------------------------------------------------
461 // The following routine was used when wxWidgets would not SetText()
462 // without clobbering the menu Bitmap icon
463 // ----------------------------------------------------------------------------
464 // ----------------------------------------------------------------------------
RebuildMenuitem(wxMenuItem * pMnuItem)465 wxMenuItem* wxMenuCmd::RebuildMenuitem(wxMenuItem* pMnuItem)
466 // ----------------------------------------------------------------------------
467 {//Reinstated v1.0.13 2006/12/30 for wx2.6.3 w/fixes and wx2.8.0
468  // which now cause the same problem as 2.6.2
469     // ---------------------------------------------------------------
470     //  Do it the slow/hard way, remove and delete the menu item
471     // ---------------------------------------------------------------
472     wxMenu* pMenu = pMnuItem->GetMenu();
473     wxMenuItemList items = pMenu->GetMenuItems();
474     int pos = items.IndexOf(pMnuItem);
475    // rebuild the menuitem
476     wxMenuItem* pnewitem = new wxMenuItem(pMenu, m_nId,
477         #if wxCHECK_VERSION(3, 0, 0)
478                 pMnuItem->GetItemLabel(),
479         #else
480                 pMnuItem->GetText(),
481         #endif
482                 pMnuItem->GetHelp(), pMnuItem->GetKind(),
483                 pMnuItem->GetSubMenu() );
484     pnewitem->SetBitmap(pMnuItem->GetBitmap() );
485     pnewitem->SetFont(pMnuItem->GetFont() );
486    #if wxUSE_OWNER_DRAWN    //TimS 2006/12/30 v1.0.13
487     if ( pMnuItem->IsOwnerDrawn() )
488     {
489         pnewitem->SetOwnerDrawn(true);
490         pnewitem->SetMarginWidth(pMnuItem->GetMarginWidth());
491         pnewitem->SetDisabledBitmap(pMnuItem->GetDisabledBitmap());
492         if (pMnuItem->IsCheckable())
493         {
494             pnewitem->SetCheckable(true);
495             pnewitem->SetBitmaps(pMnuItem->GetBitmap(true), pMnuItem->GetBitmap(false));
496         }
497     }
498    #endif
499     // remove the menuitem
500     pMenu->Destroy(pMnuItem);
501     // update keybinder array menu item pointer
502     m_pItem = pnewitem;
503     // put the menuitem back on the menu
504     pMenu->Insert(pos, pnewitem);
505     return pnewitem;
506 
507 }//RebuildMenuitem
508 #endif //#if defined( __WXMSW__ )
509 // ----------------------------------------------------------------------------
IsNumericMenuItem(wxMenuItem * pwxMenuItem)510 bool wxMenuCmd::IsNumericMenuItem(wxMenuItem* pwxMenuItem)   //v0.2
511 // ----------------------------------------------------------------------------
512 {//v0.2
513     #if wxCHECK_VERSION(3, 0, 0)
514     wxString str = pwxMenuItem->GetItemLabel();
515     #else
516     wxString str = pwxMenuItem->GetText();
517     #endif
518     if (str.Length() <2) return false;
519     if (str.Left(1).IsNumber()) return true;
520     if ( (str[0] == '&') && (str.Mid(1,1).IsNumber()) )
521         return true;
522     if ( (str[0] == '_') && (str.Mid(1,1).IsNumber()) )
523         return true;
524     return false;
525 }//IsNumericMeuItem
526 // ----------------------------------------------------------------------------
Exec(wxObject * origin,wxEvtHandler * client)527 void wxMenuCmd::Exec(wxObject *origin, wxEvtHandler *client)
528 // ----------------------------------------------------------------------------
529 {
530     wxCommandEvent menuEvent(wxEVT_COMMAND_MENU_SELECTED, GetId());
531     wxASSERT_MSG(client, wxT("An empty client handler ?!?"));
532 
533     // set up the event and process it...
534     menuEvent.SetEventObject(origin);
535 
536     // 2007/08/12
537     // Had to change AddPendingEvent() to ProcessEvent() to avoid crashes
538     // when secondary command key would close editors wx284
539     ////client->AddPendingEvent(menuEvent);//ProcessEvent(menuEvent);
540 
541     client->ProcessEvent(menuEvent);//ProcessEvent(menuEvent);
542 }
543 
544 //// ----------------------------------------------------------------------------
545 ////wxCmd *wxMenuCmd::CreateNew(int id)
546 //// ----------------------------------------------------------------------------
547 ////{-v0.3
548 ////    if (!m_pMenuBar) return NULL;
549 ////
550 ////    // search the menuitem which is tied to the given ID
551 ////    wxMenuItem *p = m_pMenuBar->FindItem(id);
552 ////
553 ////    if (!p) return NULL;
554 ////    wxASSERT(id == p->GetId());
555 ////    return new wxMenuCmd(p);
556 ////}
557 // --+v0.3---------------------------------------------------------------------
CreateNew(wxString sCmdName,int id)558 wxCmd *wxMenuCmd::CreateNew(wxString sCmdName, int id)
559 // ----------------------------------------------------------------------------
560 {
561     if (!m_pMenuBar) return NULL;
562 
563     // search for a matching menu item
564     // CodeBlocks has dynamic (shifty) menu item id's
565     // so the file loaded item may have a different/stale item id.
566 
567     wxMenuItem* pMenuItem = 0;
568     wxString fullMenuPath = sCmdName;       //(2007/6/15)
569     wxString cmdName = fullMenuPath.AfterLast(wxT('\\'));
570     cmdName.Trim();
571     int actualMenuID = id;
572 
573     // Try to match id and label to avoid duplicate named menu items
574     wxMenuItem* pMenuItemByCfgId = m_pMenuBar->FindItem(id);
575     if ( pMenuItemByCfgId && (pMenuItemByCfgId->GetItemLabelText().Trim() == cmdName) )
576         pMenuItem = pMenuItemByCfgId;
577     else
578     {   // didn't find the menu id with the specified cmd name.
579         #if defined(LOGGING)
580             wxLogMessage( _T("CreateNew() Unmatched id[%d][%s]"), id, cmdName.GetData() );
581         #endif
582         actualMenuID = FindMenuIdUsingFullMenuPath( fullMenuPath ) ;
583         if (wxFound(actualMenuID) )
584             pMenuItem = m_pMenuBar->FindItem( actualMenuID );
585         #if defined(LOGGING)
586         else
587             wxLogMessage( _T("CreateNew() UnFound id[%d][%s]"), id, cmdName.GetData() );
588         #endif
589 
590     }//end else
591 
592     if (not pMenuItem)
593     {
594         wxLogDebug(_("KeyBinder:CreateNew() not created[%d][%s]"), id, cmdName.GetData());
595         // ... also an untranslated msg so I can read it.
596         wxLogDebug(_T("KeyBinder:CreateNew() not created[%d][%s]"), id, cmdName.GetData());
597         return NULL;
598     }
599 
600     //-wxASSERT(id == p->GetId());
601     //wxLogMessage( _T("CreatingNew for [%d][%s]"), actualMenuID, cmdName.GetData() );
602 
603     //-return new wxMenuCmd(pMenuItem); //(2019/03/5)-
604     return new wxMenuCmd(pMenuItem, cmdName, pMenuItem->GetHelp()); //(2019/03/5)
605 }
606 
607 // ****************************************************************************
608 //                          wxMenuWalker
609 // ****************************************************************************
610 
611 // ----------------------------------------------------------------------------
IsNumericMenuItem(wxMenuItem * pwxMenuItem)612 bool wxMenuWalker::IsNumericMenuItem(wxMenuItem* pwxMenuItem)   //v0.2
613 // ----------------------------------------------------------------------------
614 {//v0.2
615     #if wxCHECK_VERSION(3, 0, 0)
616     wxString str = pwxMenuItem->GetItemLabel();
617     #else
618     wxString str = pwxMenuItem->GetText();
619     #endif
620     if (str.Length() <2) return false;
621     if (str.Left(1).IsNumber()) return true;
622     if ( (str[0] == '&') && (str.Mid(1,1).IsNumber()) )
623         return true;
624     if ( (str[0] == '_') && (str.Mid(1,1).IsNumber()) )
625         return true;
626     return false;
627 }
628 // ----------------------------------------------------------------------------
WalkMenuItem(wxMenuBar * p,wxMenuItem * m,void * data)629 void wxMenuWalker::WalkMenuItem(wxMenuBar* p, wxMenuItem* m, void* data)
630 // ----------------------------------------------------------------------------
631 {
632     //dont fool with itemized filenames, GetLabel cant handle file slashes //v0.2
633     if (IsNumericMenuItem(m)) return;   //v0.2
634 
635     //wxLogMessage(_("wxMenuWalker::WalkMenuItem - walking on [%s] at level [%d]"),
636     //          m->GetLabel().c_str(), m_nLevel);
637 
638     void* tmp = OnMenuItemWalk(p, m, data);
639 
640     if (m->GetSubMenu())
641     {
642         // if this item contains a sub menu, add recursively the menu items
643         // of that sub menu... using the cookie from OnMenuItemWalk.
644         //wxLogMessage(_("wxMenuWalker::WalkMenuItem - recursing on [%s]"), m->GetLabel().c_str());
645 
646         m_nLevel++;
647         WalkMenu(p, m->GetSubMenu(), tmp);
648         OnMenuExit(p, m->GetSubMenu(), tmp);
649         m_nLevel--;
650     }
651 
652     // we can delete the cookie we got form OnMenuItemWalk
653     DeleteData(tmp);
654 }
655 
656 // ----------------------------------------------------------------------------
WalkMenu(wxMenuBar * p,wxMenu * m,void * data)657 void wxMenuWalker::WalkMenu(wxMenuBar* p, wxMenu* m, void* data)
658 // ----------------------------------------------------------------------------
659 {
660 
661     //wxLogMessage(_("wxMenuWalker::WalkMenu - walking on [%s] at level [%d]"),
662     //          m->GetTitle().c_str(), m_nLevel);
663 
664     for (int i=0; i < (int)m->GetMenuItemCount(); i++)
665     {
666         wxMenuItem* pitem = m->GetMenuItems().Item(i)->GetData();
667 
668         // inform the derived class that we have reached a menu
669         // and get the cookie to give on WalkMenuItem...
670         void* tmp = OnMenuWalk(p, m, data);
671 
672         // skip separators (on wxMSW they are marked as wxITEM_NORMAL
673         // but they do have empty labels)...
674         if (pitem->GetKind() != wxITEM_SEPARATOR &&
675             pitem->GetItemLabelText().Trim() != wxEmptyString)
676             WalkMenuItem(p, pitem, tmp);
677 
678         // the cookie we gave to WalkMenuItem is not useful anymore
679         DeleteData(tmp);
680     }
681 
682     OnMenuExit(p, m, data);
683 }
684 
685 // ----------------------------------------------------------------------------
Walk(wxMenuBar * pMnuBar,void * data)686 void wxMenuWalker::Walk(wxMenuBar* pMnuBar, void *data)
687 // ----------------------------------------------------------------------------
688 {
689     wxASSERT(pMnuBar);
690 
691     for (int i=0; i < (int)pMnuBar->GetMenuCount(); i++)
692     {
693 
694         // create a new tree branch for the i-th menu of this menubar
695         wxMenu* pMnu = pMnuBar->GetMenu(i);
696 
697         m_nLevel++;
698         //wxLogMessage(_("wxMenuWalker::Walk - walking on [%s] at level [%d]"),
699         //          p->GetLabelTop(i).c_str(), m_nLevel);
700 
701         void* tmp = OnMenuWalk(pMnuBar, pMnu, data);
702 
703         // and fill it...
704         WalkMenu(pMnuBar, pMnu, tmp);
705         m_nLevel--;
706 
707         DeleteData(tmp);
708     }
709 }
710 // ****************************************************************************
711 //                          wxMenuTreeWalker
712 // ****************************************************************************
713 // ----------------------------------------------------------------------------
FillTreeBranch(wxMenuBar * pMnuBar,wxTreeCtrl * pTreectrl,wxTreeItemId branch)714 void wxMenuTreeWalker::FillTreeBranch(wxMenuBar* pMnuBar, wxTreeCtrl* pTreectrl, wxTreeItemId branch)
715 // ----------------------------------------------------------------------------
716 {
717     // these will be used in the recursive functions...
718     m_root = branch;
719     m_pTreeCtrl = pTreectrl;
720 
721     // be sure that the given tree item is empty...
722     m_pTreeCtrl->DeleteChildren(branch);
723 
724     // ...start !!!
725     Walk(pMnuBar, &branch);
726 }
727 
728 // ----------------------------------------------------------------------------
OnMenuWalk(wxMenuBar * p,wxMenu * m,void * data)729 void* wxMenuTreeWalker::OnMenuWalk(wxMenuBar *p, wxMenu *m, void *data)
730 // ----------------------------------------------------------------------------
731 {
732     wxTreeItemId* id = (wxTreeItemId *)data;
733     int i;
734 
735     // if we receive an invalid tree item ID, we must stop everything...
736     // (in fact a NULL value given as DATA in wxMenuTreeWalker function
737     // implies the immediate processing stop)...
738     if (!id->IsOk())
739         return NULL;
740 
741     // if this is the first level of menus, we must create a new tree item
742     if (*id == m_root) {
743 
744         // find the index of the given menu
745         for (i=0; i < (int)p->GetMenuCount(); i++)
746             if (p->GetMenu(i) == m)
747                 break;
748         wxASSERT(i != (int)p->GetMenuCount());
749 
750         // and append a new tree branch with the appropriate label
751         wxTreeItemId newId = m_pTreeCtrl->AppendItem(*id,
752         #if wxCHECK_VERSION(3, 0, 0)
753             wxMenuItem::GetLabelText(p->GetMenuLabel(i)));
754         #else
755             wxMenuItem::GetLabelFromText(p->GetLabelTop(i)));
756         #endif
757 
758         // menu items contained in the given menu must be added
759         // to the just created branch
760         return new wxTreeItemId(newId);
761     }
762 
763     // menu items contained in the given menu must be added
764     // to this same branch...
765     return new wxTreeItemId(*id);
766 }
767 // ----------------------------------------------------------------------------
OnMenuItemWalk(wxMenuBar *,wxMenuItem * m,void * data)768 void* wxMenuTreeWalker::OnMenuItemWalk(wxMenuBar *, wxMenuItem *m, void *data)
769 // ----------------------------------------------------------------------------
770 {
771     wxTreeItemId* id = (wxTreeItemId *)data;
772     if (id->IsOk()) {
773 
774         // to each tree branch attach a wxTreeItemData containing
775         // the ID of the menuitem which it represents...
776         wxExTreeItemData* treedata = new wxExTreeItemData(m->GetId());
777 
778         // create the new item in the tree ctrl
779         wxTreeItemId newId = m_pTreeCtrl->AppendItem(*id,
780             m->GetItemLabelText().Trim(), -1, -1, treedata);
781 
782         return new wxTreeItemId(newId);
783     }
784 
785     return NULL;
786 }
787 
788 // ----------------------------------------------------------------------------
DeleteData(void * data)789 void wxMenuTreeWalker::DeleteData(void *data)
790 // ----------------------------------------------------------------------------
791 {
792     wxTreeItemId* p = (wxTreeItemId *)data;
793     if (p) delete p;
794 }
795 
796 // ****************************************************************************
797 //                       wxMenuComboListWalker
798 // ****************************************************************************
799 // ----------------------------------------------------------------------------
FillComboListCtrl(wxMenuBar * p,wxComboBox * combo)800 void wxMenuComboListWalker::FillComboListCtrl(wxMenuBar *p, wxComboBox *combo)
801 // ----------------------------------------------------------------------------
802 {
803     // these will be used in the recursive functions...
804     m_pCategories = combo;
805 
806     // be sure that the given tree item is empty...
807     m_pCategories->Clear();
808 
809     // ...start !!!
810     Walk(p, NULL);
811 }
812 
813 // ----------------------------------------------------------------------------
OnMenuWalk(wxMenuBar * p,wxMenu * m,void *)814 void *wxMenuComboListWalker::OnMenuWalk(wxMenuBar *p, wxMenu *m, void *)
815 // ----------------------------------------------------------------------------
816 {
817     //wxLogMessage(_("wxMenuWalker::OnMenuWalk - walking on [%s]"), m->GetTitle().c_str());
818 
819     wxString toadd;
820 
821     // find the index of the given menu
822     if (m_strAcc.IsEmpty()) {
823 
824         int i;
825         for (i=0; i < (int)p->GetMenuCount(); i++)
826             if (p->GetMenu(i) == m)
827                 break;
828         wxASSERT(i != (int)p->GetMenuCount());
829         #if wxCHECK_VERSION(3, 0, 0)
830         toadd = wxMenuItem::GetLabelText(p->GetMenuLabel(i));
831         #else
832         toadd = wxMenuItem::GetLabelFromText(p->GetLabelTop(i));
833         #endif
834 
835         m_strAcc = toadd;
836 
837     } else {
838 
839         //toadd = m->GetTitle();
840         toadd = m_strAcc;
841         //wxString str((wxString)()acc);
842         //m_strAcc += str;
843     }
844 
845     //int last = m_pCategories->GetCount()-1;
846     int found;
847     if ((found = m_pCategories->FindString(toadd)) != wxNOT_FOUND)
848         return m_pCategories->GetClientObject(found);
849 
850     // create the clientdata that our new combobox item will contain
851     wxClientData* cd = new wxExComboItemData();
852 
853     // and create a new element in our combbox
854     //wxLogMessage(_("wxMenuComboListWalker::OnMenuWalk - appending [%s]"), toadd.c_str());
855 
856     m_pCategories->Append(toadd, cd);
857     return cd;
858 }
859 
860 // ----------------------------------------------------------------------------
OnMenuItemWalk(wxMenuBar *,wxMenuItem * m,void * data)861 void *wxMenuComboListWalker::OnMenuItemWalk(wxMenuBar *, wxMenuItem *m, void *data)
862 // ----------------------------------------------------------------------------
863 {
864     //wxLogMessage(_("wxMenuWalker::OnMenuItemWalk - walking on [%s]"), m->GetLabel().c_str());
865 
866     //int last = m_pCategories->GetCount()-1;
867     wxExComboItemData *p = (wxExComboItemData *)data;//m_pCategories->GetClientObject(last);
868 
869     // append a new item
870     if (m->GetSubMenu() == NULL)
871         p->Append(m->GetItemLabelText().Trim(), m->GetId());
872     else
873         m_strAcc += wxT(" | ") + m->GetItemLabelText().Trim();
874 
875     // no info to give to wxMenuComboListWalker::OnMenuWalk
876     return NULL;//(void *)str;
877 }
878 
879 // ----------------------------------------------------------------------------
OnMenuExit(wxMenuBar *,wxMenu *,void *)880 void wxMenuComboListWalker::OnMenuExit(wxMenuBar *, wxMenu * /*m*/, void *)
881 // ----------------------------------------------------------------------------
882 {
883     //-wxLogDebug(wxT("wxMenuWalker::OnMenuExit - walking on [%s]"), m->GetTitle().c_str());
884     //-wxLogDebug("\n");
885 
886     if (!m_strAcc.IsEmpty()){// && m_strAcc.Right() == str) {
887 
888         int diff = m_strAcc.Find(wxT('|'), TRUE);
889 
890         if (diff == wxNOT_FOUND)
891             m_strAcc = wxEmptyString;
892         else
893             m_strAcc = m_strAcc.Left(diff);
894         m_strAcc.Trim();
895     }
896 }
897 
898 // ----------------------------------------------------------------------------
DeleteData(void *)899 void wxMenuComboListWalker::DeleteData(void *)
900 // ----------------------------------------------------------------------------
901 { /* we need NOT TO DELETE the given pointer !! */
902 }
903 
904 // ***************************************************************************
905 //                  wxMenuShortcutWalker
906 // ***************************************************************************
907 // ----------------------------------------------------------------------------
OnMenuItemWalk(wxMenuBar *,wxMenuItem * m,void *)908 void *wxMenuShortcutWalker::OnMenuItemWalk(wxMenuBar *, wxMenuItem *m, void *)
909 // ----------------------------------------------------------------------------
910 {
911     wxASSERT(m);
912 
913     // add an entry to the command array
914     wxCmd *cmd = new wxMenuCmd(m, m->GetItemLabelText().Trim(), m->GetHelp());
915     m_pArr->Add(cmd);
916 
917     // check for shortcuts
918     wxAcceleratorEntry* a = m->GetAccel();      // returns a pointer which we have to delete
919     if (a) {
920 
921         // this menuitem has an associated accelerator... add an entry
922         // to the array of bindings for the relative command...
923         cmd->AddShortcut(a->GetFlags(), a->GetKeyCode());
924     }
925 
926     // cleanup
927     if (a) delete a;
928     return NULL;
929 }
930 
931 // ----------------------------------------------------------------------------
DeleteData(void * data)932 void wxMenuShortcutWalker::DeleteData(void *
933 #ifdef __WXDEBUG__
934                                       data
935 #endif  // to avoid warnings about unused arg
936                                       )
937 // ----------------------------------------------------------------------------
938 {
939     wxASSERT_MSG(data == NULL,
940                 wxT("wxMenuShortcutWalker does not use the 'data' parameter")
941         );
942 }
943 // ----------------------------------------------------------------------------
944 
945