]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/treectrl.cpp
using proper cmd constant
[wxWidgets.git] / src / os2 / treectrl.cpp
index 137a885dbfa7e32c9096f78376146fda7cffaf68..9bddf9c7199d68deedb0b82dde51a97089e98f2e 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
-// Name:        treectrl.cpp
-// Purpose:     wxTreeCtrl. See also Robert's generic wxTreeCtrl.
-// Author:      AUTHOR
-// Modified by:
-// Created:     ??/??/98
+// Name:        src/os2/treectrl.cpp
+// Purpose:     wxTreeCtrl
+// Author:      Julian Smart
+// Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98
+// Created:     1997
 // RCS-ID:      $Id$
-// Copyright:   (c) AUTHOR
-// Licence:    wxWindows licence
+// Copyright:   (c) Julian Smart
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#ifdef __GNUG__
-#pragma implementation "treectrl.h"
-#endif
+// ============================================================================
+// declarations
+// ============================================================================
 
-#include "wx/stubs/textctrl.h"
-#include "wx/stubs/treectrl.h"
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
 
-#if !USE_SHARED_LIBRARY
-IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
-IMPLEMENT_DYNAMIC_CLASS(wxTreeItem, wxObject)
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
 
+#ifdef __BORLANDC__
+    #pragma hdrstop
 #endif
 
-wxTreeCtrl::wxTreeCtrl()
-{
-    m_imageListNormal = NULL;
-    m_imageListState = NULL;
-    m_textCtrl = NULL;
-}
+#if wxUSE_TREECTRL
 
-bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
-            long style, const wxValidator& validator, const wxString& name)
-{
-    SetName(name);
-    SetValidator(validator);
+#include "wx/treectrl.h"
 
-    m_imageListNormal = NULL;
-    m_imageListState = NULL;
-    m_textCtrl = NULL;
+#ifndef WX_PRECOMP
+    #include "wx/dynarray.h"
+    #include "wx/log.h"
+    #include "wx/app.h"
+    #include "wx/settings.h"
+#endif
 
-    m_windowStyle = style;
+#include "wx/os2/private.h"
 
-    SetParent(parent);
+#include "wx/imaglist.h"
 
-    m_windowId = (id == -1) ? NewControlId() : id;
+// a macro to hide the ugliness of nested casts
+#define HITEM(item)     (HTREEITEM)(WXHTREEITEM)(item)
 
-    if (parent) parent->AddChild(this);
+// the native control doesn't support multiple selections under MSW and we
+// have 2 ways to emulate them: either using TVS_CHECKBOXES style and let
+// checkboxes be the selection status (checked == selected) or by really
+// emulating everything, i.e. intercepting mouse and key events &c. The first
+// approach is much easier but doesn't work with comctl32.dll < 4.71 and also
+// looks quite ugly.
+#define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0
 
-    // TODO create tree control
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
 
-    return FALSE;
-}
+// ----------------------------------------------------------------------------
+// private classes
+// ----------------------------------------------------------------------------
+
+typedef struct _MYRECORD
+{
+    RECORDCORE                      m_vRecord;
+    ULONG                           m_ulItemId;
+    ULONG                           m_ulUserData;
+} MYRECORD, *PMYRECORD;
 
-wxTreeCtrl::~wxTreeCtrl()
+struct wxTreeViewItem : public MYRECORD
 {
-    if (m_textCtrl)
+    wxTreeViewItem(const wxTreeItemId& rItem)
     {
-        delete m_textCtrl;
+        m_ulItemId = (ULONG)rItem.m_pItem;
     }
-}
+}; // end of STRUCT wxTreeViewItem
 
-// Attributes
-int wxTreeCtrl::GetCount() const
+class wxTreeItemInternalData
 {
-    // TODO
-    return 0;
-}
+public:
+
+    wxTreeItemInternalData() {}
+    ~wxTreeItemInternalData()
+    {
+        wxDELETE(m_pAttr);
+    }
+
+    wxTreeItemAttr*                 m_pAttr;
+    WXLPARAM                        m_lParam; // user data
+#if defined(C_CM_COS232)
+    PMYRECORD                       m_pMyRecord; // so we can set the m_ulUserData to 0 when this is deleted
+#endif
+}; // end of CLASS wxTreeItemInternalData
 
-int wxTreeCtrl::GetIndent() const
+void BumpTreeRecordIds (
+  HWND                              hWnd
+, PMYRECORD                         pRecord
+)
 {
-    // TODO
-    return 0;
-}
+    while(pRecord)
+    {
+        pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
+                                                      ,CM_QUERYRECORD
+                                                      ,MPFROMP(pRecord)
+                                                      ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+                                                     ));
+        if (pRecord)
+            pRecord->m_ulItemId++;
+    }
+} // end of BumpTreeRecordIds
 
-void wxTreeCtrl::SetIndent(int indent)
+PMYRECORD FindOS2TreeRecordByID (
+  HWND                              hWnd
+, long                              lItemId
+)
 {
-    // TODO
-}
+    PMYRECORD                       pRecord = NULL;
+    CNRINFO                         vCnrInfo;
+    unsigned long                   i;
+
+    if (!::WinSendMsg( hWnd
+                      ,CM_QUERYCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                     ))
+        return NULL;
+    for (i = 0; i < vCnrInfo.cRecords; i++)
+    {
+        if (i == 0)
+            pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
+                                                          ,CM_QUERYRECORD
+                                                          ,MPFROMP(pRecord)
+                                                          ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)
+                                                         ));
+        else
+            pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
+                                                          ,CM_QUERYRECORD
+                                                          ,MPFROMP(pRecord)
+                                                          ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+                                                         ));
+        if (!pRecord)
+            return NULL;
+        if (pRecord->m_ulItemId == (ULONG)lItemId)
+            break;
+    }
+    return pRecord;
+} // end of FindOS2ListRecordByID
 
-wxImageList *wxTreeCtrl::GetImageList(int which) const
+
+
+class wxTreeTraversal
 {
-  if ( which == wxIMAGE_LIST_NORMAL )
+public:
+    wxTreeTraversal(const wxTreeCtrl* pTree)
     {
-    return m_imageListNormal;
-  }
-  else if ( which == wxIMAGE_LIST_STATE )
+        m_pTree = pTree;
+    }
+
+    //
+    // Do traverse the tree: visit all items (recursively by default) under the
+    // given one; return true if all items were traversed or false if the
+    // traversal was aborted because OnVisit returned false
+    //
+    bool DoTraverse( const wxTreeItemId& rRoot
+                    ,bool                bRecursively = true
+                   );
+
+    //
+    // Override this function to do whatever is needed for each item, return
+    // false to stop traversing
+    //
+    virtual bool OnVisit(const wxTreeItemId& rItem) = 0;
+
+protected:
+    const wxTreeCtrl* GetTree(void) const { return m_pTree; }
+
+private:
+    bool Traverse( const wxTreeItemId& rRoot
+                  ,bool                bRecursively
+                 );
+
+    const wxTreeCtrl*               m_pTree;
+    wxDECLARE_NO_COPY_CLASS(wxTreeTraversal);
+}; // end of CLASS wxTreeTraversal
+
+//
+// Internal class for getting the selected items
+//
+class TraverseSelections : public wxTreeTraversal
+{
+public:
+    TraverseSelections( const wxTreeCtrl*   pTree
+                       ,wxArrayTreeItemIds& raSelections
+                      )
+                      : wxTreeTraversal(pTree)
+                      , m_aSelections(raSelections)
     {
-    return m_imageListState;
-  }
-  return NULL;
-}
+        m_aSelections.Empty();
+        DoTraverse(pTree->GetRootItem());
+    }
 
-void wxTreeCtrl::SetImageList(wxImageList *imageList, int which)
+    virtual bool OnVisit(const wxTreeItemId& rItem)
+    {
+        //
+        // Can't visit a virtual node.
+        //
+        if ((GetTree()->GetRootItem() == rItem) && (GetTree()->GetWindowStyle() & wxTR_HIDE_ROOT))
+        {
+            return true;
+        }
+        PMYRECORD                   pRecord = FindOS2TreeRecordByID( (HWND)GetTree()->GetHWND()
+                                                                    ,rItem.m_pItem
+                                                                   );
+        if (pRecord->m_vRecord.flRecordAttr & CRA_SELECTED)
+        {
+            m_aSelections.Add(rItem);
+        }
+        return true;
+    }
+
+    size_t GetCount(void) const { return m_aSelections.GetCount(); }
+
+private:
+    wxArrayTreeItemIds&             m_aSelections;
+}; // end of CLASS TraverseSelections
+
+//
+// Internal class for counting tree items
+//
+class TraverseCounter : public wxTreeTraversal
 {
-    if ( which == wxIMAGE_LIST_NORMAL )
+public:
+    TraverseCounter( const wxTreeCtrl*   pTree
+                    ,const wxTreeItemId& rRoot
+                    ,bool                bRecursively
+                   )
+                   : wxTreeTraversal(pTree)
     {
-        m_imageListNormal = imageList;
+        m_nCount = 0;
+        DoTraverse(rRoot, bRecursively);
     }
-    else if ( which == wxIMAGE_LIST_STATE )
+
+    virtual bool OnVisit(const wxTreeItemId& WXUNUSED(rItem))
     {
-        m_imageListState = imageList;
+        m_nCount++;
+        return true;
     }
-    // TODO
-}
 
