]> Creatis software - bbtk.git/blob - kernel/src/ThirdParty/wx/treemultictrl/wxTreeMultiCtrl.cpp
Started the devel of a wx package browser
[bbtk.git] / kernel / src / ThirdParty / wx / treemultictrl / wxTreeMultiCtrl.cpp
1 //---------------------------------------------------------------------------\r
2 // $RCSfile: wxTreeMultiCtrl.cpp,v $\r
3 // $Source: /cvs/creatis/bbtk/kernel/src/ThirdParty/wx/treemultictrl/wxTreeMultiCtrl.cpp,v $\r
4 // $Revision: 1.1 $\r
5 // $Date: 2008/03/28 13:42:19 $\r
6 //---------------------------------------------------------------------------\r
7 // Author:      Jorgen Bodde\r
8 // Copyright:   (c) Jorgen Bodde\r
9 // License:     wxWidgets License\r
10 //---------------------------------------------------------------------------\r
11 \r
12 #ifdef __GNUG__\r
13     #pragma implementation "wxTreeMultiCtrl.h"\r
14 #endif\r
15 \r
16 // For compilers that support precompilation, includes "wx/wx.h".\r
17 #include "wx/wxprec.h"\r
18 #include "wx/treebase.h"\r
19 \r
20 #ifdef __BORLANDC__\r
21     #pragma hdrstop\r
22 #endif\r
23 \r
24 #include "wx/arrimpl.cpp"\r
25 \r
26 #include "wx/treemultictrl/wxTreeMultiCtrl.h"\r
27 #include "wx/treemultictrl/wxTreeMultiEvent.h"\r
28 #include "tmcimages.h"\r
29 \r
30 \r
31 \r
32 //----------------------------------------------------------------------------\r
33 // wxTreeMultiItem\r
34 //----------------------------------------------------------------------------\r
35 \r
36 WX_DEFINE_OBJARRAY(wxArrayTreeMultiItem);\r
37 \r
38 //----------------------------------------------------------------------------\r
39 // wxTreeMultiCtrl\r
40 //----------------------------------------------------------------------------\r
41 \r
42 IMPLEMENT_DYNAMIC_CLASS(wxTreeMultiCtrl, wxScrolledWindow)\r
43 \r
44 // WDR: event table for wxTreeMultiCtrl\r
45 BEGIN_EVENT_TABLE(wxTreeMultiCtrl, wxScrolledWindow)\r
46   EVT_LEFT_DOWN  (wxTreeMultiCtrl::OnMouseClick)\r
47   EVT_LEFT_DCLICK(wxTreeMultiCtrl::OnMouseClick)\r
48   EVT_RIGHT_DOWN (wxTreeMultiCtrl::OnRightMouseClick)\r
49   EVT_PAINT(wxTreeMultiCtrl::OnPaint)\r
50   EVT_SIZE(wxTreeMultiCtrl::OnSize)\r
51 //  EVT_KEY_UP(wxTreeMultiCtrl::OnKey)\r
52 END_EVENT_TABLE()\r
53 \r
54 bool wxTreeMultiCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos,\r
55                                const wxSize& size, long style, const wxValidator & WXUNUSED(validator),\r
56                                const wxString& name )\r
57 {\r
58     wxScrolledWindow::Create( parent, id, pos, size, style | wxTAB_TRAVERSAL, name);\r
59 \r
60         _create_called = true;\r
61 \r
62         // do the init\r
63         Init();\r
64 \r
65     return TRUE;\r
66 }\r
67 \r
68 void wxTreeMultiCtrl::Init()\r
69 {\r
70         _root.Clear();\r
71 \r
72         _expandBmp = 0;\r
73         _collBmp = 0;\r
74 \r
75 #if(CHECKBOXVIEW)\r
76         _checkBmp = 0;\r
77         _uncheckBmp = 0;\r
78         _tristateBmp = 0;\r
79 \r
80         _checkHeight = 11;\r
81         _checkWidth = 11;\r
82 \r
83         _checkboxView = false;\r
84 #endif\r
85 \r
86         _gutterWidth = WXTMC_GUTTER_DEFAULT;\r
87         _iconWidth = 11;\r
88         _iconHeight = 11;\r
89         _maxHeight = 1;;\r
90         _iconDeltaY = 2;\r
91         _spacingY = WXTMC_YSPACING_DEFAULT;\r
92         _captionHeight = 13;\r
93 \r
94         // create two bitmap nodes for drawing\r
95 \r
96         _expandBmp = new wxBitmap(expand_xpm);\r
97         _collBmp = new wxBitmap(collapse_xpm);\r
98 \r
99         // calculate average font height for bitmap centering\r
100 \r
101         _iconWidth = _expandBmp->GetWidth();\r
102         _iconHeight = _expandBmp->GetHeight();\r
103 \r
104 #if(CHECKBOXVIEW)\r
105         // create bitmaps for checkboxes\r
106         _checkBmp = new wxBitmap(checked_icon);\r
107         _uncheckBmp = new wxBitmap(unchecked_icon);\r
108         _tristateBmp = new wxBitmap(tristate_icon);\r
109 \r
110         // adjust the height if the checkboxes are higher\r
111         // so that everything is alligned properly\r
112         _checkHeight = _checkBmp->GetHeight();\r
113         _checkWidth = _checkBmp->GetWidth();\r
114 #endif\r
115 \r
116         // remember the highest of the two bitmaps so there is\r
117         // always enough room\r
118         _maxHeight = _iconHeight;\r
119 \r
120 #if(CHECKBOXVIEW)\r
121         if(_maxHeight < _checkHeight)\r
122                 _maxHeight = _checkHeight;\r
123 #endif\r
124 \r
125  // set standard highlighting brush\r
126   this->m_HilightBrush = new wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT),wxSOLID);\r
127 \r
128         // set standard DC font\r
129     _captionFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);\r
130 \r
131         // adjust bitmap icon y position so they are centered\r
132         AdjustIconsDeltaY();\r
133 \r
134         // set virtual size to this window size\r
135         if (_create_called) {\r
136                 wxSize wndsize = GetSize();\r
137                 SetVirtualSize(wndsize.GetWidth(), wndsize.GetWidth());\r
138         }\r
139 }\r
140 \r
141 void wxTreeMultiCtrl::SetCaptionFont(const wxFont &font)\r
142 {\r
143         _captionFont = font;\r
144 \r
145         // adjust the icons so that they are in the middle\r
146         AdjustIconsDeltaY();\r
147 \r
148         RedrawFromNode(0);\r
149 };\r
150 \r
151 void wxTreeMultiCtrl::AdjustIconsDeltaY()\r
152 {\r
153         int x = 0, y = 0;\r
154 \r
155         if(_captionFont.Ok())\r
156       GetTextExtent(wxT("jG"), &x, &y, 0, 0, &_captionFont);\r
157         _captionHeight = y;\r
158 \r
159         if(_maxHeight < _captionHeight)\r
160                 _maxHeight = _captionHeight;\r
161 \r
162         // determine the center pos for the [+]\r
163         _iconDeltaY = abs(_maxHeight - _iconHeight) / 2 + 1;\r
164         if(_iconDeltaY < 1)\r
165                 _iconDeltaY = 1;\r
166 \r
167 #if(CHECKBOXVIEW)\r
168         // determine the center pos for the checkbox\r
169         _checkDeltaY = abs(_maxHeight - _checkHeight) / 2 + 1;\r
170         if(_checkDeltaY < 1)\r
171                 _checkDeltaY = 1;\r
172 #endif\r
173 }\r
174 \r
175 wxTreeMultiCtrl::~wxTreeMultiCtrl()\r
176 {\r
177         // delete the bitmap resources\r
178         delete _expandBmp;\r
179         delete _collBmp;\r
180 \r
181 #if(CHECKBOXVIEW)\r
182         delete _checkBmp;\r
183         delete _uncheckBmp;\r
184         delete _tristateBmp;\r
185 #endif\r
186 }\r
187 \r
188 wxTreeMultiItem wxTreeMultiCtrl::AddRoot(const wxString &caption, const wxString &name)\r
189 {\r
190         wxTreeMultiItem result((TreeMultiItemBase *)&_root);\r
191         result = AppendNode(result, caption, name);\r
192 \r
193         return result;\r
194 }\r
195 \r
196 wxTreeMultiItem wxTreeMultiCtrl::AppendWindow(const wxTreeMultiItem &ParentItem, wxWindow *window, const wxString &name, const wxTreeMultiWindowInfo &info, int flags)\r
197 {\r
198  // add window only if the parent item is valid and...\r
199         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));\r
200 \r
201         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes\r
202 \r
203  // ... is a node\r
204   wxCHECK(parent != NULL, wxTreeMultiItem(0));\r
205 \r
206  // now, append node to the tree control:\r
207   wxTreeMultiItem NewWindowItem(this->InsertWindow(parent,wx_static_cast(size_t,parent->GetNodeCount()),window,name,info,flags));\r
208  // redraw the stucture:\r
209         this->RedrawFromNode(parent);\r
210  // return the new window\r
211         return NewWindowItem;\r
212 }\r
213 \r
214 wxTreeMultiItem wxTreeMultiCtrl::InsertWindow(wxTreeMultiItem const& ParentItem, size_t Position, wxWindow *window, wxString const& name, wxTreeMultiWindowInfo const& info, int flags)\r
215 {\r
216  // add window only if the parent item is valid and...\r
217         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));\r
218 \r
219         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes\r
220 \r
221  // ... is a node\r
222   wxCHECK(parent != NULL, wxTreeMultiItem(0));\r
223 \r
224  // now, append node to the tree control:\r
225   wxTreeMultiItem NewWindowItem(this->InsertWindow(parent,Position,window,name,info,flags));\r
226  // redraw the stucture:\r
227         this->RedrawFromNode(parent);\r
228  // return the new window\r
229         return NewWindowItem;\r
230 } /* wxTreeMultiCtrl::InsertWindow(wxTreeMultiItem const&, size_t, wxWindow*, wxString const&, wxTreeMultiWindowInfo const&, int) */\r
231 \r
232 wxTreeMultiItem wxTreeMultiCtrl::PrependWindow(wxTreeMultiItem const& ParentItem, wxWindow *window, const wxString &name, wxTreeMultiWindowInfo const& info, int flags)\r
233 {\r
234  // add window only if the parent item is valid and...\r
235         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));\r
236 \r
237         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes\r
238 \r
239  // ... is a node\r
240   wxCHECK(parent != NULL, wxTreeMultiItem(0));\r
241 \r
242  // now, append node to the tree control:\r
243   wxTreeMultiItem NewWindowItem(this->InsertWindow(parent,0,window,name,info,flags));\r
244  // redraw the stucture:\r
245         this->RedrawFromNode(parent);\r
246  // return the new window\r
247         return NewWindowItem;\r
248 } /* wxTreeMultiCtrl::PrependWindow(wxTreeMultiItem const&, wxWindow*, const wxString &, wxTreeMultiWindowInfo const&, int) */\r
249 \r
250 wxTreeMultiItem wxTreeMultiCtrl::AppendNode(wxTreeMultiItem const& ParentItem, const wxString &caption, const wxString &name)\r
251 {\r
252  // add window only if the parent item is valid and...\r
253         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));\r
254 \r
255         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes\r
256 \r
257  // ... is a node\r
258   wxCHECK(parent != NULL, wxTreeMultiItem(0));\r
259 \r
260  // now, append node to the tree control:\r
261   wxTreeMultiItem NewNodeItem(this->InsertNode(parent,wx_static_cast(size_t,parent->GetNodeCount()),caption,name));\r
262  // redraw the structure:\r
263         this->RedrawFromNode(parent);\r
264  // return the new node:\r
265         return NewNodeItem;\r
266 } /* wxTreeMultiCtrl::AppendNode(wxTreeMultiItem const&, const wxString &, const wxString&) */\r
267 \r
268 wxTreeMultiItem wxTreeMultiCtrl::InsertNode(wxTreeMultiItem const& ParentItem, size_t Position, wxString const& caption, wxString const& name)\r
269 {\r
270  // add window only if the parent item is valid and...\r
271         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));\r
272 \r
273         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes\r
274 \r
275  // ... is a node\r
276   wxCHECK(parent != NULL, wxTreeMultiItem(0));\r
277 \r
278  // now, append node to the tree control:\r
279   wxTreeMultiItem NewNodeItem(this->InsertNode(parent,Position,caption,name));\r
280  // redraw the structure:\r
281         this->RedrawFromNode(parent);\r
282  // return the new node:\r
283         return NewNodeItem;\r
284 } /* wxTreeMultiCtrl::InsertNode(wxTreeMultiItem const&, size_t, wxString const&, wxString const&) */\r
285 \r
286 wxTreeMultiItem wxTreeMultiCtrl::PrependNode(wxTreeMultiItem const& ParentItem, wxString const& caption, wxString const& name)\r
287 {\r
288  // add window only if the parent item is valid and...\r
289         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));\r
290 \r
291         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes\r
292 \r
293  // ... is a node\r
294   wxCHECK(parent != NULL, wxTreeMultiItem(0));\r
295 \r
296  // now, append node to the tree control:\r
297   wxTreeMultiItem NewNodeItem(this->InsertNode(parent,0,caption,name));\r
298  // redraw the structure:\r
299         this->RedrawFromNode(parent);\r
300  // return the new node:\r
301         return NewNodeItem;\r
302 } /* wxTreeMultiCtrl::PrependNode(wxTreeMultiItem const&, wxString const&, wxString const&) */\r
303 \r
304 bool wxTreeMultiCtrl::Delete(wxTreeMultiItem &item)\r
305 {\r
306         bool redraw = true;\r
307         wxCHECK(item.IsOk(), false);\r
308 \r
309         wxTreeMultiItem nullItem(0);\r
310 \r
311 \r
312  // if item has been selected, remove it from the selected list:\r
313   size_t ItemIndex(this->GetSelectedItemIndex(item));\r
314 \r
315   if (ItemIndex != this->GetSelectedItemCount())\r
316     this->m_SelectedItems.RemoveAt(ItemIndex);\r
317 \r
318         // get parent, to delete item from\r
319         TreeMultiItemNode *p = item.GetItem()->GetParent();\r
320 \r
321         // first check if it was visible, if so from the parent off\r
322         // it needs redrawing\r
323         redraw = item.GetItem()->IsVisible();\r
324         if(p)\r
325                 p->DeleteNode(item.GetItem());\r
326         else\r
327                 _root.DeleteNode(item.GetItem());\r
328 \r
329         item = nullItem;\r
330 \r
331         // do redraw when node was visible\r
332         if(redraw)\r
333                 RedrawFromNode(p);\r
334 \r
335         return true;\r
336 }\r
337 \r
338 void wxTreeMultiCtrl::DeleteChildren(const wxTreeMultiItem &item)\r
339 {\r
340         if(item.IsNodeItem())\r
341         {\r
342                 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();\r
343 \r
344    // remove all children from the selected item list:\r
345           if (n->GetNodeCount() > 0)\r
346           {\r
347            // variable definitions and initializations:\r
348             int Cookie;\r
349             wxTreeMultiItem FirstItemIterator(this->GetFirstChild(item,Cookie)), LastItemIterator(this->GetLastChild(item));\r
350 \r
351             for (;;)\r
352             {\r
353               size_t ItemIndex(this->GetSelectedItemIndex(item)); // variable definition and initialization\r
354 \r
355               if (ItemIndex != this->GetSelectedItemCount())\r
356                 this->m_SelectedItems.RemoveAt(ItemIndex);\r
357               if (FirstItemIterator == LastItemIterator)\r
358                 break; // all children checked\r
359               else\r
360                 FirstItemIterator = this->GetNext(FirstItemIterator);\r
361             } /* for */\r
362           } /* if */\r
363          // delete children:\r
364                 n->Clear();\r
365         // redraw:\r
366                 RedrawFromNode(n);\r
367         }\r
368 }\r
369 \r
370 void wxTreeMultiCtrl::Expand(const wxTreeMultiItem &item, bool recursive)\r
371 {\r
372         if(item.IsOk())\r
373         {\r
374         TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();\r
375                 if(!n)\r
376                         n = item.GetItem()->GetParent();\r
377         DoFold(n, true, recursive);\r
378                 RedrawFromNode(item.GetItem()->IsTreeMultiItemNode());\r
379         }\r
380 }\r
381 \r
382 void wxTreeMultiCtrl::Collapse(const wxTreeMultiItem &item, bool recursive)\r
383 {\r
384         if(item.IsOk())\r
385         {\r
386         TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();\r
387                 if(!n)\r
388                         n = item.GetItem()->GetParent();\r
389                 DoFold(n, false, recursive);\r
390                 RedrawFromNode(item.GetItem()->IsTreeMultiItemNode());\r
391         }\r
392 }\r
393 \r
394 \r
395 void wxTreeMultiCtrl::ExpandNodes(bool recursive)\r
396 {\r
397         // go through all children and call DoFold recursively\r
398         for(int i = 0; i < _root.GetNodeCount(); i++)\r
399                 DoFold(_root.GetNode(i), true, recursive);\r
400         RedrawFromNode(0);\r
401 }\r
402 \r
403 void wxTreeMultiCtrl::CollapseNodes(bool recursive)\r
404 {\r
405         // go through all children and call DoFold recursively\r
406         for(int i = 0; i < _root.GetNodeCount(); i++)\r
407                 DoFold(_root.GetNode(i), false, recursive);\r
408         RedrawFromNode(0);\r
409 }\r
410 \r
411 void wxTreeMultiCtrl::CollapseAndReset(const wxTreeMultiItem &item)\r
412 {\r
413         if(item.IsNodeItem())\r
414         {\r
415                  TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();\r
416 \r
417                  // delete all kids\r
418                  n->Clear();\r
419                  Collapse(item, false);\r
420         }\r
421 }\r
422 \r
423 // Selection manipulation\r
424 wxTreeMultiItem wxTreeMultiCtrl::GetFirstSelectedItem(void) const\r
425 {\r
426   if (this->GetSelectedItemCount() > 0)\r
427     return this->m_SelectedItems[0];\r
428   else\r
429     return wxTreeMultiItem();\r
430 } /* wxTreeMultiCtrl::GetFirstSelectedItem(void) const */\r
431 \r
432 wxTreeMultiItem wxTreeMultiCtrl::GetLastSelectedItem(void) const\r
433 {\r
434   if (this->GetSelectedItemCount() > 0)\r
435     return this->m_SelectedItems[this->GetSelectedItemCount()-1];\r
436   else\r
437     return wxTreeMultiItem();\r
438 } /* wxTreeMultiCtrl::GetLastSelectedItem(void) const */\r
439 \r
440 wxTreeMultiItem wxTreeMultiCtrl::GetSelectedItem(size_t Index) const\r
441 {\r
442   if (Index < this->GetSelectedItemCount())\r
443     return this->m_SelectedItems[Index];\r
444   else\r
445     return wxTreeMultiItem();\r
446 } /* wxTreeMultiCtrl::GetSelectedItem(size_t Index) const */\r
447 \r
448 size_t wxTreeMultiCtrl::GetSelectedItemIndex(wxTreeMultiItem const& Item) const\r
449 {\r
450  // attention: the function wxArray::Index() can NOT be used in a save manner as it only checks the address of an item\r
451  //            element but it is not guaranteed that Item may not be a copy of the originally inserted item\r
452   const size_t NoOfSelectedItems = this->GetSelectedItemCount();\r
453 \r
454   size_t Index(0);\r
455 \r
456 \r
457   while ((Index < NoOfSelectedItems) && (this->m_SelectedItems[Index] != Item))\r
458     ++Index;\r
459   return Index;\r
460 } /* wxTreeMultiCtrl::GetSelectedItemIndex(wxTreeMultiItem const&) const */\r
461 \r
462 void wxTreeMultiCtrl::SelectItem(wxTreeMultiItem const& Item, bool UnselectOthers, bool ExpandSelection)\r
463 {\r
464   TreeMultiItemNode* NodePtr(Item.GetItem()->IsTreeMultiItemNode());\r
465 \r
466 \r
467  // only nodes can be selected and they can only be selected if they are not already selected:\r
468   if ((NodePtr == NULL) || NodePtr->IsSelected())\r
469    return;\r
470 \r
471  // inform that we are about to change:\r
472   wxTreeMultiEvent Event(wxEVT_COMMAND_TREE_MULTI_SEL_CHANGING,Item); // variable definition and initialization\r
473 \r
474   if (this->m_SelectedItems.GetCount() > 0) // the last item in the array is always the latest inserted item\r
475     Event.SetOldItem(this->m_SelectedItems.Last());\r
476   Event.SetEventObject(this);\r
477   if (this->GetEventHandler()->ProcessEvent(Event) && !(Event.IsAllowed()))\r
478       return; // vetoed\r
479 \r
480  // make sure that the to be selected item can be seen:\r
481   this->Include(Item);\r
482 \r
483  // variable definition and initialization:\r
484   wxTreeMultiItem ExcludedParent(this->GetExcludedParent(Item));\r
485 \r
486   while (ExcludedParent.IsOk())\r
487   {\r
488     this->Include(ExcludedParent);\r
489     ExcludedParent = this->GetExcludedParent(Item);\r
490   } /* while */\r
491 \r
492  // unselect items if necessary:\r
493   if (UnselectOthers)\r
494     this->UnselectAll();\r
495  // expand selection if necessary:\r
496   if (ExpandSelection)\r
497   {\r
498    // variable definition:\r
499     wxTreeMultiItem FirstItemIterator, LastItemIterator;\r
500     wxTreeMultiItem LastSelectedItem;\r
501 \r
502    // determine the last selected item or the first item in case nothing has been selected before:\r
503     if (this->m_SelectedItems.GetCount() > 0)\r
504       LastSelectedItem = this->m_SelectedItems.Last();\r
505     else\r
506       LastSelectedItem = this->GetFirstRoot();\r
507    // determine the item from which to start and the one with which to end the selection:\r
508     if (Item.GetItem()->GetY() > LastSelectedItem.GetItem()->GetY())\r
509     {\r
510       FirstItemIterator = LastSelectedItem;\r
511       LastItemIterator  = Item;\r
512     } /* if */\r
513     else\r
514     {\r
515       FirstItemIterator = Item;\r
516       LastItemIterator  = LastSelectedItem;\r
517     } /* if */\r
518    // select all items that are a node and are placed between the two limiting iterators (included the limits):\r
519     for (;;)\r
520     {\r
521       if (!(FirstItemIterator.IsSelected()) && FirstItemIterator.IsNodeItem())\r
522       {\r
523         FirstItemIterator.GetItem()->Select();\r
524         this->m_SelectedItems.Add(FirstItemIterator);\r
525         this->RefreshRect(wxRect(FirstItemIterator.GetItem()->GetX(),    FirstItemIterator.GetItem()->GetY(),\r
526                                  FirstItemIterator.GetItem()->GetWidth(),FirstItemIterator.GetItem()->GetHeight()));\r
527       } /* if */\r
528       if (FirstItemIterator == LastItemIterator)\r
529         break; // done\r
530      // continue iterating:\r
531       FirstItemIterator = this->GetNext(FirstItemIterator);\r
532     } /* for */\r
533   } /* if */\r
534   else // select passed item only\r
535   {\r
536     NodePtr->Select();\r
537     this->m_SelectedItems.Add(NodePtr);\r
538     this->RefreshRect(wxRect(NodePtr->GetX(),NodePtr->GetY(),NodePtr->GetWidth(),NodePtr->GetHeight()));\r
539   } /* if */\r
540 \r
541  // inform that we have selected the item:\r
542   Event.SetEventType(wxEVT_COMMAND_TREE_MULTI_SEL_CHANGED);\r
543   this->GetEventHandler()->ProcessEvent(Event);\r
544 } /* wxTreeMultiCtrl::SelectItem(wxTreeMultiItem const&, bool, bool) */\r
545 \r
546 void wxTreeMultiCtrl::UnselectAll(void)\r
547 {\r
548   const size_t NoOfSelectedItems = this->m_SelectedItems.GetCount();\r
549 \r
550 \r
551   for (size_t i=0; i<NoOfSelectedItems; ++i)\r
552   {\r
553     this->RefreshRect(wxRect(this->m_SelectedItems[i].GetItem()->GetX(),    this->m_SelectedItems[i].GetItem()->GetY(),\r
554                              this->m_SelectedItems[i].GetItem()->GetWidth(),this->m_SelectedItems[i].GetItem()->GetHeight()));\r
555     this->m_SelectedItems[i].GetItem()->Unselect();\r
556   } /* for */\r
557   this->m_SelectedItems.Clear();\r
558 } /* wxTreeMultiCtrl::UnselectAll(void) */\r
559 \r
560 void wxTreeMultiCtrl::Unselect(wxTreeMultiItem const& Item)\r
561 {\r
562   size_t ItemIndex(this->GetSelectedItemIndex(Item));\r
563 \r
564 \r
565   if (ItemIndex != this->GetSelectedItemCount())\r
566   {\r
567     Item.GetItem()->Unselect();\r
568     this->m_SelectedItems.RemoveAt(ItemIndex);\r
569     this->RefreshRect(wxRect(Item.GetItem()->GetX(),Item.GetItem()->GetY(),Item.GetItem()->GetWidth(),Item.GetItem()->GetHeight()));\r
570   } /* if */\r
571 } /* wxTreeMultiCtrl::Unselect(wxTreeMultiItem const&) */\r
572 \r
573 void wxTreeMultiCtrl::DoFold(TreeMultiItemBase *item, bool expand, bool recursive)\r
574 {\r
575 \r
576         // go through all node objects on this level, and expand or\r
577         // collapse them\r
578 \r
579         if(item == 0)\r
580                 return;\r
581 \r
582         // if this is a node, use it to go through all the subnodes (if needed)\r
583         // if not, then just exit.\r
584 \r
585         TreeMultiItemNode *node = item->IsTreeMultiItemNode();\r
586         if(node)\r
587         {\r
588                 node->Fold(expand);\r
589 \r
590                 // go recursive\r
591                 if(recursive)\r
592                 {\r
593                         TreeMultiItemNode *p;\r
594                         for(int i = 0; i < node->GetNodeCount(); i++)\r
595                         {\r
596                                 // get node, and if a real node, then call fold\r
597                                 p = node->GetNode(i)->IsTreeMultiItemNode();\r
598                                 if(p)\r
599                                         p->Fold(expand);\r
600 \r
601                                 // go recursive for every node\r
602                                 DoFold(p, expand, recursive);\r
603                         }\r
604                 }\r
605         }\r
606 }\r
607 \r
608 void wxTreeMultiCtrl::Exclude(const wxTreeMultiItem &item)\r
609 {\r
610         wxCHECK2(item.IsOk(), return);\r
611 \r
612         // exclude the item, and refresh\r
613         // if already excluded, skip\r
614 \r
615         if(!item.GetItem()->IsExcluded())\r
616         {\r
617                 item.GetItem()->SetExcluded(true);\r
618                 RedrawFromParentNode(item.GetItem());\r
619         }\r
620 }\r
621 \r
622 void wxTreeMultiCtrl::Include(const wxTreeMultiItem &item)\r
623 {\r
624         wxCHECK2(item.IsOk(), return);\r
625 \r
626         // include the item, and refresh. If not\r
627         // excluded, do nothing\r
628 \r
629         if(item.GetItem()->IsExcluded())\r
630         {\r
631                 item.GetItem()->SetExcluded(false);\r
632                 RedrawFromParentNode(item.GetItem());\r
633         }\r
634 }\r
635 \r
636 wxTreeMultiItem wxTreeMultiCtrl::GetExcludedParent(const wxTreeMultiItem &item)\r
637 {\r
638         wxCHECK(item.IsOk(), wxTreeMultiItem(0));\r
639 \r
640         // go find the parent (including this one) that\r
641         // can be the excluded one\r
642 \r
643         TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();\r
644         if(n && n->IsExcluded())\r
645                 return wxTreeMultiItem(n);\r
646 \r
647         n = item.GetItem()->GetParent();\r
648         while(n)\r
649         {\r
650                 if(n->IsExcluded())\r
651                         return wxTreeMultiItem(n);\r
652                 else\r
653                         n = n->GetParent();\r
654         }\r
655 \r
656         return wxTreeMultiItem(0);\r
657 }\r
658 \r
659 void wxTreeMultiCtrl::OnSize(wxSizeEvent &WXUNUSED(event))\r
660 {\r
661         RecalculateSpanSizes();\r
662 }\r
663 \r
664 void wxTreeMultiCtrl::OnPaint(wxPaintEvent& WXUNUSED(event) )\r
665 {\r
666         wxPaintDC dc(this);\r
667 \r
668         PrepareDC(dc);\r
669 \r
670         // go recursive and draw the whole visible tree.\r
671         dc.SetFont(_captionFont);\r
672         for(int i = 0; i < _root.GetNodeCount(); i++)\r
673                 DrawNode(_root.GetNode(i), dc);\r
674 }\r
675 \r
676 void wxTreeMultiCtrl::DrawNode(TreeMultiItemBase *b, wxDC &dc)\r
677 {\r
678         // go through this item .. if it is a node, draw\r
679         // the caption, else reposition the window.\r
680 \r
681         if(!b)\r
682                 return;\r
683 \r
684         // forget it if this node is not visible\r
685         if(b->IsVisible())\r
686         {\r
687                 int bmpOffsetX = b->GetX() - (_gutterWidth + _iconWidth);\r
688 \r
689 #if(CHECKBOXVIEW)\r
690                 // now draw the checkbox if there is any, in the proper state\r
691                 if(b->GetCheckbox())\r
692                 {\r
693                         DrawCheckbox(b, dc);\r
694 \r
695                         // adjust the bmpOffset because we also have a checkbox\r
696                         bmpOffsetX -= _checkWidth;\r
697                 }\r
698 #endif\r
699 \r
700                 if(b->IsTreeMultiItemNode())\r
701                 {\r
702                         // draw the node icon and the caption\r
703                         TreeMultiItemNode *n = (TreeMultiItemNode *)b;\r
704 \r
705                  // set background of caption item\r
706                   if (n->IsSelected())\r
707                   {\r
708                     dc.SetBrush(*(this->m_HilightBrush));\r
709         dc.SetPen(wxPen(this->m_HilightBrush->GetColour(),1,wxSOLID));\r
710                   } /* if */\r
711                   else\r
712                   {\r
713                     dc.SetBrush(wxBrush(*wxWHITE,wxSOLID));\r
714         dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));\r
715                   } /* if */\r
716                   dc.DrawRectangle(n->GetX(),n->GetY(),n->GetWidth(),n->GetHeight());\r
717                  // draw caption\r
718                         dc.DrawText(n->GetCaption(), n->GetX(), n->GetY());\r
719 \r
720                         // draw the bitmap for the state\r
721                         if(n->IsExpanded())\r
722                                 dc.DrawBitmap(*_expandBmp, bmpOffsetX, n->GetY() + _iconDeltaY, true);\r
723                         else\r
724                                 dc.DrawBitmap(*_collBmp, bmpOffsetX, n->GetY() + _iconDeltaY, true);\r
725 \r
726                         // now go through all the subnodes\r
727                         for(int i = 0; i < n->GetNodeCount(); i++)\r
728                                 DrawNode(n->GetNode(i), dc);\r
729 \r
730                 }\r
731         }\r
732 }\r
733 \r
734 #if(CHECKBOXVIEW)\r
735 \r
736 void wxTreeMultiCtrl::DrawCheckbox(TreeMultiItemBase *b, wxDC &dc, bool convertScrolled)\r
737 {\r
738         wxCHECK2(b, return);\r
739 \r
740         wxBitmap *bmp;\r
741         int bmpOffsetX = b->GetX() - (_gutterWidth + _iconWidth);\r
742 \r
743         switch(b->GetCheckboxState())\r
744         {\r
745         case 0:\r
746                 bmp = _uncheckBmp;\r
747                 break;\r
748         case 1:\r
749                 bmp = _checkBmp;\r
750                 break;\r
751         default:\r
752                 bmp = _tristateBmp;\r
753                 break;\r
754         }\r
755 \r
756         int x, xx, y, yy;\r
757 \r
758         if(b->IsTreeMultiItemWindow())\r
759         {\r
760                 xx = x = bmpOffsetX - ((TreeMultiItemWindow *)b)->GetFrontSpacing() + _checkWidth;\r
761                 yy = y = b->GetY() + _checkDeltaY;\r
762         }\r
763         else\r
764         {\r
765                 xx = x = bmpOffsetX;\r
766                 yy = y = b->GetY() + _checkDeltaY;\r
767         }\r
768 \r
769         if(convertScrolled)\r
770                 CalcScrolledPosition(x, y, &xx, &yy);\r
771 \r
772         dc.DrawBitmap(*bmp, xx, yy, true);\r
773 }\r
774 \r
775 #endif // #if(CHECKBOXVIEW)\r
776 \r
777 void wxTreeMultiCtrl::OnKey(wxKeyEvent &event)\r
778 {\r
779         // check if we need to traverse to upper or lower\r
780         // control in the list\r
781         if(event.GetKeyCode() == WXK_TAB)\r
782         {\r
783                 wxTreeMultiItem item = GetFocus();\r
784                 if(item.IsOk())\r
785                 {\r
786                         // traverse down direction\r
787                         if(!event.ShiftDown())\r
788                                 item = FindNextVisibleWindowItem(item.GetItem());\r
789                         //else // traverse in up direction\r
790                         //      item = FindPreviousVisibleWindowItem(item);\r
791 \r
792                         if(item.IsOk())\r
793                         {\r
794                                 TreeMultiItemWindow *w = item.GetItem()->IsTreeMultiItemWindow();\r
795                                 if(w)\r
796                                 {\r
797                                         wxWindow *wnd = w->GetWindow();\r
798                                         wnd->SetFocus();\r
799                                 }\r
800                         }\r
801                 }\r
802         }\r
803         else\r
804                 event.Skip();\r
805 }\r
806 \r
807 void wxTreeMultiCtrl::OnMouseClick( wxMouseEvent &event )\r
808 {\r
809         // react on double click and left mouse down\r
810         if(event.LeftDown() || event.LeftDClick())\r
811         {\r
812                 // get translation point\r
813                 wxPoint pt( event.GetPosition() );\r
814 \r
815                 int x = 0, y = 0;\r
816                 CalcUnscrolledPosition( pt.x, pt.y, &x, &y );\r
817 \r
818                 // go check if we clicked a treenode\r
819                 int flags;\r
820                 wxPoint p(x,y);\r
821                 wxTreeMultiItem id = HitTest(p, flags);\r
822 \r
823 #if(CHECKBOXVIEW)\r
824                 if(flags == wxTMC_HITTEST_CHECKBOX)\r
825                 {\r
826                         // toggle the checkbox, and redraw\r
827                         if(id.IsOk())\r
828                         {\r
829                                 TreeMultiItemBase *b = id.GetItem();\r
830                                 b->SetCheckboxState((b->GetCheckboxState()+1) & 0x1);\r
831 \r
832                                 TreeMultiItemWindow *w = b->IsTreeMultiItemWindow();\r
833                                 if(w)\r
834                                 {\r
835                                         // try to force a focus on the window. This could\r
836                                         // be extended by searching for the first edit control\r
837                                         // class but for now, just a focus is tried.\r
838                                         w->GetWindow()->Enable(b->GetCheckboxState() == 1);\r
839                                         w->GetWindow()->SetFocus();\r
840 \r
841                                         // draw the checkbox in the state needed\r
842                                         wxClientDC dc(this);\r
843                                         DrawCheckbox(b, dc, true);\r
844 \r
845                                         // TODO: determine if the upper parents should be\r
846                                         // tristated or not\r
847 \r
848                                         ScanTristateCheckstates(b);\r
849 \r
850                                 }\r
851                                 else if(b->IsTreeMultiItemNode())\r
852                                 {\r
853                                         // descend to all the children and set the state of the parent\r
854                                         SetRecursiveCheckState((TreeMultiItemNode *)b, b->GetCheckboxState() == 1);\r
855                                         RedrawFromNode((TreeMultiItemNode *)b);\r
856                                 }\r
857                         }\r
858                 }\r
859                 else\r
860 #endif // #if(CHECKBOXVIEW)\r
861                 {\r
862                         // react on left mouse button, to fold and on\r
863                         // right for caption doubleclick\r
864                         int area = -1;\r
865 \r
866 // adjust behaviour for Linux (single click = always fold)\r
867 #ifndef LINUX\r
868                         if(event.LeftDClick())\r
869                                 area = wxTMC_HITTEST_CAPTION;\r
870                         else\r
871                                 area = wxTMC_HITTEST_GUTTER;\r
872 #else\r
873                         area = flags;\r
874 #endif\r
875 \r
876 // Linux (single or double click -> always fold\r
877       if (id.IsOk())\r
878       {\r
879 #ifdef LINUX\r
880                                 // we have a valid item, if it is a node, then fold\r
881                                 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode();\r
882                                 if(n)\r
883                                 {\r
884                                   this->SelectItem(id);\r
885                                         Fold(n, !n->IsExpanded());\r
886                                 } /* if */\r
887 #else\r
888         if (event.LeftDown())\r
889           if (flags == wxTMC_HITTEST_GUTTER)\r
890           {\r
891                                 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode(); // for some reasons also windows may have set the flag\r
892 \r
893             if (n != NULL)\r
894                                         Fold(n, !n->IsExpanded());\r
895           } /* if */\r
896           else if (flags == wxTMC_HITTEST_CAPTION)\r
897           {\r
898                                 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode(); // for some reasons also windows may have set the flag\r
899 \r
900                                 if (n != NULL)\r
901                                 {\r
902                                   this->SelectItem(id);\r
903                                 this->RedrawFromNode(n);\r
904                                 } /* if */\r
905           } /* if */\r
906 #endif\r
907       } /* if */\r
908       else\r
909         this->UnselectAll();\r
910                 }\r
911         }\r
912 }\r
913 \r
914 void wxTreeMultiCtrl::OnRightMouseClick(wxMouseEvent& Event)\r
915 {\r
916   if (Event.RightDown())\r
917     if (Event.Dragging())\r
918       this->UnselectAll();\r
919     else\r
920     {\r
921      // variable definitions:\r
922         int Flags;\r
923         wxPoint Point;\r
924 \r
925      // translate mouse coordinates:\r
926         CalcUnscrolledPosition(Event.GetPosition().x,Event.GetPosition().y,&(Point.x),&(Point.y));\r
927      // check if the mouse is above the caption of an item:\r
928       wxTreeMultiItem Item(this->HitTest(Point,Flags)); // variable definition and initialization\r
929 \r
930       if (Item.IsOk() && (Flags == wxTMC_HITTEST_CAPTION))\r
931       {\r
932         this->SelectItem(Item);\r
933                                 this->RedrawFromNode(Item.GetItem()->IsTreeMultiItemNode());\r
934           Event.Skip(); // window will convert right mouse click to a context menu event or proceed with\r
935                         // a right mouse click event if the context menu event cannot be processed\r
936       } /* if */\r
937       else\r
938         this->UnselectAll();\r
939     } /* if */\r
940   else\r
941     this->UnselectAll();\r
942 } /* wxTreeMultiCtrl::OnRightMouseClick(wxMouseEvent&) */\r
943 \r
944 wxTreeMultiItem wxTreeMultiCtrl::HitTest(wxPoint const& pt, int &flags)\r
945 {\r
946         // scan all nodes to see which one matches\r
947         TreeMultiItemBase *b = 0;\r
948         for(int i = 0; i < _root.GetNodeCount() && !b; i++)\r
949                 b = FindNodeByPoint(_root.GetNode(i), pt, flags);\r
950 \r
951         if(!b)\r
952         {\r
953                 // none found, reset\r
954                 flags = 0;\r
955                 return wxTreeMultiItem(0);\r
956         }\r
957 \r
958         // return an item\r
959         return wxTreeMultiItem(b);\r
960 }\r
961 \r
962 TreeMultiItemBase *wxTreeMultiCtrl::FindNodeByPoint(TreeMultiItemBase *b, wxPoint const& pt, int &area)\r
963 {\r
964         wxCHECK(b, 0);\r
965 \r
966         // if this layer is not visible, return with nothing.\r
967         if(!b->IsVisible())\r
968                 return 0;\r
969 \r
970         area = 0;\r
971 \r
972         // now see if our y is matching the mouse\r
973         if(pt.y >= b->GetY() && pt.y < (b->GetY() + b->GetHeight()))\r
974         {\r
975 #if(CHECKBOXVIEW)\r
976                 // if we are checkboxed, calculate the checkbox position\r
977                 if(b->GetCheckbox())\r
978                 {\r
979                         int extraSpacing = 0, extraWidth = 0;\r
980 \r
981                         // now for a windows item, this is minus the gutter. For a normal node it is X minus checkbox\r
982                         if(b->IsTreeMultiItemWindow())\r
983                         {\r
984                             extraWidth = _checkWidth;\r
985                                 extraSpacing = ((TreeMultiItemWindow *)b)->GetFrontSpacing();\r
986                         }\r
987                         else\r
988                                 extraSpacing = 4;\r
989 \r
990                         if(pt.x > (b->GetX() - extraSpacing - _checkWidth) && pt.x < (b->GetX() - extraSpacing + extraWidth))\r
991                         {\r
992                                 area = wxTMC_HITTEST_CHECKBOX;\r
993                                 return b;\r
994                         }\r
995                 }\r
996 #endif\r
997 \r
998                 // allrighty we have something, now where and what is it (look with x)\r
999                 if(pt.x < b->GetX())\r
1000                         area = wxTMC_HITTEST_GUTTER;\r
1001 \r
1002                 /** \todo Match only the real part of the caption, window (we assume x > GetX() which is the rest)\r
1003                         HOWEVER the window probably doesn't propagate the click event back to the parent, so we might\r
1004                         leave it like this so the use can click behind a window so it will be selected.\r
1005                 */\r
1006                 else\r
1007                 {\r
1008                         // inside area, return proper flag\r
1009                         if(b->IsTreeMultiItemNode())\r
1010                                 area = wxTMC_HITTEST_CAPTION;\r
1011                         else\r
1012                                 area = wxTMC_HITTEST_WINDOW;\r
1013                 }\r
1014 \r
1015                 return b;\r
1016         }\r
1017         else\r
1018         {\r
1019                 // not found, let's try our children if we have some\r
1020                 TreeMultiItemNode *n = b->IsTreeMultiItemNode();\r
1021                 if(n)\r
1022                 {\r
1023                         TreeMultiItemBase *bb = 0;\r
1024                         for(int i = 0; i < n->GetNodeCount() && !bb; i++)\r
1025                                 bb = FindNodeByPoint(n->GetNode(i), pt, area);\r
1026 \r
1027                         // keep returning result to caller\r
1028                         return bb;\r
1029                 }\r
1030         }\r
1031 \r
1032         return 0;\r
1033 }\r
1034 \r
1035 wxTreeMultiItem wxTreeMultiCtrl::GetFocus()\r
1036 {\r
1037         wxWindow *wnd = wxWindow::FindFocus();\r
1038 \r
1039         // now find window that holds this item. if not\r
1040         // visible it cannot have focus (should not have)\r
1041 \r
1042         wxTreeMultiItem item = FindWindowNode(wnd);\r
1043         if(item.IsOk() && item.GetItem()->IsVisible())\r
1044                 return item;\r
1045 \r
1046         return wxTreeMultiItem(0);\r
1047 }\r
1048 \r
1049 #if(CHECKBOXVIEW)\r
1050 \r
1051 void wxTreeMultiCtrl::SetRecursiveCheckState(TreeMultiItemNode *n, bool check)\r
1052 {\r
1053         int state = 0;\r
1054         if(check)\r
1055                 state++;\r
1056 \r
1057         // go check all kids on this level\r
1058         for(int i = 0; i < n->GetNodeCount(); i++)\r
1059         {\r
1060                 // check all the nodes, and go deeper\r
1061                 n->GetNode(i)->SetCheckboxState(state);\r
1062                 if(n->GetNode(i)->IsTreeMultiItemNode())\r
1063                         SetRecursiveCheckState((TreeMultiItemNode *)n->GetNode(i), check);\r
1064         }\r
1065 }\r
1066 \r
1067 void wxTreeMultiCtrl::ScanTristateCheckstates(TreeMultiItemBase *b)\r
1068 {\r
1069         // check from the parent on, all node entries and see if they are\r
1070         // checked or cleared or scattered\r
1071         TreeMultiItemNode *p = b->GetParent();\r
1072 \r
1073         if(p && p->GetCheckbox())\r
1074         {\r
1075                 bool foundcheck = false, foundclear = false;\r
1076                 for(size_t i = 0; i < (size_t)p->GetNodeCount(); ++i)\r
1077                 {\r
1078                         // only evaluate when checkboxed\r
1079                         if(p->GetNode(i)->IsTreeMultiItemWindow() && p->GetNode(i)->GetCheckbox())\r
1080                         {\r
1081                                 // record instance of a cleared checkbox\r
1082                                 if(!p->GetNode(i)->GetCheckboxState())\r
1083                                         foundclear = true;\r
1084                                 // record instance of checked checkbox\r
1085                                 if(p->GetNode(i)->GetCheckboxState() == 1)\r
1086                                         foundcheck = true;\r
1087                         }\r
1088                 }\r
1089 \r
1090                 // if we have both check and clear, go tristate\r
1091                 // if all clear, clear parent and if all set, then set parent\r
1092                 if(foundclear && !foundcheck)\r
1093                         p->SetCheckboxState(0);\r
1094                 else if(!foundclear && foundcheck)\r
1095                         p->SetCheckboxState(1);\r
1096                 else if(foundclear && foundcheck)\r
1097                         p->SetCheckboxState(2);\r
1098 \r
1099                 //wxClientDC dc;\r
1100                 //DrawCheckbox(p, dc, false);\r
1101                 RedrawFromNode(p);\r
1102         }\r
1103 }\r
1104 \r
1105 #endif // #if(CHECKBOXVIEW)\r
1106 \r
1107 wxTreeMultiItem wxTreeMultiCtrl::InsertNode(TreeMultiItemNode* ParentPtr, size_t Position, wxString const& Caption, wxString const& Name)\r
1108 {\r
1109         int extX, extY;\r
1110 \r
1111   TreeMultiItemNode* NodePtr(new TreeMultiItemNode(ParentPtr,Caption,Name)); // generate new node pointer\r
1112 \r
1113 \r
1114  // continue with initializing the new node:\r
1115 #if(CHECKBOXVIEW)\r
1116  // if checkbox view is desired, tag this item as a checkbox\r
1117  // and set the state as 'false'\r
1118         NodePtr->SetCheckbox(_checkboxView);\r
1119         NodePtr->SetCheckboxState(0);\r
1120 #endif\r
1121  // calculate the height and width\r
1122         this->GetTextExtent(Caption,&extX,&extY,0,0,&(this->_captionFont));\r
1123         NodePtr->SetHeight(extY);\r
1124         NodePtr->SetWidth(extX);\r
1125  // finally, insert node:\r
1126   if (Position < (size_t)ParentPtr->GetNodeCount())\r
1127     ParentPtr->InsertNode(NodePtr,Position);\r
1128   else\r
1129     ParentPtr->AddNode(NodePtr);\r
1130  // return the newly created node:\r
1131   return wxTreeMultiItem(NodePtr);\r
1132 } /* wxTreeMultiCtrl::InsertNode(TreeMultiItemNode*, size_t, wxString const&, wxString const&) */\r
1133 \r
1134 wxTreeMultiItem wxTreeMultiCtrl::InsertWindow(TreeMultiItemNode* ParentPtr, size_t Position, wxWindow* WindowPtr, wxString const& Name, wxTreeMultiWindowInfo const& Info, int Flags)\r
1135 {\r
1136   int WindowFlags;\r
1137 \r
1138         TreeMultiItemWindow* NewWindowPtr = new TreeMultiItemWindow(ParentPtr,Name); // generate new window pointer\r
1139 \r
1140 \r
1141  // get flags from passed variable "Flags"; in case this variable does not contain any flags use the window's information flags:\r
1142   if (Flags != 0)\r
1143     WindowFlags = Flags;\r
1144   else\r
1145     WindowFlags = Info.GetFlags();\r
1146 \r
1147  // continue with initializing the new window:\r
1148 #if(CHECKBOXVIEW)\r
1149         // if checkbox view is desired, tag this item as a checkbox\r
1150         // and set the state as 'false'\r
1151         NewWindowPtr->SetCheckbox(_checkboxView);\r
1152 #endif\r
1153  // if style wants us to change background, set it to our background\r
1154         if (WindowFlags & wxTMC_BG_ADJUST_ALL)\r
1155         {\r
1156                 // go through all children of this window, and set the\r
1157                 // background of it (recursively)\r
1158                 this->SetWindowBackgroundColour(WindowPtr,this->GetBackgroundColour(),WindowFlags);\r
1159         } /* if */\r
1160 \r
1161  // set the spacing:\r
1162         NewWindowPtr->SetTopSpacing(Info.GetTopSpacing());\r
1163 #if(CHECKBOXVIEW)\r
1164         // make sure that the checkboxes are at least indented enough\r
1165         if (this->_checkboxView)\r
1166                 NewWindowPtr->SetFrontSpacing(Info.GetFrontSpacing() + this->_checkWidth);\r
1167         else\r
1168 #endif\r
1169                 NewWindowPtr->SetFrontSpacing(Info.GetFrontSpacing());\r
1170  // assign finally the window:\r
1171         NewWindowPtr->AssignWindow(WindowPtr);\r
1172 \r
1173 #if(CHECKBOXVIEW)\r
1174  // set the checkbox state after the window is assigned\r
1175         NewWindowPtr->SetCheckboxState(Info.GetDefaultCheckState());\r
1176 #endif\r
1177 \r
1178  // if the window is not visible, set hide flag\r
1179         this->ShowTreeMultiWindow(NewWindowPtr,NewWindowPtr->IsVisible());\r
1180 \r
1181  // finally, insert the newly constructed window:\r
1182   if (Position < (size_t)ParentPtr->GetNodeCount())\r
1183     ParentPtr->InsertNode(NewWindowPtr,Position);\r
1184   else\r
1185     ParentPtr->AddNode(NewWindowPtr);\r
1186  // return the newly created window:\r
1187         return wxTreeMultiItem(NewWindowPtr);\r
1188 } /* wxTreeMultiCtrl::InsertWindow(TreeMultiItemNode*, size_t, wxWindow*, wxString const&, wxTreeMultiWindowInfo const&, int) */\r
1189 \r
1190 void wxTreeMultiCtrl::RedrawFromParentNode(TreeMultiItemBase *n)\r
1191 {\r
1192         TreeMultiItemNode *p = 0;\r
1193         if(n)\r
1194                 p = n->GetParent();\r
1195 \r
1196         RedrawFromNode(p);\r
1197 }\r
1198 \r
1199 void wxTreeMultiCtrl::RedrawFromNode(TreeMultiItemNode *n)\r
1200 {\r
1201         static int recalcMutex = 0;\r
1202         bool visible = true;\r
1203 \r
1204         if(recalcMutex > 0)\r
1205                 return;\r
1206 \r
1207         recalcMutex ++;\r
1208 \r
1209         // when node is not visible or excluded\r
1210         // then don't redraw.\r
1211 \r
1212         if(n)\r
1213                 visible = n->IsVisible();\r
1214 \r
1215         if(visible)\r
1216         {\r
1217                 int h, h1,w, w1;\r
1218                 GetVirtualSize(&w, &h);\r
1219 \r
1220                 UpdateAllWindowVisibility();\r
1221                 RecalculateNodePositions();\r
1222                 RecalculateVirtualSize();\r
1223 \r
1224                 // why is this needed? Because folding or collapsing can change\r
1225                 // the state. When the virtual area gets smaller, we need to keep\r
1226                 // the largest one and the other way atound. And since we do not\r
1227                 // know here we are folding or collapsing, we remember the biggest\r
1228                 GetVirtualSize(&w1, &h1);\r
1229 \r
1230                 if(h1 > h)\r
1231                         h = h1;\r
1232 \r
1233                 // only refresh the part from x,y down\r
1234                 if(n)\r
1235                 {\r
1236                         int x, y;\r
1237                         CalcScrolledPosition(n->GetX(), n->GetY(), &x, &y);\r
1238                         if(h - y > 0)\r
1239                         {\r
1240                                 wxRect rect(0, y, w, h - y);\r
1241                                 RefreshRect(rect);\r
1242                         }\r
1243                         else\r
1244                                 Refresh();\r
1245                 }\r
1246                 else\r
1247                         Refresh();      // do a full refresh\r
1248         }\r
1249 \r
1250         recalcMutex --;\r
1251 }\r
1252 \r
1253 void wxTreeMultiCtrl::RecalculateNodePositions()\r
1254 {\r
1255         int currentY = _spacingY;\r
1256         // go recursive on every node, and store the information in the node\r
1257 \r
1258         for(int i = 0; i < _root.GetNodeCount(); i++)\r
1259         currentY += CalculateNodeDimensions(_root.GetNode(i), currentY, 0);\r
1260 }\r
1261 \r
1262 int wxTreeMultiCtrl::CalculateNodeDimensions(TreeMultiItemBase *b, int currentY, int level)\r
1263 {\r
1264         int gutter = (_gutterWidth * 2) + _iconWidth;\r
1265         int y = 0, topSpacing = 0;\r
1266 \r
1267         // return same if no proper object\r
1268         wxCHECK(b, 0);\r
1269 \r
1270 #if(CHECKBOXVIEW)\r
1271         if(b->GetCheckbox())\r
1272                 gutter += _checkWidth;\r
1273 #endif\r
1274 \r
1275         // if we are not visible, skip recalculation and descending\r
1276         if(b->IsVisible())\r
1277         {\r
1278                 b->SetY(currentY);\r
1279 \r
1280                 // if level is 0, calculate with front gutter, else without\r
1281                 y = currentY + b->GetHeight();\r
1282                 if(b->IsTreeMultiItemNode())\r
1283                 {\r
1284                         TreeMultiItemNode *n = (TreeMultiItemNode *)b;\r
1285 \r
1286                         if(level == 0)\r
1287                                 b->SetX(gutter);\r
1288                         else\r
1289                                 b->SetX(gutter + (level * (_gutterWidth + _iconWidth)));\r
1290 \r
1291                         // now do children of this node\r
1292 \r
1293                         for(int i = 0; i < n->GetNodeCount(); i++)\r
1294                                 y += CalculateNodeDimensions(n->GetNode(i), y + _spacingY, level+1);\r
1295                 }\r
1296                 else if(b->IsTreeMultiItemWindow())\r
1297                 {\r
1298                         TreeMultiItemWindow *w = (TreeMultiItemWindow *)b;\r
1299 \r
1300                         if(level == 0)\r
1301                                 b->SetX(gutter + w->GetFrontSpacing());\r
1302                         else\r
1303                                 b->SetX(_gutterWidth + (level * (_gutterWidth + _iconWidth)) + w->GetFrontSpacing());\r
1304 \r
1305                         topSpacing = w->GetTopSpacing();\r
1306 \r
1307                         // reposition the window\r
1308 \r
1309                         wxWindow *wnd = w->GetWindow();\r
1310                         if(wnd)\r
1311                         {\r
1312                                 int x = 0, y = 0;\r
1313                                 CalcScrolledPosition(w->GetX(), w->GetY(), &x, &y);\r
1314                                 wnd->SetSize(x, y, w->GetWidth(), w->GetHeight());\r
1315                         }\r
1316                 }\r
1317 \r
1318                 if(y > 0)\r
1319                         return (y - currentY) + _spacingY + topSpacing; // return delta\r
1320                 else\r
1321                         return 0;\r
1322         }\r
1323 \r
1324         return 0;       // not visible, thus we skip calculations\r
1325 }\r
1326 \r
1327 void wxTreeMultiCtrl::RecalculateSpanSizes()\r
1328 {\r
1329         for(int i = 0; i < _root.GetNodeCount(); i++)\r
1330         CalculateNodeSpanning(_root.GetNode(i));\r
1331 }\r
1332 \r
1333 void wxTreeMultiCtrl::CalculateNodeSpanning(TreeMultiItemBase *b)\r
1334 {\r
1335         // return same if no proper object\r
1336         wxCHECK2(b, return);\r
1337 \r
1338         if(b->IsTreeMultiItemNode())\r
1339         {\r
1340                 TreeMultiItemNode *n = (TreeMultiItemNode *)b;\r
1341 \r
1342                 // now do children of this node\r
1343 \r
1344                 for(int i = 0; i < n->GetNodeCount(); i++)\r
1345                         CalculateNodeSpanning(n->GetNode(i));\r
1346         }\r
1347         else if(b->IsTreeMultiItemWindow())\r
1348         {\r
1349                 TreeMultiItemWindow *w = (TreeMultiItemWindow *)b;\r
1350                 wxWindow *wnd = w->GetWindow();\r
1351                 if(wnd)\r
1352                 {\r
1353                         // if the window is spanning, we adjust the width to the max width of the control\r
1354                         if(w->GetHorizontalSpan())\r
1355                         {\r
1356                                 wxSize tmcsize = GetClientSize();\r
1357                                 int maxwidth = tmcsize.GetWidth() - w->GetX() - 8; // extract 3 for border\r
1358 \r
1359                                 wxSizer *sz = wnd->GetSizer();\r
1360                                 if(sz)\r
1361                                 {\r
1362                                         if(maxwidth < sz->GetMinSize().GetWidth())\r
1363                                                 maxwidth = sz->GetMinSize().GetWidth();\r
1364                                 }\r
1365 \r
1366                                 // prevent a size of 0\r
1367                                 if(maxwidth < 1)\r
1368                                         maxwidth = 1;\r
1369 \r
1370                                 // set the size\r
1371                                 w->SetWidth(maxwidth);\r
1372                                 wnd->SetSize(w->GetWidth(), w->GetHeight());\r
1373 \r
1374                                 // layout by sizer (not sure if this is needed)\r
1375                                 if(wnd->GetSizer())\r
1376                                         wnd->GetSizer()->Layout();\r
1377                         }\r
1378                 }\r
1379         }\r
1380 }\r
1381 \r
1382 void wxTreeMultiCtrl::RecalculateVirtualSize()\r
1383 {\r
1384         // go through all the nodes, and store the largest x and largest y\r
1385 \r
1386         int x = 0, y = 0;\r
1387         RecalculateVirtualSizeFromNode(&_root, x, y);\r
1388 \r
1389         // now adjust virtual size\r
1390         SetVirtualSize(x, y);\r
1391         AdjustScrollbars(x, y);\r
1392 }\r
1393 \r
1394 void wxTreeMultiCtrl::AdjustScrollbars(int x, int y)\r
1395 {\r
1396         // adjust scrollbars\r
1397         // courtesy of treectrlg.cpp\r
1398 \r
1399         y += WXTMC_PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels\r
1400     x += WXTMC_PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels\r
1401     int x_pos = GetScrollPos( wxHORIZONTAL );\r
1402     int y_pos = GetScrollPos( wxVERTICAL );\r
1403     SetScrollbars( WXTMC_PIXELS_PER_UNIT, WXTMC_PIXELS_PER_UNIT, x/WXTMC_PIXELS_PER_UNIT,\r
1404                            y/WXTMC_PIXELS_PER_UNIT, x_pos, y_pos, true );\r
1405 }\r
1406 \r
1407 void wxTreeMultiCtrl::RecalculateVirtualSizeFromNode(const TreeMultiItemNode *node, int &x, int &y)\r
1408 {\r
1409         if(node->IsExcluded())\r
1410                 return;\r
1411 \r
1412         // if calulate this node's dimensions\r
1413         if(x < (node->GetWidth() + node->GetX()))\r
1414                 x = node->GetWidth() + node->GetX();\r
1415 \r
1416         y = node->GetY() + node->GetHeight();\r
1417 \r
1418         // if this node is collapsed, no subnodes are visible, else\r
1419         // go through all subnodes as well, node needs to be included as well\r
1420         if(node->IsExpanded())\r
1421         {\r
1422                 TreeMultiItemBase *b;\r
1423                 for(int i = 0; i < node->GetNodeCount(); i++)\r
1424                 {\r
1425                         b = node->GetNode(i);\r
1426 \r
1427                         // calculate x and y\r
1428                         if(x < (b->GetWidth() + b->GetX()))\r
1429                                 x = b->GetWidth() + b->GetX();\r
1430 \r
1431                         y = b->GetY() + b->GetHeight();\r
1432 \r
1433                         if(b->IsTreeMultiItemNode())\r
1434                                 RecalculateVirtualSizeFromNode((TreeMultiItemNode *)b, x, y);\r
1435                 }\r
1436         }\r
1437 }\r
1438 \r
1439 void wxTreeMultiCtrl::SetWindowBackgroundColour(wxWindow *wnd, const wxColour &col, int flags)\r
1440 {\r
1441         if(wnd)\r
1442         {\r
1443                 // if we cannot change a button, make sure all button\r
1444                 // classes are not changed\r
1445 \r
1446                 wxButton *btn = wxDynamicCast(wnd, wxButton);\r
1447                 if(!btn || ((flags & wxTMC_BG_ADJUST_BTN) != 0))\r
1448                         wnd->SetBackgroundColour(col);\r
1449 \r
1450                 // get every window, and make the background equal to the given one\r
1451                 wxWindowListNode *node = wnd->GetChildren().GetFirst();\r
1452                 while (node)\r
1453                 {\r
1454                         SetWindowBackgroundColour(node->GetData(), col, flags);\r
1455                         node = node->GetNext();\r
1456                 }\r
1457         }\r
1458 }\r
1459 \r
1460 void wxTreeMultiCtrl::ShowTreeMultiWindow(TreeMultiItemWindow *window, bool show)\r
1461 {\r
1462         // show or hide window\r
1463         if(window && window->GetWindow())\r
1464                 window->GetWindow()->Show(show);\r
1465 }\r
1466 \r
1467 void wxTreeMultiCtrl::UpdateAllWindowVisibility()\r
1468 {\r
1469         // all roots are visible, but what lies beneath ... who knows\r
1470         for(int i = 0; i < _root.GetNodeCount(); i++)\r
1471                 UpdateTreeMultiWindowVisibility(_root.GetNode(i), true);\r
1472 }\r
1473 \r
1474 void wxTreeMultiCtrl::UpdateTreeMultiWindowVisibility(TreeMultiItemBase *b, bool show)\r
1475 {\r
1476         if(b)\r
1477         {\r
1478                 // this is done for performance issues. IsVisible can go all\r
1479                 // the way up the tree to check. However if show is already\r
1480                 // false, there is no need to check (some higher one is collapsed)\r
1481                 bool showMe = show;\r
1482 \r
1483                 if(showMe)\r
1484                         showMe = b->IsVisible();\r
1485 \r
1486                 if(b->IsTreeMultiItemWindow())\r
1487                 {\r
1488                         // if this level must be hidden, hide\r
1489                         ShowTreeMultiWindow((TreeMultiItemWindow*)b, showMe);\r
1490                 }\r
1491                 else if(b->IsTreeMultiItemNode())\r
1492                 {\r
1493                         TreeMultiItemNode *node = (TreeMultiItemNode *)b;\r
1494 \r
1495                         // if hidden, descend and hide all windows\r
1496                         for(int i = 0; i < node->GetNodeCount(); i++)\r
1497                                 UpdateTreeMultiWindowVisibility(node->GetNode(i), showMe);\r
1498                 }\r
1499         }\r
1500 }\r
1501 \r
1502 wxTreeMultiItem wxTreeMultiCtrl::FindItem(const wxTreeMultiItem &item, const wxString &name, bool ignoreCase, bool skipFirst)\r
1503 {\r
1504         if(item.IsOk())\r
1505         {\r
1506                 TreeMultiItemBase *b = item.GetItem();\r
1507 \r
1508                 // check this item first (or not)\r
1509 \r
1510                 if(!skipFirst)\r
1511                 {\r
1512                         if(b->GetName().IsSameAs(name, !ignoreCase))\r
1513                                 return wxTreeMultiItem(b);\r
1514                 }\r
1515 \r
1516                 if(b->IsTreeMultiItemNode())\r
1517                 {\r
1518                         // now check whether we are a node, then go check children\r
1519 \r
1520                         TreeMultiItemNode *n = (TreeMultiItemNode *)b;\r
1521                         wxTreeMultiItem result(0);\r
1522                         for(int i = 0; i < n->GetNodeCount() && !result.IsOk(); i++)\r
1523                                 result = FindItem(wxTreeMultiItem(n->GetNode(i)), name, ignoreCase, false);\r
1524 \r
1525                         return result;\r
1526                 }\r
1527         }\r
1528 \r
1529         return wxTreeMultiItem(0);\r
1530 }\r
1531 \r
1532 wxTreeMultiItem wxTreeMultiCtrl::FindWindowNode(wxWindow *wnd, TreeMultiItemNode *n)\r
1533 {\r
1534         wxCHECK(wnd, wxTreeMultiItem(0));\r
1535 \r
1536         // take root node if not assigned one\r
1537 \r
1538         if(!n)\r
1539                 n = (TreeMultiItemNode *)&_root;\r
1540 \r
1541         // check on this level for the wxWindow pointer\r
1542 \r
1543         TreeMultiItemWindow *w;\r
1544         wxTreeMultiItem result(0);\r
1545         for(int i = 0; i < n->GetNodeCount() && !result.IsOk(); i++)\r
1546         {\r
1547                 // if window node\r
1548                 w = n->GetNode(i)->IsTreeMultiItemWindow();\r
1549                 if(w && w->GetWindow() == wnd)\r
1550                         return wxTreeMultiItem(n);\r
1551 \r
1552                 // if node, go deeper\r
1553                 if(n->GetNode(i)->IsTreeMultiItemNode())\r
1554                         result = FindWindowNode(wnd, (TreeMultiItemNode*)n->GetNode(i));\r
1555         }\r
1556 \r
1557         return result;\r
1558 }\r
1559 \r
1560 TreeMultiItemWindow *wxTreeMultiCtrl::FindNextVisibleWindowItem(TreeMultiItemBase *b, int index)\r
1561 {\r
1562         wxCHECK(b, 0);\r
1563 \r
1564         // check on this level, go deeper with every node we got. When a node is not\r
1565         // visible anymore, skip the node.\r
1566 \r
1567         TreeMultiItemWindow *value = 0;\r
1568         if(b->IsVisible())\r
1569         {\r
1570                 // if we are already searching on a node with an index\r
1571 \r
1572                 TreeMultiItemBase *bn = 0;\r
1573                 TreeMultiItemNode *n = b->IsTreeMultiItemNode();\r
1574                 if(n)\r
1575                 {\r
1576                         for(int i = index + 1; i < n->GetNodeCount() && !value; i++)\r
1577                         {\r
1578                                 bn = n->GetNode(i);\r
1579                                 value = bn->IsTreeMultiItemWindow();\r
1580 \r
1581                                 // assume a node, root when not a a window\r
1582                                 if(!value)\r
1583                                         value = FindNextVisibleWindowItem(bn, -1);\r
1584                         }\r
1585 \r
1586                 }\r
1587                 else\r
1588                 {\r
1589                         if(b->IsTreeMultiItemWindow())\r
1590                         {\r
1591                                 // get parent first, and locate child as ptr\r
1592                                 TreeMultiItemNode *p = b->GetParent();\r
1593                                 wxCHECK(p, 0);\r
1594 \r
1595                                 // go scan the parent from the given index, if\r
1596                                 // the index is valid else there is no child with that index\r
1597 \r
1598                                 int idx = p->Index(b);\r
1599                                 wxCHECK(idx >= 0, 0);\r
1600 \r
1601                                 value = FindNextVisibleWindowItem(p, idx);\r
1602                         }\r
1603                 }\r
1604         }\r
1605 \r
1606         return value;\r
1607 \r
1608 }\r
1609 \r
1610 bool wxTreeMultiCtrl::GetBooleanValue(int wndId)\r
1611 {\r
1612         wxWindow *wnd = wxWindow::FindWindow(wndId);\r
1613         wxCHECK(wnd, false);\r
1614 \r
1615         // try a radio button\r
1616         wxRadioButton *b = wxDynamicCast(wnd, wxRadioButton);\r
1617         if(b)\r
1618                 return b->GetValue();\r
1619 \r
1620         // try a check box\r
1621         wxCheckBox *c = wxDynamicCast(wnd, wxCheckBox);\r
1622         if(c)\r
1623                 return c->GetValue();\r
1624 \r
1625         /** \todo For custom controls we should put something in wxMultiTreeItemData class\r
1626             which can be overridden to retrieve the boolean value. It will also be passed\r
1627             the pointer to the window, so the derived class can figure out how to get a boolean\r
1628             value.\r
1629         */\r
1630 \r
1631         // generate assert or just return with false\r
1632         wxCHECK(0, false);\r
1633 }\r
1634 \r
1635 void wxTreeMultiCtrl::SetBooleanValue(int wndId, bool value)\r
1636 {\r
1637         wxWindow *wnd = wxWindow::FindWindow(wndId);\r
1638         wxCHECK2(wnd, return);\r
1639 \r
1640         // try a radio button\r
1641         wxRadioButton *b = wxDynamicCast(wnd, wxRadioButton);\r
1642         if(b)\r
1643         {\r
1644                 b->SetValue(value);\r
1645                 return;\r
1646         }\r
1647 \r
1648         // try a check box\r
1649         wxCheckBox *c = wxDynamicCast(wnd, wxCheckBox);\r
1650         if(c)\r
1651         {\r
1652                 c->SetValue(value);\r
1653                 return;\r
1654         }\r
1655 \r
1656         /** \todo For custom controls we should put something in wxMultiTreeItemData class\r
1657                     which can be overridden to retrieve the boolean value. It will also be passed\r
1658                     the pointer to the window, so the derived class can figure out how to get a boolean\r
1659                     value.\r
1660         */\r
1661 \r
1662         // generate assert\r
1663         wxCHECK2(0, return);\r
1664 }\r
1665 \r
1666 void wxTreeMultiCtrl::SetTextValue(int wndId, const wxString &value)\r
1667 {\r
1668         wxWindow *wnd = wxWindow::FindWindow(wndId);\r
1669         wxCHECK2(wnd, return);\r
1670 \r
1671         // try a radio button\r
1672         wxTextCtrl *t = wxDynamicCast(wnd, wxTextCtrl);\r
1673         if(t)\r
1674         {\r
1675                 t->SetValue(value);\r
1676                 return;\r
1677         }\r
1678 \r
1679         /** \todo For custom controls we should put something in wxMultiTreeItemData class\r
1680                     which can be overridden to retrieve the boolean value. It will also be passed\r
1681                     the pointer to the window, so the derived class can figure out how to get a boolean\r
1682                     value.\r
1683         */\r
1684 \r
1685         // generate assert\r
1686         wxCHECK2(0, return);\r
1687 }\r
1688 \r
1689 wxString wxTreeMultiCtrl::GetTextValue(int wndId)\r
1690 {\r
1691         wxWindow *wnd = wxWindow::FindWindow(wndId);\r
1692         wxCHECK(wnd, wxEmptyString);\r
1693 \r
1694         // try a radio button\r
1695         wxTextCtrl *t = wxDynamicCast(wnd, wxTextCtrl);\r
1696         if(t)\r
1697                 return t->GetValue();\r
1698 \r
1699         // try a choice box\r
1700         wxChoice *c1 = wxDynamicCast(wnd, wxChoice);\r
1701         if(c1)\r
1702                 return c1->GetStringSelection();\r
1703 \r
1704         // try a combo box\r
1705         wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);\r
1706         if(c2)\r
1707                 return c2->GetStringSelection();\r
1708 \r
1709         // try a listbox\r
1710         wxListBox *l = wxDynamicCast(wnd, wxListBox);\r
1711         if(l)\r
1712                 return l->GetStringSelection();\r
1713 \r
1714         /** \todo For custom controls we should put something in wxMultiTreeItemData class\r
1715             which can be overridden to retrieve the boolean value. It will also be passed\r
1716             the pointer to the window, so the derived class can figure out how to get a boolean\r
1717             value.\r
1718         */\r
1719 \r
1720         // generate assert or just return with string\r
1721         wxCHECK(0, wxEmptyString);\r
1722 }\r
1723 \r
1724 int wxTreeMultiCtrl::GetSelectionValue(int wndId)\r
1725 {\r
1726         wxWindow *wnd = wxWindow::FindWindow(wndId);\r
1727         wxCHECK(wnd, -1);\r
1728 \r
1729         // try a choice box\r
1730         wxChoice *c1 = wxDynamicCast(wnd, wxChoice);\r
1731         if(c1)\r
1732                 return c1->GetSelection();\r
1733 \r
1734         // try a combo box\r
1735         wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);\r
1736         if(c2)\r
1737                 return c2->GetSelection();\r
1738 \r
1739         // try a listbox\r
1740         wxListBox *l = wxDynamicCast(wnd, wxListBox);\r
1741         if(l)\r
1742                 return l->GetSelection();\r
1743 \r
1744         /** \todo For custom controls we should put something in wxMultiTreeItemData class\r
1745             which can be overridden to retrieve the boolean value. It will also be passed\r
1746             the pointer to the window, so the derived class can figure out how to get a boolean\r
1747             value.\r
1748         */\r
1749 \r
1750         // generate assert or just return with string\r
1751         wxCHECK(0, -1);\r
1752 }\r
1753 \r
1754 void wxTreeMultiCtrl::GetSelectionValues(int wndId, wxArrayInt &sels)\r
1755 {\r
1756         sels.Clear();\r
1757 \r
1758         wxWindow *wnd = wxWindow::FindWindow(wndId);\r
1759         wxCHECK2(wnd, return);\r
1760 \r
1761         // try a listbox\r
1762         wxListBox *l = wxDynamicCast(wnd, wxListBox);\r
1763         if(l)\r
1764         {\r
1765                 l->GetSelections(sels);\r
1766                 return;\r
1767         }\r
1768 \r
1769         /** \todo For custom controls we should put something in wxMultiTreeItemData class\r
1770             which can be overridden to retrieve the boolean value. It will also be passed\r
1771             the pointer to the window, so the derived class can figure out how to get a boolean\r
1772             value.\r
1773         */\r
1774 \r
1775         // generate assert or just return with string\r
1776         wxCHECK2(0, return);\r
1777 }\r
1778 \r
1779 void wxTreeMultiCtrl::SetSelectionValue(int wndId, int sel)\r
1780 {\r
1781         wxWindow *wnd = wxWindow::FindWindow(wndId);\r
1782         wxCHECK2(wnd, return);\r
1783 \r
1784         // try a choice box\r
1785         wxChoice *c1 = wxDynamicCast(wnd, wxChoice);\r
1786         if(c1)\r
1787         {\r
1788                 c1->SetSelection(sel);\r
1789                 return;\r
1790         }\r
1791 \r
1792         // try a combo box\r
1793         wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);\r
1794         if(c2)\r
1795         {\r
1796                 c2->SetSelection(sel);\r
1797                 return;\r
1798         }\r
1799 \r
1800         // try a listbox\r
1801         wxListBox *l = wxDynamicCast(wnd, wxListBox);\r
1802         if(l)\r
1803         {\r
1804                 l->SetSelection(sel);\r
1805                 return;\r
1806         }\r
1807 \r
1808         /** \todo For custom controls we should put something in wxMultiTreeItemData class\r
1809             which can be overridden to retrieve the boolean value. It will also be passed\r
1810             the pointer to the window, so the derived class can figure out how to get a boolean\r
1811             value.\r
1812         */\r
1813 \r
1814         // generate assert or just return with string\r
1815         wxCHECK2(0, return);\r
1816 }\r
1817 \r
1818 \r
1819 wxTreeMultiItem wxTreeMultiCtrl::GetParent(wxTreeMultiItem const& item) const\r
1820 {\r
1821  // check if valid or root item has been passed, both do not have parents:\r
1822   if (!(item.IsOk()) || item.GetItem()->IsTreeMultiItemRoot())\r
1823     return wxTreeMultiItem();\r
1824   else\r
1825     return wxTreeMultiItem(item.GetItem()->GetParent()); // GetParent() returns a valid pointer in case of a root item!!\r
1826                                                          // therefore, the check if the passed item is a root item is necessary\r
1827 } /* wxTreeMultiCtrl::GetParent(wxTreeMultiItem const& item) const */\r
1828 \r
1829 wxTreeMultiItem wxTreeMultiCtrl::GetFirstChild(const wxTreeMultiItem &item, int &cookie) const\r
1830 {\r
1831         if(item.IsNodeItem())\r
1832         {\r
1833                 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();\r
1834 \r
1835                 if(n->GetNodeCount() > 0)\r
1836                 {\r
1837                         cookie = 0;\r
1838                         return wxTreeMultiItem(n->GetNode(0));\r
1839                 }\r
1840         }\r
1841 \r
1842         // no children or no valid node\r
1843         cookie = -1;\r
1844         return wxTreeMultiItem(0);\r
1845 }\r
1846 \r
1847 wxTreeMultiItem wxTreeMultiCtrl::GetNextChild(const wxTreeMultiItem &item, int &cookie) const\r
1848 {\r
1849         if(item.IsNodeItem())\r
1850         {\r
1851                 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();\r
1852 \r
1853                 if(cookie >= 0 && cookie < (n->GetNodeCount()-1))\r
1854                 {\r
1855                         // increment cookie, return node\r
1856                         cookie ++;\r
1857                         return wxTreeMultiItem(n->GetNode(cookie));\r
1858                 }\r
1859         }\r
1860 \r
1861         // end of query, or no valid node\r
1862         cookie = -1;\r
1863         return wxTreeMultiItem(0);\r
1864 }\r
1865 \r
1866 wxTreeMultiItem wxTreeMultiCtrl::GetLastChild(const wxTreeMultiItem &item) const\r
1867 {\r
1868         if(item.IsNodeItem())\r
1869         {\r
1870                 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();\r
1871 \r
1872                 if(n->GetNodeCount() > 0)\r
1873                         return wxTreeMultiItem(n->GetNode(n->GetNodeCount()-1));\r
1874         }\r
1875 \r
1876         return wxTreeMultiItem(0);\r
1877 }\r
1878 \r
1879 wxTreeMultiItem wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const& item) const\r
1880 {\r
1881  // check if a valid item has been passed:\r
1882   if (!(item.IsOk()))\r
1883     return wxTreeMultiItem();\r
1884 \r
1885   TreeMultiItemNode* ParentPtr(item.GetItem()->GetParent());\r
1886 \r
1887 \r
1888   if (ParentPtr != NULL) // the parent pointer is only null if the passed item is the root\r
1889   {\r
1890    // find the current item in the parent's list; the next sibling has an index that is one higher than the one of the current item:\r
1891     int NextItemIndex(ParentPtr->Index(item.GetItem())+1); // variable definition and initialization\r
1892 \r
1893     if (NextItemIndex < ParentPtr->GetNodeCount())\r
1894       return ParentPtr->GetNode(NextItemIndex);\r
1895     else\r
1896       return wxTreeMultiItem();\r
1897   } /* if */\r
1898   else\r
1899     return wxTreeMultiItem();\r
1900 } /* wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const&) const */\r
1901 \r
1902 wxTreeMultiItem wxTreeMultiCtrl::GetPrevSibling(wxTreeMultiItem const& item) const\r
1903 {\r
1904  // check if a valid item has been passed:\r
1905   if (!(item.IsOk()))\r
1906     return wxTreeMultiItem();\r
1907 \r
1908   TreeMultiItemNode* ParentPtr(item.GetItem()->GetParent());\r
1909 \r
1910 \r
1911   if (ParentPtr != NULL)\r
1912   {\r
1913    // find the current item in the parent's list; the next sibling has an index that is one higher than the one of the current item:\r
1914     int PrevItemIndex(ParentPtr->Index(item.GetItem())-1); // variable definition and initialization\r
1915 \r
1916     if (PrevItemIndex >= 0)\r
1917       return ParentPtr->GetNode(PrevItemIndex);\r
1918     else\r
1919       return wxTreeMultiItem();\r
1920   } /* if */\r
1921   else\r
1922     return wxTreeMultiItem();\r
1923 } /* wxTreeMultiCtrl::GetPrevSibling(wxTreeMultiItem const&) const */\r
1924 \r
1925 wxTreeMultiItem wxTreeMultiCtrl::GetNext(wxTreeMultiItem const& item) const\r
1926 {\r
1927  // check if a valid item has been passed:\r
1928   if (!(item.IsOk()))\r
1929     return wxTreeMultiItem();\r
1930 \r
1931   TreeMultiItemNode* NodePtr(item.GetItem()->IsTreeMultiItemNode()); // variable definition and initialization\r
1932 \r
1933   if ((NodePtr != NULL) && (NodePtr->GetNodeCount() > 0))\r
1934     return wxTreeMultiItem(NodePtr->First());\r
1935   else\r
1936   {\r
1937    // variable definitions and initializations:\r
1938     wxTreeMultiItem Parent(item);\r
1939     wxTreeMultiItem Sibling;\r
1940 \r
1941     do\r
1942     {\r
1943       Sibling = this->GetNextSibling(Parent); // try to find next sibling\r
1944       Parent = this->GetParent(Parent);       // get next ancestor\r
1945     } while (!(Sibling.IsOk()) && Parent.IsOk());\r
1946    // in case the loop ended with Sibling.IsOk() "Sibling" contains a valid sibling otherwise an invalid\r
1947     return Sibling;\r
1948   } /* if */\r
1949 } /* wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const&) const */\r
1950 \r
1951 wxTreeMultiItem wxTreeMultiCtrl::GetPrevious(wxTreeMultiItem const& item) const\r
1952 {\r
1953  // check if a valid item has been passed:\r
1954   if (!(item.IsOk()))\r
1955     return wxTreeMultiItem();\r
1956 \r
1957   TreeMultiItemNode* NodePtr(item.GetItem()->IsTreeMultiItemNode()); // variable definition and initialization\r
1958 \r
1959   if ((NodePtr != NULL) && (NodePtr->GetNodeCount() > 0))\r
1960     return wxTreeMultiItem(NodePtr->Last());\r
1961   else\r
1962   {\r
1963    // variable definitions and initializations:\r
1964     wxTreeMultiItem Parent(item);\r
1965     wxTreeMultiItem Sibling;\r
1966 \r
1967     do\r
1968     {\r
1969       Sibling = this->GetPrevSibling(Parent); // try to find next sibling\r
1970       Parent = this->GetParent(Parent);       // get next ancestor\r
1971     } while (!(Sibling.IsOk()) && Parent.IsOk());\r
1972    // in case the loop ended with Sibling.IsOk() "Sibling" contains a valid sibling otherwise an invalid\r
1973     return Sibling;\r
1974   } /* if */\r
1975 } /* wxTreeMultiCtrl::GetPrevious(wxTreeMultiItem const&) const */\r
1976 \r
1977 // WDR: handler implementations for wxTreeMultiCtrl\r
1978 \r
1979 void wxTreeMultiCtrl::OnDraw(wxDC& dc)\r
1980 {\r
1981         // go recursive and draw the whole visible tree.\r
1982         dc.SetFont(_captionFont);\r
1983         for(int i = 0; i < _root.GetNodeCount(); i++)\r
1984                 DrawNode(_root.GetNode(i), dc);\r
1985 } /*  */\r