]> git.saurik.com Git - wxWidgets.git/blob - samples/regtest/regtest.cpp
better ownership handling
[wxWidgets.git] / samples / regtest / regtest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: regtest.cpp
3 // Purpose: wxRegKey class demo
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 03.04.98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 # pragma hdrstop
23 #endif
24
25 #ifndef WX_PRECOMP
26 # include "wx/wx.h"
27 #endif
28
29 #include "wx/treectrl.h"
30 #include "wx/config.h"
31 #include "wx/imaglist.h"
32 #include "wx/tokenzr.h"
33
34 #if wxUSE_CONFIG_NATIVE && defined( __WXMSW__ )
35 # define DO_REGTEST 1
36 #else
37 # define DO_REGTEST 0
38 #endif
39
40 // ----------------------------------------------------------------------------
41 // application type
42 // ----------------------------------------------------------------------------
43 class RegApp : public wxApp
44 {
45 public:
46 bool OnInit();
47 };
48
49 // ----------------------------------------------------------------------------
50 // image list with registry icons
51 // ----------------------------------------------------------------------------
52 class RegImageList : public wxImageList
53 {
54 public:
55 enum Icon
56 {
57 Root,
58 ClosedKey,
59 OpenedKey,
60 TextValue,
61 BinaryValue
62 };
63
64 RegImageList();
65 };
66
67 #if DO_REGTEST
68
69 // ----------------------------------------------------------------------------
70 // our control
71 // ----------------------------------------------------------------------------
72 class RegTreeCtrl : public wxTreeCtrl
73 {
74 public:
75 // ctor & dtor
76 RegTreeCtrl(wxWindow *parent, wxWindowID id);
77 virtual ~RegTreeCtrl();
78
79 // notifications
80 void OnDeleteItem (wxTreeEvent& event);
81 void OnItemExpanding (wxTreeEvent& event);
82 void OnSelChanged (wxTreeEvent& event);
83
84 void OnBeginEdit (wxTreeEvent& event);
85 void OnEndEdit (wxTreeEvent& event);
86
87 void OnBeginDrag (wxTreeEvent& event);
88 void OnEndDrag (wxTreeEvent& event);
89
90 void OnRightClick (wxMouseEvent& event);
91 void OnChar (wxKeyEvent& event);
92 void OnIdle (wxIdleEvent& event);
93
94 // forwarded notifications (by the frame)
95 void OnMenuTest();
96
97 // operations
98 void GoTo(const wxString& location);
99 void DoRefresh();
100 void DeleteSelected();
101 void ShowProperties();
102 void CreateNewKey(const wxString& strName);
103 void CreateNewTextValue(const wxString& strName);
104 void CreateNewBinaryValue(const wxString& strName);
105 void SetRegistryView(wxRegKey::WOW64ViewMode viewMode);
106
107 // information
108 bool IsKeySelected() const;
109
110 private:
111 // structure describing a registry key/value
112 class TreeNode : public wxTreeItemData
113 {
114 WX_DEFINE_ARRAY_PTR(TreeNode *, TreeChildren);
115 public:
116 RegTreeCtrl *m_pTree; // must be !NULL
117 TreeNode *m_pParent; // NULL only for the root node
118 wxTreeItemId m_id; // the id of the tree control item
119 wxString m_strName; // name of the key/value
120 TreeChildren m_aChildren; // array of subkeys/values
121 bool m_bKey; // key or value?
122 wxRegKey *m_pKey; // only may be !NULL if m_bKey == true
123 wxRegKey::WOW64ViewMode m_viewMode; // How to view the registry.
124
125 // trivial accessors
126 wxTreeItemId Id() const { return m_id; }
127 bool IsRoot() const { return m_pParent == NULL; }
128 bool IsKey() const { return m_bKey; }
129 TreeNode *Parent() const { return m_pParent; }
130
131 // notifications
132 bool OnExpand();
133 void OnCollapse();
134
135 // operations
136 void Refresh();
137 bool DeleteChild(TreeNode *child);
138 void DestroyChildren();
139 const wxChar *FullName() const;
140 void SetRegistryView(wxRegKey::WOW64ViewMode viewMode);
141
142 // get the associated key: make sure the pointer is !NULL
143 wxRegKey& Key() { if ( !m_pKey ) OnExpand(); return *m_pKey; }
144
145 // dtor deletes all children
146 ~TreeNode();
147 };
148
149 wxImageList *m_imageList;
150 wxMenu *m_pMenuPopup;
151
152 TreeNode *m_pRoot;
153
154 TreeNode *m_draggedItem; // the item being dragged
155 bool m_copyOnDrop; // if false, then move
156
157 bool m_restoreStatus; // after OnItemExpanding()
158
159 wxString m_nameOld; // the initial value of item being renamed
160
161 wxRegKey::WOW64ViewMode m_viewMode; // Registry view to use for keys.
162
163 TreeNode *GetNode(const wxTreeEvent& event)
164 { return (TreeNode *)GetItemData(event.GetItem()); }
165
166 public:
167 // create a new node and insert it to the tree
168 TreeNode *InsertNewTreeNode(TreeNode *pParent,
169 const wxString& strName,
170 int idImage = RegImageList::ClosedKey,
171 const wxString *pstrValue = NULL,
172 wxRegKey::WOW64ViewMode viewMode = wxRegKey::WOW64ViewMode_Default);
173
174 // add standard registry keys
175 void AddStdKeys();
176
177 private:
178 DECLARE_EVENT_TABLE()
179 };
180
181 #endif // #if DO_REGTEST
182
183 // ----------------------------------------------------------------------------
184 // the main window of our application
185 // ----------------------------------------------------------------------------
186 class RegFrame : public wxFrame
187 {
188 public:
189 // ctor & dtor
190 RegFrame(wxFrame *parent, const wxChar *title, int x, int y, int w, int h);
191 virtual ~RegFrame();
192
193 // callbacks
194 void OnQuit (wxCommandEvent& event);
195 void OnAbout(wxCommandEvent& event);
196 void OnTest (wxCommandEvent& event);
197
198 void OnGoTo (wxCommandEvent& event);
199
200 void OnExpand (wxCommandEvent& event);
201 void OnCollapse(wxCommandEvent& event);
202 void OnToggle (wxCommandEvent& event);
203 void OnRefresh (wxCommandEvent& event);
204
205 void OnDelete (wxCommandEvent& event);
206 void OnNewKey (wxCommandEvent& event);
207 void OnNewText (wxCommandEvent& event);
208 void OnNewBinary(wxCommandEvent& event);
209
210 void OnInfo (wxCommandEvent& event);
211
212 void OnViewChange (wxCommandEvent& event);
213
214 DECLARE_EVENT_TABLE()
215
216 private:
217
218 #if DO_REGTEST
219 RegTreeCtrl *m_treeCtrl;
220 #endif
221 };
222
223 // ----------------------------------------------------------------------------
224 // various ids
225 // ----------------------------------------------------------------------------
226
227 enum
228 {
229 Menu_Quit = 100,
230 Menu_About,
231 Menu_Test,
232 Menu_GoTo,
233 Menu_Expand,
234 Menu_Collapse,
235 Menu_Toggle,
236 Menu_Refresh,
237 Menu_New,
238 Menu_NewKey,
239 Menu_NewText,
240 Menu_NewBinary,
241 Menu_Delete,
242 Menu_Info,
243 Menu_View,
244 Menu_ViewDefault,
245 Menu_View32,
246 Menu_View64,
247
248 Ctrl_RegTree = 200
249 };
250
251 // ----------------------------------------------------------------------------
252 // event tables
253 // ----------------------------------------------------------------------------
254
255 BEGIN_EVENT_TABLE(RegFrame, wxFrame)
256 EVT_MENU(Menu_Test, RegFrame::OnTest)
257 EVT_MENU(Menu_About, RegFrame::OnAbout)
258 EVT_MENU(Menu_Quit, RegFrame::OnQuit)
259 EVT_MENU(Menu_GoTo, RegFrame::OnGoTo)
260 EVT_MENU(Menu_Expand, RegFrame::OnExpand)
261 EVT_MENU(Menu_Collapse, RegFrame::OnCollapse)
262 EVT_MENU(Menu_Toggle, RegFrame::OnToggle)
263 EVT_MENU(Menu_Refresh, RegFrame::OnRefresh)
264 EVT_MENU(Menu_Delete, RegFrame::OnDelete)
265 EVT_MENU(Menu_NewKey, RegFrame::OnNewKey)
266 EVT_MENU(Menu_NewText, RegFrame::OnNewText)
267 EVT_MENU(Menu_NewBinary, RegFrame::OnNewBinary)
268 EVT_MENU(Menu_Info, RegFrame::OnInfo)
269 EVT_MENU(Menu_ViewDefault, RegFrame::OnViewChange)
270 EVT_MENU(Menu_View32, RegFrame::OnViewChange)
271 EVT_MENU(Menu_View64, RegFrame::OnViewChange)
272 END_EVENT_TABLE()
273
274 #if DO_REGTEST
275
276 BEGIN_EVENT_TABLE(RegTreeCtrl, wxTreeCtrl)
277 EVT_TREE_DELETE_ITEM (Ctrl_RegTree, RegTreeCtrl::OnDeleteItem)
278 EVT_TREE_ITEM_EXPANDING (Ctrl_RegTree, RegTreeCtrl::OnItemExpanding)
279 EVT_TREE_ITEM_COLLAPSING(Ctrl_RegTree, RegTreeCtrl::OnItemExpanding)
280 EVT_TREE_SEL_CHANGED (Ctrl_RegTree, RegTreeCtrl::OnSelChanged)
281
282 EVT_TREE_BEGIN_LABEL_EDIT(Ctrl_RegTree, RegTreeCtrl::OnBeginEdit)
283 EVT_TREE_END_LABEL_EDIT (Ctrl_RegTree, RegTreeCtrl::OnEndEdit)
284
285 EVT_TREE_BEGIN_DRAG (Ctrl_RegTree, RegTreeCtrl::OnBeginDrag)
286 EVT_TREE_BEGIN_RDRAG (Ctrl_RegTree, RegTreeCtrl::OnBeginDrag)
287 EVT_TREE_END_DRAG (Ctrl_RegTree, RegTreeCtrl::OnEndDrag)
288
289 EVT_CHAR (RegTreeCtrl::OnChar)
290 EVT_RIGHT_DOWN(RegTreeCtrl::OnRightClick)
291 EVT_IDLE (RegTreeCtrl::OnIdle)
292 END_EVENT_TABLE()
293
294 #endif
295
296 // ============================================================================
297 // implementation
298 // ============================================================================
299
300 // ----------------------------------------------------------------------------
301 // global functions
302 // ----------------------------------------------------------------------------
303
304 // create the "registry operations" menu
305 wxMenu *CreateRegistryMenu()
306 {
307 wxMenu *pMenuNew = new wxMenu;
308 pMenuNew->Append(Menu_NewKey, wxT("&Key"), wxT("Create a new key"));
309 pMenuNew->AppendSeparator();
310 pMenuNew->Append(Menu_NewText, wxT("&Text value"), wxT("Create a new text value"));
311 pMenuNew->Append(Menu_NewBinary, wxT("&Binary value"), wxT("Create a new binary value"));
312
313 wxMenu *pMenuView = new wxMenu;
314 pMenuView->AppendRadioItem(
315 Menu_ViewDefault,
316 wxT("&Default"),
317 wxT("Default registry view for the program environment."));
318 pMenuView->AppendRadioItem(
319 Menu_View32,
320 wxT("32-bit Registry"),
321 wxT("View 32-bit registry."));
322 pMenuView->AppendRadioItem(
323 Menu_View64,
324 wxT("64-bit Registry"),
325 wxT("View 64-bit registry."));
326
327 wxMenu *pMenuReg = new wxMenu;
328 pMenuReg->Append(Menu_New, wxT("&New"), pMenuNew);
329 pMenuReg->Append(Menu_Delete, wxT("&Delete..."), wxT("Delete selected key/value"));
330 pMenuReg->AppendSeparator();
331 pMenuReg->Append(Menu_GoTo, wxT("&Go to...\tCtrl-G"), wxT("Go to registry key"));
332 pMenuReg->Append(Menu_Expand, wxT("&Expand"), wxT("Expand current key"));
333 pMenuReg->Append(Menu_Collapse, wxT("&Collapse"), wxT("Collapse current key"));
334 pMenuReg->Append(Menu_Toggle, wxT("&Toggle"), wxT("Toggle current key"));
335 pMenuReg->AppendSeparator();
336 pMenuReg->Append(Menu_Refresh, wxT("&Refresh"), wxT("Refresh the subtree"));
337 pMenuReg->Append(Menu_View, wxT("&View"), pMenuView);
338 pMenuReg->AppendSeparator();
339 pMenuReg->Append(Menu_Info, wxT("&Properties"),wxT("Information about current selection"));
340
341 return pMenuReg;
342 }
343
344 // ----------------------------------------------------------------------------
345 // application class
346 // ----------------------------------------------------------------------------
347 IMPLEMENT_APP(RegApp)
348
349 // `Main program' equivalent, creating windows and returning main app frame
350 bool RegApp::OnInit()
351 {
352 if ( !wxApp::OnInit() )
353 return false;
354
355 // create the main frame window and show it
356 RegFrame *frame = new RegFrame(NULL, wxT("wxRegTest"), 50, 50, 600, 350);
357 frame->Show(true);
358
359 return true;
360 }
361
362 // ----------------------------------------------------------------------------
363 // RegFrame
364 // ----------------------------------------------------------------------------
365
366 RegFrame::RegFrame(wxFrame *parent, const wxChar *title, int x, int y, int w, int h)
367 : wxFrame(parent, wxID_ANY, title, wxPoint(x, y), wxSize(w, h))
368 {
369 // this reduces flicker effects
370 SetBackgroundColour(wxColour(255, 255, 255));
371
372 // set the icon
373 // ------------
374 SetIcon(wxIcon(wxT("app_icon")));
375
376 // create menu
377 // -----------
378 wxMenu *pMenuFile = new wxMenu;
379 pMenuFile->Append(Menu_Test, wxT("Te&st"), wxT("Test key creation"));
380 pMenuFile->AppendSeparator();
381 pMenuFile->Append(Menu_About, wxT("&About..."), wxT("Show an extraordinarly beautiful dialog"));
382 pMenuFile->AppendSeparator();
383 pMenuFile->Append(Menu_Quit, wxT("E&xit"), wxT("Quit this program"));
384
385 wxMenuBar *pMenu = new wxMenuBar;
386 pMenu->Append(pMenuFile, wxT("&File"));
387 pMenu->Append(CreateRegistryMenu(), wxT("&Registry"));
388 SetMenuBar(pMenu);
389
390 #if DO_REGTEST
391 // create child controls
392 // ---------------------
393 m_treeCtrl = new RegTreeCtrl(this, Ctrl_RegTree);
394 #endif
395
396 #if wxUSE_STATUSBAR
397 // create the status line
398 // ----------------------
399 CreateStatusBar(2);
400 #endif // wxUSE_STATUSBAR
401 }
402
403 RegFrame::~RegFrame()
404 {
405 #if DO_REGTEST
406 // this makes deletion of it *much* quicker
407 m_treeCtrl->Hide();
408 #endif
409 }
410
411 void RegFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
412 {
413 Close(true);
414 }
415
416 void RegFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
417 {
418 wxMessageDialog dialog(this,
419 wxT("wxRegistry sample\n")
420 wxT("(c) 1998, 2000 Vadim Zeitlin"),
421 wxT("About wxRegTest"), wxOK);
422
423 dialog.ShowModal();
424 }
425
426 void RegFrame::OnTest(wxCommandEvent& WXUNUSED(event))
427 {
428 #if DO_REGTEST
429 m_treeCtrl->OnMenuTest();
430 #endif
431 }
432
433 void RegFrame::OnGoTo(wxCommandEvent& WXUNUSED(event))
434 {
435 static wxString s_location = wxT("HKEY_CURRENT_USER\\Software\\wxWidgets");
436
437 wxString location = wxGetTextFromUser(
438 wxT("Enter the location to go to:"),
439 wxT("wxRegTest question"),
440 s_location,
441 this);
442
443 if ( !location )
444 return;
445
446 s_location = location;
447 #if DO_REGTEST
448 m_treeCtrl->GoTo(location);
449 #endif
450 }
451
452 void RegFrame::OnExpand(wxCommandEvent& WXUNUSED(event))
453 {
454 #if DO_REGTEST
455 m_treeCtrl->Expand(m_treeCtrl->GetSelection());
456 #endif
457 }
458
459 void RegFrame::OnCollapse(wxCommandEvent& WXUNUSED(event))
460 {
461 #if DO_REGTEST
462 m_treeCtrl->Collapse(m_treeCtrl->GetSelection());
463 #endif
464 }
465
466 void RegFrame::OnToggle(wxCommandEvent& WXUNUSED(event))
467 {
468 #if DO_REGTEST
469 m_treeCtrl->Toggle(m_treeCtrl->GetSelection());
470 #endif
471 }
472
473 void RegFrame::OnRefresh(wxCommandEvent& WXUNUSED(event))
474 {
475 #if DO_REGTEST
476 m_treeCtrl->DoRefresh();
477 #endif
478 }
479
480 void RegFrame::OnDelete(wxCommandEvent& WXUNUSED(event))
481 {
482 #if DO_REGTEST
483 m_treeCtrl->DeleteSelected();
484 #endif
485 }
486
487 void RegFrame::OnNewKey(wxCommandEvent& WXUNUSED(event))
488 {
489 #if DO_REGTEST
490 if ( m_treeCtrl->IsKeySelected() )
491 {
492 m_treeCtrl->CreateNewKey(
493 wxGetTextFromUser(wxT("Enter the name of the new key")));
494 }
495 #endif
496 }
497
498 void RegFrame::OnNewText(wxCommandEvent& WXUNUSED(event))
499 {
500 #if DO_REGTEST
501 if ( m_treeCtrl->IsKeySelected() )
502 {
503 m_treeCtrl->CreateNewTextValue(
504 wxGetTextFromUser(wxT("Enter the name for the new text value")));
505 }
506 #endif
507 }
508
509 void RegFrame::OnNewBinary(wxCommandEvent& WXUNUSED(event))
510 {
511 #if DO_REGTEST
512 if ( m_treeCtrl->IsKeySelected() )
513 {
514 m_treeCtrl->CreateNewBinaryValue(
515 wxGetTextFromUser(wxT("Enter the name for the new binary value")));
516 }
517 #endif
518 }
519
520 void RegFrame::OnInfo(wxCommandEvent& WXUNUSED(event))
521 {
522 #if DO_REGTEST
523 m_treeCtrl->ShowProperties();
524 #endif
525 }
526
527 void RegFrame::OnViewChange(wxCommandEvent& event)
528 {
529 #if DO_REGTEST
530 wxRegKey::WOW64ViewMode view;
531 switch ( event.GetId() )
532 {
533 case Menu_ViewDefault:
534 view = wxRegKey::WOW64ViewMode_Default;
535 break;
536
537 case Menu_View32:
538 view = wxRegKey::WOW64ViewMode_32;
539 break;
540
541 case Menu_View64:
542 view = wxRegKey::WOW64ViewMode_64;
543 break;
544
545 default:
546 wxFAIL_MSG("Unexpected event source for view change.");
547 return;
548 }
549
550 m_treeCtrl->SetRegistryView(view);
551 #endif
552 }
553
554 // ----------------------------------------------------------------------------
555 // RegImageList
556 // ----------------------------------------------------------------------------
557 RegImageList::RegImageList() : wxImageList(16, 16, true)
558 {
559 // should be in sync with enum RegImageList::RegIcon
560 static const wxChar *aszIcons[] = { wxT("key1"),wxT("key2"),wxT("key3"),wxT("value1"),wxT("value2") };
561 wxString str = wxT("icon_");
562 for ( unsigned int n = 0; n < WXSIZEOF(aszIcons); n++ )
563 {
564 Add(wxIcon(str + aszIcons[n], wxBITMAP_TYPE_ICO_RESOURCE));
565 }
566 }
567
568 #if DO_REGTEST
569
570 // ----------------------------------------------------------------------------
571 // RegTreeCtrl
572 // ----------------------------------------------------------------------------
573
574 // create a new tree item and insert it into the tree
575 RegTreeCtrl::TreeNode *RegTreeCtrl::InsertNewTreeNode(
576 TreeNode *pParent,
577 const wxString& strName,
578 int idImage,
579 const wxString *pstrValue,
580 wxRegKey::WOW64ViewMode viewMode)
581 {
582 // create new item & insert it
583 TreeNode *pNewNode = new TreeNode;
584 pNewNode->m_pTree = this;
585 pNewNode->m_pParent = pParent;
586 pNewNode->m_strName = strName;
587 pNewNode->m_bKey = pstrValue == NULL;
588 pNewNode->m_pKey = NULL;
589 pNewNode->m_viewMode = viewMode;
590 if (pParent)
591 {
592 pNewNode->m_id = AppendItem(pParent->Id(),
593 pNewNode->IsKey() ? strName : *pstrValue,
594 idImage);
595 }
596 else
597 {
598 pNewNode->m_id = AddRoot(strName);
599 }
600
601 wxASSERT_MSG( pNewNode->m_id, wxT("can't create tree control item!"));
602
603 // save the pointer in the item
604 SetItemData(pNewNode->m_id, pNewNode);
605
606 // add it to the list of parent's children
607 if ( pParent != NULL )
608 {
609 pParent->m_aChildren.Add(pNewNode);
610 }
611
612 if ( pNewNode->IsKey() )
613 {
614 SetItemHasChildren(pNewNode->Id());
615
616 if ( !pNewNode->IsRoot() )
617 {
618 // set the expanded icon as well
619 SetItemImage(pNewNode->Id(),
620 RegImageList::OpenedKey,
621 wxTreeItemIcon_Expanded);
622 }
623 }
624
625 return pNewNode;
626 }
627
628 RegTreeCtrl::RegTreeCtrl(wxWindow *parent, wxWindowID id)
629 : wxTreeCtrl(parent, id, wxDefaultPosition, wxDefaultSize,
630 wxTR_HAS_BUTTONS | wxTR_EDIT_LABELS | wxSUNKEN_BORDER)
631 {
632 // init members
633 m_draggedItem = NULL;
634 m_restoreStatus = false;
635 m_viewMode = wxRegKey::WOW64ViewMode_Default;
636
637 // create the image list
638 // ---------------------
639 m_imageList = new RegImageList;
640 SetImageList(m_imageList);
641
642 // create root keys
643 // ----------------
644 m_pRoot =
645 InsertNewTreeNode(
646 NULL,
647 wxT("Registry Root"),
648 RegImageList::Root,
649 NULL,
650 m_viewMode);
651
652 // create popup menu
653 // -----------------
654 m_pMenuPopup = CreateRegistryMenu();
655 }
656
657 RegTreeCtrl::~RegTreeCtrl()
658 {
659 delete m_pMenuPopup;
660 // delete m_pRoot; -- this is done by the tree now
661 delete m_imageList;
662 }
663
664 void RegTreeCtrl::AddStdKeys()
665 {
666 for ( unsigned int ui = 0; ui < wxRegKey::nStdKeys; ui++ )
667 {
668 InsertNewTreeNode(
669 m_pRoot,
670 wxRegKey::GetStdKeyName(ui),
671 RegImageList::ClosedKey,
672 NULL,
673 m_viewMode);
674 }
675 }
676
677 // ----------------------------------------------------------------------------
678 // notifications
679 // ----------------------------------------------------------------------------
680
681 void RegTreeCtrl::OnIdle(wxIdleEvent& WXUNUSED(event))
682 {
683 if ( m_restoreStatus )
684 {
685 // restore it after OnItemExpanding()
686 wxLogStatus(wxT("Ok"));
687 wxSetCursor(*wxSTANDARD_CURSOR);
688
689 m_restoreStatus = false;
690 }
691 }
692
693 void RegTreeCtrl::OnRightClick(wxMouseEvent& event)
694 {
695 int iFlags;
696 wxTreeItemId lId = HitTest(wxPoint(event.GetX(), event.GetY()), iFlags);
697 if ( iFlags & wxTREE_HITTEST_ONITEMLABEL )
698 {
699 // select the item first
700 SelectItem(lId);
701 }
702 //else: take the currently selected item if click not on item
703
704 PopupMenu(m_pMenuPopup, event.GetX(), event.GetY());
705 }
706
707
708 void RegTreeCtrl::OnDeleteItem(wxTreeEvent& WXUNUSED(event))
709 {
710 }
711
712 // test the key creation functions
713 void RegTreeCtrl::OnMenuTest()
714 {
715 wxTreeItemId lId = GetSelection();
716 TreeNode *pNode = (TreeNode *)GetItemData(lId);
717
718 wxCHECK_RET( pNode != NULL, wxT("tree item without data?") );
719
720 if ( pNode->IsRoot() )
721 {
722 wxLogError(wxT("Can't create a subkey under the root key."));
723 return;
724 }
725
726 if ( !pNode->IsKey() )
727 {
728 wxLogError(wxT("Can't create a subkey under a value!"));
729 return;
730 }
731
732 wxRegKey key1(pNode->Key(), wxT("key1"));
733 if ( key1.Create() )
734 {
735 wxRegKey key2a(key1, wxT("key2a")), key2b(key1, wxT("key2b"));
736 if ( key2a.Create() && key2b.Create() )
737 {
738 // put some values under the newly created keys
739 key1.SetValue(wxT("first_term"), wxT("10"));
740 key1.SetValue(wxT("second_term"), wxT("7"));
741 key2a = wxT("this is the unnamed value");
742 key2b.SetValue(wxT("sum"), 17);
743
744 // refresh tree
745 pNode->Refresh();
746 wxLogStatus(wxT("Test keys successfully added."));
747 return;
748 }
749 }
750
751 wxLogError(wxT("Creation of test keys failed."));
752 }
753
754 void RegTreeCtrl::OnChar(wxKeyEvent& event)
755 {
756 switch ( event.GetKeyCode() )
757 {
758 case WXK_DELETE:
759 DeleteSelected();
760 return;
761
762 case WXK_RETURN:
763 if ( event.AltDown() )
764 {
765 ShowProperties();
766
767 return;
768 }
769 }
770
771 event.Skip();
772 }
773
774 void RegTreeCtrl::OnSelChanged(wxTreeEvent& event)
775 {
776 #if wxUSE_STATUSBAR
777 wxFrame *pFrame = (wxFrame *) wxWindow::GetParent();
778 pFrame->SetStatusText(GetNode(event)->FullName(), 1);
779 #else
780 wxUnusedVar(event);
781 #endif // wxUSE_STATUSBAR
782 }
783
784 void RegTreeCtrl::OnItemExpanding(wxTreeEvent& event)
785 {
786 TreeNode *pNode = GetNode(event);
787 bool bExpanding = event.GetEventType() == wxEVT_COMMAND_TREE_ITEM_EXPANDING;
788
789 // expansion might take some time
790 wxSetCursor(*wxHOURGLASS_CURSOR);
791 wxLogStatus(wxT("Working..."));
792 wxYield(); // to give the status line a chance to refresh itself
793 m_restoreStatus = true; // some time later...
794
795 if ( pNode->IsKey() )
796 {
797 if ( bExpanding )
798 {
799 // expanding: add subkeys/values
800 if ( !pNode->OnExpand() )
801 return;
802 }
803 else
804 {
805 // collapsing: clean up
806 pNode->OnCollapse();
807 }
808 }
809 }
810
811 void RegTreeCtrl::OnBeginEdit(wxTreeEvent& event)
812 {
813 TreeNode *pNode = GetNode(event);
814 if ( pNode->IsRoot() || pNode->Parent()->IsRoot() )
815 {
816 wxLogStatus(wxT("This registry key can't be renamed."));
817
818 event.Veto();
819 }
820 else
821 {
822 m_nameOld = pNode->m_strName;
823 }
824 }
825
826 void RegTreeCtrl::OnEndEdit(wxTreeEvent& event)
827 {
828 bool ok;
829
830 wxString name = event.GetLabel();
831
832 TreeNode *pNode = GetNode(event);
833 if ( pNode->IsKey() )
834 {
835 wxRegKey& key = pNode->Key();
836 ok = key.Rename(name);
837 }
838 else
839 {
840 pNode = pNode->Parent();
841 wxRegKey& key = pNode->Key();
842
843 ok = key.RenameValue(m_nameOld, name);
844 }
845
846 if ( !ok )
847 {
848 wxLogError(wxT("Failed to rename '%s' to '%s'."),
849 m_nameOld.c_str(), name.c_str());
850 }
851 #if 0 // MSW tree ctrl doesn't like this at all, it hangs
852 else
853 {
854 pNode->Refresh();
855 }
856 #endif // 0
857 }
858
859 void RegTreeCtrl::OnBeginDrag(wxTreeEvent& event)
860 {
861 m_copyOnDrop = event.GetEventType() == wxEVT_COMMAND_TREE_BEGIN_DRAG;
862
863 TreeNode *pNode = GetNode(event);
864 if ( pNode->IsRoot() || pNode->Parent()->IsRoot() )
865 {
866 wxLogStatus(wxT("This registry key can't be %s."),
867 m_copyOnDrop ? wxT("copied") : wxT("moved"));
868 }
869 else
870 {
871 wxLogStatus(wxT("%s item %s..."),
872 m_copyOnDrop ? wxT("Copying") : wxT("Moving"),
873 pNode->FullName());
874
875 m_draggedItem = pNode;
876
877 event.Allow();
878 }
879 }
880
881 void RegTreeCtrl::OnEndDrag(wxTreeEvent& event)
882 {
883 wxCHECK_RET( m_draggedItem, wxT("end drag without begin drag?") );
884
885 // clear the pointer anyhow
886 TreeNode *src = m_draggedItem;
887 m_draggedItem = NULL;
888
889 // where are we going to drop it?
890 TreeNode *dst = GetNode(event);
891 if ( dst && !dst->IsKey() )
892 {
893 // we need a parent key
894 dst = dst->Parent();
895 }
896
897 if ( !dst || dst->IsRoot() )
898 {
899 wxLogError(wxT("Can't create a key here."));
900
901 return;
902 }
903
904 bool isKey = src->IsKey();
905 if ( (isKey && (src == dst)) ||
906 (!isKey && (dst->Parent() == src)) ) {
907 wxLogStatus(wxT("Can't copy something on itself"));
908
909 return;
910 }
911
912 // remove the "Registry Root\\" from the full name
913 wxString nameSrc, nameDst;
914 nameSrc << wxString(src->FullName()).AfterFirst('\\');
915 nameDst << wxString(dst->FullName()).AfterFirst('\\') << '\\'
916 << wxString(src->FullName()).AfterLast('\\');
917
918 wxString verb = m_copyOnDrop ? wxT("copy") : wxT("move");
919 wxString what = isKey ? wxT("key") : wxT("value");
920
921 if ( wxMessageBox(wxString::Format
922 (
923 wxT("Do you really want to %s the %s %s to %s?"),
924 verb.c_str(),
925 what.c_str(),
926 nameSrc.c_str(),
927 nameDst.c_str()
928 ),
929 wxT("RegTest Confirm"),
930 wxICON_QUESTION | wxYES_NO | wxCANCEL, this) != wxYES ) {
931 return;
932 }
933
934 bool ok;
935 if ( isKey )
936 {
937 wxRegKey& key = src->Key();
938 wxRegKey keyDst(dst->Key(), src->m_strName);
939 ok = keyDst.Create(false);
940 if ( !ok )
941 {
942 wxLogError(wxT("Key '%s' already exists"), keyDst.GetName().c_str());
943 }
944 else
945 {
946 ok = key.Copy(keyDst);
947 }
948
949 if ( ok && !m_copyOnDrop )
950 {
951 // delete the old key
952 ok = key.DeleteSelf();
953 if ( ok )
954 {
955 src->Parent()->Refresh();
956 }
957 }
958 }
959 else // value
960 {
961 wxRegKey& key = src->Parent()->Key();
962 ok = key.CopyValue(src->m_strName, dst->Key());
963 if ( ok && !m_copyOnDrop )
964 {
965 // we moved it, so delete the old one
966 ok = key.DeleteValue(src->m_strName);
967 }
968 }
969
970 if ( !ok )
971 {
972 wxLogError(wxT("Failed to %s registry %s."),
973 verb.c_str(), what.c_str());
974 }
975 else
976 {
977 dst->Refresh();
978 }
979 }
980
981 // ----------------------------------------------------------------------------
982 // TreeNode implementation
983 // ----------------------------------------------------------------------------
984 bool RegTreeCtrl::TreeNode::OnExpand()
985 {
986 // we add children only once
987 if ( !m_aChildren.IsEmpty() )
988 {
989 // we've been already expanded
990 return true;
991 }
992
993 if ( IsRoot() )
994 {
995 // we're the root key
996 m_pTree->AddStdKeys();
997 return true;
998 }
999
1000 if ( Parent()->IsRoot() )
1001 {
1002 // we're a standard key
1003 m_pKey = new wxRegKey(m_strName, m_viewMode);
1004 }
1005 else
1006 {
1007 // we're a normal key
1008 m_pKey = new wxRegKey(*(Parent()->m_pKey), m_strName);
1009 }
1010
1011 if ( !m_pKey->Open() )
1012 {
1013 wxLogError(wxT("The key '%s' can't be opened."), FullName());
1014 return false;
1015 }
1016
1017 // if we're empty, we shouldn't be expandable at all
1018 bool isEmpty = true;
1019
1020 // enumeration variables
1021 long l;
1022 wxString str;
1023 bool bCont;
1024
1025 // enumerate all subkeys
1026 bCont = m_pKey->GetFirstKey(str, l);
1027 while ( bCont )
1028 {
1029 m_pTree->InsertNewTreeNode(
1030 this,
1031 str,
1032 RegImageList::ClosedKey,
1033 NULL,
1034 m_viewMode);
1035 bCont = m_pKey->GetNextKey(str, l);
1036
1037 // we have at least this key...
1038 isEmpty = false;
1039 }
1040
1041 // enumerate all values
1042 bCont = m_pKey->GetFirstValue(str, l);
1043 while ( bCont )
1044 {
1045 wxString strItem;
1046 if (str.empty())
1047 strItem = wxT("<default>");
1048 else
1049 strItem = str;
1050 strItem += wxT(" = ");
1051
1052 // determine the appropriate icon
1053 RegImageList::Icon icon;
1054 switch ( m_pKey->GetValueType(str) )
1055 {
1056 case wxRegKey::Type_String:
1057 case wxRegKey::Type_Expand_String:
1058 case wxRegKey::Type_Multi_String:
1059 {
1060 wxString strValue;
1061 icon = RegImageList::TextValue;
1062 m_pKey->QueryValue(str, strValue);
1063 strItem += strValue;
1064 }
1065 break;
1066
1067 case wxRegKey::Type_None:
1068 // @@ handle the error...
1069 icon = RegImageList::BinaryValue;
1070 break;
1071
1072 case wxRegKey::Type_Dword:
1073 {
1074 long l;
1075 m_pKey->QueryValue(str, &l);
1076 strItem << l;
1077 }
1078
1079 // fall through
1080
1081 default:
1082 icon = RegImageList::BinaryValue;
1083 }
1084
1085 m_pTree->InsertNewTreeNode(this, str, icon, &strItem, m_viewMode);
1086 bCont = m_pKey->GetNextValue(str, l);
1087
1088 // we have at least this value...
1089 isEmpty = false;
1090 }
1091
1092 if ( isEmpty )
1093 {
1094 // this is for the case when our last child was just deleted
1095 wxTreeItemId theId(Id()); // Temp variable seems necessary for BC++
1096 m_pTree->Collapse(theId);
1097
1098 // we won't be expanded any more
1099 m_pTree->SetItemHasChildren(theId, false);
1100 }
1101
1102 return true;
1103 }
1104
1105 void RegTreeCtrl::TreeNode::OnCollapse()
1106 {
1107 DestroyChildren();
1108
1109 wxDELETE(m_pKey);
1110 }
1111
1112 void RegTreeCtrl::TreeNode::Refresh()
1113 {
1114 if ( !IsKey() )
1115 return;
1116
1117 wxTreeItemId theId(Id()); // Temp variable seems necessary for BC++
1118 bool wasExpanded = m_pTree->IsExpanded(theId);
1119 if ( wasExpanded )
1120 m_pTree->Collapse(theId);
1121
1122 OnCollapse();
1123 m_pTree->SetItemHasChildren(theId);
1124 if ( wasExpanded )
1125 {
1126 m_pTree->Expand(theId);
1127 OnExpand();
1128 }
1129 }
1130
1131 bool RegTreeCtrl::TreeNode::DeleteChild(TreeNode *child)
1132 {
1133 int index = m_aChildren.Index(child);
1134 wxCHECK_MSG( index != wxNOT_FOUND, false,
1135 wxT("our child in tree should be in m_aChildren") );
1136
1137 m_aChildren.RemoveAt((size_t)index);
1138
1139 bool ok;
1140 if ( child->IsKey() )
1141 {
1142 // must close key before deleting it
1143 child->OnCollapse();
1144
1145 ok = Key().DeleteKey(child->m_strName);
1146 }
1147 else
1148 {
1149 ok = Key().DeleteValue(child->m_strName);
1150 }
1151
1152 if ( ok )
1153 {
1154 wxTreeItemId theId(child->Id()); // Temp variable seems necessary for BC++
1155 m_pTree->Delete(theId);
1156
1157 Refresh();
1158 }
1159
1160 return ok;
1161 }
1162
1163 void RegTreeCtrl::TreeNode::DestroyChildren()
1164 {
1165 // destroy all children
1166 size_t nCount = m_aChildren.GetCount();
1167 for ( size_t n = 0; n < nCount; n++ )
1168 {
1169 wxTreeItemId lId = m_aChildren[n]->Id();
1170 m_pTree->Delete(lId);
1171 }
1172
1173 m_aChildren.Empty();
1174 }
1175
1176 RegTreeCtrl::TreeNode::~TreeNode()
1177 {
1178 delete m_pKey;
1179 }
1180
1181 const wxChar *RegTreeCtrl::TreeNode::FullName() const
1182 {
1183 static wxString s_strName;
1184
1185 if ( IsRoot() )
1186 {
1187 return wxT("Registry Root");
1188 }
1189 else
1190 {
1191 // our own registry key might not (yet) exist or we might be a value,
1192 // so just use the parent's and concatenate
1193 s_strName = Parent()->FullName();
1194 s_strName << wxT('\\') << m_strName;
1195
1196 return s_strName;
1197 }
1198 }
1199
1200 void RegTreeCtrl::TreeNode::SetRegistryView(wxRegKey::WOW64ViewMode viewMode)
1201 {
1202 m_viewMode = viewMode;
1203
1204 // Update children with new view.
1205 size_t nCount = m_aChildren.GetCount();
1206 for (size_t n = 0; n < nCount; n++)
1207 m_aChildren[n]->SetRegistryView(viewMode);
1208 }
1209
1210 // ----------------------------------------------------------------------------
1211 // operations on RegTreeCtrl
1212 // ----------------------------------------------------------------------------
1213
1214 void RegTreeCtrl::GoTo(const wxString& location)
1215 {
1216 wxStringTokenizer tk(location, wxT("\\"));
1217
1218 wxTreeItemId id = GetRootItem();
1219
1220 while ( tk.HasMoreTokens() )
1221 {
1222 wxString subkey = tk.GetNextToken();
1223
1224 wxTreeItemId idCurrent = id;
1225 if ( !IsExpanded(idCurrent) )
1226 Expand(idCurrent);
1227
1228 wxTreeItemIdValue dummy;
1229 id = GetFirstChild(idCurrent, dummy);
1230
1231 if ( idCurrent == GetRootItem() )
1232 {
1233 // special case: we understand both HKCU and HKEY_CURRENT_USER here
1234 for ( size_t key = 0; key < wxRegKey::nStdKeys; key++ )
1235 {
1236 if ( subkey == wxRegKey::GetStdKeyName(key)
1237 || subkey == wxRegKey::GetStdKeyShortName(key) )
1238 {
1239 break;
1240 }
1241
1242 id = GetNextChild(idCurrent, dummy);
1243 }
1244 }
1245 else
1246 {
1247 // enum all children
1248 while ( id.IsOk() )
1249 {
1250 if ( subkey == ((TreeNode *)GetItemData(id))->m_strName )
1251 break;
1252
1253 id = GetNextChild(idCurrent, dummy);
1254 }
1255 }
1256
1257 if ( !id.IsOk() )
1258 {
1259 wxLogError(wxT("No such key '%s'."), location.c_str());
1260
1261 return;
1262 }
1263 }
1264
1265 if ( id.IsOk() )
1266 SelectItem(id);
1267 }
1268
1269 void RegTreeCtrl::DeleteSelected()
1270 {
1271 wxTreeItemId lCurrent = GetSelection(),
1272 lParent = GetItemParent(lCurrent);
1273
1274 if ( lParent == GetRootItem() )
1275 {
1276 wxLogError(wxT("Can't delete root key."));
1277 return;
1278 }
1279
1280 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent),
1281 *pParent = (TreeNode *)GetItemData(lParent);
1282
1283 wxCHECK_RET(pCurrent && pParent, wxT("either node or parent without data?"));
1284
1285 if ( pParent->IsRoot() )
1286 {
1287 wxLogError(wxT("Can't delete standard key."));
1288 return;
1289 }
1290
1291 wxString what = pCurrent->IsKey() ? wxT("key") : wxT("value");
1292 if ( wxMessageBox(wxString::Format
1293 (
1294 wxT("Do you really want to delete this %s?"),
1295 what.c_str()
1296 ),
1297 wxT("Confirmation"),
1298 wxICON_QUESTION | wxYES_NO | wxCANCEL, this) != wxYES )
1299 {
1300 return;
1301 }
1302
1303 pParent->DeleteChild(pCurrent);
1304 }
1305
1306 void RegTreeCtrl::CreateNewKey(const wxString& strName)
1307 {
1308 wxTreeItemId lCurrent = GetSelection();
1309 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent);
1310
1311 wxCHECK_RET( pCurrent != NULL, wxT("node without data?") );
1312
1313 wxASSERT( pCurrent->IsKey() ); // check must have been done before
1314
1315 if ( pCurrent->IsRoot() )
1316 {
1317 wxLogError(wxT("Can't create a new key under the root key."));
1318 return;
1319 }
1320
1321 wxRegKey key(pCurrent->Key(), strName);
1322 if ( key.Create() )
1323 pCurrent->Refresh();
1324 }
1325
1326 void RegTreeCtrl::CreateNewTextValue(const wxString& strName)
1327 {
1328 wxTreeItemId lCurrent = GetSelection();
1329 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent);
1330
1331 wxCHECK_RET( pCurrent != NULL, wxT("node without data?") );
1332
1333 wxASSERT( pCurrent->IsKey() ); // check must have been done before
1334
1335 if ( pCurrent->IsRoot() )
1336 {
1337 wxLogError(wxT("Can't create a new value under the root key."));
1338 return;
1339 }
1340
1341 if ( pCurrent->Key().SetValue(strName, wxEmptyString) )
1342 pCurrent->Refresh();
1343 }
1344
1345 void RegTreeCtrl::CreateNewBinaryValue(const wxString& strName)
1346 {
1347 wxTreeItemId lCurrent = GetSelection();
1348 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent);
1349
1350 wxCHECK_RET( pCurrent != NULL, wxT("node without data?") );
1351
1352 wxASSERT( pCurrent->IsKey() ); // check must have been done before
1353
1354 if ( pCurrent->IsRoot() )
1355 {
1356 wxLogError(wxT("Can't create a new value under the root key."));
1357 return;
1358 }
1359
1360 if ( pCurrent->Key().SetValue(strName, 0) )
1361 pCurrent->Refresh();
1362 }
1363
1364 void RegTreeCtrl::SetRegistryView(wxRegKey::WOW64ViewMode viewMode)
1365 {
1366 m_viewMode = viewMode;
1367 m_pRoot->SetRegistryView(viewMode);
1368 m_pRoot->Refresh();
1369 }
1370
1371 void RegTreeCtrl::ShowProperties()
1372 {
1373 wxTreeItemId lCurrent = GetSelection();
1374 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent);
1375
1376 if ( !pCurrent || pCurrent->IsRoot() )
1377 {
1378 wxLogStatus(wxT("No properties"));
1379
1380 return;
1381 }
1382
1383 if ( pCurrent->IsKey() )
1384 {
1385 const wxRegKey& key = pCurrent->Key();
1386 size_t nSubKeys, nValues;
1387 if ( !key.GetKeyInfo(&nSubKeys, NULL, &nValues, NULL) )
1388 {
1389 wxLogError(wxT("Couldn't get key info"));
1390 }
1391 else
1392 {
1393 wxLogMessage(wxT("Key '%s' has %u subkeys and %u values."),
1394 key.GetName().c_str(), nSubKeys, nValues);
1395 }
1396 }
1397 else // it's a value
1398 {
1399 TreeNode *parent = pCurrent->Parent();
1400 wxCHECK_RET( parent, wxT("reg value without key?") );
1401
1402 const wxRegKey& key = parent->Key();
1403 const wxChar *value = pCurrent->m_strName.c_str();
1404 wxLogMessage(wxT("Value '%s' under the key '%s' is of type ")
1405 wxT("%d (%s)."),
1406 value,
1407 parent->m_strName.c_str(),
1408 key.GetValueType(value),
1409 key.IsNumericValue(value) ? wxT("numeric") : wxT("string"));
1410
1411 }
1412 }
1413
1414 bool RegTreeCtrl::IsKeySelected() const
1415 {
1416 wxTreeItemId lCurrent = GetSelection();
1417 TreeNode *pCurrent = (TreeNode *) GetItemData(lCurrent);
1418
1419 wxCHECK( pCurrent != NULL, false );
1420
1421 return pCurrent->IsKey();
1422 }
1423
1424 void RegTreeCtrl::DoRefresh()
1425 {
1426 wxTreeItemId lId = GetSelection();
1427 if ( !lId )
1428 return;
1429
1430 TreeNode *pNode = (TreeNode *) GetItemData(lId);
1431
1432 wxCHECK_RET( pNode != NULL, wxT("tree item without data?") );
1433
1434 pNode->Refresh();
1435 }
1436
1437 #endif