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