1. implemented wxRegKey::Copy() and CopyValue()
[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/log.h"
30 #include "wx/treectrl.h"
31 #include "wx/msw/registry.h"
32 #include "wx/msw/imaglist.h"
33
34 // ----------------------------------------------------------------------------
35 // application type
36 // ----------------------------------------------------------------------------
37 class RegApp : public wxApp
38 {
39 public:
40 bool OnInit();
41 };
42
43 // ----------------------------------------------------------------------------
44 // image list with registry icons
45 // ----------------------------------------------------------------------------
46 class RegImageList : public wxImageList
47 {
48 public:
49 enum Icon
50 {
51 Root,
52 ClosedKey,
53 OpenedKey,
54 TextValue,
55 BinaryValue,
56 };
57
58 RegImageList();
59 };
60
61 // ----------------------------------------------------------------------------
62 // our control
63 // ----------------------------------------------------------------------------
64 class RegTreeCtrl : public wxTreeCtrl
65 {
66 public:
67 // ctor & dtor
68 RegTreeCtrl(wxWindow *parent, wxWindowID id);
69 virtual ~RegTreeCtrl();
70
71 // notifications
72 void OnDeleteItem (wxTreeEvent& event);
73 void OnItemExpanding(wxTreeEvent& event);
74 void OnSelChanged (wxTreeEvent& event);
75
76 void OnBeginDrag (wxTreeEvent& event);
77 void OnEndDrag (wxTreeEvent& event);
78
79 void OnRightClick (wxMouseEvent& event);
80 void OnChar (wxKeyEvent& event);
81 void OnIdle (wxIdleEvent& event);
82
83 // forwarded notifications (by the frame)
84 void OnMenuTest();
85
86 // operations
87 void DeleteSelected();
88 void ShowProperties();
89 void CreateNewKey(const wxString& strName);
90 void CreateNewTextValue(const wxString& strName);
91 void CreateNewBinaryValue(const wxString& strName);
92
93 // information
94 bool IsKeySelected() const;
95
96 private:
97 // structure describing a registry key/value
98 class TreeNode : public wxTreeItemData
99 {
100 WX_DEFINE_ARRAY(TreeNode *, TreeChildren);
101 public:
102 RegTreeCtrl *m_pTree; // must be !NULL
103 TreeNode *m_pParent; // NULL only for the root node
104 long m_id; // the id of the tree control item
105 wxString m_strName; // name of the key/value
106 TreeChildren m_aChildren; // array of subkeys/values
107 bool m_bKey; // key or value?
108 wxRegKey *m_pKey; // only may be !NULL if m_bKey == true
109
110 // trivial accessors
111 long Id() const { return m_id; }
112 bool IsRoot() const { return m_pParent == NULL; }
113 bool IsKey() const { return m_bKey; }
114 TreeNode *Parent() const { return m_pParent; }
115
116 // notifications
117 bool OnExpand();
118 void OnCollapse();
119
120 // operations
121 void Refresh();
122 bool DeleteChild(TreeNode *child);
123 void DestroyChildren();
124 const char *FullName() const;
125
126 // get the associated key: make sure the pointer is !NULL
127 wxRegKey& Key() { if ( !m_pKey ) OnExpand(); return *m_pKey; }
128
129 // dtor deletes all children
130 ~TreeNode();
131 };
132
133 wxImageList *m_imageList;
134 wxMenu *m_pMenuPopup;
135
136 TreeNode *m_pRoot;
137
138 TreeNode *m_draggedItem; // the item being dragged
139 bool m_copyOnDrop; // if FALSE, then move
140
141 bool m_restoreStatus; // after OnItemExpanding()
142
143 TreeNode *GetNode(const wxTreeEvent& event)
144 { return (TreeNode *)GetItemData((WXHTREEITEM)event.GetItem()); }
145
146 public:
147 // create a new node and insert it to the tree
148 TreeNode *InsertNewTreeNode(TreeNode *pParent,
149 const wxString& strName,
150 int idImage = RegImageList::ClosedKey,
151 const wxString *pstrValue = NULL);
152 // add standard registry keys
153 void AddStdKeys();
154
155 private:
156 DECLARE_EVENT_TABLE();
157 };
158
159 // ----------------------------------------------------------------------------
160 // the main window of our application
161 // ----------------------------------------------------------------------------
162 class RegFrame : public wxFrame
163 {
164 public:
165 // ctor & dtor
166 RegFrame(wxFrame *parent, char *title, int x, int y, int w, int h);
167 virtual ~RegFrame();
168
169 // callbacks
170 void OnQuit (wxCommandEvent& event);
171 void OnAbout(wxCommandEvent& event);
172 void OnTest (wxCommandEvent& event);
173
174 void OnExpand (wxCommandEvent& event);
175 void OnCollapse(wxCommandEvent& event);
176 void OnToggle (wxCommandEvent& event);
177
178 void OnDelete (wxCommandEvent& event);
179 void OnNewKey (wxCommandEvent& event);
180 void OnNewText (wxCommandEvent& event);
181 void OnNewBinary(wxCommandEvent& event);
182
183 void OnInfo (wxCommandEvent& event);
184
185 DECLARE_EVENT_TABLE();
186
187 private:
188 RegTreeCtrl *m_treeCtrl;
189 };
190
191 // ----------------------------------------------------------------------------
192 // various ids
193 // ----------------------------------------------------------------------------
194
195 enum
196 {
197 Menu_Quit = 100,
198 Menu_About,
199 Menu_Test,
200 Menu_Expand,
201 Menu_Collapse,
202 Menu_Toggle,
203 Menu_New,
204 Menu_NewKey,
205 Menu_NewText,
206 Menu_NewBinary,
207 Menu_Delete,
208 Menu_Info,
209
210 Ctrl_RegTree = 200,
211 };
212
213 // ----------------------------------------------------------------------------
214 // event tables
215 // ----------------------------------------------------------------------------
216
217 BEGIN_EVENT_TABLE(RegFrame, wxFrame)
218 EVT_MENU(Menu_Test, RegFrame::OnTest)
219 EVT_MENU(Menu_About, RegFrame::OnAbout)
220 EVT_MENU(Menu_Quit, RegFrame::OnQuit)
221 EVT_MENU(Menu_Expand, RegFrame::OnExpand)
222 EVT_MENU(Menu_Collapse, RegFrame::OnCollapse)
223 EVT_MENU(Menu_Toggle, RegFrame::OnToggle)
224 EVT_MENU(Menu_Delete, RegFrame::OnDelete)
225 EVT_MENU(Menu_NewKey, RegFrame::OnNewKey)
226 EVT_MENU(Menu_NewText, RegFrame::OnNewText)
227 EVT_MENU(Menu_NewBinary,RegFrame::OnNewBinary)
228 EVT_MENU(Menu_Info, RegFrame::OnInfo)
229 END_EVENT_TABLE()
230
231 BEGIN_EVENT_TABLE(RegTreeCtrl, wxTreeCtrl)
232 EVT_TREE_DELETE_ITEM (Ctrl_RegTree, RegTreeCtrl::OnDeleteItem)
233 EVT_TREE_ITEM_EXPANDING(Ctrl_RegTree, RegTreeCtrl::OnItemExpanding)
234 EVT_TREE_SEL_CHANGED (Ctrl_RegTree, RegTreeCtrl::OnSelChanged)
235 EVT_TREE_BEGIN_DRAG (Ctrl_RegTree, RegTreeCtrl::OnBeginDrag)
236 EVT_TREE_BEGIN_RDRAG (Ctrl_RegTree, RegTreeCtrl::OnBeginDrag)
237 EVT_TREE_END_DRAG (Ctrl_RegTree, RegTreeCtrl::OnEndDrag)
238
239 EVT_CHAR (RegTreeCtrl::OnChar)
240 EVT_RIGHT_DOWN(RegTreeCtrl::OnRightClick)
241 EVT_IDLE (RegTreeCtrl::OnIdle)
242 END_EVENT_TABLE()
243
244 // ============================================================================
245 // implementation
246 // ============================================================================
247
248 // ----------------------------------------------------------------------------
249 // global functions
250 // ----------------------------------------------------------------------------
251
252 // create the "registry operations" menu
253 wxMenu *CreateRegistryMenu()
254 {
255 wxMenu *pMenuNew = new wxMenu;
256 pMenuNew->Append(Menu_NewKey, "&Key", "Create a new key");
257 pMenuNew->AppendSeparator();
258 pMenuNew->Append(Menu_NewText, "&Text value", "Create a new text value");
259 pMenuNew->Append(Menu_NewBinary, "&Binary value", "Create a new binary value");
260
261 wxMenu *pMenuReg = new wxMenu;
262 pMenuReg->Append(Menu_New, "&New", pMenuNew);
263 pMenuReg->Append(Menu_Delete, "&Delete...", "Delete selected key/value");
264 pMenuReg->AppendSeparator();
265 pMenuReg->Append(Menu_Expand, "&Expand", "Expand current key");
266 pMenuReg->Append(Menu_Collapse, "&Collapse", "Collapse current key");
267 pMenuReg->Append(Menu_Toggle, "&Toggle", "Toggle current key");
268 pMenuReg->AppendSeparator();
269 pMenuReg->Append(Menu_Info, "&Properties","Information about current selection");
270
271 return pMenuReg;
272 }
273
274 // ----------------------------------------------------------------------------
275 // application class
276 // ----------------------------------------------------------------------------
277 IMPLEMENT_APP(RegApp)
278
279 // `Main program' equivalent, creating windows and returning main app frame
280 bool RegApp::OnInit()
281 {
282 // create the main frame window and show it
283 RegFrame *frame = new RegFrame(NULL, "wxRegTest", 50, 50, 600, 350);
284 frame->Show(TRUE);
285
286 SetTopWindow(frame);
287
288 return TRUE;
289 }
290
291 // ----------------------------------------------------------------------------
292 // RegFrame
293 // ----------------------------------------------------------------------------
294
295 RegFrame::RegFrame(wxFrame *parent, char *title, int x, int y, int w, int h)
296 : wxFrame(parent, -1, title, wxPoint(x, y), wxSize(w, h))
297 {
298 // this reduces flicker effects
299 SetBackgroundColour(wxColour(255, 255, 255));
300
301 // set the icon
302 // ------------
303 SetIcon(wxIcon("app_icon"));
304
305 // create menu
306 // -----------
307 wxMenu *pMenuFile = new wxMenu;
308 pMenuFile->Append(Menu_Test, "Te&st", "Test key creation");
309 pMenuFile->AppendSeparator();
310 pMenuFile->Append(Menu_About, "&About...", "Show an extraordinarly beautiful dialog");
311 pMenuFile->AppendSeparator();
312 pMenuFile->Append(Menu_Quit, "E&xit", "Quit this program");
313
314 wxMenuBar *pMenu = new wxMenuBar;
315 pMenu->Append(pMenuFile, "&File");
316 pMenu->Append(CreateRegistryMenu(), "&Registry");
317 SetMenuBar(pMenu);
318
319 // create child controls
320 // ---------------------
321 m_treeCtrl = new RegTreeCtrl(this, Ctrl_RegTree);
322
323 // create the status line
324 // ----------------------
325 int aWidths[2];
326 aWidths[0] = 200;
327 aWidths[1] = -1;
328 CreateStatusBar(2);
329 SetStatusWidths(2, aWidths);
330 }
331
332 RegFrame::~RegFrame()
333 {
334 // this makes deletion of it *much* quicker
335 m_treeCtrl->Hide();
336 }
337
338 void RegFrame::OnQuit(wxCommandEvent& event)
339 {
340 Close(TRUE);
341 }
342
343 void RegFrame::OnAbout(wxCommandEvent& event)
344 {
345 wxMessageDialog dialog(this,
346 "wxRegistry sample\n"
347 "© 1998, 2000 Vadim Zeitlin",
348 "About wxRegTest", wxOK);
349
350 dialog.ShowModal();
351 }
352
353 void RegFrame::OnTest(wxCommandEvent& event)
354 {
355 m_treeCtrl->OnMenuTest();
356 }
357
358 void RegFrame::OnExpand(wxCommandEvent& event)
359 {
360 m_treeCtrl->ExpandItem(m_treeCtrl->GetSelection(), wxTREE_EXPAND_EXPAND);
361 }
362
363 void RegFrame::OnCollapse(wxCommandEvent& event)
364 {
365 m_treeCtrl->ExpandItem(m_treeCtrl->GetSelection(), wxTREE_EXPAND_COLLAPSE);
366 }
367
368 void RegFrame::OnToggle(wxCommandEvent& event)
369 {
370 m_treeCtrl->ExpandItem(m_treeCtrl->GetSelection(), wxTREE_EXPAND_TOGGLE);
371 }
372
373 void RegFrame::OnDelete(wxCommandEvent& event)
374 {
375 m_treeCtrl->DeleteSelected();
376 }
377
378 void RegFrame::OnNewKey(wxCommandEvent& event)
379 {
380 if ( m_treeCtrl->IsKeySelected() ) {
381 m_treeCtrl->CreateNewKey(
382 wxGetTextFromUser("Enter the name of the new key"));
383 }
384 }
385
386 void RegFrame::OnNewText(wxCommandEvent& event)
387 {
388 if ( m_treeCtrl->IsKeySelected() ) {
389 m_treeCtrl->CreateNewTextValue(
390 wxGetTextFromUser("Enter the name for the new text value"));
391 }
392 }
393
394 void RegFrame::OnNewBinary(wxCommandEvent& event)
395 {
396 if ( m_treeCtrl->IsKeySelected() ) {
397 m_treeCtrl->CreateNewBinaryValue(
398 wxGetTextFromUser("Enter the name for the new binary value"));
399 }
400 }
401
402 void RegFrame::OnInfo(wxCommandEvent& event)
403 {
404 m_treeCtrl->ShowProperties();
405 }
406
407 // ----------------------------------------------------------------------------
408 // RegImageList
409 // ----------------------------------------------------------------------------
410 RegImageList::RegImageList() : wxImageList(16, 16, TRUE)
411 {
412 // should be in sync with enum RegImageList::RegIcon
413 static const char *aszIcons[] = { "key1","key2","key3","value1","value2" };
414 wxString str = "icon_";
415 for ( unsigned int n = 0; n < WXSIZEOF(aszIcons); n++ ) {
416 Add(wxIcon(str + aszIcons[n], wxBITMAP_TYPE_ICO_RESOURCE));
417 }
418 }
419
420 // ----------------------------------------------------------------------------
421 // RegTreeCtrl
422 // ----------------------------------------------------------------------------
423
424 // create a new tree item and insert it into the tree
425 RegTreeCtrl::TreeNode *RegTreeCtrl::InsertNewTreeNode(TreeNode *pParent,
426 const wxString& strName,
427 int idImage,
428 const wxString *pstrValue)
429 {
430 // create new item & insert it
431 TreeNode *pNewNode = new TreeNode;
432 pNewNode->m_pTree = this;
433 pNewNode->m_pParent = pParent;
434 pNewNode->m_strName = strName;
435 pNewNode->m_bKey = pstrValue == NULL;
436 pNewNode->m_pKey = NULL;
437 pNewNode->m_id = InsertItem(pParent ? pParent->Id() : 0,
438 pNewNode->IsKey() ? strName : *pstrValue,
439 idImage);
440
441 wxASSERT_MSG( pNewNode->m_id, "can't create tree control item!");
442
443 // save the pointer in the item
444 SetItemData(pNewNode->m_id, pNewNode);
445
446 // add it to the list of parent's children
447 if ( pParent != NULL ) {
448 pParent->m_aChildren.Add(pNewNode);
449 }
450
451 if ( pNewNode->IsKey() ) {
452 SetItemHasChildren(pNewNode->Id());
453
454 if ( !pNewNode->IsRoot() ) {
455 // set the expanded icon as well
456 SetItemImage(pNewNode->Id(),
457 RegImageList::OpenedKey,
458 wxTreeItemIcon_Expanded);
459 }
460 }
461
462 return pNewNode;
463 }
464
465 RegTreeCtrl::RegTreeCtrl(wxWindow *parent, wxWindowID id)
466 : wxTreeCtrl(parent, id, wxDefaultPosition, wxDefaultSize,
467 wxTR_HAS_BUTTONS | wxSUNKEN_BORDER)
468 {
469 // init members
470 m_draggedItem = NULL;
471 m_restoreStatus = FALSE;
472
473 // create the image list
474 // ---------------------
475 m_imageList = new RegImageList;
476 SetImageList(m_imageList, wxIMAGE_LIST_NORMAL);
477
478 // create root keys
479 // ----------------
480 m_pRoot = InsertNewTreeNode(NULL, "Registry Root", RegImageList::Root);
481
482 // create popup menu
483 // -----------------
484 m_pMenuPopup = CreateRegistryMenu();
485 }
486
487 RegTreeCtrl::~RegTreeCtrl()
488 {
489 delete m_pMenuPopup;
490 // delete m_pRoot; -- this is done by the tree now
491 delete m_imageList;
492 }
493
494 void RegTreeCtrl::AddStdKeys()
495 {
496 for ( unsigned int ui = 0; ui < wxRegKey::nStdKeys; ui++ ) {
497 InsertNewTreeNode(m_pRoot, wxRegKey::GetStdKeyName(ui));
498 }
499 }
500
501 // ----------------------------------------------------------------------------
502 // notifications
503 // ----------------------------------------------------------------------------
504
505 void RegTreeCtrl::OnIdle(wxIdleEvent& WXUNUSED(event))
506 {
507 if ( m_restoreStatus ) {
508 // restore it after OnItemExpanding()
509 wxLogStatus("Ok");
510 wxSetCursor(*wxSTANDARD_CURSOR);
511
512 m_restoreStatus = FALSE;
513 }
514 }
515
516 void RegTreeCtrl::OnRightClick(wxMouseEvent& event)
517 {
518 int iFlags;
519 long lId = HitTest(wxPoint(event.GetX(), event.GetY()), iFlags);
520 if ( !(iFlags & wxTREE_HITTEST_ONITEMLABEL) ) {
521 // take the currently selected item if click not on item
522 lId = GetSelection();
523 }
524 else {
525 SelectItem(lId);
526 }
527
528 PopupMenu(m_pMenuPopup, event.GetX(), event.GetY());
529 }
530
531
532 void RegTreeCtrl::OnDeleteItem(wxTreeEvent& event)
533 {
534 }
535
536 // test the key creation functions
537 void RegTreeCtrl::OnMenuTest()
538 {
539 long lId = GetSelection();
540 TreeNode *pNode = (TreeNode *)GetItemData(lId);
541
542 wxCHECK_RET( pNode != NULL, "tree item without data?" );
543
544 if ( pNode->IsRoot() ) {
545 wxLogError("Can't create a subkey under the root key.");
546 return;
547 }
548 if ( !pNode->IsKey() ) {
549 wxLogError("Can't create a subkey under a value!");
550 return;
551 }
552
553 wxRegKey key1(pNode->Key(), "key1");
554 if ( key1.Create() ) {
555 wxRegKey key2a(key1, "key2a"), key2b(key1, "key2b");
556 if ( key2a.Create() && key2b.Create() ) {
557 // put some values under the newly created keys
558 key1.SetValue("first_term", "10");
559 key1.SetValue("second_term", "7");
560 key2a = "this is the unnamed value";
561 key2b.SetValue("sum", 17);
562
563 // refresh tree
564 pNode->Refresh();
565 wxLogStatus("Test keys successfully added.");
566 return;
567 }
568 }
569
570 wxLogError("Creation of test keys failed.");
571 }
572
573 void RegTreeCtrl::OnChar(wxKeyEvent& event)
574 {
575 switch ( event.KeyCode() )
576 {
577 case WXK_DELETE:
578 DeleteSelected();
579 return;
580
581 case WXK_RETURN:
582 if ( event.AltDown() )
583 {
584 ShowProperties();
585
586 return;
587 }
588 }
589
590 event.Skip();
591 }
592
593 void RegTreeCtrl::OnSelChanged(wxTreeEvent& event)
594 {
595 wxFrame *pFrame = (wxFrame *)(wxWindow::GetParent());
596 pFrame->SetStatusText(GetNode(event)->FullName(), 1);
597 }
598
599 void RegTreeCtrl::OnItemExpanding(wxTreeEvent& event)
600 {
601 TreeNode *pNode = GetNode(event);
602 bool bExpanding = event.GetCode() == wxTREE_EXPAND_EXPAND;
603
604 // expansion might take some time
605 wxSetCursor(*wxHOURGLASS_CURSOR);
606 wxLogStatus("Working...");
607 wxYield(); // to give the status line a chance to refresh itself
608 m_restoreStatus = TRUE; // some time later...
609
610 if ( pNode->IsKey() ) {
611 if ( bExpanding ) {
612 // expanding: add subkeys/values
613 if ( !pNode->OnExpand() )
614 return;
615 }
616 else {
617 // collapsing: clean up
618 pNode->OnCollapse();
619 }
620 }
621 }
622
623 void RegTreeCtrl::OnBeginDrag(wxTreeEvent& event)
624 {
625 m_copyOnDrop = event.GetEventType() == wxEVT_COMMAND_TREE_BEGIN_DRAG;
626
627 TreeNode *pNode = GetNode(event);
628 if ( pNode->IsRoot() || pNode->Parent()->IsRoot() )
629 {
630 wxLogStatus("This registry key can't be %s.",
631 m_copyOnDrop ? "copied" : "moved");
632 }
633 else
634 {
635 wxLogStatus("%s item %s...",
636 m_copyOnDrop ? "Copying" : "Moving",
637 pNode->FullName());
638
639 m_draggedItem = pNode;
640
641 event.Allow();
642 }
643 }
644
645 void RegTreeCtrl::OnEndDrag(wxTreeEvent& event)
646 {
647 wxCHECK_RET( m_draggedItem, "end drag without begin drag?" );
648
649 // clear the pointer anyhow
650 TreeNode *src = m_draggedItem;
651 m_draggedItem = NULL;
652
653 // where are we going to drop it?
654 TreeNode *dst = GetNode(event);
655 if ( dst && !dst->IsKey() ) {
656 // we need a parent key
657 dst = dst->Parent();
658 }
659 if ( !dst || dst->IsRoot() ) {
660 wxLogError("Can't create a key here.");
661
662 return;
663 }
664
665 bool isKey = src->IsKey();
666 if ( (isKey && (src == dst)) ||
667 (!isKey && (src->Parent() == dst)) ) {
668 wxLogStatus("Can't copy something on itself");
669
670 return;
671 }
672
673 // remove the "Registry Root\\" from the full name
674 wxString nameSrc, nameDst;
675 nameSrc << wxString(src->FullName()).AfterFirst('\\');
676 nameDst << wxString(dst->FullName()).AfterFirst('\\') << '\\'
677 << wxString(src->FullName()).AfterLast('\\');
678
679 wxString verb = m_copyOnDrop ? "copy" : "move";
680 wxString what = isKey ? "key" : "value";
681
682 if ( wxMessageBox(wxString::Format
683 (
684 "Do you really want to %s the %s %s to %s?",
685 verb.c_str(),
686 what.c_str(),
687 nameSrc.c_str(),
688 nameDst.c_str()
689 ),
690 "RegTest Confirm",
691 wxICON_QUESTION | wxYES_NO | wxCANCEL, this) != wxYES ) {
692 return;
693 }
694
695 bool dstExpanded = IsExpanded(dst->Id());
696
697 bool ok;
698 if ( isKey ) {
699 wxRegKey& key = src->Key();
700 ok = key.Copy(dst->Key());
701 if ( ok && dstExpanded ) {
702 dst->OnCollapse();
703 dst->OnExpand();
704 }
705
706 if ( ok && !m_copyOnDrop ) {
707 // delete the old key
708 ok = key.DeleteSelf();
709 if ( ok ) {
710 src->Parent()->Refresh();
711 }
712 }
713 }
714 else { // value
715 wxRegKey& key = src->Parent()->Key();
716 ok = key.CopyValue(src->m_strName, dst->Key());
717 if ( ok && !m_copyOnDrop ) {
718 // we move it, so delete the old one
719 ok = key.DeleteValue(src->m_strName);
720 if ( ok ) {
721 // reexpand the key
722 dst->Refresh();
723 }
724 }
725 }
726
727 if ( !ok ) {
728 wxLogError("Failed to %s registry %s.", verb.c_str(), what.c_str());
729 }
730 }
731
732 // ----------------------------------------------------------------------------
733 // TreeNode implementation
734 // ----------------------------------------------------------------------------
735 bool RegTreeCtrl::TreeNode::OnExpand()
736 {
737 // we add children only once
738 if ( !m_aChildren.IsEmpty() ) {
739 // we've been already expanded
740 return TRUE;
741 }
742
743 if ( IsRoot() ) {
744 // we're the root key
745 m_pTree->AddStdKeys();
746 return TRUE;
747 }
748
749 if ( Parent()->IsRoot() ) {
750 // we're a standard key
751 m_pKey = new wxRegKey(m_strName);
752 }
753 else {
754 // we're a normal key
755 m_pKey = new wxRegKey(*(Parent()->m_pKey), m_strName);
756 }
757
758 if ( !m_pKey->Open() ) {
759 wxLogError("The key '%s' can't be opened.", FullName());
760 return FALSE;
761 }
762
763 // if we're empty, we shouldn't be expandable at all
764 bool isEmpty = TRUE;
765
766 // enumeration variables
767 long l;
768 wxString str;
769 bool bCont;
770
771 // enumerate all subkeys
772 bCont = m_pKey->GetFirstKey(str, l);
773 while ( bCont ) {
774 m_pTree->InsertNewTreeNode(this, str, RegImageList::ClosedKey);
775 bCont = m_pKey->GetNextKey(str, l);
776
777 // we have at least this key...
778 isEmpty = FALSE;
779 }
780
781 // enumerate all values
782 bCont = m_pKey->GetFirstValue(str, l);
783 while ( bCont ) {
784 wxString strItem;
785 if (str.IsEmpty())
786 strItem = "<default>";
787 else
788 strItem = str;
789 strItem += " = ";
790
791 // determine the appropriate icon
792 RegImageList::Icon icon;
793 switch ( m_pKey->GetValueType(str) ) {
794 case wxRegKey::Type_String:
795 case wxRegKey::Type_Expand_String:
796 case wxRegKey::Type_Multi_String:
797 {
798 wxString strValue;
799 icon = RegImageList::TextValue;
800 m_pKey->QueryValue(str, strValue);
801 strItem += strValue;
802 }
803 break;
804
805 case wxRegKey::Type_None:
806 // @@ handle the error...
807 icon = RegImageList::BinaryValue;
808 break;
809
810 case wxRegKey::Type_Dword:
811 {
812 long l;
813 m_pKey->QueryValue(str, &l);
814 strItem << l;
815 }
816
817 // fall through
818
819 default:
820 icon = RegImageList::BinaryValue;
821 }
822
823 m_pTree->InsertNewTreeNode(this, str, icon, &strItem);
824 bCont = m_pKey->GetNextValue(str, l);
825
826 // we have at least this value...
827 isEmpty = FALSE;
828 }
829
830 if ( isEmpty ) {
831 // this is for the case when our last child was just deleted
832 m_pTree->Collapse(Id());
833
834 // we won't be expanded any more
835 m_pTree->SetItemHasChildren(Id(), FALSE);
836 }
837
838 return TRUE;
839 }
840
841 void RegTreeCtrl::TreeNode::OnCollapse()
842 {
843 DestroyChildren();
844
845 delete m_pKey;
846 m_pKey = NULL;
847 }
848
849 void RegTreeCtrl::TreeNode::Refresh()
850 {
851 if ( m_pTree->IsExpanded(Id()) )
852 {
853 m_pTree->Collapse(Id());
854 m_pTree->SetItemHasChildren(Id());
855 m_pTree->Expand(Id());
856 }
857 }
858
859 bool RegTreeCtrl::TreeNode::DeleteChild(TreeNode *child)
860 {
861 int index = m_aChildren.Index(child);
862 wxCHECK_MSG( index != wxNOT_FOUND, FALSE,
863 "our child in tree should be in m_aChildren" );
864
865 m_aChildren.RemoveAt((size_t)index);
866
867 bool ok;
868 if ( child->IsKey() ) {
869 // must close key before deleting it
870 child->OnCollapse();
871
872 ok = Key().DeleteKey(child->m_strName);
873 }
874 else {
875 ok = Key().DeleteValue(child->m_strName);
876 }
877
878 if ( ok ) {
879 m_pTree->Delete(child->Id());
880
881 Refresh();
882 }
883
884 return ok;
885 }
886
887 void RegTreeCtrl::TreeNode::DestroyChildren()
888 {
889 // destroy all children
890 size_t nCount = m_aChildren.GetCount();
891 for ( size_t n = 0; n < nCount; n++ ) {
892 long lId = m_aChildren[n]->Id();
893 // no, wxTreeCtrl will do it
894 //delete m_aChildren[n];
895 m_pTree->Delete(lId);
896 }
897
898 m_aChildren.Empty();
899 }
900
901 RegTreeCtrl::TreeNode::~TreeNode()
902 {
903 delete m_pKey;
904 }
905
906 const char *RegTreeCtrl::TreeNode::FullName() const
907 {
908 static wxString s_strName;
909
910 if ( IsRoot() ) {
911 return "Registry Root";
912 }
913 else {
914 // our own registry key might not (yet) exist or we might be a value,
915 // so just use the parent's and concatenate
916 s_strName = Parent()->FullName();
917 s_strName << '\\' << m_strName;
918
919 return s_strName;
920 }
921 }
922
923 // ----------------------------------------------------------------------------
924 // operations on RegTreeCtrl
925 // ----------------------------------------------------------------------------
926
927 void RegTreeCtrl::DeleteSelected()
928 {
929 long lCurrent = GetSelection(),
930 lParent = GetParent(lCurrent);
931
932 if ( lParent == 0 ) {
933 wxLogError("Can't delete root key.");
934 return;
935 }
936
937 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent),
938 *pParent = (TreeNode *)GetItemData(lParent);
939
940 wxCHECK_RET( pCurrent && pParent, "either node or parent without data?" );
941
942 if ( pParent->IsRoot() ) {
943 wxLogError("Can't delete standard key.");
944 return;
945 }
946
947 wxString what = pCurrent->IsKey() ? "key" : "value";
948 if ( wxMessageBox(wxString::Format
949 (
950 "Do you really want to delete this %s?",
951 what.c_str()
952 ),
953 "Confirmation",
954 wxICON_QUESTION | wxYES_NO | wxCANCEL, this) != wxYES ) {
955 return;
956 }
957
958 pParent->DeleteChild(pCurrent);
959 }
960
961 void RegTreeCtrl::CreateNewKey(const wxString& strName)
962 {
963 long lCurrent = GetSelection();
964 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent);
965
966 wxCHECK_RET( pCurrent != NULL, "node without data?" );
967
968 wxASSERT( pCurrent->IsKey() ); // check must have been done before
969
970 if ( pCurrent->IsRoot() ) {
971 wxLogError("Can't create a new key under the root key.");
972 return;
973 }
974
975 wxRegKey key(pCurrent->Key(), strName);
976 if ( key.Create() )
977 pCurrent->Refresh();
978 }
979
980 void RegTreeCtrl::CreateNewTextValue(const wxString& strName)
981 {
982 long lCurrent = GetSelection();
983 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent);
984
985 wxCHECK_RET( pCurrent != NULL, "node without data?" );
986
987 wxASSERT( pCurrent->IsKey() ); // check must have been done before
988
989 if ( pCurrent->IsRoot() ) {
990 wxLogError("Can't create a new value under the root key.");
991 return;
992 }
993
994 if ( pCurrent->Key().SetValue(strName, "") )
995 pCurrent->Refresh();
996 }
997
998 void RegTreeCtrl::CreateNewBinaryValue(const wxString& strName)
999 {
1000 long lCurrent = GetSelection();
1001 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent);
1002
1003 wxCHECK_RET( pCurrent != NULL, "node without data?" );
1004
1005 wxASSERT( pCurrent->IsKey() ); // check must have been done before
1006
1007 if ( pCurrent->IsRoot() ) {
1008 wxLogError("Can't create a new value under the root key.");
1009 return;
1010 }
1011
1012 if ( pCurrent->Key().SetValue(strName, 0) )
1013 pCurrent->Refresh();
1014 }
1015
1016 void RegTreeCtrl::ShowProperties()
1017 {
1018 long lCurrent = GetSelection();
1019 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent);
1020
1021 if ( !pCurrent || pCurrent->IsRoot() )
1022 {
1023 wxLogStatus("No properties");
1024
1025 return;
1026 }
1027
1028 if ( pCurrent->IsKey() )
1029 {
1030 const wxRegKey& key = pCurrent->Key();
1031 size_t nSubKeys, nValues;
1032 if ( !key.GetKeyInfo(&nSubKeys, NULL, &nValues, NULL) )
1033 {
1034 wxLogError("Couldn't get key info");
1035 }
1036 else
1037 {
1038 wxLogMessage("Key '%s' has %u subkeys and %u values.",
1039 key.GetName().c_str(), nSubKeys, nValues);
1040 }
1041 }
1042 else // it's a value
1043 {
1044 TreeNode *parent = pCurrent->Parent();
1045 wxCHECK_RET( parent, "reg value without key?" );
1046
1047 const wxRegKey& key = parent->Key();
1048 const char *value = pCurrent->m_strName.c_str();
1049 wxLogMessage("Value '%s' under the key '%s' is of type "
1050 "%d (%s).",
1051 value,
1052 parent->m_strName.c_str(),
1053 key.GetValueType(value),
1054 key.IsNumericValue(value) ? "numeric" : "string");
1055
1056 }
1057 }
1058
1059 bool RegTreeCtrl::IsKeySelected() const
1060 {
1061 long lCurrent = GetSelection();
1062 TreeNode *pCurrent = (TreeNode *)GetItemData(lCurrent);
1063
1064 wxCHECK( pCurrent != NULL, FALSE );
1065
1066 return pCurrent->IsKey();
1067 }