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