-long wxTreeCtrl::GetNextItem(long item, int code) const
+    size_t GetCount(void) const { return m_nCount; }
+
+private:
+    size_t                          m_nCount;
+}; // end of CLASS TraverseCounter
+
+// ----------------------------------------------------------------------------
+// wxWin macros
+// ----------------------------------------------------------------------------
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// indices in gs_expandEvents table below
+enum
 {
-    // TODO
-    return 0;
-}
+    IDX_COLLAPSE,
+    IDX_EXPAND,
+    IDX_WHAT_MAX
+};
 
-bool wxTreeCtrl::ItemHasChildren(long item) const
+enum
 {
-    // TODO
-    return FALSE;
-}
+    IDX_DONE,
+    IDX_DOING,
+    IDX_HOW_MAX
+};
+
+// handy table for sending events - it has to be initialized during run-time
+// now so can't be const any more
+static /* const */ wxEventType gs_expandEvents[IDX_WHAT_MAX][IDX_HOW_MAX];
+
+/*
+   but logically it's a const table with the following entries:
+=
+{
+    { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
+    { wxEVT_COMMAND_TREE_ITEM_EXPANDED,  wxEVT_COMMAND_TREE_ITEM_EXPANDING  }
+};
+*/
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// tree traversal
+// ----------------------------------------------------------------------------
+
+bool wxTreeTraversal::DoTraverse (
+  const wxTreeItemId&               rRoot
+, bool                              bRecursively
+)
+{
+    if (!OnVisit(rRoot))
+        return false;
+
+    return Traverse( rRoot
+                    ,bRecursively
+                   );
+} // end of wxTreeTraversal::DoTraverse
+
+bool wxTreeTraversal::Traverse (
+  const wxTreeItemId&               rRoot
+, bool                              bRecursively
+)
+{
+    long                            lCookie;
+    wxTreeItemId                    vChild = m_pTree->GetFirstChild( rRoot
+                                                                    ,lCookie
+                                                                   );
+    while (vChild.IsOk())
+    {
+        //
+        // Depth first traversal
+        //
+        if (bRecursively && !Traverse(vChild, true))
+            return false;
+        if (!OnVisit(vChild))
+            return false;
+        vChild = m_pTree->GetNextChild( rRoot
+                                       ,lCookie
+                                      );
+    }
+    return true;
+} // end of wxTreeTraversal::Traverse
 
-long wxTreeCtrl::GetChild(long item) const
+// ----------------------------------------------------------------------------
+// construction and destruction
+// ----------------------------------------------------------------------------
+
+void wxTreeCtrl::Init ()
 {
-    // TODO
-    return 0;
-}
+    m_pImageListNormal     = NULL;
+    m_pImageListState      = NULL;
+    m_bOwnsImageListNormal = false;
+    m_bOwnsImageListState  = false;
+    m_bHasAnyAttr          = false;
+    m_pDragImage           = NULL;
+
+    //
+    // Initialize the global array of events now as it can't be done statically
+    // with the wxEVT_XXX values being allocated during run-time only
+    //
+    gs_expandEvents[IDX_COLLAPSE][IDX_DONE]  = wxEVT_COMMAND_TREE_ITEM_COLLAPSED;
+    gs_expandEvents[IDX_COLLAPSE][IDX_DOING] = wxEVT_COMMAND_TREE_ITEM_COLLAPSING;
+    gs_expandEvents[IDX_EXPAND][IDX_DONE]    = wxEVT_COMMAND_TREE_ITEM_EXPANDED;
+    gs_expandEvents[IDX_EXPAND][IDX_DOING]   = wxEVT_COMMAND_TREE_ITEM_EXPANDING;
+} // end of wxTreeCtrl::Init
+
+bool wxTreeCtrl::Create (
+  wxWindow*                         pParent
+, wxWindowID                        vId
+, const wxPoint&                    rPos
+, const wxSize&                     rSize
+, long                              lStyle
+, const wxValidator&                rValidator
+, const wxString&                   rsName
+)
+{
+    CNRINFO                         vCnrInfo;
+
+    Init();
+    if (!CreateControl( pParent
+                       ,vId
+                       ,rPos
+                       ,rSize
+                       ,lStyle
+                       ,rValidator
+                       ,rsName
+                      ))
+        return false;
+
+    DWORD                           dwStyle = WS_VISIBLE | WS_TABSTOP;
+
+    if (m_windowStyle & wxCLIP_SIBLINGS)
+        dwStyle |= WS_CLIPSIBLINGS;
+
+    // Create the tree control.
+    if (!OS2CreateControl( "CONTAINER"
+                          ,dwStyle
+                         ))
+        return false;
+
+    //
+    // Now set the display attributes to show a TREE/ICON view of the
+    // OS/2 Container
+    //
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                     ))
+
+    vCnrInfo.flWindowAttr = CV_TREE|CV_ICON;
+    vCnrInfo.flWindowAttr |= CA_DRAWBITMAP;
+    if (m_windowStyle & wxTR_NO_LINES)
+        vCnrInfo.flWindowAttr |= CA_TREELINE;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_SETCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)CMA_FLWINDOWATTR
+                );
+
+    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+    SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
+    SetFont(*wxSMALL_FONT);
+    SetXComp(0);
+    SetYComp(0);
+    SetSize( rPos.x
+            ,rPos.y
+            ,rSize.x
+            ,rSize.y
+           );
+    return true;
+} // end of wxTreeCtrl::Create
+
+wxTreeCtrl::~wxTreeCtrl ()
+{
+    //
+    // Delete any attributes
+    //
+    if (m_bHasAnyAttr)
+    {
+        for (wxNode* pNode = m_vAttrs.Next(); pNode; pNode = m_vAttrs.Next())
+        {
+            delete (wxTreeItemAttr *)pNode->Data();
+        }
+        m_bHasAnyAttr = false;
+    }
+    DeleteTextCtrl();
+
+    //
+    // Delete user data to prevent memory leaks
+    // also deletes hidden root node storage.
+    //
+    DeleteAllItems();
+    if (m_bOwnsImageListNormal)
+        delete m_pImageListNormal;
+    if (m_bOwnsImageListState)
+        delete m_pImageListState;
+} // end of wxTreeCtrl::~wxTreeCtrl
+
+// ----------------------------------------------------------------------------
+// accessors
+// ----------------------------------------------------------------------------
+
+//
+// simple wrappers which add error checking in debug mode.  These methods
+// assume the items are properly filled out already.  If not, you get errors
+//
+bool wxTreeCtrl::DoGetItem (
+  wxTreeViewItem*                   pTvItem
+) const
+{
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID( GetHWND()
+                                                                    ,pTvItem->m_ulItemId
+                                                                   );
+
+    if (!pRecord)
+    {
+        wxLogLastError(wxT("Item not obtained"));
+        return false;
+    }
+    return true;
+} // end of wxTreeCtrl::DoGetItem
 
-long wxTreeCtrl::GetParent(long item) const
+void wxTreeCtrl::DoSetItem (
+  wxTreeViewItem*                   pTvItem
+)
 {
-    // TODO
-    return 0;
-}
+    //
+    // Just invalidate the record to redisplay it
+    //
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_INVALIDATERECORD
+                      ,MPFROMP(pTvItem)
+                      ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
+                     ));
+    {
+        wxLogLastError(wxT("CM_INVALIDATERECORD"));
+    }
+} // end of wxTreeCtrl::DoSetItem
 
-long wxTreeCtrl::GetFirstVisibleItem() const
+unsigned int wxTreeCtrl::GetCount () const
 {
-    // TODO
-    return 0;
-}
+    CNRINFO  vCnrInfo;
 
-long wxTreeCtrl::GetNextVisibleItem(long item) const
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                );
+
+    return (unsigned int)vCnrInfo.cRecords;
+} // end of wxTreeCtrl::GetCount
+
+unsigned int wxTreeCtrl::GetIndent () const
 {
-    // TODO
-    return 0;
-}
+    CNRINFO                         vCnrInfo;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                );
+    return (unsigned int)vCnrInfo.cxTreeIndent;
+} // end of wxTreeCtrl::GetIndent
+
+void wxTreeCtrl::SetIndent (
+  unsigned int                  uIndent
+)
+{
+    CNRINFO                         vCnrInfo;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                );
+    vCnrInfo.cxTreeIndent = (LONG)uIndent;
+    ::WinSendMsg( GetHWND()
+                 ,CM_SETCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)CMA_CXTREEINDENT
+                );
+} // end of wxTreeCtrl::SetIndent
+
+wxImageList* wxTreeCtrl::GetImageList () const
+{
+    return m_pImageListNormal;
+} // end of wxTreeCtrl::GetImageList
 
