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