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