-long wxTreeCtrl::GetSelection() const
+wxImageList* wxTreeCtrl::GetStateImageList () const
 {
-    // TODO
-    return 0;
-}
+    return m_pImageListNormal;
+} // end of wxTreeCtrl::GetStateImageList
+
+//
+// The SETS of imagelists really do nothing under OS2 as a RECORDCORE
+// struct has the icon imbedded in it that it uses for the icon being
+// displayed via the TREEITEMDESC member.  Provided for interface
+// compatibility only
+//
+void wxTreeCtrl::SetAnyImageList (
+  wxImageList*                      WXUNUSED(pImageList)
+, int                               WXUNUSED(nWhich)
+)
+{
+} // end of wxTreeCtrl::SetAnyImageList
 
-long wxTreeCtrl::GetRootItem() const
+void wxTreeCtrl::SetImageList (
+  wxImageList*                      WXUNUSED(pImageList)
+)
 {
-    // TODO
-    return 0;
-}
+    if (m_bOwnsImageListNormal)
+        delete m_pImageListNormal;
+    m_bOwnsImageListNormal = false;
+} // end of wxTreeCtrl::SetImageList
+
+void wxTreeCtrl::SetStateImageList (
+  wxImageList*                      WXUNUSED(pImageList)
+)
+{
+    if (m_bOwnsImageListState)
+        delete m_pImageListState;
+    m_bOwnsImageListState = false;
+} // end of wxTreeCtrl::SetStateImageList
+
+void wxTreeCtrl::AssignImageList (
+  wxImageList*                      WXUNUSED(pImageList)
+)
+{
+    m_bOwnsImageListNormal = true;
+} // end of wxTreeCtrl::AssignImageList
 
-bool wxTreeCtrl::GetItem(wxTreeItem& info) const
+void wxTreeCtrl::AssignStateImageList (
+  wxImageList*                      WXUNUSED(pImageList)
+)
 {
-    // TODO
-    return FALSE;
-}
+    m_bOwnsImageListState = true;
+} // end of wxTreeCtrl::AssignStateImageList
 
-bool wxTreeCtrl::SetItem(wxTreeItem& info)
+size_t wxTreeCtrl::GetChildrenCount (
+  const wxTreeItemId&               rItem
+, bool                              bRecursively
+) const
 {
-    // TODO
-    return FALSE;
-}
+    TraverseCounter                 vCounter( this
+                                             ,rItem
+                                             ,bRecursively
+                                            );
+    return vCounter.GetCount() - 1;
+} // end of wxTreeCtrl::GetChildrenCount
+
+// ----------------------------------------------------------------------------
+// control colours
+// ----------------------------------------------------------------------------
+
+bool wxTreeCtrl::SetBackgroundColour (
+  const wxColour&                   rColour
+)
+{
+    ULONG                           ulColor = wxColourToRGB(rColour);
+
+    if ( !wxWindowBase::SetBackgroundColour(rColour) )
+        return false;
+    ::WinSetPresParam( GetHWND()
+                      ,PP_BACKGROUNDCOLOR
+                      ,sizeof(ULONG)
+                      ,&ulColor
+                     );
+    return true;
+} // end of wxTreeCtrl::SetBackgroundColour
+
+bool wxTreeCtrl::SetForegroundColour (
+  const wxColour&                   rColour
+)
+{
+    ULONG                           ulColor = wxColourToRGB(rColour);
+
+    if (!wxWindowBase::SetForegroundColour(rColour))
+        return false;
+    ::WinSetPresParam( GetHWND()
+                      ,PP_FOREGROUNDCOLOR
+                      ,sizeof(ULONG)
+                      ,&ulColor
+                     );
+    return true;
+} // end of wxTreeCtrl::SetForegroundColour
+
+// ----------------------------------------------------------------------------
+// Item access
+// ----------------------------------------------------------------------------
+
+wxString wxTreeCtrl::GetItemText (
+  const wxTreeItemId&               rItem
+) const
+{
+    wxChar                          zBuf[512];  // the size is arbitrary...
+    wxTreeViewItem                  vTvItem(rItem);
 
-int wxTreeCtrl::GetItemState(long item, long stateMask) const
+    if (!DoGetItem(&vTvItem))
+    {
+        //
+        // Don't return some garbage which was on stack, but an empty string
+        //
+        zBuf[0] = wxT('\0');
+    }
+    else
+        strcpy(zBuf, vTvItem.m_vRecord.pszTree);
+    return wxString(zBuf);
+} // end of wxTreeCtrl::GetItemText
+
+void wxTreeCtrl::SetItemText (
+  const wxTreeItemId&               rItem
+, const wxString&                   rsText
+)
+{
+    wxTreeViewItem                  vTvItem(rItem);
+
+    vTvItem.m_vRecord.pszTree = (wxChar *)rsText.c_str();  // conversion is ok
+    DoSetItem(&vTvItem);
+} // end of wxTreeCtrl::SetItemText
+
+//
+// These functions under OS/2 PM are not needed.  OS/2 containers in tree view
+// provide for storing a custom expanded and collapsed icons and selected
+// and non selected icons, natively.  For instance, by default, a disk display
+// will display a tree list of folder icons with "+" icons (collapsed) beside
+// those folder which contain child members.  Double clicking a folder changes
+// the closed folder icon to an open folder icon with hatched selection
+// highlighting indicating an ICON view container of the folder is open
+// elsewhere on the desktop.  So the below is not really needed, but we will
+// simply return the appropriate icon requested out of OS/2's native PM
+// data structures.
+//
+int wxTreeCtrl::DoGetItemImageFromData (
+  const wxTreeItemId&               WXUNUSED(rItem)
+, wxTreeItemIcon                    nWhich
+) const
 {
-    wxTreeItem info;
+    //
+    // Image handles stored in CNRINFO.
+    //
+    CNRINFO                         vCnrInfo;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                );
+
+    //
+    // We really only have two to chose from.  If not custom (set in CNRINFO
+    // then return the handle to system bitmap).  OS/2 automatically provides
+    // in_use and selected bitmaps/icons
+    //
+    switch(nWhich)
+    {
+        case wxTreeItemIcon_Normal:
+            if (vCnrInfo.hbmCollapsed == NULLHANDLE)
+                return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEPLUS);
+            return vCnrInfo.hbmCollapsed;
 
-    info.m_mask = wxTREE_MASK_STATE ;
-    info.m_stateMask = stateMask;
-    info.m_itemId = item;
 
-    if (!GetItem(info))
-        return 0;
+        case wxTreeItemIcon_Expanded:
+            if (vCnrInfo.hbmExpanded == NULLHANDLE)
+                return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEMINUS);
+            return vCnrInfo.hbmExpanded;
 
-    return info.m_state;
+        default:
+            return vCnrInfo.hbmCollapsed;
+    }
 }
 
-bool wxTreeCtrl::SetItemState(long item, long state, long stateMask)
+void wxTreeCtrl::DoSetItemImageFromData (
+  const wxTreeItemId&               WXUNUSED(rItem)
+, int                               nImage
+, wxTreeItemIcon                    nWhich
+) const
 {
-    wxTreeItem info;
+    //
+    // Image handles stored in CNRINFO.
+    //
+    CNRINFO                         vCnrInfo;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                );
+    if (nWhich == wxTreeItemIcon_Normal)
+         vCnrInfo.hbmCollapsed = (HBITMAP)nImage;
+    if (nWhich == wxTreeItemIcon_Expanded)
+        vCnrInfo.hbmExpanded = (HBITMAP)nImage;
+    ::WinSendMsg( GetHWND()
+                 ,CM_SETCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)CMA_TREEBITMAP
+                );
+} // end of wxTreeCtrl::DoSetItemImageFromData
+
+// Useless for OS/2
+void wxTreeCtrl::DoSetItemImages (
+  const wxTreeItemId&               rItem
+, int                               nImage
+, int                               nImageSel
+)
+{
+} // end of wxTreeCtrl::DoSetItemImages
+
+int wxTreeCtrl::GetItemImage (
+  const wxTreeItemId&               rItem
+, wxTreeItemIcon                    nWhich
+) const
+{
+    if (HasIndirectData(rItem))
+    {
+        return DoGetItemImageFromData( rItem
+                                      ,nWhich
+                                     );
+    }
 
-    info.m_mask = wxTREE_MASK_STATE ;
-    info.m_state = state;
-    info.m_stateMask = stateMask;
-    info.m_itemId = item;
+    CNRINFO                         vCnrInfo;
 
-    return SetItem(info);
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                );
+    switch (nWhich)
+    {
+        default:
+            wxFAIL_MSG( wxT("unknown tree item image type") );
+
+        case wxTreeItemIcon_Normal:
+            if (vCnrInfo.hbmCollapsed == NULLHANDLE)
+                return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEPLUS);
+            return vCnrInfo.hbmCollapsed;
+
+
+        case wxTreeItemIcon_Expanded:
+            if (vCnrInfo.hbmExpanded == NULLHANDLE)
+                return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEMINUS);
+            return vCnrInfo.hbmExpanded;
+
+        case wxTreeItemIcon_Selected:
+        case wxTreeItemIcon_SelectedExpanded:
+            return -1;
+    }
 }
 
