Avoid events when implicitly selecting first wxBookCtrl page.
[wxWidgets.git] / src / os2 / treectrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/treectrl.cpp
3 // Purpose: wxTreeCtrl
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98
6 // Created: 1997
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_TREECTRL
28
29 #include "wx/treectrl.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/dynarray.h"
33 #include "wx/log.h"
34 #include "wx/app.h"
35 #include "wx/settings.h"
36 #endif
37
38 #include "wx/os2/private.h"
39
40 #include "wx/imaglist.h"
41
42 // a macro to hide the ugliness of nested casts
43 #define HITEM(item) (HTREEITEM)(WXHTREEITEM)(item)
44
45 // the native control doesn't support multiple selections under MSW and we
46 // have 2 ways to emulate them: either using TVS_CHECKBOXES style and let
47 // checkboxes be the selection status (checked == selected) or by really
48 // emulating everything, i.e. intercepting mouse and key events &c. The first
49 // approach is much easier but doesn't work with comctl32.dll < 4.71 and also
50 // looks quite ugly.
51 #define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0
52
53 // ----------------------------------------------------------------------------
54 // private functions
55 // ----------------------------------------------------------------------------
56
57 // ----------------------------------------------------------------------------
58 // private classes
59 // ----------------------------------------------------------------------------
60
61 typedef struct _MYRECORD
62 {
63 RECORDCORE m_vRecord;
64 ULONG m_ulItemId;
65 ULONG m_ulUserData;
66 } MYRECORD, *PMYRECORD;
67
68 struct wxTreeViewItem : public MYRECORD
69 {
70 wxTreeViewItem(const wxTreeItemId& rItem)
71 {
72 m_ulItemId = (ULONG)rItem.m_pItem;
73 }
74 }; // end of STRUCT wxTreeViewItem
75
76 class wxTreeItemInternalData
77 {
78 public:
79
80 wxTreeItemInternalData() {}
81 ~wxTreeItemInternalData()
82 {
83 wxDELETE(m_pAttr);
84 }
85
86 wxTreeItemAttr* m_pAttr;
87 WXLPARAM m_lParam; // user data
88 #if defined(C_CM_COS232)
89 PMYRECORD m_pMyRecord; // so we can set the m_ulUserData to 0 when this is deleted
90 #endif
91 }; // end of CLASS wxTreeItemInternalData
92
93 void BumpTreeRecordIds (
94 HWND hWnd
95 , PMYRECORD pRecord
96 )
97 {
98 while(pRecord)
99 {
100 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
101 ,CM_QUERYRECORD
102 ,MPFROMP(pRecord)
103 ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
104 ));
105 if (pRecord)
106 pRecord->m_ulItemId++;
107 }
108 } // end of BumpTreeRecordIds
109
110 PMYRECORD FindOS2TreeRecordByID (
111 HWND hWnd
112 , long lItemId
113 )
114 {
115 PMYRECORD pRecord = NULL;
116 CNRINFO vCnrInfo;
117 unsigned long i;
118
119 if (!::WinSendMsg( hWnd
120 ,CM_QUERYCNRINFO
121 ,MPFROMP(&vCnrInfo)
122 ,(MPARAM)(USHORT)sizeof(CNRINFO)
123 ))
124 return NULL;
125 for (i = 0; i < vCnrInfo.cRecords; i++)
126 {
127 if (i == 0)
128 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
129 ,CM_QUERYRECORD
130 ,MPFROMP(pRecord)
131 ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)
132 ));
133 else
134 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
135 ,CM_QUERYRECORD
136 ,MPFROMP(pRecord)
137 ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
138 ));
139 if (!pRecord)
140 return NULL;
141 if (pRecord->m_ulItemId == (ULONG)lItemId)
142 break;
143 }
144 return pRecord;
145 } // end of FindOS2ListRecordByID
146
147
148
149 class wxTreeTraversal
150 {
151 public:
152 wxTreeTraversal(const wxTreeCtrl* pTree)
153 {
154 m_pTree = pTree;
155 }
156
157 //
158 // Do traverse the tree: visit all items (recursively by default) under the
159 // given one; return true if all items were traversed or false if the
160 // traversal was aborted because OnVisit returned false
161 //
162 bool DoTraverse( const wxTreeItemId& rRoot
163 ,bool bRecursively = true
164 );
165
166 //
167 // Override this function to do whatever is needed for each item, return
168 // false to stop traversing
169 //
170 virtual bool OnVisit(const wxTreeItemId& rItem) = 0;
171
172 protected:
173 const wxTreeCtrl* GetTree(void) const { return m_pTree; }
174
175 private:
176 bool Traverse( const wxTreeItemId& rRoot
177 ,bool bRecursively
178 );
179
180 const wxTreeCtrl* m_pTree;
181 wxDECLARE_NO_COPY_CLASS(wxTreeTraversal);
182 }; // end of CLASS wxTreeTraversal
183
184 //
185 // Internal class for getting the selected items
186 //
187 class TraverseSelections : public wxTreeTraversal
188 {
189 public:
190 TraverseSelections( const wxTreeCtrl* pTree
191 ,wxArrayTreeItemIds& raSelections
192 )
193 : wxTreeTraversal(pTree)
194 , m_aSelections(raSelections)
195 {
196 m_aSelections.Empty();
197 DoTraverse(pTree->GetRootItem());
198 }
199
200 virtual bool OnVisit(const wxTreeItemId& rItem)
201 {
202 //
203 // Can't visit a virtual node.
204 //
205 if ((GetTree()->GetRootItem() == rItem) && (GetTree()->GetWindowStyle() & wxTR_HIDE_ROOT))
206 {
207 return true;
208 }
209 PMYRECORD pRecord = FindOS2TreeRecordByID( (HWND)GetTree()->GetHWND()
210 ,rItem.m_pItem
211 );
212 if (pRecord->m_vRecord.flRecordAttr & CRA_SELECTED)
213 {
214 m_aSelections.Add(rItem);
215 }
216 return true;
217 }
218
219 size_t GetCount(void) const { return m_aSelections.GetCount(); }
220
221 private:
222 wxArrayTreeItemIds& m_aSelections;
223 }; // end of CLASS TraverseSelections
224
225 //
226 // Internal class for counting tree items
227 //
228 class TraverseCounter : public wxTreeTraversal
229 {
230 public:
231 TraverseCounter( const wxTreeCtrl* pTree
232 ,const wxTreeItemId& rRoot
233 ,bool bRecursively
234 )
235 : wxTreeTraversal(pTree)
236 {
237 m_nCount = 0;
238 DoTraverse(rRoot, bRecursively);
239 }
240
241 virtual bool OnVisit(const wxTreeItemId& WXUNUSED(rItem))
242 {
243 m_nCount++;
244 return true;
245 }
246
247 size_t GetCount(void) const { return m_nCount; }
248
249 private:
250 size_t m_nCount;
251 }; // end of CLASS TraverseCounter
252
253 // ----------------------------------------------------------------------------
254 // wxWin macros
255 // ----------------------------------------------------------------------------
256
257 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
258
259 // ----------------------------------------------------------------------------
260 // constants
261 // ----------------------------------------------------------------------------
262
263 // indices in gs_expandEvents table below
264 enum
265 {
266 IDX_COLLAPSE,
267 IDX_EXPAND,
268 IDX_WHAT_MAX
269 };
270
271 enum
272 {
273 IDX_DONE,
274 IDX_DOING,
275 IDX_HOW_MAX
276 };
277
278 // handy table for sending events - it has to be initialized during run-time
279 // now so can't be const any more
280 static /* const */ wxEventType gs_expandEvents[IDX_WHAT_MAX][IDX_HOW_MAX];
281
282 /*
283 but logically it's a const table with the following entries:
284 =
285 {
286 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
287 { wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxEVT_COMMAND_TREE_ITEM_EXPANDING }
288 };
289 */
290
291 // ============================================================================
292 // implementation
293 // ============================================================================
294
295 // ----------------------------------------------------------------------------
296 // tree traversal
297 // ----------------------------------------------------------------------------
298
299 bool wxTreeTraversal::DoTraverse (
300 const wxTreeItemId& rRoot
301 , bool bRecursively
302 )
303 {
304 if (!OnVisit(rRoot))
305 return false;
306
307 return Traverse( rRoot
308 ,bRecursively
309 );
310 } // end of wxTreeTraversal::DoTraverse
311
312 bool wxTreeTraversal::Traverse (
313 const wxTreeItemId& rRoot
314 , bool bRecursively
315 )
316 {
317 long lCookie;
318 wxTreeItemId vChild = m_pTree->GetFirstChild( rRoot
319 ,lCookie
320 );
321 while (vChild.IsOk())
322 {
323 //
324 // Depth first traversal
325 //
326 if (bRecursively && !Traverse(vChild, true))
327 return false;
328 if (!OnVisit(vChild))
329 return false;
330 vChild = m_pTree->GetNextChild( rRoot
331 ,lCookie
332 );
333 }
334 return true;
335 } // end of wxTreeTraversal::Traverse
336
337 // ----------------------------------------------------------------------------
338 // construction and destruction
339 // ----------------------------------------------------------------------------
340
341 void wxTreeCtrl::Init ()
342 {
343 m_pImageListNormal = NULL;
344 m_pImageListState = NULL;
345 m_bOwnsImageListNormal = false;
346 m_bOwnsImageListState = false;
347 m_bHasAnyAttr = false;
348 m_pDragImage = NULL;
349
350 //
351 // Initialize the global array of events now as it can't be done statically
352 // with the wxEVT_XXX values being allocated during run-time only
353 //
354 gs_expandEvents[IDX_COLLAPSE][IDX_DONE] = wxEVT_COMMAND_TREE_ITEM_COLLAPSED;
355 gs_expandEvents[IDX_COLLAPSE][IDX_DOING] = wxEVT_COMMAND_TREE_ITEM_COLLAPSING;
356 gs_expandEvents[IDX_EXPAND][IDX_DONE] = wxEVT_COMMAND_TREE_ITEM_EXPANDED;
357 gs_expandEvents[IDX_EXPAND][IDX_DOING] = wxEVT_COMMAND_TREE_ITEM_EXPANDING;
358 } // end of wxTreeCtrl::Init
359
360 bool wxTreeCtrl::Create (
361 wxWindow* pParent
362 , wxWindowID vId
363 , const wxPoint& rPos
364 , const wxSize& rSize
365 , long lStyle
366 , const wxValidator& rValidator
367 , const wxString& rsName
368 )
369 {
370 CNRINFO vCnrInfo;
371
372 Init();
373 if (!CreateControl( pParent
374 ,vId
375 ,rPos
376 ,rSize
377 ,lStyle
378 ,rValidator
379 ,rsName
380 ))
381 return false;
382
383 DWORD dwStyle = WS_VISIBLE | WS_TABSTOP;
384
385 if (m_windowStyle & wxCLIP_SIBLINGS)
386 dwStyle |= WS_CLIPSIBLINGS;
387
388 // Create the tree control.
389 if (!OS2CreateControl( "CONTAINER"
390 ,dwStyle
391 ))
392 return false;
393
394 //
395 // Now set the display attributes to show a TREE/ICON view of the
396 // OS/2 Container
397 //
398 if (!::WinSendMsg( GetHWND()
399 ,CM_QUERYCNRINFO
400 ,MPFROMP(&vCnrInfo)
401 ,(MPARAM)(USHORT)sizeof(CNRINFO)
402 ))
403
404 vCnrInfo.flWindowAttr = CV_TREE|CV_ICON;
405 vCnrInfo.flWindowAttr |= CA_DRAWBITMAP;
406 if (m_windowStyle & wxTR_NO_LINES)
407 vCnrInfo.flWindowAttr |= CA_TREELINE;
408
409 ::WinSendMsg( GetHWND()
410 ,CM_SETCNRINFO
411 ,MPFROMP(&vCnrInfo)
412 ,(MPARAM)CMA_FLWINDOWATTR
413 );
414
415 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
416 SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
417 SetFont(*wxSMALL_FONT);
418 SetXComp(0);
419 SetYComp(0);
420 SetSize( rPos.x
421 ,rPos.y
422 ,rSize.x
423 ,rSize.y
424 );
425 return true;
426 } // end of wxTreeCtrl::Create
427
428 wxTreeCtrl::~wxTreeCtrl ()
429 {
430 //
431 // Delete any attributes
432 //
433 if (m_bHasAnyAttr)
434 {
435 for (wxNode* pNode = m_vAttrs.Next(); pNode; pNode = m_vAttrs.Next())
436 {
437 delete (wxTreeItemAttr *)pNode->Data();
438 }
439 m_bHasAnyAttr = false;
440 }
441 DeleteTextCtrl();
442
443 //
444 // Delete user data to prevent memory leaks
445 // also deletes hidden root node storage.
446 //
447 DeleteAllItems();
448 if (m_bOwnsImageListNormal)
449 delete m_pImageListNormal;
450 if (m_bOwnsImageListState)
451 delete m_pImageListState;
452 } // end of wxTreeCtrl::~wxTreeCtrl
453
454 // ----------------------------------------------------------------------------
455 // accessors
456 // ----------------------------------------------------------------------------
457
458 //
459 // simple wrappers which add error checking in debug mode. These methods
460 // assume the items are properly filled out already. If not, you get errors
461 //
462 bool wxTreeCtrl::DoGetItem (
463 wxTreeViewItem* pTvItem
464 ) const
465 {
466 PMYRECORD pRecord = FindOS2TreeRecordByID( GetHWND()
467 ,pTvItem->m_ulItemId
468 );
469
470 if (!pRecord)
471 {
472 wxLogLastError(wxT("Item not obtained"));
473 return false;
474 }
475 return true;
476 } // end of wxTreeCtrl::DoGetItem
477
478 void wxTreeCtrl::DoSetItem (
479 wxTreeViewItem* pTvItem
480 )
481 {
482 //
483 // Just invalidate the record to redisplay it
484 //
485 if (!::WinSendMsg( GetHWND()
486 ,CM_INVALIDATERECORD
487 ,MPFROMP(pTvItem)
488 ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
489 ));
490 {
491 wxLogLastError(wxT("CM_INVALIDATERECORD"));
492 }
493 } // end of wxTreeCtrl::DoSetItem
494
495 unsigned int wxTreeCtrl::GetCount () const
496 {
497 CNRINFO vCnrInfo;
498
499 ::WinSendMsg( GetHWND()
500 ,CM_QUERYCNRINFO
501 ,MPFROMP(&vCnrInfo)
502 ,(MPARAM)(USHORT)sizeof(CNRINFO)
503 );
504
505 return (unsigned int)vCnrInfo.cRecords;
506 } // end of wxTreeCtrl::GetCount
507
508 unsigned int wxTreeCtrl::GetIndent () const
509 {
510 CNRINFO vCnrInfo;
511
512 ::WinSendMsg( GetHWND()
513 ,CM_QUERYCNRINFO
514 ,MPFROMP(&vCnrInfo)
515 ,(MPARAM)(USHORT)sizeof(CNRINFO)
516 );
517 return (unsigned int)vCnrInfo.cxTreeIndent;
518 } // end of wxTreeCtrl::GetIndent
519
520 void wxTreeCtrl::SetIndent (
521 unsigned int uIndent
522 )
523 {
524 CNRINFO vCnrInfo;
525
526 ::WinSendMsg( GetHWND()
527 ,CM_QUERYCNRINFO
528 ,MPFROMP(&vCnrInfo)
529 ,(MPARAM)(USHORT)sizeof(CNRINFO)
530 );
531 vCnrInfo.cxTreeIndent = (LONG)uIndent;
532 ::WinSendMsg( GetHWND()
533 ,CM_SETCNRINFO
534 ,MPFROMP(&vCnrInfo)
535 ,(MPARAM)CMA_CXTREEINDENT
536 );
537 } // end of wxTreeCtrl::SetIndent
538
539 wxImageList* wxTreeCtrl::GetImageList () const
540 {
541 return m_pImageListNormal;
542 } // end of wxTreeCtrl::GetImageList
543
544 wxImageList* wxTreeCtrl::GetStateImageList () const
545 {
546 return m_pImageListNormal;
547 } // end of wxTreeCtrl::GetStateImageList
548
549 //
550 // The SETS of imagelists really do nothing under OS2 as a RECORDCORE
551 // struct has the icon imbedded in it that it uses for the icon being
552 // displayed via the TREEITEMDESC member. Provided for interface
553 // compatibility only
554 //
555 void wxTreeCtrl::SetAnyImageList (
556 wxImageList* WXUNUSED(pImageList)
557 , int WXUNUSED(nWhich)
558 )
559 {
560 } // end of wxTreeCtrl::SetAnyImageList
561
562 void wxTreeCtrl::SetImageList (
563 wxImageList* WXUNUSED(pImageList)
564 )
565 {
566 if (m_bOwnsImageListNormal)
567 delete m_pImageListNormal;
568 m_bOwnsImageListNormal = false;
569 } // end of wxTreeCtrl::SetImageList
570
571 void wxTreeCtrl::SetStateImageList (
572 wxImageList* WXUNUSED(pImageList)
573 )
574 {
575 if (m_bOwnsImageListState)
576 delete m_pImageListState;
577 m_bOwnsImageListState = false;
578 } // end of wxTreeCtrl::SetStateImageList
579
580 void wxTreeCtrl::AssignImageList (
581 wxImageList* WXUNUSED(pImageList)
582 )
583 {
584 m_bOwnsImageListNormal = true;
585 } // end of wxTreeCtrl::AssignImageList
586
587 void wxTreeCtrl::AssignStateImageList (
588 wxImageList* WXUNUSED(pImageList)
589 )
590 {
591 m_bOwnsImageListState = true;
592 } // end of wxTreeCtrl::AssignStateImageList
593
594 size_t wxTreeCtrl::GetChildrenCount (
595 const wxTreeItemId& rItem
596 , bool bRecursively
597 ) const
598 {
599 TraverseCounter vCounter( this
600 ,rItem
601 ,bRecursively
602 );
603 return vCounter.GetCount() - 1;
604 } // end of wxTreeCtrl::GetChildrenCount
605
606 // ----------------------------------------------------------------------------
607 // control colours
608 // ----------------------------------------------------------------------------
609
610 bool wxTreeCtrl::SetBackgroundColour (
611 const wxColour& rColour
612 )
613 {
614 ULONG ulColor = wxColourToRGB(rColour);
615
616 if ( !wxWindowBase::SetBackgroundColour(rColour) )
617 return false;
618 ::WinSetPresParam( GetHWND()
619 ,PP_BACKGROUNDCOLOR
620 ,sizeof(ULONG)
621 ,&ulColor
622 );
623 return true;
624 } // end of wxTreeCtrl::SetBackgroundColour
625
626 bool wxTreeCtrl::SetForegroundColour (
627 const wxColour& rColour
628 )
629 {
630 ULONG ulColor = wxColourToRGB(rColour);
631
632 if (!wxWindowBase::SetForegroundColour(rColour))
633 return false;
634 ::WinSetPresParam( GetHWND()
635 ,PP_FOREGROUNDCOLOR
636 ,sizeof(ULONG)
637 ,&ulColor
638 );
639 return true;
640 } // end of wxTreeCtrl::SetForegroundColour
641
642 // ----------------------------------------------------------------------------
643 // Item access
644 // ----------------------------------------------------------------------------
645
646 wxString wxTreeCtrl::GetItemText (
647 const wxTreeItemId& rItem
648 ) const
649 {
650 wxChar zBuf[512]; // the size is arbitrary...
651 wxTreeViewItem vTvItem(rItem);
652
653 if (!DoGetItem(&vTvItem))
654 {
655 //
656 // Don't return some garbage which was on stack, but an empty string
657 //
658 zBuf[0] = wxT('\0');
659 }
660 else
661 strcpy(zBuf, vTvItem.m_vRecord.pszTree);
662 return wxString(zBuf);
663 } // end of wxTreeCtrl::GetItemText
664
665 void wxTreeCtrl::SetItemText (
666 const wxTreeItemId& rItem
667 , const wxString& rsText
668 )
669 {
670 wxTreeViewItem vTvItem(rItem);
671
672 vTvItem.m_vRecord.pszTree = (wxChar *)rsText.c_str(); // conversion is ok
673 DoSetItem(&vTvItem);
674 } // end of wxTreeCtrl::SetItemText
675
676 //
677 // These functions under OS/2 PM are not needed. OS/2 containers in tree view
678 // provide for storing a custom expanded and collapsed icons and selected
679 // and non selected icons, natively. For instance, by default, a disk display
680 // will display a tree list of folder icons with "+" icons (collapsed) beside
681 // those folder which contain child members. Double clicking a folder changes
682 // the closed folder icon to an open folder icon with hatched selection
683 // highlighting indicating an ICON view container of the folder is open
684 // elsewhere on the desktop. So the below is not really needed, but we will
685 // simply return the appropriate icon requested out of OS/2's native PM
686 // data structures.
687 //
688 int wxTreeCtrl::DoGetItemImageFromData (
689 const wxTreeItemId& WXUNUSED(rItem)
690 , wxTreeItemIcon nWhich
691 ) const
692 {
693 //
694 // Image handles stored in CNRINFO.
695 //
696 CNRINFO vCnrInfo;
697
698 ::WinSendMsg( GetHWND()
699 ,CM_QUERYCNRINFO
700 ,MPFROMP(&vCnrInfo)
701 ,(MPARAM)(USHORT)sizeof(CNRINFO)
702 );
703
704 //
705 // We really only have two to chose from. If not custom (set in CNRINFO
706 // then return the handle to system bitmap). OS/2 automatically provides
707 // in_use and selected bitmaps/icons
708 //
709 switch(nWhich)
710 {
711 case wxTreeItemIcon_Normal:
712 if (vCnrInfo.hbmCollapsed == NULLHANDLE)
713 return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEPLUS);
714 return vCnrInfo.hbmCollapsed;
715
716
717 case wxTreeItemIcon_Expanded:
718 if (vCnrInfo.hbmExpanded == NULLHANDLE)
719 return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEMINUS);
720 return vCnrInfo.hbmExpanded;
721
722 default:
723 return vCnrInfo.hbmCollapsed;
724 }
725 }
726
727 void wxTreeCtrl::DoSetItemImageFromData (
728 const wxTreeItemId& WXUNUSED(rItem)
729 , int nImage
730 , wxTreeItemIcon nWhich
731 ) const
732 {
733 //
734 // Image handles stored in CNRINFO.
735 //
736 CNRINFO vCnrInfo;
737
738 ::WinSendMsg( GetHWND()
739 ,CM_QUERYCNRINFO
740 ,MPFROMP(&vCnrInfo)
741 ,(MPARAM)(USHORT)sizeof(CNRINFO)
742 );
743 if (nWhich == wxTreeItemIcon_Normal)
744 vCnrInfo.hbmCollapsed = (HBITMAP)nImage;
745 if (nWhich == wxTreeItemIcon_Expanded)
746 vCnrInfo.hbmExpanded = (HBITMAP)nImage;
747 ::WinSendMsg( GetHWND()
748 ,CM_SETCNRINFO
749 ,MPFROMP(&vCnrInfo)
750 ,(MPARAM)CMA_TREEBITMAP
751 );
752 } // end of wxTreeCtrl::DoSetItemImageFromData
753
754 // Useless for OS/2
755 void wxTreeCtrl::DoSetItemImages (
756 const wxTreeItemId& rItem
757 , int nImage
758 , int nImageSel
759 )
760 {
761 } // end of wxTreeCtrl::DoSetItemImages
762
763 int wxTreeCtrl::GetItemImage (
764 const wxTreeItemId& rItem
765 , wxTreeItemIcon nWhich
766 ) const
767 {
768 if (HasIndirectData(rItem))
769 {
770 return DoGetItemImageFromData( rItem
771 ,nWhich
772 );
773 }
774
775 CNRINFO vCnrInfo;
776
777 ::WinSendMsg( GetHWND()
778 ,CM_QUERYCNRINFO
779 ,MPFROMP(&vCnrInfo)
780 ,(MPARAM)(USHORT)sizeof(CNRINFO)
781 );
782 switch (nWhich)
783 {
784 default:
785 wxFAIL_MSG( wxT("unknown tree item image type") );
786
787 case wxTreeItemIcon_Normal:
788 if (vCnrInfo.hbmCollapsed == NULLHANDLE)
789 return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEPLUS);
790 return vCnrInfo.hbmCollapsed;
791
792
793 case wxTreeItemIcon_Expanded:
794 if (vCnrInfo.hbmExpanded == NULLHANDLE)
795 return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEMINUS);
796 return vCnrInfo.hbmExpanded;
797
798 case wxTreeItemIcon_Selected:
799 case wxTreeItemIcon_SelectedExpanded:
800 return -1;
801 }
802 }
803
804 void wxTreeCtrl::SetItemImage (
805 const wxTreeItemId& WXUNUSED(rItem)
806 , int nImage
807 , wxTreeItemIcon nWhich
808 )
809 {
810 CNRINFO vCnrInfo;
811
812 ::WinSendMsg( GetHWND()
813 ,CM_QUERYCNRINFO
814 ,MPFROMP(&vCnrInfo)
815 ,(MPARAM)(USHORT)sizeof(CNRINFO)
816 );
817 switch (nWhich)
818 {
819 case wxTreeItemIcon_Normal:
820 vCnrInfo.hbmCollapsed = (HBITMAP)nImage;
821 break;
822
823 case wxTreeItemIcon_Expanded:
824 vCnrInfo.hbmExpanded = (HBITMAP)nImage;
825 break;
826
827 default:
828 wxFAIL_MSG( wxT("unknown tree item image type") );
829 }
830 ::WinSendMsg( GetHWND()
831 ,CM_SETCNRINFO
832 ,MPFROMP(&vCnrInfo)
833 ,(MPARAM)CMA_TREEBITMAP
834 );
835 } // end of wxTreeCtrl::SetItemImage
836
837 wxTreeItemData* wxTreeCtrl::GetItemData (
838 const wxTreeItemId& rItem
839 ) const
840 {
841 wxTreeViewItem vTvItem(rItem);
842
843 if (!DoGetItem(&vTvItem))
844 {
845 return NULL;
846 }
847
848 return (wxTreeItemData *)vTvItem.m_ulUserData;
849 } // end of wxTreeCtrl::GetItemData
850
851 void wxTreeCtrl::SetItemData (
852 const wxTreeItemId& rItem
853 , wxTreeItemData* pData
854 )
855 {
856 //
857 // first, associate this piece of data with this item
858 if (pData)
859 {
860 pData->SetId(rItem);
861 }
862
863 wxTreeViewItem vTvItem(rItem);
864
865 vTvItem.m_ulUserData = (ULONG)pData;
866 DoSetItem(&vTvItem);
867 } // end of wxTreeCtrl::SetItemData
868
869 // The following two do nothing under OS/2
870 void wxTreeCtrl::SetIndirectItemData (
871 const wxTreeItemId& WXUNUSED(rItem)
872 , wxTreeItemIndirectData* WXUNUSED(pData)
873 )
874 {
875 } // end of wxTreeCtrl::SetIndirectItemData
876
877 bool wxTreeCtrl::HasIndirectData (
878 const wxTreeItemId& WXUNUSED(rItem)
879 ) const
880 {
881 return false;
882 } // end of wxTreeCtrl::HasIndirectData
883
884 // Irreleveant under OS/2 --- item either has child records or it doesn't.
885 void wxTreeCtrl::SetItemHasChildren (
886 const wxTreeItemId& WXUNUSED(rItem)
887 , bool WXUNUSED(bHas)
888 )
889 {
890 } // end of wxTreeCtrl::SetItemHasChildren
891
892 // Irreleveant under OS/2 --- function of the font in PM
893 void wxTreeCtrl::SetItemBold (
894 const wxTreeItemId& WXUNUSED(rItem)
895 , bool WXUNUSED(bBold)
896 )
897 {
898 } // end of wxTreeCtrl::SetItemBold
899
900 void wxTreeCtrl::SetItemDropHighlight (
901 const wxTreeItemId& rItem
902 , bool bHighlight
903 )
904 {
905 wxTreeViewItem vTvItem(rItem);
906
907 ::WinSendMsg( GetHWND()
908 ,CM_SETRECORDEMPHASIS
909 ,MPFROMP(&vTvItem)
910 ,MPFROM2SHORT(bHighlight, CRA_SELECTED)
911 );
912 DoSetItem(&vTvItem);
913 } // end of wxTreeCtrl::SetItemDropHighlight
914
915 void wxTreeCtrl::RefreshItem (
916 const wxTreeItemId& rItem
917 )
918 {
919 wxTreeViewItem vTvItem(rItem);
920
921 //
922 // This just does a record invalidate causing it to be re-displayed
923 //
924 DoSetItem(&vTvItem);
925 } // end of wxTreeCtrl::RefreshItem
926
927 wxColour wxTreeCtrl::GetItemTextColour (
928 const wxTreeItemId& rItem
929 ) const
930 {
931 long lId = (long)rItem.m_pItem;
932 wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
933
934 if (!pAttr)
935 {
936 return wxNullColour;
937 }
938 return pAttr->GetTextColour();
939 } // end of wxTreeCtrl::GetItemTextColour
940
941 wxColour wxTreeCtrl::GetItemBackgroundColour (
942 const wxTreeItemId& rItem
943 ) const
944 {
945 long lId = (long)rItem.m_pItem;
946 wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
947
948 if (!pAttr)
949 {
950 return wxNullColour;
951 }
952 return pAttr->GetBackgroundColour();
953 } // end of wxTreeCtrl::GetItemBackgroundColour
954
955 wxFont wxTreeCtrl::GetItemFont (
956 const wxTreeItemId& rItem
957 ) const
958 {
959 long lId = (long)rItem.m_pItem;
960 wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
961
962 if (!pAttr)
963 {
964 return wxNullFont;
965 }
966 return pAttr->GetFont();
967 } // end of wxTreeCtrl::GetItemFont
968
969 void wxTreeCtrl::SetItemTextColour (
970 const wxTreeItemId& rItem
971 , const wxColour& rCol
972 )
973 {
974 m_bHasAnyAttr = true;
975
976 long lId = (long)rItem.m_pItem;
977 wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
978
979 if (!pAttr)
980 {
981 pAttr = new wxTreeItemAttr;
982 m_vAttrs.Put(lId, (wxObject *)pAttr);
983 }
984 pAttr->SetTextColour(rCol);
985 RefreshItem(rItem);
986 } // end of wxTreeCtrl::SetItemTextColour
987
988 void wxTreeCtrl::SetItemBackgroundColour (
989 const wxTreeItemId& rItem
990 , const wxColour& rCol
991 )
992 {
993 m_bHasAnyAttr = true;
994
995 long lId = (long)rItem.m_pItem;
996 wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
997
998 if (!pAttr)
999 {
1000 pAttr = new wxTreeItemAttr;
1001 m_vAttrs.Put(lId, (wxObject *)pAttr);
1002 }
1003 pAttr->SetBackgroundColour(rCol);
1004 RefreshItem(rItem);
1005 } // end of wxTreeCtrl::SetItemBackgroundColour
1006
1007 void wxTreeCtrl::SetItemFont (
1008 const wxTreeItemId& rItem
1009 , const wxFont& rFont
1010 )
1011 {
1012 m_bHasAnyAttr = true;
1013
1014 long lId = (long)rItem.m_pItem;
1015 wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
1016
1017 if (!pAttr)
1018 {
1019 pAttr = new wxTreeItemAttr;
1020 m_vAttrs.Put(lId, (wxObject *)pAttr);
1021 }
1022 pAttr->SetFont(rFont);
1023 RefreshItem(rItem);
1024 } // end of wxTreeCtrl::SetItemFont
1025
1026 // ----------------------------------------------------------------------------
1027 // Item status
1028 // ----------------------------------------------------------------------------
1029
1030 bool wxTreeCtrl::IsVisible (
1031 const wxTreeItemId& rItem
1032 ) const
1033 {
1034 // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
1035 RECTL vRectRecord;
1036 RECTL vRectContainer;
1037 wxRect vWxRectRecord;
1038 wxRect vWxRectContainer;
1039 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1040 ,rItem.m_pItem
1041 );
1042 QUERYRECORDRECT vQuery;
1043
1044 vQuery.cb = sizeof(QUERYRECORDRECT);
1045 vQuery.pRecord = (PRECORDCORE)pRecord;
1046 vQuery.fRightSplitWindow = FALSE;
1047 vQuery.fsExtent = CMA_TREEICON;
1048
1049 ::WinSendMsg( GetHWND()
1050 ,CM_QUERYVIEWPORTRECT
1051 ,MPFROMP(&vRectContainer)
1052 ,MPFROM2SHORT(CMA_WINDOW, FALSE)
1053 );
1054 ::WinSendMsg( GetHWND()
1055 ,CM_QUERYRECORDRECT
1056 ,MPFROMP(&vRectRecord)
1057 ,MPFROMP(&vQuery)
1058 );
1059 vWxRectRecord.SetLeft(vRectRecord.xLeft);
1060 vWxRectRecord.SetTop(vRectRecord.yTop);
1061 vWxRectRecord.SetRight(vRectRecord.xRight);
1062 vWxRectRecord.SetBottom(vRectRecord.yBottom);
1063
1064 vWxRectContainer.SetLeft(vRectContainer.xLeft);
1065 vWxRectContainer.SetTop(vRectContainer.yTop);
1066 vWxRectContainer.SetRight(vRectContainer.xRight);
1067 vWxRectContainer.SetBottom(vRectContainer.yBottom);
1068 return (vWxRectContainer.Contains(wxPoint(vWxRectRecord.x, vWxRectRecord.y)));
1069 } // end of wxTreeCtrl::IsVisible
1070
1071 bool wxTreeCtrl::ItemHasChildren (
1072 const wxTreeItemId& rItem
1073 ) const
1074 {
1075 wxTreeViewItem vTvItem(rItem);
1076 DoGetItem(&vTvItem);
1077
1078 //
1079 // A tree record with children will have one of these attributes
1080 //
1081 return (vTvItem.m_vRecord.flRecordAttr & CRA_EXPANDED ||
1082 vTvItem.m_vRecord.flRecordAttr & CRA_COLLAPSED) != 0;
1083 }
1084
1085 bool wxTreeCtrl::IsExpanded (
1086 const wxTreeItemId& rItem
1087 ) const
1088 {
1089 wxTreeViewItem vTvItem(rItem);
1090 DoGetItem(&vTvItem);
1091
1092 return (vTvItem.m_vRecord.flRecordAttr & CRA_EXPANDED) != 0;
1093 } // end of wxTreeCtrl::IsExpanded
1094
1095 bool wxTreeCtrl::IsSelected (
1096 const wxTreeItemId& rItem
1097 ) const
1098 {
1099 wxTreeViewItem vTvItem(rItem);
1100 DoGetItem(&vTvItem);
1101
1102 return (vTvItem.m_vRecord.flRecordAttr & CRA_SELECTED) != 0;
1103 } // end of wxTreeCtrl::IsSelected
1104
1105 // Not supported
1106 bool wxTreeCtrl::IsBold (
1107 const wxTreeItemId& rItem
1108 ) const
1109 {
1110 return false;
1111 } // end of wxTreeCtrl::IsBold
1112
1113 // ----------------------------------------------------------------------------
1114 // navigation
1115 // ----------------------------------------------------------------------------
1116
1117 wxTreeItemId wxTreeCtrl::GetRootItem () const
1118 {
1119 PMYRECORD pRecord = NULL;
1120
1121 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1122 ,CM_QUERYRECORD
1123 ,MPFROMP(pRecord)
1124 ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)
1125 ));
1126
1127 if (!pRecord)
1128 return wxTreeItemId(-1L);
1129 return wxTreeItemId((long)pRecord->m_ulItemId);
1130 } // end of wxTreeCtrl::GetRootItem
1131
1132 wxTreeItemId wxTreeCtrl::GetSelection () const
1133 {
1134 wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (long)(WXHTREEITEM)0,
1135 wxT("this only works with single selection controls") );
1136
1137 PMYRECORD pRecord = NULL;
1138
1139 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1140 ,CM_QUERYRECORDEMPHASIS
1141 ,MPARAM(CMA_FIRST)
1142 ,MPARAM(CRA_SELECTED)
1143 ));
1144 if (!pRecord)
1145 return wxTreeItemId(-1L);
1146 return wxTreeItemId((long)pRecord->m_ulItemId);
1147 } // end of wxTreeCtrl::GetSelection
1148
1149 wxTreeItemId wxTreeCtrl::GetItemParent (
1150 const wxTreeItemId& rItem
1151 ) const
1152 {
1153 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1154 ,rItem.m_pItem
1155 );
1156
1157 if (!pRecord)
1158 return wxTreeItemId(-1L);
1159 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1160 ,CM_QUERYRECORD
1161 ,MPFROMP(pRecord)
1162 ,MPFROM2SHORT(CMA_PARENT, CMA_ITEMORDER)
1163 ));
1164 if (!pRecord)
1165 return wxTreeItemId(-1L);
1166 return wxTreeItemId((long)pRecord->m_ulItemId);
1167 } // end of wxTreeCtrl::GetItemParent
1168
1169 wxTreeItemId wxTreeCtrl::GetFirstChild (
1170 const wxTreeItemId& rItem
1171 , long& rCookie
1172 ) const
1173 {
1174 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1175 ,rItem.m_pItem
1176 );
1177
1178 if (!pRecord)
1179 return wxTreeItemId(-1L);
1180 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1181 ,CM_QUERYRECORD
1182 ,MPFROMP(pRecord)
1183 ,MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER)
1184 ));
1185 if (!pRecord)
1186 return wxTreeItemId(-1L);
1187 //
1188 // Remember the last child returned in 'cookie'
1189 //
1190 rCookie = (long)pRecord->m_ulItemId;
1191 return wxTreeItemId(rCookie);
1192 } // end of wxTreeCtrl::GetFirstChild
1193
1194 wxTreeItemId wxTreeCtrl::GetNextChild (
1195 const wxTreeItemId& WXUNUSED(rItem)
1196 , long& rCookie
1197 ) const
1198 {
1199 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1200 ,rCookie
1201 );
1202
1203 if (!pRecord)
1204 return wxTreeItemId(-1L);
1205 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1206 ,CM_QUERYRECORD
1207 ,MPFROMP(pRecord)
1208 ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
1209 ));
1210 if (!pRecord)
1211 return wxTreeItemId(-1L);
1212 rCookie = (long)pRecord->m_ulItemId;
1213 return wxTreeItemId(rCookie);
1214 } // end of wxTreeCtrl::GetNextChild
1215
1216 wxTreeItemId wxTreeCtrl::GetLastChild (
1217 const wxTreeItemId& rItem
1218 ) const
1219 {
1220 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1221 ,rItem.m_pItem
1222 );
1223
1224 if (!pRecord)
1225 return wxTreeItemId(-1L);
1226 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1227 ,CM_QUERYRECORD
1228 ,MPFROMP(pRecord)
1229 ,MPFROM2SHORT(CMA_LASTCHILD, CMA_ITEMORDER)
1230 ));
1231 if (!pRecord)
1232 return wxTreeItemId(-1L);
1233 return wxTreeItemId((long)pRecord->m_ulItemId);
1234 } // end of wxTreeCtrl::GetLastChild
1235
1236 wxTreeItemId wxTreeCtrl::GetNextSibling (
1237 const wxTreeItemId& rItem
1238 ) const
1239 {
1240 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1241 ,rItem.m_pItem
1242 );
1243
1244 if (!pRecord)
1245 return wxTreeItemId(-1L);
1246 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1247 ,CM_QUERYRECORD
1248 ,MPFROMP(pRecord)
1249 ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
1250 ));
1251 if (!pRecord)
1252 return wxTreeItemId(-1L);
1253 return wxTreeItemId((long)pRecord->m_ulItemId);
1254 } // end of wxTreeCtrl::GetNextSibling
1255
1256 wxTreeItemId wxTreeCtrl::GetPrevSibling (
1257 const wxTreeItemId& rItem
1258 ) const
1259 {
1260 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1261 ,rItem.m_pItem
1262 );
1263
1264 if (!pRecord)
1265 return wxTreeItemId(-1L);
1266 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1267 ,CM_QUERYRECORD
1268 ,MPFROMP(pRecord)
1269 ,MPFROM2SHORT(CMA_PREV, CMA_ITEMORDER)
1270 ));
1271 if (!pRecord)
1272 return wxTreeItemId(-1L);
1273 return wxTreeItemId((long)pRecord->m_ulItemId);
1274 } // end of wxTreeCtrl::GetPrevSibling
1275
1276 wxTreeItemId wxTreeCtrl::GetFirstVisibleItem () const
1277 {
1278 PMYRECORD pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1279 ,CM_QUERYRECORD
1280 ,MPFROMP(pRecord)
1281 ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)
1282 ));
1283 if (!pRecord)
1284 return wxTreeItemId(-1L);
1285
1286 if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId)))
1287 return wxTreeItemId((long)pRecord->m_ulItemId);
1288 while(pRecord)
1289 {
1290 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1291 ,CM_QUERYRECORD
1292 ,MPFROMP(pRecord)
1293 ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
1294 ));
1295 if (!pRecord)
1296 return wxTreeItemId(-1L);
1297 if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId)))
1298 return wxTreeItemId((long)pRecord->m_ulItemId);
1299 }
1300 return wxTreeItemId(-1L);
1301 } // end of wxTreeCtrl::GetFirstVisibleItem
1302
1303 wxTreeItemId wxTreeCtrl::GetNextVisible (
1304 const wxTreeItemId& rItem
1305 ) const
1306 {
1307 wxASSERT_MSG(IsVisible(rItem), wxT("The item you call GetNextVisible() for must be visible itself!"));
1308
1309 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1310 ,rItem.m_pItem
1311 );
1312
1313 if (!pRecord)
1314 return wxTreeItemId(-1L);
1315 while(pRecord)
1316 {
1317 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1318 ,CM_QUERYRECORD
1319 ,MPFROMP(pRecord)
1320 ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
1321 ));
1322 if (!pRecord)
1323 return wxTreeItemId(-1L);
1324 if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId)))
1325 return wxTreeItemId((long)pRecord->m_ulItemId);
1326 }
1327 return wxTreeItemId(-1L);
1328 } // end of wxTreeCtrl::GetNextVisible
1329
1330 wxTreeItemId wxTreeCtrl::GetPrevVisible (
1331 const wxTreeItemId& rItem
1332 ) const
1333 {
1334 wxASSERT_MSG( IsVisible(rItem), wxT("The item you call GetPrevVisible() for must be visible itself!"));
1335
1336 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1337 ,rItem.m_pItem
1338 );
1339
1340 if (!pRecord)
1341 return wxTreeItemId(-1L);
1342 while(pRecord)
1343 {
1344 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1345 ,CM_QUERYRECORD
1346 ,MPFROMP(pRecord)
1347 ,MPFROM2SHORT(CMA_PREV, CMA_ITEMORDER)
1348 ));
1349 if (!pRecord)
1350 return wxTreeItemId(-1L);
1351 if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId)))
1352 return wxTreeItemId((long)pRecord->m_ulItemId);
1353 }
1354 return wxTreeItemId(-1L);
1355 } // end of wxTreeCtrl::GetPrevVisible
1356
1357 // ----------------------------------------------------------------------------
1358 // multiple selections emulation -- under OS/2 checked tree items is not
1359 // supported, but multisel is. So we'll just check for selections here.
1360 // ----------------------------------------------------------------------------
1361
1362 bool wxTreeCtrl::IsItemChecked (
1363 const wxTreeItemId& rItem
1364 ) const
1365 {
1366 wxTreeViewItem vTvItem(rItem);
1367
1368 DoGetItem(&vTvItem);
1369 return (vTvItem.m_vRecord.flRecordAttr & CRA_SELECTED);
1370 } // end of wxTreeCtrl::IsItemChecked
1371
1372 void wxTreeCtrl::SetItemCheck (
1373 const wxTreeItemId& rItem
1374 , bool bCheck
1375 )
1376 {
1377 wxTreeViewItem vTvItem(rItem);
1378
1379 DoGetItem(&vTvItem);
1380 ::WinSendMsg( GetHWND()
1381 ,CM_SETRECORDEMPHASIS
1382 ,MPFROMP(&vTvItem)
1383 ,MPFROM2SHORT(TRUE, CRA_SELECTED)
1384 );
1385 DoSetItem(&vTvItem);
1386 } // end of wxTreeCtrl::SetItemCheck
1387
1388 size_t wxTreeCtrl::GetSelections (
1389 wxArrayTreeItemIds& raSelections
1390 ) const
1391 {
1392 TraverseSelections vSelector( this
1393 ,raSelections
1394 );
1395 return vSelector.GetCount();
1396 } // end of wxTreeCtrl::GetSelections
1397
1398 // ----------------------------------------------------------------------------
1399 // Usual operations
1400 // ----------------------------------------------------------------------------
1401
1402 wxTreeItemId wxTreeCtrl::DoInsertItem (
1403 const wxTreeItemId& rParent
1404 , wxTreeItemId vInsertAfter
1405 , const wxString& rsText
1406 , int nImage
1407 , int selectedImage
1408 , wxTreeItemData* pData
1409 )
1410 {
1411 PMYRECORD pRecordAfter = FindOS2TreeRecordByID( GetHWND()
1412 ,vInsertAfter.m_pItem
1413 );
1414
1415 PMYRECORD pRecordParent = FindOS2TreeRecordByID( GetHWND()
1416 ,rParent.m_pItem
1417 );
1418
1419 PMYRECORD pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
1420 ,CM_ALLOCRECORD
1421 ,MPFROMLONG(sizeof(MYRECORD) - sizeof(RECORDCORE))
1422 ,MPFROMLONG(1)
1423 );
1424 RECORDINSERT vInsert;
1425
1426 vInsert.cb = sizeof(RECORDINSERT);
1427 if (rParent.m_pItem == 0L)
1428 {
1429 if (vInsertAfter.m_pItem == -1)
1430 vInsert.pRecordOrder = (PRECORDCORE)CMA_END;
1431 else
1432 vInsert.pRecordOrder = (PRECORDCORE)CMA_FIRST;
1433 vInsert.pRecordParent = NULL;
1434 }
1435 else
1436 {
1437 if (vInsertAfter.m_pItem == 0)
1438 vInsert.pRecordOrder = (PRECORDCORE)CMA_FIRST;
1439 else if (vInsertAfter.m_pItem == -1)
1440 vInsert.pRecordOrder = (PRECORDCORE)CMA_END;
1441 else
1442 vInsert.pRecordOrder = (PRECORDCORE)pRecordAfter;
1443 vInsert.pRecordParent = (PRECORDCORE)pRecordParent;
1444 }
1445 vInsert.fInvalidateRecord = TRUE;
1446 vInsert.zOrder = CMA_TOP;
1447 vInsert.cRecordsInsert = 1;
1448
1449 pRecord->m_vRecord.pszTree = (wxChar*)rsText.c_str();
1450 pRecord->m_vRecord.hbmBitmap = nImage;
1451 pRecord->m_ulItemId = pRecordAfter->m_ulItemId + 1;
1452 if (pData != NULL)
1453 {
1454 pRecord->m_ulUserData = (ULONG)pData;
1455 }
1456 ::WinSendMsg( GetHWND()
1457 ,CM_INSERTRECORD
1458 ,MPFROMP(pRecord)
1459 ,MPFROMP(&vInsert)
1460 );
1461
1462 //
1463 // OS/2 must mannually bump the index's of following records
1464 //
1465 BumpTreeRecordIds( GetHWND()
1466 ,pRecord
1467 );
1468 if (pData != NULL)
1469 {
1470 //
1471 // Associate the application tree item with PM tree item handle
1472 //
1473 pData->SetId((long)pRecord->m_ulItemId);
1474 }
1475 return wxTreeItemId((long)pRecord->m_ulItemId);
1476 }
1477
1478 wxTreeItemId wxTreeCtrl::AddRoot (
1479 const wxString& rsText
1480 , int nImage
1481 , int nSelectedImage
1482 , wxTreeItemData* pData)
1483 {
1484
1485 return DoInsertItem( wxTreeItemId((long)0)
1486 ,wxTreeItemId((long)-1)
1487 ,rsText
1488 ,nImage
1489 ,nSelectedImage
1490 ,pData
1491 );
1492 } // end of wxTreeCtrl::AddRoot
1493
1494 wxTreeItemId wxTreeCtrl::PrependItem (
1495 const wxTreeItemId& rParent
1496 , const wxString& rsText
1497 , int nImage
1498 , int nSelectedImage
1499 , wxTreeItemData* pData
1500 )
1501 {
1502 return DoInsertItem( rParent
1503 ,wxTreeItemId((long)0)
1504 ,rsText
1505 ,nImage
1506 ,nSelectedImage
1507 ,pData
1508 );
1509 } // end of wxTreeCtrl::PrependItem
1510
1511 wxTreeItemId wxTreeCtrl::InsertItem (
1512 const wxTreeItemId& rParent
1513 , const wxTreeItemId& rIdPrevious
1514 , const wxString& rsText
1515 , int nImage
1516 , int nSelectedImage
1517 , wxTreeItemData* pData
1518 )
1519 {
1520 return DoInsertItem( rParent
1521 ,rIdPrevious
1522 ,rsText
1523 ,nImage
1524 ,nSelectedImage
1525 ,pData
1526 );
1527 } // end of wxTreeCtrl::InsertItem
1528
1529 wxTreeItemId wxTreeCtrl::InsertItem (
1530 const wxTreeItemId& rParent
1531 , size_t nIndex
1532 , const wxString& rsText
1533 , int nImage
1534 , int nSelectedImage
1535 , wxTreeItemData* pData
1536 )
1537 {
1538 return DoInsertItem( rParent
1539 ,wxTreeItemId((long)nIndex)
1540 ,rsText
1541 ,nImage
1542 ,nSelectedImage
1543 ,pData
1544 );
1545 } // end of wxTreeCtrl::InsertItem
1546
1547 wxTreeItemId wxTreeCtrl::AppendItem (
1548 const wxTreeItemId& rParent
1549 , const wxString& rsText
1550 , int nImage
1551 , int nSelectedImage
1552 , wxTreeItemData* pData
1553 )
1554 {
1555 return DoInsertItem( rParent
1556 ,wxTreeItemId((long)-1)
1557 ,rsText
1558 ,nImage
1559 ,nSelectedImage
1560 ,pData
1561 );
1562 } // end of wxTreeCtrl::AppendItem
1563
1564 void wxTreeCtrl::Delete (
1565 const wxTreeItemId& rItem
1566 )
1567 {
1568 //
1569 // OS/2 does not generate DELETEITEM events so do it here
1570 //
1571 wxEventType vEventType = wxEVT_NULL;
1572 wxTreeEvent vEvent( wxEVT_NULL
1573 ,m_windowId
1574 );
1575 PMYRECORD pRecord = FindOS2TreeRecordByID( GetHWND()
1576 ,rItem.m_pItem
1577 );
1578 vEvent.SetEventObject(this);
1579 ::WinSendMsg( GetHWND()
1580 ,CM_REMOVERECORD
1581 ,MPFROMP(pRecord)
1582 ,(MPARAM)(CMA_FREE | CMA_INVALIDATE)
1583 );
1584 vEvent.m_item = rItem.m_pItem;
1585 if (m_bHasAnyAttr)
1586 {
1587 delete (wxTreeItemAttr *)m_vAttrs.Delete((long)rItem.m_pItem);
1588 }
1589 vEvent.SetEventType(vEventType);
1590 HandleWindowEvent(vEvent);
1591 } // end of wxTreeCtrl::Delete
1592
1593 // delete all children (but don't delete the item itself)
1594 void wxTreeCtrl::DeleteChildren (
1595 const wxTreeItemId& rItem
1596 )
1597 {
1598 long lCookie;
1599 wxArrayLong aChildren;
1600 wxTreeItemId vChild = GetFirstChild( rItem
1601 ,lCookie
1602 );
1603
1604 while (vChild.IsOk())
1605 {
1606 aChildren.Add((long)(WXHTREEITEM)vChild);
1607 vChild = GetNextChild( rItem
1608 ,lCookie
1609 );
1610 }
1611
1612 size_t nCount = aChildren.Count();
1613
1614 for (size_t n = 0; n < nCount; n++)
1615 {
1616 Delete(aChildren[n]);
1617 }
1618 } // end of wxTreeCtrl::DeleteChildren
1619
1620 void wxTreeCtrl::DeleteAllItems ()
1621 {
1622 ::WinSendMsg( GetHWND()
1623 ,CM_REMOVERECORD
1624 ,NULL // Remove all
1625 ,(MPARAM)(CMA_FREE | CMA_INVALIDATE)
1626 );
1627 } // end of wxTreeCtrl::DeleteAllItems
1628
1629 void wxTreeCtrl::DoExpand (
1630 const wxTreeItemId& rItem
1631 , int nFlag
1632 )
1633 {
1634 PMYRECORD pRecord = FindOS2TreeRecordByID( GetHWND()
1635 ,rItem.m_pItem
1636 );
1637 switch(nFlag)
1638 {
1639 case wxTREE_EXPAND_EXPAND:
1640 ::WinSendMsg( GetHWND()
1641 ,CM_EXPANDTREE
1642 ,MPFROMP(pRecord)
1643 ,NULL
1644 );
1645 break;
1646
1647 case wxTREE_EXPAND_COLLAPSE:
1648 ::WinSendMsg( GetHWND()
1649 ,CM_COLLAPSETREE
1650 ,MPFROMP(pRecord)
1651 ,NULL
1652 );
1653 break;
1654
1655 case wxTREE_EXPAND_COLLAPSE_RESET:
1656 ::WinSendMsg( GetHWND()
1657 ,CM_COLLAPSETREE
1658 ,MPFROMP(pRecord)
1659 ,NULL
1660 );
1661 DeleteChildren(rItem);
1662 break;
1663
1664 case wxTREE_EXPAND_TOGGLE:
1665 if (pRecord->m_vRecord.flRecordAttr & CRA_COLLAPSED)
1666 ::WinSendMsg( GetHWND()
1667 ,CM_EXPANDTREE
1668 ,MPFROMP(pRecord)
1669 ,NULL
1670 );
1671 else if (pRecord->m_vRecord.flRecordAttr & CRA_EXPANDED)
1672 ::WinSendMsg( GetHWND()
1673 ,CM_COLLAPSETREE
1674 ,MPFROMP(pRecord)
1675 ,NULL
1676 );
1677 break;
1678
1679 }
1680 } // end of wxTreeCtrl::DoExpand
1681
1682 void wxTreeCtrl::Expand (
1683 const wxTreeItemId& rItem
1684 )
1685 {
1686 DoExpand( rItem
1687 ,wxTREE_EXPAND_EXPAND
1688 );
1689 } // end of wxTreeCtrl::Expand
1690
1691 void wxTreeCtrl::Collapse (
1692 const wxTreeItemId& rItem
1693 )
1694 {
1695 DoExpand( rItem
1696 ,wxTREE_EXPAND_COLLAPSE
1697 );
1698 } // end of wxTreeCtrl::Collapse
1699
1700 void wxTreeCtrl::CollapseAndReset (
1701 const wxTreeItemId& rItem
1702 )
1703 {
1704 DoExpand( rItem
1705 ,wxTREE_EXPAND_COLLAPSE_RESET
1706 );
1707 } // end of wxTreeCtrl::CollapseAndReset
1708
1709 void wxTreeCtrl::Toggle (
1710 const wxTreeItemId& rItem
1711 )
1712 {
1713 DoExpand( rItem
1714 ,wxTREE_EXPAND_TOGGLE
1715 );
1716 } // end of wxTreeCtrl::Toggle
1717
1718 void wxTreeCtrl::Unselect ()
1719 {
1720 wxASSERT_MSG( !(m_windowStyle & wxTR_MULTIPLE),
1721 wxT("doesn't make sense, may be you want UnselectAll()?") );
1722
1723 //
1724 // Just remove the selection
1725 //
1726 SelectItem(wxTreeItemId((long)0));
1727 } // end of wxTreeCtrl::Unselect
1728
1729 void wxTreeCtrl::UnselectAll ()
1730 {
1731 if (m_windowStyle & wxTR_MULTIPLE)
1732 {
1733 wxArrayTreeItemIds aSelections;
1734 size_t nCount = GetSelections(aSelections);
1735
1736 for (size_t n = 0; n < nCount; n++)
1737 {
1738 SetItemCheck( aSelections[n]
1739 ,false
1740 );
1741 }
1742 }
1743 else
1744 {
1745 //
1746 // Just remove the selection
1747 //
1748 Unselect();
1749 }
1750 } // end of wxTreeCtrl::UnselectAll
1751
1752 void wxTreeCtrl::SelectItem (
1753 const wxTreeItemId& rItem
1754 )
1755 {
1756 SetItemCheck(rItem);
1757 } // end of wxTreeCtrl::SelectItem
1758
1759 void wxTreeCtrl::EnsureVisible (
1760 const wxTreeItemId& rItem
1761 )
1762 {
1763 wxTreeViewItem vTvItem(rItem);
1764
1765 DoGetItem(&vTvItem);
1766 if (!::WinSendMsg( GetHWND()
1767 ,CM_INVALIDATERECORD
1768 ,MPFROMP(&vTvItem)
1769 ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
1770 ));
1771 } // end of wxTreeCtrl::EnsureVisible
1772
1773 void wxTreeCtrl::ScrollTo (
1774 const wxTreeItemId& rItem
1775 )
1776 {
1777 wxTreeViewItem vTvItem(rItem);
1778
1779 DoGetItem(&vTvItem);
1780 if (!::WinSendMsg( GetHWND()
1781 ,CM_INVALIDATERECORD
1782 ,MPFROMP(&vTvItem)
1783 ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
1784 ));
1785 }
1786
1787 wxTextCtrl* wxTreeCtrl::EditLabel (
1788 const wxTreeItemId& rItem
1789 , wxClassInfo* WXUNUSED(pTextControlClass)
1790 )
1791 {
1792 CNREDITDATA vEdit;
1793 PMYRECORD pRecord = FindOS2TreeRecordByID( GetHWND()
1794 ,rItem.m_pItem
1795 );
1796
1797 vEdit.cb = sizeof(CNREDITDATA);
1798 vEdit.hwndCnr = GetHWND();
1799 vEdit.pRecord = &pRecord->m_vRecord;
1800 vEdit.pFieldInfo = NULL;
1801 vEdit.ppszText = NULL;
1802 vEdit.cbText = 0;
1803 vEdit.id = 0;
1804
1805 ::WinSendMsg( GetHWND()
1806 ,CM_OPENEDIT
1807 ,MPFROMP(&vEdit)
1808 ,(MPARAM)0
1809 );
1810 return NULL;
1811 } // end of wxTreeCtrl::EditLabel
1812
1813 // End label editing, optionally cancelling the edit
1814 void wxTreeCtrl::EndEditLabel (
1815 const wxTreeItemId& WXUNUSED(rItem)
1816 , bool WXUNUSED(bDiscardChanges)
1817 )
1818 {
1819 ::WinSendMsg( GetHWND()
1820 ,CM_CLOSEEDIT
1821 ,(MPARAM)0
1822 ,(MPARAM)0
1823 );
1824 } // end of wxTreeCtrl::EndEditLabel
1825
1826 wxTreeItemId wxTreeCtrl::HitTest (
1827 const wxPoint& rPoint
1828 , int& WXUNUSED(rFlags)
1829 )
1830 {
1831 PMYRECORD pRecord = NULL;
1832 QUERYRECFROMRECT vQueryRect;
1833 RECTL vRect;
1834 long lHeight;
1835
1836 //
1837 // Get height for OS/2 point conversion
1838 //
1839 ::WinSendMsg( GetHWND()
1840 ,CM_QUERYVIEWPORTRECT
1841 ,MPFROMP(&vRect)
1842 ,MPFROM2SHORT(CMA_WINDOW, TRUE)
1843 );
1844 lHeight = vRect.yTop - vRect.yBottom;
1845
1846 //
1847 // For now just try and get a record in the general vicinity and forget
1848 // the flag
1849 //
1850 vRect.xLeft = rPoint.x - 2;
1851 vRect.xRight = rPoint.x + 2;
1852 vRect.yTop = (lHeight - rPoint.y) + 2;
1853 vRect.yBottom = (lHeight - rPoint.y) - 2;
1854
1855 vQueryRect.cb = sizeof(QUERYRECFROMRECT);
1856 vQueryRect.rect = vRect;
1857 vQueryRect.fsSearch = CMA_PARTIAL;
1858
1859 pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
1860 ,CM_QUERYRECORDFROMRECT
1861 ,(MPARAM)CMA_FIRST
1862 ,MPFROMP(&vQueryRect)
1863 );
1864
1865 if (!pRecord)
1866 return -1L;
1867 return wxTreeItemId((long)pRecord->m_ulItemId);
1868 } // end of wxTreeCtrl::HitTest
1869
1870 bool wxTreeCtrl::GetBoundingRect (
1871 const wxTreeItemId& rItem
1872 , wxRect& rRect
1873 , bool bTextOnly
1874 ) const
1875 {
1876 RECTL vRectRecord;
1877 PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND()
1878 ,rItem.m_pItem
1879 );
1880 QUERYRECORDRECT vQuery;
1881
1882 vQuery.cb = sizeof(QUERYRECORDRECT);
1883 vQuery.pRecord = (PRECORDCORE)pRecord;
1884 vQuery.fRightSplitWindow = FALSE;
1885 if (bTextOnly)
1886 vQuery.fsExtent = CMA_TEXT;
1887 else
1888 vQuery.fsExtent = CMA_TREEICON | CMA_TEXT;
1889
1890 if (!::WinSendMsg( GetHWND()
1891 ,CM_QUERYRECORDRECT
1892 ,MPFROMP(&vRectRecord)
1893 ,MPFROMP(&vQuery)
1894 ))
1895 return false;
1896 rRect.SetLeft(vRectRecord.xLeft);
1897 rRect.SetTop(vRectRecord.yTop);
1898 rRect.SetRight(vRectRecord.xRight);
1899 rRect.SetBottom(vRectRecord.yBottom);
1900 return true;
1901 } // end of wxTreeCtrl::GetBoundingRect
1902
1903 // ----------------------------------------------------------------------------
1904 // sorting stuff
1905 // ----------------------------------------------------------------------------
1906
1907 SHORT EXPENTRY InternalDataCompareTreeFunc (
1908 PMYRECORD p1
1909 , PMYRECORD p2
1910 , PVOID pStorage
1911 )
1912 {
1913 wxCHECK_MSG( p1 && p2, 0,
1914 wxT("sorting tree without data doesn't make sense") );
1915
1916 wxTreeCtrl* pTree = (wxTreeCtrl*)pStorage;
1917
1918 return pTree->OnCompareItems( p1->m_ulItemId
1919 ,p2->m_ulItemId
1920 );
1921 } // end of wxTreeSortHelper::Compare
1922
1923 int wxTreeCtrl::OnCompareItems (
1924 const wxTreeItemId& rItem1
1925 , const wxTreeItemId& rItem2
1926 )
1927 {
1928 return wxStrcmp( GetItemText(rItem1)
1929 ,GetItemText(rItem2)
1930 );
1931 } // end of wxTreeCtrl::OnCompareItems
1932
1933 void wxTreeCtrl::SortChildren (
1934 const wxTreeItemId& rItem
1935 )
1936 {
1937 ::WinSendMsg( GetHWND()
1938 ,CM_SORTRECORD
1939 ,(PFN)InternalDataCompareTreeFunc
1940 ,NULL
1941 );
1942 } // end of wxTreeCtrl::SortChildren
1943
1944 // ----------------------------------------------------------------------------
1945 // implementation
1946 // ----------------------------------------------------------------------------
1947
1948 bool wxTreeCtrl::OS2Command (
1949 WXUINT uCmd
1950 , WXWORD wId
1951 )
1952 {
1953 if (uCmd == CN_ENDEDIT)
1954 {
1955 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED
1956 ,wId
1957 );
1958
1959 vEvent.SetEventObject( this );
1960 ProcessCommand(vEvent);
1961 return true;
1962 }
1963 else if (uCmd == CN_KILLFOCUS)
1964 {
1965 wxCommandEvent vEvent( wxEVT_KILL_FOCUS
1966 ,wId
1967 );
1968 vEvent.SetEventObject( this );
1969 ProcessCommand(vEvent);
1970 return true;
1971 }
1972 else
1973 return false;
1974 } // end of wxTreeCtrl::OS2Command
1975
1976 //
1977 // TODO: Fully implement direct manipulation when I figure it out
1978 //
1979 MRESULT wxTreeCtrl::OS2WindowProc (
1980 WXUINT uMsg
1981 , WXWPARAM wParam
1982 , WXLPARAM lParam
1983 )
1984 {
1985 bool bProcessed = false;
1986 MRESULT mRc = 0;
1987 wxTreeEvent vEvent( wxEVT_NULL
1988 ,m_windowId
1989 );
1990 wxEventType vEventType = wxEVT_NULL;
1991 PCNRDRAGINIT pDragInit = NULL;
1992 PCNREDITDATA pEditData = NULL;
1993 PNOTIFYRECORDENTER pNotifyEnter = NULL;
1994
1995 vEvent.SetEventObject(this);
1996 switch (uMsg)
1997 {
1998 case WM_CONTROL:
1999 switch(SHORT2FROMMP(wParam))
2000 {
2001 case CN_INITDRAG:
2002 pDragInit = (PCNRDRAGINIT)lParam;
2003 if (pDragInit)
2004 {
2005 PMYRECORD pRecord = (PMYRECORD)pDragInit->pRecord;
2006
2007 vEventType = wxEVT_COMMAND_TREE_BEGIN_DRAG;
2008 vEvent.m_item = pRecord->m_ulItemId;
2009 vEvent.m_pointDrag.x = pDragInit->x;
2010 vEvent.m_pointDrag.y = pDragInit->y;
2011 }
2012 break;
2013
2014 case CN_BEGINEDIT:
2015 pEditData = (PCNREDITDATA)lParam;
2016 if (pEditData)
2017 {
2018 PMYRECORD pRecord = (PMYRECORD)pEditData->pRecord;
2019
2020 vEventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT;
2021 vEvent.m_item = pRecord->m_ulItemId;
2022 vEvent.m_label = pRecord->m_vRecord.pszTree;
2023 vEvent.m_editCancelled = false;
2024 }
2025 break;
2026
2027 case CN_ENDEDIT:
2028 pEditData = (PCNREDITDATA)lParam;
2029 if (pEditData)
2030 {
2031 PMYRECORD pRecord = (PMYRECORD)pEditData->pRecord;
2032
2033 vEventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT;
2034 vEvent.m_item = pRecord->m_ulItemId;
2035 vEvent.m_label = pRecord->m_vRecord.pszTree;
2036 if (pRecord->m_vRecord.pszTree == NULL)
2037 {
2038 vEvent.m_editCancelled = true;
2039 }
2040 else
2041 {
2042 vEvent.m_editCancelled = false;
2043 }
2044 }
2045 break;
2046
2047 case CN_EXPANDTREE:
2048 {
2049 PMYRECORD pRecord = (PMYRECORD)lParam;
2050
2051 vEventType = gs_expandEvents[IDX_EXPAND][IDX_DONE];
2052 vEvent.m_item = pRecord->m_ulItemId;
2053 }
2054 break;
2055 }
2056 vEvent.SetEventType(vEventType);
2057 bProcessed = HandleWindowEvent(vEvent);
2058 break;
2059 }
2060 if (!bProcessed)
2061 mRc = wxControl::OS2WindowProc( uMsg
2062 ,wParam
2063 ,lParam
2064 );
2065 return mRc;
2066 } // end of wxTreeCtrl::OS2WindowProc
2067
2068 #endif // wxUSE_TREECTRL