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