-bool wxTreeCtrl::SetItemImage(long item, int image, int selImage)
+void wxTreeCtrl::SetItemImage (
+  const wxTreeItemId&               WXUNUSED(rItem)
+, int                               nImage
+, wxTreeItemIcon                    nWhich
+)
+{
+    CNRINFO                         vCnrInfo;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                );
+    switch (nWhich)
+    {
+        case wxTreeItemIcon_Normal:
+            vCnrInfo.hbmCollapsed = (HBITMAP)nImage;
+            break;
+
+        case wxTreeItemIcon_Expanded:
+            vCnrInfo.hbmExpanded = (HBITMAP)nImage;
+            break;
+
+        default:
+            wxFAIL_MSG( wxT("unknown tree item image type") );
+    }
+    ::WinSendMsg( GetHWND()
+                 ,CM_SETCNRINFO
+                 ,MPFROMP(&vCnrInfo)
+                 ,(MPARAM)CMA_TREEBITMAP
+                );
+} // end of wxTreeCtrl::SetItemImage
+
+wxTreeItemData* wxTreeCtrl::GetItemData (
+  const wxTreeItemId&               rItem
+) const
 {
-    wxTreeItem info;
+    wxTreeViewItem                  vTvItem(rItem);
 
-    info.m_mask = wxTREE_MASK_IMAGE ;
-    info.m_image = image;
-    if ( selImage > -1)
+    if (!DoGetItem(&vTvItem))
     {
-        info.m_selectedImage = selImage;
-        info.m_mask |= wxTREE_MASK_SELECTED_IMAGE;
+        return NULL;
     }
-    info.m_itemId = item;
 
-    return SetItem(info);
-}
+    return (wxTreeItemData *)vTvItem.m_ulUserData;
+} // end of wxTreeCtrl::GetItemData
 
-wxString wxTreeCtrl::GetItemText(long item) const
+void wxTreeCtrl::SetItemData (
+  const wxTreeItemId&               rItem
+, wxTreeItemData*                   pData
+)
 {
-    wxTreeItem info;
+    //
+    // first, associate this piece of data with this item
+    if (pData)
+    {
+        pData->SetId(rItem);
+    }
 
-    info.m_mask = wxTREE_MASK_TEXT ;
-    info.m_itemId = item;
+    wxTreeViewItem                  vTvItem(rItem);
 
-    if (!GetItem(info))
-        return wxString("");
-    return info.m_text;
-}
+    vTvItem.m_ulUserData = (ULONG)pData;
+    DoSetItem(&vTvItem);
+} // end of wxTreeCtrl::SetItemData
 
-void wxTreeCtrl::SetItemText(long item, const wxString& str)
+// The following two do nothing under OS/2
+void wxTreeCtrl::SetIndirectItemData (
+  const wxTreeItemId&               WXUNUSED(rItem)
+, wxTreeItemIndirectData*           WXUNUSED(pData)
+)
 {
-    wxTreeItem info;
+} // end of wxTreeCtrl::SetIndirectItemData
 
-    info.m_mask = wxTREE_MASK_TEXT ;
-    info.m_itemId = item;
-    info.m_text = str;
+bool wxTreeCtrl::HasIndirectData (
+  const wxTreeItemId&               WXUNUSED(rItem)
+) const
+{
+    return false;
+} // end of wxTreeCtrl::HasIndirectData
+
+// Irreleveant under OS/2 --- item either has child records or it doesn't.
+void wxTreeCtrl::SetItemHasChildren (
+  const wxTreeItemId&               WXUNUSED(rItem)
+, bool                              WXUNUSED(bHas)
+)
+{
+} // end of wxTreeCtrl::SetItemHasChildren
 
-    SetItem(info);
-}
+// Irreleveant under OS/2 --- function of the font in PM
+void wxTreeCtrl::SetItemBold (
+  const wxTreeItemId&               WXUNUSED(rItem)
+, bool                              WXUNUSED(bBold)
+)
+{
+} // end of wxTreeCtrl::SetItemBold
 
-long wxTreeCtrl::GetItemData(long item) const
+void wxTreeCtrl::SetItemDropHighlight (
+  const wxTreeItemId&               rItem
+, bool                              bHighlight
+)
+{
+    wxTreeViewItem                  vTvItem(rItem);
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_SETRECORDEMPHASIS
+                 ,MPFROMP(&vTvItem)
+                 ,MPFROM2SHORT(bHighlight, CRA_SELECTED)
+                );
+    DoSetItem(&vTvItem);
+} // end of wxTreeCtrl::SetItemDropHighlight
+
+void wxTreeCtrl::RefreshItem (
+  const wxTreeItemId&               rItem
+)
 {
-    wxTreeItem info;
+    wxTreeViewItem                  vTvItem(rItem);
 
-    info.m_mask = wxTREE_MASK_DATA ;
-    info.m_itemId = item;
+    //
+    // This just does a record invalidate causing it to be re-displayed
+    //
+    DoSetItem(&vTvItem);
+} // end of wxTreeCtrl::RefreshItem
 
-    if (!GetItem(info))
-        return 0;
-    return info.m_data;
-}
+wxColour wxTreeCtrl::GetItemTextColour (
+  const wxTreeItemId&               rItem
+) const
+{
+    long                            lId = (long)rItem.m_pItem;
+    wxTreeItemAttr*                 pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
+
+    if (!pAttr)
+    {
+        return wxNullColour;
+    }
+    return pAttr->GetTextColour();
+} // end of wxTreeCtrl::GetItemTextColour
 
-bool wxTreeCtrl::SetItemData(long item, long data)
+wxColour wxTreeCtrl::GetItemBackgroundColour (
+  const wxTreeItemId&               rItem
+) const
 {
-    wxTreeItem info;
+    long                            lId = (long)rItem.m_pItem;
+    wxTreeItemAttr*                 pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
 
-    info.m_mask = wxTREE_MASK_DATA ;
-    info.m_itemId = item;
-    info.m_data = data;
+    if (!pAttr)
+    {
+        return wxNullColour;
+    }
+    return pAttr->GetBackgroundColour();
+} // end of wxTreeCtrl::GetItemBackgroundColour
 
-    return SetItem(info);
-}
+wxFont wxTreeCtrl::GetItemFont (
+  const wxTreeItemId&               rItem
+) const
+{
+    long                            lId = (long)rItem.m_pItem;
+    wxTreeItemAttr*                 pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
+
+    if (!pAttr)
+    {
+        return wxNullFont;
+    }
+    return pAttr->GetFont();
+} // end of wxTreeCtrl::GetItemFont
 
-bool wxTreeCtrl::GetItemRect(long item, wxRect& rect, bool textOnly) const
+void wxTreeCtrl::SetItemTextColour (
+  const wxTreeItemId&               rItem
+, const wxColour&                   rCol
+)
 {
-    // TODO
-    return FALSE;
-}
+    m_bHasAnyAttr = true;
+
+    long                            lId = (long)rItem.m_pItem;
+    wxTreeItemAttr*                 pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
 
-wxTextCtrl* wxTreeCtrl::GetEditControl() const
+    if (!pAttr)
+    {
+        pAttr = new wxTreeItemAttr;
+        m_vAttrs.Put(lId, (wxObject *)pAttr);
+    }
+    pAttr->SetTextColour(rCol);
+    RefreshItem(rItem);
+} // end of wxTreeCtrl::SetItemTextColour
+
+void wxTreeCtrl::SetItemBackgroundColour (
+  const wxTreeItemId&               rItem
+, const wxColour&                   rCol
+)
 {
-    return m_textCtrl;
-}
+    m_bHasAnyAttr = true;
+
+    long                            lId = (long)rItem.m_pItem;
+    wxTreeItemAttr*                 pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
 
-// Operations
-bool wxTreeCtrl::DeleteItem(long item)
+    if (!pAttr)
+    {
+        pAttr = new wxTreeItemAttr;
+        m_vAttrs.Put(lId, (wxObject *)pAttr);
+    }
+    pAttr->SetBackgroundColour(rCol);
+    RefreshItem(rItem);
+} // end of wxTreeCtrl::SetItemBackgroundColour
+
+void wxTreeCtrl::SetItemFont (
+  const wxTreeItemId&               rItem
+, const wxFont&                     rFont
+)
 {
-    // TODO
-    return FALSE;
+    m_bHasAnyAttr = true;
+
+    long                            lId = (long)rItem.m_pItem;
+    wxTreeItemAttr*                 pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId);
+
+    if (!pAttr)
+    {
+        pAttr = new wxTreeItemAttr;
+        m_vAttrs.Put(lId, (wxObject *)pAttr);
+    }
+    pAttr->SetFont(rFont);
+    RefreshItem(rItem);
+} // end of wxTreeCtrl::SetItemFont
+
+// ----------------------------------------------------------------------------
+// Item status
+// ----------------------------------------------------------------------------
+
+bool wxTreeCtrl::IsVisible (
+  const wxTreeItemId&               rItem
+) const
+{
+    // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
+    RECTL                           vRectRecord;
+    RECTL                           vRectContainer;
+    wxRect                          vWxRectRecord;
+    wxRect                          vWxRectContainer;
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rItem.m_pItem
+                                                                    );
+    QUERYRECORDRECT                 vQuery;
+
+    vQuery.cb                = sizeof(QUERYRECORDRECT);
+    vQuery.pRecord           = (PRECORDCORE)pRecord;
+    vQuery.fRightSplitWindow = FALSE;
+    vQuery.fsExtent          = CMA_TREEICON;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYVIEWPORTRECT
+                 ,MPFROMP(&vRectContainer)
+                 ,MPFROM2SHORT(CMA_WINDOW, FALSE)
+                );
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYRECORDRECT
+                 ,MPFROMP(&vRectRecord)
+                 ,MPFROMP(&vQuery)
+                );
+    vWxRectRecord.SetLeft(vRectRecord.xLeft);
+    vWxRectRecord.SetTop(vRectRecord.yTop);
+    vWxRectRecord.SetRight(vRectRecord.xRight);
+    vWxRectRecord.SetBottom(vRectRecord.yBottom);
+
+    vWxRectContainer.SetLeft(vRectContainer.xLeft);
+    vWxRectContainer.SetTop(vRectContainer.yTop);
+    vWxRectContainer.SetRight(vRectContainer.xRight);
+    vWxRectContainer.SetBottom(vRectContainer.yBottom);
+    return (vWxRectContainer.Contains(wxPoint(vWxRectRecord.x, vWxRectRecord.y)));
+} // end of wxTreeCtrl::IsVisible
+
+bool wxTreeCtrl::ItemHasChildren (
+  const wxTreeItemId&               rItem
+) const
+{
+    wxTreeViewItem                  vTvItem(rItem);
+    DoGetItem(&vTvItem);
+
+    //
+    // A tree record with children will have one of these attributes
+    //
+    return (vTvItem.m_vRecord.flRecordAttr & CRA_EXPANDED ||
+            vTvItem.m_vRecord.flRecordAttr & CRA_COLLAPSED) != 0;
 }
 
