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