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