-bool wxTreeCtrl::ExpandItem(long item, int action)
+bool wxTreeCtrl::IsExpanded (
+  const wxTreeItemId&               rItem
+) const
 {
-    // TODO
-  switch ( action )
-  {
-    case wxTREE_EXPAND_EXPAND:
-      break;
+    wxTreeViewItem                  vTvItem(rItem);
+    DoGetItem(&vTvItem);
 
-    case wxTREE_EXPAND_COLLAPSE:
-      break;
+    return (vTvItem.m_vRecord.flRecordAttr & CRA_EXPANDED) != 0;
+} // end of wxTreeCtrl::IsExpanded
 
-    case wxTREE_EXPAND_COLLAPSE_RESET:
-      break;
+bool wxTreeCtrl::IsSelected (
+  const wxTreeItemId&               rItem
+) const
+{
+    wxTreeViewItem                  vTvItem(rItem);
+    DoGetItem(&vTvItem);
 
-    case wxTREE_EXPAND_TOGGLE:
-      break;
+    return (vTvItem.m_vRecord.flRecordAttr & CRA_SELECTED) != 0;
+} // end of wxTreeCtrl::IsSelected
 
-    default:
-      wxFAIL_MSG("unknown action in wxTreeCtrl::ExpandItem");
-  }
+// Not supported
+bool wxTreeCtrl::IsBold (
+  const wxTreeItemId&               rItem
+) const
+{
+    return false;
+} // end of wxTreeCtrl::IsBold
 
-  bool bOk = FALSE; // TODO expand item
+// ----------------------------------------------------------------------------
+// navigation
+// ----------------------------------------------------------------------------
 
-  // May not send messages, so emulate them
-  if ( bOk ) {
-    wxTreeEvent event(wxEVT_NULL, m_windowId);
-    event.m_item.m_itemId  = item;
-    event.m_item.m_mask      =
-    event.m_item.m_stateMask = 0xffff; // get all
-    GetItem(event.m_item);
+wxTreeItemId wxTreeCtrl::GetRootItem () const
+{
+    PMYRECORD                       pRecord = NULL;
 
-    bool bIsExpanded = (event.m_item.m_state & wxTREE_STATE_EXPANDED) != 0;
+    pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                  ,CM_QUERYRECORD
+                                                  ,MPFROMP(pRecord)
+                                                  ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)
+                                                 ));
 
-    event.m_code = action;
-    event.SetEventObject(this);
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    return wxTreeItemId((long)pRecord->m_ulItemId);
+} // end of wxTreeCtrl::GetRootItem
 
-    // @@@ return values of {EXPAND|COLLAPS}ING event handler is discarded
-    event.SetEventType(bIsExpanded ? wxEVT_COMMAND_TREE_ITEM_EXPANDING
-                                   : wxEVT_COMMAND_TREE_ITEM_COLLAPSING);
-    GetEventHandler()->ProcessEvent(event);
+wxTreeItemId wxTreeCtrl::GetSelection () const
+{
+    wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (long)(WXHTREEITEM)0,
+                 wxT("this only works with single selection controls") );
+
+    PMYRECORD                       pRecord = NULL;
+
+    pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                  ,CM_QUERYRECORDEMPHASIS
+                                                  ,MPARAM(CMA_FIRST)
+                                                  ,MPARAM(CRA_SELECTED)
+                                                 ));
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    return wxTreeItemId((long)pRecord->m_ulItemId);
+} // end of wxTreeCtrl::GetSelection
+
+wxTreeItemId wxTreeCtrl::GetItemParent (
+  const wxTreeItemId&               rItem
+) const
+{
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rItem.m_pItem
+                                                                    );
+
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                  ,CM_QUERYRECORD
+                                                  ,MPFROMP(pRecord)
+                                                  ,MPFROM2SHORT(CMA_PARENT, CMA_ITEMORDER)
+                                                 ));
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    return wxTreeItemId((long)pRecord->m_ulItemId);
+} // end of wxTreeCtrl::GetItemParent
+
+wxTreeItemId wxTreeCtrl::GetFirstChild (
+  const wxTreeItemId&               rItem
+, long&                             rCookie
+) const
+{
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rItem.m_pItem
+                                                                    );
+
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                  ,CM_QUERYRECORD
+                                                  ,MPFROMP(pRecord)
+                                                  ,MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER)
+                                                 ));
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    //
+    // Remember the last child returned in 'cookie'
+    //
+    rCookie = (long)pRecord->m_ulItemId;
+    return wxTreeItemId(rCookie);
+} // end of wxTreeCtrl::GetFirstChild
+
+wxTreeItemId wxTreeCtrl::GetNextChild (
+  const wxTreeItemId&               WXUNUSED(rItem)
+, long&                             rCookie
+) const
+{
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rCookie
+                                                                    );
+
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                  ,CM_QUERYRECORD
+                                                  ,MPFROMP(pRecord)
+                                                  ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+                                                 ));
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    rCookie = (long)pRecord->m_ulItemId;
+    return wxTreeItemId(rCookie);
+} // end of wxTreeCtrl::GetNextChild
+
+wxTreeItemId wxTreeCtrl::GetLastChild (
+  const wxTreeItemId&               rItem
+) const
+{
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rItem.m_pItem
+                                                                    );
+
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                  ,CM_QUERYRECORD
+                                                  ,MPFROMP(pRecord)
+                                                  ,MPFROM2SHORT(CMA_LASTCHILD, CMA_ITEMORDER)
+                                                 ));
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    return wxTreeItemId((long)pRecord->m_ulItemId);
+} // end of wxTreeCtrl::GetLastChild
+
+wxTreeItemId wxTreeCtrl::GetNextSibling (
+  const wxTreeItemId&               rItem
+) const
+{
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rItem.m_pItem
+                                                                    );
+
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                  ,CM_QUERYRECORD
+                                                  ,MPFROMP(pRecord)
+                                                  ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+                                                 ));
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    return wxTreeItemId((long)pRecord->m_ulItemId);
+} // end of wxTreeCtrl::GetNextSibling
+
+wxTreeItemId wxTreeCtrl::GetPrevSibling (
+  const wxTreeItemId&               rItem
+) const
+{
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rItem.m_pItem
+                                                                    );
+
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                  ,CM_QUERYRECORD
+                                                  ,MPFROMP(pRecord)
+                                                  ,MPFROM2SHORT(CMA_PREV, CMA_ITEMORDER)
+                                                 ));
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    return wxTreeItemId((long)pRecord->m_ulItemId);
+} // end of wxTreeCtrl::GetPrevSibling
+
+wxTreeItemId wxTreeCtrl::GetFirstVisibleItem () const
+{
+    PMYRECORD                       pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                                                  ,CM_QUERYRECORD
+                                                                                  ,MPFROMP(pRecord)
+                                                                                  ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)
+                                                                                 ));
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+
+    if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId)))
+        return wxTreeItemId((long)pRecord->m_ulItemId);
+    while(pRecord)
+    {
+        pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                      ,CM_QUERYRECORD
+                                                      ,MPFROMP(pRecord)
+                                                      ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+                                                     ));
+        if (!pRecord)
+            return wxTreeItemId(-1L);
+        if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId)))
+            return wxTreeItemId((long)pRecord->m_ulItemId);
+    }
+    return wxTreeItemId(-1L);
+} // end of wxTreeCtrl::GetFirstVisibleItem
 
