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