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