-    event.SetEventType(bIsExpanded ? wxEVT_COMMAND_TREE_ITEM_EXPANDED
-                                   : wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
-    GetEventHandler()->ProcessEvent(event);
-  }
+wxTreeItemId wxTreeCtrl::GetNextVisible (
+  const wxTreeItemId&               rItem
+) const
+{
+    wxASSERT_MSG(IsVisible(rItem), wxT("The item you call GetNextVisible() for must be visible itself!"));
 
-  return bOk;
-}
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rItem.m_pItem
+                                                                    );
+
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    while(pRecord)
+    {
+        pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                      ,CM_QUERYRECORD
+                                                      ,MPFROMP(pRecord)
+                                                      ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+                                                     ));
+        if (!pRecord)
+            return wxTreeItemId(-1L);
+        if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId)))
+            return wxTreeItemId((long)pRecord->m_ulItemId);
+    }
+    return wxTreeItemId(-1L);
+} // end of wxTreeCtrl::GetNextVisible
 
-long wxTreeCtrl::InsertItem(long parent, wxTreeItem& info, long insertAfter)
+wxTreeItemId wxTreeCtrl::GetPrevVisible (
+  const wxTreeItemId&               rItem
+) const
 {
-    // TODO
-    return 0;
-}
+    wxASSERT_MSG( IsVisible(rItem), wxT("The item you call GetPrevVisible() for must be visible itself!"));
+
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rItem.m_pItem
+                                                                    );
+
+    if (!pRecord)
+        return wxTreeItemId(-1L);
+    while(pRecord)
+    {
+        pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                      ,CM_QUERYRECORD
+                                                      ,MPFROMP(pRecord)
+                                                      ,MPFROM2SHORT(CMA_PREV, CMA_ITEMORDER)
+                                                     ));
+        if (!pRecord)
+            return wxTreeItemId(-1L);
+        if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId)))
+            return wxTreeItemId((long)pRecord->m_ulItemId);
+    }
+    return wxTreeItemId(-1L);
+} // end of wxTreeCtrl::GetPrevVisible
 
-long wxTreeCtrl::InsertItem(long parent, const wxString& label, int image, int selImage,
-  long insertAfter)
+// ----------------------------------------------------------------------------
+// multiple selections emulation -- under OS/2 checked tree items is not
+// supported, but multisel is.  So we'll just check for selections here.
+// ----------------------------------------------------------------------------
+
+bool wxTreeCtrl::IsItemChecked (
+  const wxTreeItemId&               rItem
+) const
+{
+    wxTreeViewItem                  vTvItem(rItem);
+
+    DoGetItem(&vTvItem);
+    return (vTvItem.m_vRecord.flRecordAttr & CRA_SELECTED);
+} // end of wxTreeCtrl::IsItemChecked
+
+void wxTreeCtrl::SetItemCheck (
+  const wxTreeItemId&               rItem
+, bool                              bCheck
+)
 {
-    wxTreeItem info;
-    info.m_text = label;
-    info.m_mask = wxTREE_MASK_TEXT;
-    if ( image > -1 )
+    wxTreeViewItem                  vTvItem(rItem);
+
+    DoGetItem(&vTvItem);
+    ::WinSendMsg( GetHWND()
+                 ,CM_SETRECORDEMPHASIS
+                 ,MPFROMP(&vTvItem)
+                 ,MPFROM2SHORT(TRUE, CRA_SELECTED)
+                );
+    DoSetItem(&vTvItem);
+} // end of wxTreeCtrl::SetItemCheck
+
+size_t wxTreeCtrl::GetSelections (
+  wxArrayTreeItemIds&               raSelections
+) const
+{
+    TraverseSelections              vSelector( this
+                                              ,raSelections
+                                             );
+    return vSelector.GetCount();
+} // end of wxTreeCtrl::GetSelections
+
+// ----------------------------------------------------------------------------
+// Usual operations
+// ----------------------------------------------------------------------------
+
+wxTreeItemId wxTreeCtrl::DoInsertItem (
+  const wxTreeItemId&               rParent
+, wxTreeItemId                      vInsertAfter
+, const wxString&                   rsText
+, int                               nImage
+, int                               selectedImage
+, wxTreeItemData*                   pData
+)
+{
+    PMYRECORD                       pRecordAfter = FindOS2TreeRecordByID( GetHWND()
+                                                                         ,vInsertAfter.m_pItem
+                                                                        );
+
+    PMYRECORD                       pRecordParent = FindOS2TreeRecordByID( GetHWND()
+                                                                          ,rParent.m_pItem
+                                                                         );
+
+    PMYRECORD                       pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+                                                                      ,CM_ALLOCRECORD
+                                                                      ,MPFROMLONG(sizeof(MYRECORD) - sizeof(RECORDCORE))
+                                                                      ,MPFROMLONG(1)
+                                                                     );
+    RECORDINSERT                    vInsert;
+
+    vInsert.cb                = sizeof(RECORDINSERT);
+    if (rParent.m_pItem == 0L)
     {
-        info.m_mask |= wxTREE_MASK_IMAGE | wxTREE_MASK_SELECTED_IMAGE;
-        info.m_image = image;
-        if ( selImage == -1 )
-            info.m_selectedImage = image;
+        if (vInsertAfter.m_pItem == -1)
+            vInsert.pRecordOrder      = (PRECORDCORE)CMA_END;
         else
-            info.m_selectedImage = selImage;
+            vInsert.pRecordOrder      = (PRECORDCORE)CMA_FIRST;
+        vInsert.pRecordParent     = NULL;
     }
-
-    return InsertItem(parent, info, insertAfter);
+    else
+    {
+        if (vInsertAfter.m_pItem == 0)
+            vInsert.pRecordOrder      = (PRECORDCORE)CMA_FIRST;
+        else if (vInsertAfter.m_pItem == -1)
+            vInsert.pRecordOrder      = (PRECORDCORE)CMA_END;
+        else
+            vInsert.pRecordOrder  = (PRECORDCORE)pRecordAfter;
+        vInsert.pRecordParent     = (PRECORDCORE)pRecordParent;
+    }
+    vInsert.fInvalidateRecord = TRUE;
+    vInsert.zOrder            = CMA_TOP;
+    vInsert.cRecordsInsert    = 1;
+
+    pRecord->m_vRecord.pszTree   = (wxChar*)rsText.c_str();
+    pRecord->m_vRecord.hbmBitmap = nImage;
+    pRecord->m_ulItemId = pRecordAfter->m_ulItemId + 1;
+    if (pData != NULL)
+    {
+        pRecord->m_ulUserData = (ULONG)pData;
+    }
+    ::WinSendMsg( GetHWND()
+                 ,CM_INSERTRECORD
+                 ,MPFROMP(pRecord)
+                 ,MPFROMP(&vInsert)
+                );
+
+    //
+    // OS/2 must mannually bump the index's of following records
+    //
+    BumpTreeRecordIds( GetHWND()
+                  ,pRecord
+                 );
+    if (pData != NULL)
+    {
+        //
+        // Associate the application tree item with PM tree item handle
+        //
+        pData->SetId((long)pRecord->m_ulItemId);
+    }
+    return wxTreeItemId((long)pRecord->m_ulItemId);
 }
 
-bool wxTreeCtrl::SelectItem(long item)
+wxTreeItemId wxTreeCtrl::AddRoot (
+  const wxString&                   rsText
+, int                               nImage
+, int                               nSelectedImage
+, wxTreeItemData*                   pData)
 {
-    // TODO
-    return FALSE;
-}
 
-bool wxTreeCtrl::ScrollTo(long item)
+    return DoInsertItem( wxTreeItemId((long)0)
+                        ,wxTreeItemId((long)-1)
+                        ,rsText
+                        ,nImage
+                        ,nSelectedImage
+                        ,pData
+                       );
+} // end of wxTreeCtrl::AddRoot
+
+wxTreeItemId wxTreeCtrl::PrependItem (
+  const wxTreeItemId&               rParent
+, const wxString&                   rsText
+, int                               nImage
+, int                               nSelectedImage
+, wxTreeItemData*                   pData
+)
 {
-    // TODO
-    return FALSE;
-}
+    return DoInsertItem( rParent
+                        ,wxTreeItemId((long)0)
+                        ,rsText
+                        ,nImage
+                        ,nSelectedImage
+                        ,pData
+                       );
+} // end of wxTreeCtrl::PrependItem
+
+wxTreeItemId wxTreeCtrl::InsertItem (
+  const wxTreeItemId&               rParent
+, const wxTreeItemId&               rIdPrevious
+, const wxString&                   rsText
+, int                               nImage
+, int                               nSelectedImage
+, wxTreeItemData*                   pData
+)
+{
+    return DoInsertItem( rParent
+                        ,rIdPrevious
+                        ,rsText
+                        ,nImage
+                        ,nSelectedImage
+                        ,pData
+                       );
+} // end of wxTreeCtrl::InsertItem
+
+wxTreeItemId wxTreeCtrl::InsertItem (
+  const wxTreeItemId&               rParent
+, size_t                            nIndex
+, const wxString&                   rsText
+, int                               nImage
+, int                               nSelectedImage
+, wxTreeItemData*                   pData
+)
+{
+    return DoInsertItem( rParent
+                        ,wxTreeItemId((long)nIndex)
+                        ,rsText
+                        ,nImage
+                        ,nSelectedImage
+                        ,pData
+                       );
+} // end of wxTreeCtrl::InsertItem
+
+wxTreeItemId wxTreeCtrl::AppendItem (
+  const wxTreeItemId&               rParent
+, const wxString&                   rsText
+, int                               nImage
+, int                               nSelectedImage
+, wxTreeItemData*                   pData
+)
+{
+    return DoInsertItem( rParent
+                        ,wxTreeItemId((long)-1)
+                        ,rsText
+                        ,nImage
+                        ,nSelectedImage
+                        ,pData
+                       );
+} // end of wxTreeCtrl::AppendItem
+
+void wxTreeCtrl::Delete (
+  const wxTreeItemId&               rItem
+)
+{
+    //
+    // OS/2 does not generate DELETEITEM events so do it here
+    //
+    wxEventType                     vEventType = wxEVT_NULL;
+    wxTreeEvent                     vEvent( wxEVT_NULL
+                                           ,m_windowId
+                                          );
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID( GetHWND()
+                                                                    ,rItem.m_pItem
+                                                                   );
+    vEvent.SetEventObject(this);
+    ::WinSendMsg( GetHWND()
+                 ,CM_REMOVERECORD
+                 ,MPFROMP(pRecord)
+                 ,(MPARAM)(CMA_FREE | CMA_INVALIDATE)
+                );
+    vEvent.m_item = rItem.m_pItem;
+    if (m_bHasAnyAttr)
+    {
+        delete (wxTreeItemAttr *)m_vAttrs.Delete((long)rItem.m_pItem);
+    }
+    vEvent.SetEventType(vEventType);
+    HandleWindowEvent(vEvent);
+} // end of wxTreeCtrl::Delete
+
+// delete all children (but don't delete the item itself)
+void wxTreeCtrl::DeleteChildren (
+  const wxTreeItemId&               rItem
+)
+{
+    long                            lCookie;
+    wxArrayLong                     aChildren;
+    wxTreeItemId                    vChild = GetFirstChild( rItem
+                                                           ,lCookie
+                                                          );
+
+    while (vChild.IsOk())
+    {
+        aChildren.Add((long)(WXHTREEITEM)vChild);
+        vChild = GetNextChild( rItem
+                              ,lCookie
+                             );
+    }
+
+    size_t                          nCount = aChildren.Count();
+
+    for (size_t n = 0; n < nCount; n++)
+    {
+        Delete(aChildren[n]);
+    }
+} // end of wxTreeCtrl::DeleteChildren
 
-bool wxTreeCtrl::DeleteAllItems()
+void wxTreeCtrl::DeleteAllItems ()
 {
-    // TODO
-    return FALSE;
-}
+    ::WinSendMsg( GetHWND()
+                 ,CM_REMOVERECORD
+                 ,NULL                // Remove all
+                 ,(MPARAM)(CMA_FREE | CMA_INVALIDATE)
+                );
+} // end of wxTreeCtrl::DeleteAllItems
+
+void wxTreeCtrl::DoExpand (
+  const wxTreeItemId&               rItem
+, int                               nFlag
+)
+{
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID( GetHWND()
+                                                                    ,rItem.m_pItem
+                                                                   );
+    switch(nFlag)
+    {
+        case wxTREE_EXPAND_EXPAND:
+            ::WinSendMsg( GetHWND()
+                         ,CM_EXPANDTREE
+                         ,MPFROMP(pRecord)
+                         ,NULL
+                        );
+            break;
+
+        case wxTREE_EXPAND_COLLAPSE:
+            ::WinSendMsg( GetHWND()
+                         ,CM_COLLAPSETREE
+                         ,MPFROMP(pRecord)
+                         ,NULL
+                        );
+            break;
+
+        case wxTREE_EXPAND_COLLAPSE_RESET:
+            ::WinSendMsg( GetHWND()
+                         ,CM_COLLAPSETREE
+                         ,MPFROMP(pRecord)
+                         ,NULL
+                        );
+            DeleteChildren(rItem);
+            break;
+
+        case wxTREE_EXPAND_TOGGLE:
+            if (pRecord->m_vRecord.flRecordAttr & CRA_COLLAPSED)
+                ::WinSendMsg( GetHWND()
+                             ,CM_EXPANDTREE
+                             ,MPFROMP(pRecord)
+                             ,NULL
+                            );
+            else if (pRecord->m_vRecord.flRecordAttr & CRA_EXPANDED)
+                ::WinSendMsg( GetHWND()
+                             ,CM_COLLAPSETREE
+                             ,MPFROMP(pRecord)
+                             ,NULL
+                            );
+            break;
+
+    }
+} // end of wxTreeCtrl::DoExpand
 
-wxTextCtrl* wxTreeCtrl::EditLabel(long item, wxClassInfo* textControlClass)
+void wxTreeCtrl::Expand (
+  const wxTreeItemId&               rItem
+)
 {
-    // TODO
-    return NULL;
-}
+    DoExpand( rItem
+             ,wxTREE_EXPAND_EXPAND
+            );
+} // end of wxTreeCtrl::Expand
+
+void wxTreeCtrl::Collapse (
+  const wxTreeItemId&               rItem
+)
+{
+    DoExpand( rItem
+             ,wxTREE_EXPAND_COLLAPSE
+            );
+} // end of wxTreeCtrl::Collapse
+
+void wxTreeCtrl::CollapseAndReset (
+  const wxTreeItemId&               rItem
+)
+{
+    DoExpand( rItem
+             ,wxTREE_EXPAND_COLLAPSE_RESET
+            );
+} // end of wxTreeCtrl::CollapseAndReset
+
+void wxTreeCtrl::Toggle (
+  const wxTreeItemId&               rItem
+)
+{
+    DoExpand( rItem
+             ,wxTREE_EXPAND_TOGGLE
+            );
+} // end of wxTreeCtrl::Toggle
 
-// End label editing, optionally cancelling the edit
-bool wxTreeCtrl::EndEditLabel(bool cancel)
+void wxTreeCtrl::Unselect ()
 {
-    // TODO
-    return FALSE;
-}
+    wxASSERT_MSG( !(m_windowStyle & wxTR_MULTIPLE),
+                  wxT("doesn't make sense, may be you want UnselectAll()?") );
 
-long wxTreeCtrl::HitTest(const wxPoint& point, int& flags)
+    //
+    // Just remove the selection
+    //
+    SelectItem(wxTreeItemId((long)0));
+} // end of wxTreeCtrl::Unselect
+
+void wxTreeCtrl::UnselectAll ()
 {
-    // TODO
-    return 0;
-}
+    if (m_windowStyle & wxTR_MULTIPLE)
+    {
+        wxArrayTreeItemIds          aSelections;
+        size_t                      nCount = GetSelections(aSelections);
+
+        for (size_t n = 0; n < nCount; n++)
+        {
+            SetItemCheck( aSelections[n]
+                         ,false
+                        );
+        }
+    }
+    else
+    {
+        //
+        // Just remove the selection
+        //
+        Unselect();
+    }
+} // end of wxTreeCtrl::UnselectAll
 
-bool wxTreeCtrl::SortChildren(long item)
+void wxTreeCtrl::SelectItem (
+  const wxTreeItemId&               rItem
+)
 {
-    // TODO
-    return FALSE;
-}
+    SetItemCheck(rItem);
+} // end of wxTreeCtrl::SelectItem
 
-bool wxTreeCtrl::EnsureVisible(long item)
+void wxTreeCtrl::EnsureVisible (
+  const wxTreeItemId&               rItem
+)
 {
-    // TODO
-    return FALSE;
+    wxTreeViewItem                  vTvItem(rItem);
+
+    DoGetItem(&vTvItem);
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_INVALIDATERECORD
+                      ,MPFROMP(&vTvItem)
+                      ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
+                     ));
+} // end of wxTreeCtrl::EnsureVisible
+
+void wxTreeCtrl::ScrollTo (
+  const wxTreeItemId&               rItem
+)
+{
+    wxTreeViewItem                  vTvItem(rItem);
+
+    DoGetItem(&vTvItem);
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_INVALIDATERECORD
+                      ,MPFROMP(&vTvItem)
+                      ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
+                     ));
 }
 
-// Tree item structure
-wxTreeItem::wxTreeItem()
-{
-    m_mask = 0;
-    m_itemId = 0;
-    m_state = 0;
-    m_stateMask = 0;
-    m_image = -1;
-    m_selectedImage = -1;
-    m_children = 0;
-    m_data = 0;
-}
+wxTextCtrl* wxTreeCtrl::EditLabel (
+  const wxTreeItemId&               rItem
+, wxClassInfo*                      WXUNUSED(pTextControlClass)
+)
+{
+    CNREDITDATA                     vEdit;
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID( GetHWND()
+                                                                    ,rItem.m_pItem
+                                                                   );
+
+    vEdit.cb         = sizeof(CNREDITDATA);
+    vEdit.hwndCnr    = GetHWND();
+    vEdit.pRecord    = &pRecord->m_vRecord;
+    vEdit.pFieldInfo = NULL;
+    vEdit.ppszText   = NULL;
+    vEdit.cbText     = 0;
+    vEdit.id         = 0;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_OPENEDIT
+                 ,MPFROMP(&vEdit)
+                 ,(MPARAM)0
+                );
+    return NULL;
+} // end of wxTreeCtrl::EditLabel
+
+// End label editing, optionally cancelling the edit
+void wxTreeCtrl::EndEditLabel (
+  const wxTreeItemId&               WXUNUSED(rItem)
+, bool                              WXUNUSED(bDiscardChanges)
+)
+{
+    ::WinSendMsg( GetHWND()
+                 ,CM_CLOSEEDIT
+                 ,(MPARAM)0
+                 ,(MPARAM)0
+                );
+} // end of wxTreeCtrl::EndEditLabel
+
+wxTreeItemId wxTreeCtrl::HitTest (
+  const wxPoint&                    rPoint
+, int&                              WXUNUSED(rFlags)
+)
+{
+    PMYRECORD                       pRecord = NULL;
+    QUERYRECFROMRECT                vQueryRect;
+    RECTL                           vRect;
+    long                            lHeight;
+
+    //
+    // Get height for OS/2 point conversion
+    //
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYVIEWPORTRECT
+                 ,MPFROMP(&vRect)
+                 ,MPFROM2SHORT(CMA_WINDOW, TRUE)
+                );
+    lHeight = vRect.yTop - vRect.yBottom;
+
+    //
+    // For now just try and get a record in the general vicinity and forget
+    // the flag
+    //
+    vRect.xLeft   = rPoint.x - 2;
+    vRect.xRight  = rPoint.x + 2;
+    vRect.yTop    = (lHeight - rPoint.y) + 2;
+    vRect.yBottom = (lHeight - rPoint.y) - 2;
+
+    vQueryRect.cb = sizeof(QUERYRECFROMRECT);
+    vQueryRect.rect = vRect;
+    vQueryRect.fsSearch = CMA_PARTIAL;
+
+    pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+                                      ,CM_QUERYRECORDFROMRECT
+                                      ,(MPARAM)CMA_FIRST
+                                      ,MPFROMP(&vQueryRect)
+                                    );
+
+    if (!pRecord)
+        return -1L;
+    return wxTreeItemId((long)pRecord->m_ulItemId);
+} // end of wxTreeCtrl::HitTest
+
+bool wxTreeCtrl::GetBoundingRect (
+  const wxTreeItemId&               rItem
+, wxRect&                           rRect
+, bool                              bTextOnly
+) const
+{
+    RECTL                           vRectRecord;
+    PMYRECORD                       pRecord = FindOS2TreeRecordByID ( GetHWND()
+                                                                     ,rItem.m_pItem
+                                                                    );
+    QUERYRECORDRECT                 vQuery;
+
+    vQuery.cb                = sizeof(QUERYRECORDRECT);
+    vQuery.pRecord           = (PRECORDCORE)pRecord;
+    vQuery.fRightSplitWindow = FALSE;
+    if (bTextOnly)
+        vQuery.fsExtent          = CMA_TEXT;
+    else
+        vQuery.fsExtent          = CMA_TREEICON | CMA_TEXT;
+
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYRECORDRECT
+                      ,MPFROMP(&vRectRecord)
+                      ,MPFROMP(&vQuery)
+                     ))
+        return false;
+    rRect.SetLeft(vRectRecord.xLeft);
+    rRect.SetTop(vRectRecord.yTop);
+    rRect.SetRight(vRectRecord.xRight);
+    rRect.SetBottom(vRectRecord.yBottom);
+    return true;
+} // end of wxTreeCtrl::GetBoundingRect
+
+// ----------------------------------------------------------------------------
+// sorting stuff
+// ----------------------------------------------------------------------------
+
+SHORT EXPENTRY InternalDataCompareTreeFunc (
+  PMYRECORD                         p1
+, PMYRECORD                         p2
+, PVOID                             pStorage
+)
+{
+    wxCHECK_MSG( p1 && p2, 0,
+                 wxT("sorting tree without data doesn't make sense") );
+
+    wxTreeCtrl*                     pTree = (wxTreeCtrl*)pStorage;
 
-// Tree event
-IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxCommandEvent)
+    return pTree->OnCompareItems( p1->m_ulItemId
+                                 ,p2->m_ulItemId
+                                );
+} // end of wxTreeSortHelper::Compare
 
-wxTreeEvent::wxTreeEvent(wxEventType commandType, int id):
-  wxCommandEvent(commandType, id)
+int wxTreeCtrl::OnCompareItems (
+  const wxTreeItemId&               rItem1
+, const wxTreeItemId&               rItem2
+)
 {
-    m_code = 0;
-    m_oldItem = 0;
-}
+    return wxStrcmp( GetItemText(rItem1)
+                    ,GetItemText(rItem2)
+                   );
+} // end of wxTreeCtrl::OnCompareItems
+
+void wxTreeCtrl::SortChildren (
+  const wxTreeItemId&               rItem
+)
+{
+    ::WinSendMsg( GetHWND()
+                 ,CM_SORTRECORD
+                 ,(PFN)InternalDataCompareTreeFunc
+                 ,NULL
+                );
+} // end of wxTreeCtrl::SortChildren
+
+// ----------------------------------------------------------------------------
+// implementation
+// ----------------------------------------------------------------------------
+
+bool wxTreeCtrl::OS2Command (
+  WXUINT                            uCmd
+, WXWORD                            wId
+)
+{
+    if (uCmd == CN_ENDEDIT)
+    {
+        wxCommandEvent              vEvent( wxEVT_COMMAND_TEXT_UPDATED
+                                           ,wId
+                                          );
 
+        vEvent.SetEventObject( this );
+        ProcessCommand(vEvent);
+        return true;
+    }
+    else if (uCmd == CN_KILLFOCUS)
+    {
+        wxCommandEvent              vEvent( wxEVT_KILL_FOCUS
+                                           ,wId
+                                          );
+        vEvent.SetEventObject( this );
+        ProcessCommand(vEvent);
+        return true;
+    }
+    else
+        return false;
+} // end of wxTreeCtrl::OS2Command
+
+//
+// TODO:  Fully implement direct manipulation when I figure it out
+//
+MRESULT wxTreeCtrl::OS2WindowProc (
+  WXUINT                            uMsg
+, WXWPARAM                          wParam
+, WXLPARAM                          lParam
+)
+{
+    bool                            bProcessed = false;
+    MRESULT                         mRc = 0;
+    wxTreeEvent                     vEvent( wxEVT_NULL
+                                           ,m_windowId
+                                          );
+    wxEventType                     vEventType = wxEVT_NULL;
+    PCNRDRAGINIT                    pDragInit = NULL;
+    PCNREDITDATA                    pEditData = NULL;
+    PNOTIFYRECORDENTER              pNotifyEnter = NULL;
+
+    vEvent.SetEventObject(this);
+    switch (uMsg)
+    {
+        case WM_CONTROL:
+            switch(SHORT2FROMMP(wParam))
+            {
+                case CN_INITDRAG:
+                    pDragInit = (PCNRDRAGINIT)lParam;
+                    if (pDragInit)
+                    {
+                        PMYRECORD       pRecord = (PMYRECORD)pDragInit->pRecord;
+
+                        vEventType = wxEVT_COMMAND_TREE_BEGIN_DRAG;
+                        vEvent.m_item        = pRecord->m_ulItemId;
+                        vEvent.m_pointDrag.x = pDragInit->x;
+                        vEvent.m_pointDrag.y = pDragInit->y;
+                    }
+                    break;
+
+                case CN_BEGINEDIT:
+                    pEditData = (PCNREDITDATA)lParam;
+                    if (pEditData)
+                    {
+                        PMYRECORD       pRecord = (PMYRECORD)pEditData->pRecord;
+
+                        vEventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT;
+                        vEvent.m_item = pRecord->m_ulItemId;
+                        vEvent.m_label = pRecord->m_vRecord.pszTree;
+                        vEvent.m_editCancelled = false;
+                    }
+                    break;
+
+                case CN_ENDEDIT:
+                    pEditData = (PCNREDITDATA)lParam;
+                    if (pEditData)
+                    {
+                        PMYRECORD       pRecord = (PMYRECORD)pEditData->pRecord;
+
+                        vEventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT;
+                        vEvent.m_item = pRecord->m_ulItemId;
+                        vEvent.m_label = pRecord->m_vRecord.pszTree;
+                        if (pRecord->m_vRecord.pszTree == NULL)
+                        {
+                            vEvent.m_editCancelled = true;
+                        }
+                        else
+                        {
+                            vEvent.m_editCancelled = false;
+                        }
+                    }
+                    break;
+
+                case CN_EXPANDTREE:
+                    {
+                        PMYRECORD       pRecord = (PMYRECORD)lParam;
+
+                        vEventType = gs_expandEvents[IDX_EXPAND][IDX_DONE];
+                        vEvent.m_item = pRecord->m_ulItemId;
+                    }
+                    break;
+            }
+            vEvent.SetEventType(vEventType);
+            bProcessed = HandleWindowEvent(vEvent);
+            break;
+    }
+    if (!bProcessed)
+        mRc = wxControl::OS2WindowProc( uMsg
+                                       ,wParam
+                                       ,lParam
+                                      );
+    return mRc;
+} // end of wxTreeCtrl::OS2WindowProc
+
+#endif // wxUSE_TREECTRL