]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/listctrl.cpp
Caret dropout fix
[wxWidgets.git] / src / os2 / listctrl.cpp
index d1d844565201ff29c49e1f4de52ee49ec1495579..cf9a922745ad94eb873bce1ba172f293bfcf90e7 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
-// Name:        listctrl.cpp
-// Purpose:     wxListCtrl. See also Robert's generic wxListCtrl
-// Author:      AUTHOR
+// Name:        src/os2/listctrl.cpp
+// Purpose:     wxListCtrl
+// Author:      David Webster
 // Modified by:
-// Created:     ??/??/98
+// Created:     01/21/03
 // RCS-ID:      $Id$
-// Copyright:   (c) AUTHOR
-// Licence:    wxWindows licence
+// Copyright:   (c) David Webster
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#ifdef __GNUG__
-#pragma implementation "listctrl.h"
-#endif
+// ============================================================================
+// declarations
+// ============================================================================
 
-#include "wx/stubs/textctrl.h"
-#include "wx/stubs/listctrl.h"
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
 
-#if !USE_SHARED_LIBRARY
-IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
-IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
 
+#ifdef __BORLANDC__
+    #pragma hdrstop
 #endif
 
-wxListCtrl::wxListCtrl()
+#if wxUSE_LISTCTRL
+
+#ifndef WX_PRECOMP
+    #include "wx/app.h"
+    #include "wx/intl.h"
+    #include "wx/log.h"
+    #include "wx/settings.h"
+    #include "wx/dcclient.h"
+    #include "wx/textctrl.h"
+#endif
+
+#include "wx/imaglist.h"
+#include "wx/listctrl.h"
+
+#include "wx/os2/private.h"
+
+//
+// FIELDOFFSET in DETAIL view as defined in the OS2TK45 simply doesn't work
+// We use this, which does!
+//
+#undef  FIELDOFFSET
+#define FIELDOFFSET(type, field)    ((ULONG)&(((type *)0)->field))
+
+// ----------------------------------------------------------------------------
+// private helper classes
+// ----------------------------------------------------------------------------
+
+/////////////////////////////////////////////////////////////////////////////
+// STRUCT SMYRECORD
+//   Under OS/2 we have to use our own RECORDCORE based struct if we have
+//   user data to store in a PM Container Control (and wxListCtrl is a PM
+//   Container in ICON, NAME, TEXT or DETAIL view). m_ulUserData is a four
+//   byte value containing a pointer to our CListIntemInternalData class
+//   instance.
+//
+//   And now for the big time OS/2 Kludge.  In traditional OS/2 PM
+//   applications using containers, programmers determine BEFORE creation
+//   how many records the view will have, initially, and how many columns
+//   the detail view of the container will have, as the container represents
+//   a known data block.  Thus the OS/2 PM CV_DETAIL view, i.e.
+//   the wxWidgets wxLC_REPORT view, relies on STATIC structure for its
+//   columnar data.  It gets the data to display by telling it the specific
+//   offset of the field in the struct containing the displayable data.  That
+//   data has be of OS/2 Types, PSZ (char string), CDATE or CTIME format.
+//   wxWidgets is dynamic in nature, however.  We insert columns, one at a
+//   time and do not know how many until the app is done inserting them. So
+//   for OS/2 I have to set a max allowable since they are fixed.  We return
+//   an error to the app if they include more than we can handle.
+//
+//   For example to display the data "Col 4 of Item 6" in a report view, I'd
+//   have to do:
+//   pRecord->m_pzColumn4 = "Col 4 of Item 6";
+//   pField->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn4);
+//   and then call the PM API to set it.
+//
+//   This really stinks but I can't use a pointer to another struct as the
+//   FIELDOFFSET call could only tell OS/2 the four byte value offset of
+//   pointer field and it would display giberish in the column.
+/////////////////////////////////////////////////////////////////////////////
+typedef struct _MYRECORD
 {
-       m_imageListNormal = NULL;
-       m_imageListSmall = NULL;
-       m_imageListState = NULL;
-       m_baseStyle = 0;
-    m_colCount = 0;
-}
+    RECORDCORE                      m_vRecord;
+    unsigned long                   m_ulItemId;
+    unsigned long                   m_ulUserData; //actually a pointer value to real data (a CListItemInternalData class instance)
+    PSZ                             m_pzColumn1;
+    PSZ                             m_pzColumn2;
+    PSZ                             m_pzColumn3;
+    PSZ                             m_pzColumn4;
+    PSZ                             m_pzColumn5;
+    PSZ                             m_pzColumn6;
+    PSZ                             m_pzColumn7;
+    PSZ                             m_pzColumn8;
+    PSZ                             m_pzColumn9;
+    PSZ                             m_pzColumn10;
+} MYRECORD, *PMYRECORD;
 
-bool wxListCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
-            long style, const wxValidator& validator, const wxString& name)
+/////////////////////////////////////////////////////////////////////////////
+// CLASS CListItemInternalData
+//
+// Problem:
+//  The MSW version had problems with SetTextColour() et al as the
+//  CListItemAttr's were stored keyed on the item index. If a item was
+//  inserted anywhere but the end of the list the text attributes
+//  (colour etc) for the following items were out of sync.
+//
+// Solution:
+//  Under MSW the only way to associate data with a
+//  List item independent of its position in the list is to store a pointer
+//  to it in its lParam attribute. However user programs are already using
+//  this (via the SetItemData() GetItemData() calls).
+//
+//  However what we can do is store a pointer to a structure which contains
+//  the attributes we want *and* a lParam for the users data, e.g.
+//
+//  class CListItemInternalData
+//  {
+//  public:
+//       GuiAdvCtrl_CListItemAttr* pAttr;
+//       long                      lParam; // user data
+//  };
+//
+//  To conserve memory, a CListItemInternalData is only allocated for a
+//  LV_ITEM if text attributes or user data(lparam) are being set.
+//
+//  For OS/2, the lParam value points to whatever actual data we have
+/////////////////////////////////////////////////////////////////////////////
+class CListItemInternalData
 {
-    m_imageListNormal = NULL;
-    m_imageListSmall = NULL;
-    m_imageListState = NULL;
-    m_colCount = 0;
+public:
 
-    SetValidator(validator);
-    SetName(name);
+    CListItemInternalData(): m_pAttr(NULL)
+                            ,m_lParam(0)
+    {}
 
-    m_windowStyle = style;
+    ~CListItemInternalData()
+    {
+        wxDELETE(m_pAttr);
+    }
 
-    SetParent(parent);
+    wxListItemAttr*                 m_pAttr;
+    WXLPARAM                        m_lParam; // user data
+    PMYRECORD                       m_pMyRecord; // so we can set the m_ulUserData to 0 when this is deleted
+}; // end of CLASS CListItemInternalData
 
-    m_windowId = (id == -1) ? NewControlId() : id;
+/////////////////////////////////////////////////////////////////////////////
+// STRUCT SInternalDataSort
+//
+// Sort items.
+//
+// fn is a function which takes 3 long arguments: item1, item2, data.
+// item1 is the long data associated with a first item (NOT the index).
+// item2 is the long data associated with a second item (NOT the index).
+// data is the same value as passed to SortItems.
+//
+// The return value is a negative number if the first item should precede the
+// second item, a positive number of the second item should precede the first,
+// or zero if the two items are equivalent.
+//
+// data is arbitrary data to be passed to the sort function.
+//
+// Internal structures for proxying the user compare function
+// so that we can pass it the *real* user data
+/////////////////////////////////////////////////////////////////////////////
+typedef struct internalDataSort
+{
+    wxListCtrlCompare               m_fnUser;
+    long                            m_lData;
+} SInternalDataSort; // end of STRUCT SInternalDataSort
 
-    if (parent) parent->AddChild(this);
+// ----------------------------------------------------------------------------
+// private helper functions
+// ----------------------------------------------------------------------------
 
-    // TODO create list control
-    return TRUE;
-}
+/////////////////////////////////////////////////////////////////////////////
+//
+// FindOS2ListFieldByColNum
+//
+//  There is no way, under OS/2 to get a field in a container by index,
+//  directly, so you must get the first one, then cycle through the list
+//  until you get to where you want to be.
+//
+// PARAMETERS
+//  hWnd   -- window handle of container to search
+//  lIndex -- index to set
+//
+// RETURN VALUE
+//  pointer to the FIELDINFO struct at the index in the container record
+//
+/////////////////////////////////////////////////////////////////////////////
+PFIELDINFO FindOS2ListFieldByColNum (
+  HWND                              hWnd
+, long                              lIndex
+)
+{
+    PFIELDINFO                      pFieldInfo = NULL;
+    CNRINFO                         vCnrInfo;
+    ULONG                           i;
+
+    if (!::WinSendMsg( hWnd
+                      ,CM_QUERYCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                     ))
+        return NULL;
+    for (i = 0; i < vCnrInfo.cFields; i++)
+    {
+        if (i == 0)
+            pFieldInfo = (PFIELDINFO)PVOIDFROMMR(::WinSendMsg( hWnd
+                                                              ,CM_QUERYDETAILFIELDINFO
+                                                              ,MPFROMP(pFieldInfo)
+                                                              ,(MPARAM)CMA_FIRST
+                                                             ));
+        else
+            pFieldInfo = (PFIELDINFO)PVOIDFROMMR(::WinSendMsg( hWnd
+                                                              ,CM_QUERYDETAILFIELDINFO
+                                                              ,MPFROMP(pFieldInfo)
+                                                              ,(MPARAM)CMA_NEXT
+                                                             ));
+        if (!pFieldInfo)
+            return NULL;
+        if (i == (ULONG)lIndex)
+            break;
+    }
+    if (!pFieldInfo)
+        return NULL;
+    return pFieldInfo;
+} // end of FindOS2ListFieldByColNum
 
-wxListCtrl::~wxListCtrl()
+/////////////////////////////////////////////////////////////////////////////
+//
+// FindOS2ListRecordByID
+//
+//  There is no way, under OS/2 to get a record in a container by index,
+//  directly, so you must get the first one, then cycle through the list
+//  until you get to where you want to be.
+//
+// PARAMETERS
+//  hWnd    -- window handle of container to search
+//  lItemId -- index to set
+//
+// RETURN VALUE
+//  pointer to the internal RECORDCORE struct at the index in the container
+//
+/////////////////////////////////////////////////////////////////////////////
+PMYRECORD FindOS2ListRecordByID (
+  HWND                              hWnd
+, long                              lItemId
+)
 {
-}
+    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
 
-// Add or remove a single window style
-void wxListCtrl::SetSingleStyle(long style, bool add)
-{
-       long flag = GetWindowStyleFlag();
-
-       // Get rid of conflicting styles
-       if ( add )
-       {
-               if ( style & wxLC_MASK_TYPE)
-                       flag = flag & ~wxLC_MASK_TYPE ;
-               if ( style & wxLC_MASK_ALIGN )
-                       flag = flag & ~wxLC_MASK_ALIGN ;
-               if ( style & wxLC_MASK_SORT )
-                       flag = flag & ~wxLC_MASK_SORT ;
+/////////////////////////////////////////////////////////////////////////////
+//
+// BumpRecordIds
+//
+//  Since OS/2 does not keep native record id's but wx insists on inserting
+//  and selecting via ID's, when we insert a record in the middle we need
+//  to bump the id's of each record after the one we just inserted.
+//
+// PARAMETERS
+//  hWnd    -- window handle of container to search
+//  pRecord -- record after which we starting bumping id's
+//
+// RETURN VALUE
+//  none
+//
+/////////////////////////////////////////////////////////////////////////////
+void BumpRecordIds (
+  HWND                              hWnd
+, PMYRECORD                         pRecord
+)
+{
+    while(pRecord)
+    {
+        pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
+                                                      ,CM_QUERYRECORD
+                                                      ,MPFROMP(pRecord)
+                                                      ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+                                                     ));
+        if (pRecord)
+            pRecord->m_ulItemId++;
+    }
+} // end of BumpRecordIds
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GetInternalData
+//
+//  Get the internal data given a handle and an id
+//
+// PARAMETERS
+//  hWnd    -- window handle to the control in which item is located
+//  lItemId -- ID to get
+//
+// RETURN VALUE
+//  pointer to the internal data
+//
+// Note:
+//  Under OS/2 PM a container item cannot be obtained via a simple index or
+//  id retrieval.  We have to walk the record list if we are looking for
+//  a record at a specific index location
+/////////////////////////////////////////////////////////////////////////////
+CListItemInternalData* GetInternalData (
+  HWND                              hWnd
+, long                              lItemId
+)
+{
+    PMYRECORD                       pRecord = FindOS2ListRecordByID( hWnd
+                                                                    ,lItemId
+                                                                   );
+    //
+    // Internal user data is stored AFTER the last field of the RECORDCORE
+    //
+    if (!pRecord)
+        return NULL;
+    return((CListItemInternalData *)(pRecord->m_ulUserData));
+} // end of GetInternalData
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GetInternalData
+//
+//  Get the internal data given a pointer to a list control and an id
+//
+// PARAMETERS
+//  pCtl    -- pointer to control inwhich item is located
+//  lItemId -- ID to get
+//
+// RETURN VALUE
+//  pointer to the internal data
+//
+/////////////////////////////////////////////////////////////////////////////
+CListItemInternalData* GetInternalData (
+  wxListCtrl*                       pCtl
+, long                              lItemId
+)
+{
+    return(GetInternalData( (HWND)pCtl->GetHWND()
+                           ,lItemId
+                          ));
+} // end of GetInternalData
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DeleteInternalData
+//
+//  Delete the internal data for a record
+//
+// PARAMETERS
+//  pCtl    -- pointer to the list control containing the record
+//  lItemId -- the record index to delete the internal data from
+//
+// RETURN VALUE
+//  pointer to the internal data attribute
+//
+/////////////////////////////////////////////////////////////////////////////
+void DeleteInternalData (
+  wxListCtrl*                       pCtl
+, long                              lItemId
+)
+{
+    CListItemInternalData*          pData = GetInternalData( pCtl
+                                                            ,lItemId
+                                                           );
+    if (pData)
+    {
+        if (pData->m_pMyRecord)
+            pData->m_pMyRecord->m_ulUserData = 0;
+        delete pData;
+    }
+} // end of DeleteInternalData
+
+// #pragma page   "GetInternalDataAttr"
+/////////////////////////////////////////////////////////////////////////////
+//
+// GetInternalDataAttr
+//
+//  Get the internal data item attribute given a pointer to a list control
+//  and an id
+//
+// PARAMETERS
+//  pCtl    -- pointer to control to set
+//  lItemId -- ID to set
+//
+// RETURN VALUE
+//  pointer to the internal data attribute
+//
+/////////////////////////////////////////////////////////////////////////////
+wxListItemAttr* GetInternalDataAttr (
+  wxListCtrl*                       pCtl
+, long                              lItemId
+)
+{
+    CListItemInternalData*          pData = GetInternalData( pCtl
+                                                            ,lItemId
+                                                           );
+
+    if (pData)
+        return(pData->m_pAttr);
+    else
+        return NULL;
+} // end of GetInternalDataAttr
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// InternalDataCompareFunc
+//
+//  This is compare function we pass to PM.  It wraps the real compare
+//  function in SInternalDataSort
+//
+// PARAMETERS
+//  p1       -- is the first record structure to compare
+//  p2       -- is the second record structure to compare
+//  lStorage -- is the same value as passed to SortItems.
+//
+// RETURN VALUE
+//  pointer to the internal data attribute
+//
+/////////////////////////////////////////////////////////////////////////////
+SHORT EXPENTRY InternalDataCompareFunc (
+  PMYRECORD                         p1
+, PMYRECORD                         p2
+, PVOID                             pStorage
+)
+{
+    SInternalDataSort*              pInternalData = (SInternalDataSort *)pStorage;
+    CListItemInternalData*          pData1 = (CListItemInternalData *)p1->m_ulUserData;
+    CListItemInternalData*          pData2 = (CListItemInternalData *)p2->m_ulUserData;
+    long                            lD1 = (pData1 == NULL ? 0 : (long)pData1->m_lParam);
+    long                            lD2 = (pData2 == NULL ? 0 : (long)pData2->m_lParam);
+
+    return(pInternalData->m_fnUser( lD1
+                                   ,lD2
+                                   ,pInternalData->m_lData
+                                  ));
+} // end of InternalDataCompareFunc
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ConvertFromOS2ListItem
+//
+//  Convert from an internal PM List item to a Toolkit List item
+//
+// PARAMETERS
+//  hWndListCtrl -- the control's windows handle
+//  rInfo        -- the library list control to convert to
+//  pRecord      -- the OS list control to convert from
+//
+// RETURN VALUE
+//  none
+//
+/////////////////////////////////////////////////////////////////////////////
+void ConvertFromOS2ListItem ( HWND hWndListCtrl,
+                              wxListItem& rInfo,
+                              PMYRECORD pRecord )
+{
+    CListItemInternalData* pInternaldata = (CListItemInternalData *)pRecord->m_ulUserData;
+    bool bNeedText = false;
+
+    if (pInternaldata)
+        rInfo.SetData(pInternaldata->m_lParam);
+
+    rInfo.SetMask(0);
+    rInfo.SetState(0);
+    rInfo.SetStateMask(0);
+    rInfo.SetId((long)pRecord->m_ulItemId);
+    if (hWndListCtrl != 0)
+    {
+        pRecord = FindOS2ListRecordByID( hWndListCtrl
+                                        ,rInfo.GetId()
+                                       );
+    }
+
+    //
+    // The wxListItem class is really set up to handle the WIN32 list item
+    // and OS/2 are not as complicated.  Just set both state members to the
+    // same thing under OS/2
+    //
+    if (pRecord->m_vRecord.flRecordAttr & CRA_DROPONABLE)
+    {
+        rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_DROPHILITED);
+        rInfo.SetState(rInfo.m_state | wxLIST_STATE_DROPHILITED);
+    }
+    if (pRecord->m_vRecord.flRecordAttr & CRA_SELECTED)
+    {
+        rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_SELECTED);
+        rInfo.SetState(rInfo.m_state | wxLIST_STATE_SELECTED);
+    }
+    if (pRecord->m_vRecord.flRecordAttr & CRA_DISABLED)
+    {
+        rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_DISABLED);
+        rInfo.SetState(rInfo.m_state | wxLIST_STATE_DISABLED);
+    }
+    if (pRecord->m_vRecord.flRecordAttr & CRA_FILTERED)
+    {
+        rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_FILTERED);
+        rInfo.SetState(rInfo.m_state | wxLIST_STATE_FILTERED);
+    }
+    if (pRecord->m_vRecord.flRecordAttr & CRA_INUSE)
+    {
+        rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_INUSE);
+        rInfo.SetState(rInfo.m_state | wxLIST_STATE_INUSE);
+    }
+    if (pRecord->m_vRecord.flRecordAttr & CRA_PICKED)
+    {
+        rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_PICKED);
+        rInfo.SetState(rInfo.m_state | wxLIST_STATE_PICKED);
+    }
+    if (pRecord->m_vRecord.flRecordAttr & CRA_SOURCE)
+    {
+        rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_SOURCE);
+        rInfo.SetState(rInfo.m_state | wxLIST_STATE_SOURCE);
+    }
+
+    if (pRecord->m_vRecord.pszText != (PSZ)NULL)
+    {
+        rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_TEXT);
+        rInfo.SetText(pRecord->m_vRecord.pszText);
+    }
+    if (pRecord->m_vRecord.pszIcon != (PSZ)NULL ||
+        pRecord->m_vRecord.pszName != (PSZ)NULL)
+    {
+        rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_IMAGE);
+        rInfo.SetImage(pRecord->m_vRecord.hptrIcon);
+    }
+    if (pRecord->m_ulUserData)
+        rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_DATA);
+} // end of ConvertFromOS2ListItem
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ConvertToOS2Flags
+//
+//  Convert from an library states to OS states
+//
+// PARAMETERS
+//  lState       -- the state
+//  pRecord      -- the OS list control to use
+//
+// RETURN VALUE
+//  none
+//
+/////////////////////////////////////////////////////////////////////////////
+void ConvertToOS2Flags (
+  long                              lState
+, PMYRECORD                         pRecord
+)
+{
+    if (lState & wxLIST_STATE_DROPHILITED)
+        pRecord->m_vRecord.flRecordAttr |= CRA_DROPONABLE;
+    if (lState & wxLIST_STATE_SELECTED)
+        pRecord->m_vRecord.flRecordAttr |= CRA_SELECTED;
+    if (lState & wxLIST_STATE_DISABLED)
+        pRecord->m_vRecord.flRecordAttr |= CRA_DISABLED;
+    if (lState & wxLIST_STATE_FILTERED)
+        pRecord->m_vRecord.flRecordAttr |= CRA_FILTERED;
+    if (lState & wxLIST_STATE_INUSE)
+        pRecord->m_vRecord.flRecordAttr |= CRA_INUSE;
+    if (lState & wxLIST_STATE_PICKED)
+        pRecord->m_vRecord.flRecordAttr |= CRA_PICKED;
+    if (lState & wxLIST_STATE_SOURCE)
+        pRecord->m_vRecord.flRecordAttr |= CRA_SOURCE;
+} // end of ConvertToOS2Flags
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ConvertToOS2ListItem
+//
+//  Convert from a library List item to an internal OS2 List item. We set
+//  only the fields we need to set.  Some of them are set by the API when
+//  they are added to the container.
+//
+// PARAMETERS
+//  pCtrl      -- the control to use
+//  rInfo      -- the item to convert
+//  pRecord    -- the OS list control to use, should be zeroed out
+//  pFieldinfo -- a field struct that may contain columnar data for detail view
+//
+// RETURN VALUE
+//  none
+//
+/////////////////////////////////////////////////////////////////////////////
+void ConvertToOS2ListItem (
+  const wxListCtrl*                 pCtrl
+, const wxListItem&                 rInfo
+, PMYRECORD                         pRecord
+, PFIELDINFO                        pFieldInfo
+)
+{
+    pRecord->m_ulItemId    = (ULONG)rInfo.GetId();
+    pRecord->m_vRecord.cb = sizeof(RECORDCORE);
+    if (rInfo.GetMask() & wxLIST_MASK_STATE)
+    {
+        ConvertToOS2Flags( rInfo.m_state
+                          ,pRecord
+                         );
+    }
+    if (pCtrl->GetWindowStyleFlag() & wxLC_ICON ||
+        pCtrl->GetWindowStyleFlag() & wxLC_SMALL_ICON)
+    {
+        pRecord->m_vRecord.pszIcon = (char*)rInfo.GetText().c_str();
+    }
+    if (pCtrl->GetWindowStyleFlag() & wxLC_LIST) // PM TEXT view
+    {
+        pRecord->m_vRecord.pszText = (char*)rInfo.GetText().c_str();
+    }
+    //
+    // In the case of a report view the text will be the data in the lead column
+    // ???? Don't know why, but that is how it works in other ports.
+    //
+    if (pCtrl->GetWindowStyleFlag() & wxLC_REPORT)
+    {
+        if (pFieldInfo)
+        {
+            switch(rInfo.GetColumn())
+            {
+                case 0:
+                    pRecord->m_pzColumn1 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn1);
+                    break;
+
+                case 1:
+                    pRecord->m_pzColumn2 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn2);
+                    break;
+
+                case 2:
+                    pRecord->m_pzColumn3 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn3);
+                    break;
+
+                case 3:
+                    pRecord->m_pzColumn4 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn4);
+                    break;
+
+                case 4:
+                    pRecord->m_pzColumn5 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn5);
+                    break;
+
+                case 5:
+                    pRecord->m_pzColumn6 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn6);
+                    break;
+
+                case 6:
+                    pRecord->m_pzColumn7 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn7);
+                    break;
+
+                case 7:
+                    pRecord->m_pzColumn8 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn8);
+                    break;
+
+                case 8:
+                    pRecord->m_pzColumn9 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn9);
+                    break;
+
+                case 9:
+                    pRecord->m_pzColumn10 = (char*)rInfo.GetText().c_str();
+                    pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn10);
+                    break;
+
+                default:
+                    wxFAIL_MSG( wxT("wxOS2 does not support more than 10 columns in REPORT view") );
+                    break;
+            }
         }
+    }
+    if (rInfo.GetMask() & wxLIST_MASK_IMAGE)
+    {
+        pRecord->m_vRecord.hptrIcon      = (HPOINTER)rInfo.GetImage();
+        pRecord->m_vRecord.hptrMiniIcon  = (HPOINTER)rInfo.m_miniImage;
+    }
+} // end of ConvertToOS2ListItem
 
-       if ( flag & style )
-       {
-               if ( !add )
-                       flag -= style;
-       }
-       else
-       {
-               if ( add )
-               {
-                       flag |= style;
-               }
-       }
-
-       m_windowStyle = flag;
-
-       /* TODO RecreateWindow(); */
-}
+/////////////////////////////////////////////////////////////////////////////
+//
+// ConvertToOS2ListCol
+//
+//  Convert from a library List column to an internal PM List column
+//
+// PARAMETERS
+//  lCol   -- the columnd to convert
+//  rItem  -- the item to convert
+//  pField -- the OS list column to use
+//
+// RETURN VALUE
+//  none
+//
+/////////////////////////////////////////////////////////////////////////////
+void ConvertToOS2ListCol (
+  long                              lCol
+, const wxListItem&                 rItem
+, PFIELDINFO                        pField
+)
+{
+    memset(pField, '\0', sizeof(FIELDINFO));
+    pField->cb = sizeof(FIELDINFO);
+
+    //
+    // Default some settings
+    //
+    pField->flData  = CFA_HORZSEPARATOR | CFA_SEPARATOR;
+    pField->flTitle = CFA_CENTER;
+
+    if (rItem.GetMask() & wxLIST_MASK_TEXT)
+    {
+        pField->flData |= CFA_STRING;
+        pField->pTitleData = (PVOID)rItem.GetText().c_str(); // text is column title not data
+    }
+    if (rItem.GetMask() & wxLIST_MASK_FORMAT)
+    {
+        if (rItem.m_format == wxLIST_FORMAT_LEFT)
+            pField->flData |= CFA_LEFT;
+        else if (rItem.m_format == wxLIST_FORMAT_RIGHT)
+            pField->flData |= CFA_RIGHT;
+        else if (rItem.m_format == wxLIST_FORMAT_CENTRE)
+            pField->flData |= CFA_CENTER;
+    }
+    else
+        pField->flData |= CFA_CENTER;  // Just ensure the default is centered
+    if (rItem.GetMask() & wxLIST_MASK_WIDTH)
+    {
+        if (!(rItem.GetWidth() == wxLIST_AUTOSIZE ||
+             rItem.GetWidth() == wxLIST_AUTOSIZE_USEHEADER))
+            pField->cxWidth = rItem.GetWidth();
+        // else: OS/2 automatically sets the width if created with the approppriate style
+    }
+
+    //
+    // Still need to set the actual data
+    //
+    pField->offStruct = 0;
+} // end of ConvertToOS2ListCol
+
+BEGIN_EVENT_TABLE(wxListCtrl, wxControl)
+    EVT_PAINT(wxListCtrl::OnPaint)
+END_EVENT_TABLE()
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxListCtrl construction
+// ----------------------------------------------------------------------------
+
+void wxListCtrl::Init ()
+{
+    m_pImageListNormal     = NULL;
+    m_pImageListSmall      = NULL;
+    m_pImageListState      = NULL;
+    m_bOwnsImageListNormal = false;
+    m_bOwnsImageListSmall  = false;
+    m_bOwnsImageListState  = false;
+    m_lBaseStyle           = 0L;
+    m_nColCount            = 0;
+    m_pTextCtrl            = NULL;
+    m_bAnyInternalData     = false;
+    m_bHasAnyAttr          = false;
+} // end of wxListCtrl::Init
+
+bool wxListCtrl::Create ( wxWindow* pParent,
+                          wxWindowID vId,
+                          const wxPoint& rPos,
+                          const wxSize& rSize,
+                          long lStyle,
+                          const wxValidator& rValidator,
+                          const wxString& rsName )
+{
+    int nX = rPos.x;
+    int nY = rPos.y;
+    int nWidth = rSize.x;
+    int nHeight = rSize.y;
+
+#if wxUSE_VALIDATORS
+    SetValidator(rValidator);
+#endif // wxUSE_VALIDATORS
+
+    SetName(rsName);
+    SetWindowStyleFlag(lStyle);
+    SetParent(pParent);
+    if (nWidth <= 0)
+        nWidth = 100;
+    if (nHeight <= 0)
+        nHeight = 30;
+    if (nX < 0)
+        nX = 0;
+    if (nY < 0)
+        nY = 0;
+
+    m_windowId = (vId == -1) ? NewControlId() : vId;
+
+    long lSstyle = WS_VISIBLE | WS_TABSTOP;
+
+    if (GetWindowStyleFlag() & wxCLIP_SIBLINGS)
+        lSstyle |= WS_CLIPSIBLINGS;
+    m_lBaseStyle = lSstyle;
+    if (!DoCreateControl( nX
+                         ,nY
+                         ,nWidth
+                         ,nHeight
+                        ))
+        return false;
+    if (pParent)
+        pParent->AddChild(this);
+   return true;
+} // end of wxListCtrl::Create
+
+bool wxListCtrl::DoCreateControl ( int nX, int nY,
+                                   int nWidth, int nHeight )
+{
+    DWORD lWstyle = m_lBaseStyle;
+    long lOldStyle = 0; // Dummy
+
+    CNRINFO vCnrInfo;
+
+    lWstyle |= ConvertToOS2Style( lOldStyle
+                                 ,GetWindowStyleFlag()
+                                );
+
+    m_hWnd = (WXHWND)::WinCreateWindow( GetParent()->GetHWND()
+                                       ,WC_CONTAINER
+                                       ,NULL
+                                       ,m_lBaseStyle
+                                       ,0, 0, 0, 0
+                                       ,GetParent()->GetHWND()
+                                       ,HWND_BOTTOM
+                                       ,(ULONG)m_windowId
+                                       ,NULL
+                                       ,NULL
+                                      );
+    if (!m_hWnd)
+    {
+        return false;
+    }
+
+    //
+    // Now set the display attributes of the container
+    //
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                     ))
+        return false;
+    lWstyle = ConvertViewToOS2Style(GetWindowStyleFlag());
+    vCnrInfo.flWindowAttr |= lWstyle;
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_SETCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)CMA_FLWINDOWATTR
+                     ))
+        return false;
+
+    //
+    // And now set needed arrangement flags
+    //
+    lWstyle = ConvertArrangeToOS2Style(GetWindowStyleFlag());
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_ARRANGE
+                      ,(MPARAM)CMA_ARRANGEGRID
+                      ,(MPARAM)lWstyle
+                     ))
+        return false;
+    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+    SetForegroundColour(GetParent()->GetForegroundColour());
+    SubclassWin(m_hWnd);
+    SetFont(*wxSMALL_FONT);
+    SetXComp(0);
+    SetYComp(0);
+    SetSize( nX, nY, nWidth, nHeight );
+    return true;
+} // end of wxListCtrl::DoCreateControl
+
+void wxListCtrl::UpdateStyle ()
+{
+    if (GetHWND())
+    {
+        long lDummy;
+        DWORD dwStyleNew = ConvertToOS2Style( lDummy, GetWindowStyleFlag() );
+
+        dwStyleNew |= m_lBaseStyle;
+
+        //
+        // Get the current window style.
+        //
+        ULONG dwStyleOld = ::WinQueryWindowULong(GetHWND(), QWL_STYLE);
+
+        //
+        // Only set the window style if the view bits have changed.
+        //
+        if (dwStyleOld != dwStyleNew)
+        {
+            ::WinSetWindowULong(GetHWND(), QWL_STYLE, dwStyleNew);
+        }
+    }
+} // end of wxListCtrl::UpdateStyle
+
+void wxListCtrl::FreeAllInternalData ()
+{
+    if (m_bAnyInternalData)
+    {
+        int n = GetItemCount();
+        int i = 0;
+
+        for (i = 0; i < n; i++)
+            DeleteInternalData(this, (long)i);
+        m_bAnyInternalData = false;
+    }
+} // end of wxListCtrl::FreeAllInternalData
+
+wxListCtrl::~wxListCtrl ()
+{
+    FreeAllInternalData();
+    if (m_pTextCtrl )
+    {
+        m_pTextCtrl->SetHWND(0);
+        m_pTextCtrl->UnsubclassWin();
+        wxDELETE(m_pTextCtrl);
+    }
+
+    if (m_bOwnsImageListNormal)
+        delete m_pImageListNormal;
+    if (m_bOwnsImageListSmall)
+        delete m_pImageListSmall;
+    if (m_bOwnsImageListState)
+        delete m_pImageListState;
+} // end of wxListCtrl::~wxListCtrl
+
+// ----------------------------------------------------------------------------
+// set/get/change style
+// ----------------------------------------------------------------------------
+
+// Add or remove a single window style
+void wxListCtrl::SetSingleStyle (
+  long                              lStyle
+, bool                              bAdd
+)
+{
+    long                            lFlag = GetWindowStyleFlag();
+
+    //
+    // Get rid of conflicting styles
+    //
+    if (bAdd)
+    {
+        if (lStyle & wxLC_MASK_TYPE)
+            lFlag = lFlag & ~wxLC_MASK_TYPE;
+        if (lStyle & wxLC_MASK_ALIGN )
+            lFlag = lFlag & ~wxLC_MASK_ALIGN;
+        if (lStyle & wxLC_MASK_SORT )
+            lFlag = lFlag & ~wxLC_MASK_SORT;
+    }
+    if (lFlag & lStyle)
+    {
+        if (!bAdd)
+            lFlag -= lStyle;
+    }
+    else
+    {
+        if (bAdd)
+        {
+            lFlag |= lStyle;
+        }
+    }
+    m_windowStyle = lFlag;
+    UpdateStyle();
+} // end of wxListCtrl::SetSingleStyle
 
 // Set the whole window style
-void wxListCtrl::SetWindowStyleFlag(long flag)
+void wxListCtrl::SetWindowStyleFlag (
+  long                              lFlag
+)
+{
+    m_windowStyle = lFlag;
+    UpdateStyle();
+} // end of wxListCtrl::SetWindowStyleFlag
+
+long wxListCtrl::ConvertToOS2Style (
+  long&                             rOldStyle
+, long                              lStyle
+) const
+{
+    long                            lWstyle = 0L;
+
+    //
+    // The only styles OS2 uses on creation are auto arrange, read only, and
+    // and selection styles.  This lib does not support OS/2 MINIRECORDCORE
+    // or VERIFYPOINTER styles
+    //
+    if (lStyle & wxLC_AUTOARRANGE)
+        lWstyle |= CCS_AUTOPOSITION;
+    if (lStyle & wxLC_SINGLE_SEL)
+        lWstyle |= CCS_SINGLESEL;
+    else
+        lWstyle |= CCS_EXTENDSEL;
+    if (!(lStyle & wxLC_EDIT_LABELS))
+        lWstyle |= CCS_READONLY;
+    return lWstyle;
+} // end of wxListCtrl::ConvertToOS2Style
+
+long wxListCtrl::ConvertArrangeToOS2Style (
+  long                              lStyle
+)
 {
-       m_windowStyle = flag;
+    long                            lWstyle = 0;
 
-       /* TODO RecreateWindow(); */
-}
+    if (lStyle & wxLC_ALIGN_LEFT)
+    {
+        lWstyle |= CMA_LEFT;
+    }
+
+    if (lStyle & wxLC_ALIGN_TOP)
+    {
+        lWstyle |= CMA_TOP;
+    }
+    return lWstyle;
+} // end of wxListCtrl::ConvertArrangeToOS2Style
+
+long wxListCtrl::ConvertViewToOS2Style (
+  long                              lStyle
+)
+{
+    long                            lWstyle = CA_DRAWICON; // we will only use icons
+
+    if (lStyle & wxLC_ICON)
+    {
+        lWstyle |= CV_ICON;
+    }
+    if (lStyle & wxLC_SMALL_ICON)
+    {
+        lWstyle |= (CV_ICON | CV_MINI);
+    }
+    if (lStyle & wxLC_LIST)
+    {
+        lWstyle |= CV_TEXT;
+    }
+    if (lStyle & wxLC_REPORT)
+    {
+        lWstyle |= CV_DETAIL;
+    }
+    if (lStyle & wxLC_VIRTUAL)
+    {
+        lWstyle |= CA_OWNERDRAW;
+    }
+    if (lStyle & wxLC_AUTOARRANGE)
+    {
+        lWstyle |= CV_FLOW;
+    }
+    if (!(lStyle & wxLC_NO_HEADER))
+    {
+        lWstyle |= CA_DETAILSVIEWTITLES;
+    }
+    return lWstyle;
+} // end of wxListCtrl::ConvertViewToOS2Style
+
+// ----------------------------------------------------------------------------
+// accessors
+// ----------------------------------------------------------------------------
+
+// Sets the foreground, i.e. text, colour
+bool wxListCtrl::SetForegroundColour (const wxColour& rCol)
+{
+    ULONG ulColor = wxColourToRGB(rCol);
+
+    if (!wxWindow::SetForegroundColour(rCol))
+        return false;
 
+    ::WinSetPresParam( GetHWND()
+                      ,PP_FOREGROUNDCOLOR
+                      ,sizeof(ULONG)
+                      ,&ulColor
+                     );
+    return true;
+} // end of wxListCtrl::SetForegroundColour
+
+// Sets the background colour
+bool wxListCtrl::SetBackgroundColour ( const wxColour& rCol )
+{
+    if (!wxWindow::SetBackgroundColour(rCol))
+        return false;
+
+    //
+    // We set the same colour for both the "empty" background and the items
+    // background
+    //
+    ULONG ulColor = wxColourToRGB(rCol);
+
+    ::WinSetPresParam( GetHWND()
+                      ,PP_BACKGROUNDCOLOR
+                      ,sizeof(ULONG)
+                      ,&ulColor
+                     );
+    return true;
+} // end of wxListCtrl::SetBackgroundColour
 
 // Gets information about this column
-bool wxListCtrl::GetColumn(int col, wxListItem& item) const
+bool wxListCtrl::GetColumn ( int nCol, wxListItem& rItem ) const
 {
-       // TODO
-    return FALSE;
-}
+    PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND(), nCol );
+
+    if (!pFieldInfo)
+        return false;
+    rItem.SetWidth(pFieldInfo->cxWidth);
+    if ((rItem.GetMask() & wxLIST_MASK_TEXT) &&
+        (pFieldInfo->flData & CFA_STRING) &&
+        (pFieldInfo->pUserData != NULL))
+    {
+        rItem.SetText((char*)pFieldInfo->pUserData);
+    }
+    if (rItem.GetMask() & wxLIST_MASK_FORMAT )
+    {
+        if (pFieldInfo->flData & CFA_LEFT)
+            rItem.m_format = wxLIST_FORMAT_LEFT;
+        else if (pFieldInfo->flData & CFA_RIGHT)
+            rItem.m_format = wxLIST_FORMAT_RIGHT;
+        else if (pFieldInfo->flData & CFA_CENTER)
+            rItem.m_format = wxLIST_FORMAT_CENTRE;
+    }
+    return true;
+} // end of wxListCtrl::GetColumn
 
 // Sets information about this column
-bool wxListCtrl::SetColumn(int col, wxListItem& item)
+bool wxListCtrl::SetColumn ( int nCol, wxListItem& rItem )
 {
-       // TODO
-    return FALSE;
-}
+    PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum( GetHWND(), nCol );
+    ConvertToOS2ListCol( nCol, rItem, pFieldInfo );
+    //
+    // Since we changed the field pointed to, we invalidate to see the result
+    //
+    ::WinSendMsg(GetHWND(), CM_INVALIDATEDETAILFIELDINFO, NULL, NULL);
+    return true;
+} // end of wxListCtrl::SetColumn
 
 // Gets the column width
-int wxListCtrl::GetColumnWidth(int col) const
+int wxListCtrl::GetColumnWidth ( int nCol ) const
 {
-       // TODO
-    return 0;
-}
+    PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND(), nCol );
+
+    if (!pFieldInfo)
+        return 0;
+    return((int)pFieldInfo->cxWidth);
+} // end of wxListCtrl::GetColumnWidth
 
 // Sets the column width
-bool wxListCtrl::SetColumnWidth(int col, int width)
+bool wxListCtrl::SetColumnWidth ( int nCol, int nWidth )
 {
-       // TODO
-    return FALSE;
-}
+    int nCol2 = nCol;
+    int nWidth2 = nWidth;
+
+    if (GetWindowStyleFlag() & wxLC_LIST)
+        nCol2 = -1;
+
+    PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum( GetHWND(), nCol );
+    pFieldInfo->cxWidth = nWidth;
+    ::WinSendMsg(GetHWND(), CM_INVALIDATEDETAILFIELDINFO, NULL, NULL);
+    return true;
+} // end of wxListCtrl::SetColumnWidth
 
 // Gets the number of items that can fit vertically in the
 // visible area of the list control (list or report view)
 // or the total number of items in the list control (icon
 // or small icon view)
-int wxListCtrl::GetCountPerPage() const
+int wxListCtrl::GetCountPerPage () const
 {
-       // TODO
-    return 0;
-}
+    QUERYRECORDRECT                 vQueryRect;
+    CNRINFO                         vCnrInfo;
+    RECTL                           vRectRecord;
+    RECTL                           vRectControl;
+    int                             nCount;
+
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                     ))
+        return 0;
+    memset(&vQueryRect, '\0', sizeof(QUERYRECORDRECT));
+    vQueryRect.cb = sizeof(QUERYRECORDRECT);
+    if (vCnrInfo.flWindowAttr & CV_ICON)
+        vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
+    else if (vCnrInfo.flWindowAttr & CV_NAME)
+        vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
+    else if (vCnrInfo.flWindowAttr & CV_TEXT)
+        vQueryRect.fsExtent = CMA_TEXT;
+    else if (vCnrInfo.flWindowAttr & CV_DETAIL)
+        vQueryRect.fsExtent = CMA_TEXT;
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYRECORDRECT
+                      ,MPFROMP(&vRectRecord)
+                      ,MPFROMP(&vQueryRect)
+                     ))
+        return 0;
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYVIEWPORTRECT
+                      ,MPFROMP(&vRectControl)
+                      ,MPFROM2SHORT(CMA_WINDOW, (USHORT)FALSE)
+                     ))
+        return 0;
+    nCount = (int)((int)((vRectControl.xRight - vRectControl.xLeft) / (vRectRecord.xRight - vRectRecord.xLeft)) *
+                   (int)((vRectControl.yTop - vRectControl.yBottom) / (vRectRecord.yTop - vRectRecord.yBottom))
+                     );
+    if (nCount > (int)vCnrInfo.cFields)
+        nCount = (int)vCnrInfo.cFields;
+    return nCount;
+} // end of wxListCtrl::GetCountPerPage
 
 // Gets the edit control for editing labels.
 wxTextCtrl* wxListCtrl::GetEditControl() const
 {
-       return m_textCtrl;
+    return m_pTextCtrl;
 }
 
 // Gets information about the item
-bool wxListCtrl::GetItem(wxListItem& info) const
+bool wxListCtrl::GetItem ( wxListItem& rInfo ) const
 {
-       // TODO
-    return FALSE;
-}
+    PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), rInfo.GetId() );
+
+    //
+    // Give NULL as hwnd as we already have everything we need
+    //
+    ConvertFromOS2ListItem( NULL, rInfo, pRecord );
+    return true;
+} // end of wxListCtrl::GetItem
 
 // Sets information about the item
-bool wxListCtrl::SetItem(wxListItem& info)
+bool wxListCtrl::SetItem ( wxListItem& rInfo )
 {
-       // TODO
-    return FALSE;
-}
-
-long wxListCtrl::SetItem(long index, int col, const wxString& label, int imageId)
-{
-       wxListItem info;
-       info.m_text = label;
-       info.m_mask = wxLIST_MASK_TEXT;
-       info.m_itemId = index;
-       info.m_col = col;
-       if ( imageId > -1 )
-       {
-               info.m_image = imageId;
-               info.m_mask |= wxLIST_MASK_IMAGE;
-       }
-       return SetItem(info);
-}
+    PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND(), rInfo.GetColumn() );
+    PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), rInfo.GetId() );
+
+    ConvertToOS2ListItem( this
+                         ,rInfo
+                         ,pRecord
+                         ,pFieldInfo
+                        );
+
+    //
+    // Check if setting attributes or lParam
+    //
+    if (rInfo.HasAttributes() || (rInfo.GetMask()  & wxLIST_MASK_DATA))
+    {
+        //
+        // Get internal item data
+        // perhaps a cache here ?
+        //
+        CListItemInternalData*      pData = GetInternalData( this
+                                                            ,rInfo.GetId()
+                                                           );
+
+        if (!pData)
+        {
+            //
+            // Need to set it
+            //
+            m_bAnyInternalData    = true;
+            pData                 = new CListItemInternalData();
+            pRecord->m_ulUserData = (unsigned long)pData;
+        };
+
+        //
+        // User data
+        //
+        if (rInfo.GetMask()  & wxLIST_MASK_DATA)
+            pData->m_lParam = (WXLPARAM)rInfo.GetData();
+
+        // attributes
+        if (rInfo.HasAttributes())
+        {
+            if (pData->m_pAttr)
+                *pData->m_pAttr = *rInfo.GetAttributes();
+            else
+                pData->m_pAttr = new wxListItemAttr(*rInfo.GetAttributes());
+        }
+        pData->m_pMyRecord = pRecord;  // they point to each other
+    }
+
+    //
+    // We need to update the item immediately to show the new image
+    //
+    bool bUpdateNow = (rInfo.GetMask() & wxLIST_MASK_IMAGE) != 0;
+
+    //
+    // Check whether it has any custom attributes
+    //
+    if (rInfo.HasAttributes())
+    {
+        m_bHasAnyAttr = true;
+
+        //
+        // If the colour has changed, we must redraw the item
+        //
+        bUpdateNow = true;
+    }
+    if (::WinIsWindowVisible(GetHWND()))
+    {
+        ::WinSendMsg( GetHWND()
+                     ,CM_INVALIDATERECORD
+                     ,MPFROMP(pRecord)
+                     ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
+                    );
+        RefreshItem(pRecord->m_ulItemId);
+    }
+    ::WinSendMsg( GetHWND()
+                 ,CM_INVALIDATEDETAILFIELDINFO
+                 ,NULL
+                 ,NULL
+                );
+    return true;
+} // end of wxListCtrl::SetItem
+
+long wxListCtrl::SetItem (
+  long                              lIndex
+, int                               nCol
+, const wxString&                   rsLabel
+, int                               nImageId
+)
+{
+    wxListItem                      vInfo;
 
+    vInfo.m_text   = rsLabel;
+    vInfo.m_mask   = wxLIST_MASK_TEXT;
+    vInfo.m_itemId = lIndex;
+    vInfo.m_col    = nCol;
+    if (nImageId > -1)
+    {
+        vInfo.m_image = nImageId;
+        vInfo.m_mask |= wxLIST_MASK_IMAGE;
+    }
+    return SetItem(vInfo);
+} // end of wxListCtrl::SetItem
 
 // Gets the item state
-int wxListCtrl::GetItemState(long item, long stateMask) const
+int wxListCtrl::GetItemState (
+  long                              lItem
+, long                              lStateMask
+) const
 {
-       wxListItem info;
-
-       info.m_mask = wxLIST_MASK_STATE ;
-       info.m_stateMask = stateMask;
-       info.m_itemId = item;
+    wxListItem                      vInfo;
 
-       if (!GetItem(info))
-               return 0;
+    vInfo.m_mask      = wxLIST_MASK_STATE;
+    vInfo.m_stateMask = lStateMask;
+    vInfo.m_itemId    = lItem;
 
-       return info.m_state;
-}
+    if (!GetItem(vInfo))
+        return 0;
+    return vInfo.m_state;
+} // end of wxListCtrl::GetItemState
 
 // Sets the item state
-bool wxListCtrl::SetItemState(long item, long state, long stateMask)
+bool wxListCtrl::SetItemState ( long lItem, long lState, long lStateMask )
 {
-       wxListItem info;
-
-       info.m_mask = wxLIST_MASK_STATE ;
-       info.m_state = state;
-       info.m_stateMask = stateMask;
-       info.m_itemId = item;
-
-       return SetItem(info);
-}
+    PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), lItem );
+
+    //
+    // Don't use SetItem() here as it doesn't work with the virtual list
+    // controls
+    //
+    ConvertToOS2Flags( lState, pRecord );
+
+    //
+    // for the virtual list controls we need to refresh the previously focused
+    // item manually when changing focus without changing selection
+    // programmatically because otherwise it keeps its focus rectangle until
+    // next repaint (yet another comctl32 bug)
+    //
+    long                            lFocusOld;
+
+    if (IsVirtual() &&
+        (lStateMask & wxLIST_STATE_FOCUSED) &&
+         (lState & wxLIST_STATE_FOCUSED) )
+    {
+        lFocusOld = GetNextItem( -1
+                                ,wxLIST_NEXT_ALL
+                                ,wxLIST_STATE_FOCUSED
+                               );
+    }
+    else
+    {
+        lFocusOld = -1;
+    }
+    ::WinSendMsg( GetHWND()
+                 ,CM_INVALIDATERECORD
+                 ,MPFROMP(pRecord)
+                 ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
+                );
+
+    if (lFocusOld != -1)
+    {
+        //
+        // No need to refresh the item if it was previously selected, it would
+        // only result in annoying flicker
+        //
+        if (!(GetItemState( lFocusOld
+                           ,wxLIST_STATE_SELECTED
+                          ) & wxLIST_STATE_SELECTED))
+        {
+            RefreshItem(lFocusOld);
+        }
+    }
+    return true;
+} // end of wxListCtrl::SetItemState
 
 // Sets the item image
-bool wxListCtrl::SetItemImage(long item, int image, int selImage)
+bool wxListCtrl::SetItemImage (
+  long                              lItem
+, int                               nImage
+, int                               WXUNUSED(nSelImage))
 {
-       wxListItem info;
+    return SetItemColumnInfo(lItem, 0, nImage);
+} // end of wxListCtrl::SetItemImage
 
-       info.m_mask = wxLIST_MASK_IMAGE ;
-       info.m_image = image;
-       info.m_itemId = item;
+// Sets the item image
+bool wxListCtrl::SetItemColumnImage (
+  long                              lItem
+, long                              lColumn
+, int                               nImage)
+{
+    wxListItem                      vInfo;
 
-       return SetItem(info);
-}
+    vInfo.m_mask   = wxLIST_MASK_IMAGE;
+    vInfo.m_image  = nImage;
+    vInfo.m_itemId = lItem;
+    vInfo.m_col    = lColumn;
+    return SetItem(vInfo);
+} // end of wxListCtrl::SetItemColumnImage
 
 // Gets the item text
-wxString wxListCtrl::GetItemText(long item) const
+wxString wxListCtrl::GetItemText (
+  long                              lItem
+) const
 {
-       wxListItem info;
+    wxListItem                      vInfo;
 
-       info.m_mask = wxLIST_MASK_TEXT ;
-       info.m_itemId = item;
+    vInfo.m_mask   = wxLIST_MASK_TEXT;
+    vInfo.m_itemId = lItem;
 
-       if (!GetItem(info))
-               return wxString("");
-       return info.m_text;
-}
+    if (!GetItem(vInfo))
+        return wxEmptyString;
+    return vInfo.m_text;
+} // end of wxListCtrl::GetItemText
 
 // Sets the item text
-void wxListCtrl::SetItemText(long item, const wxString& str)
+void wxListCtrl::SetItemText (
+  long                              lItem
+, const wxString&                   rsStr
+)
 {
-       wxListItem info;
-
-       info.m_mask = wxLIST_MASK_TEXT ;
-       info.m_itemId = item;
-       info.m_text = str;
+    wxListItem                      vInfo;
 
-       SetItem(info);
-}
+    vInfo.m_mask   = wxLIST_MASK_TEXT;
+    vInfo.m_itemId = lItem;
+    vInfo.m_text   = rsStr;
+    SetItem(vInfo);
+} // end of wxListCtrl::SetItemText
 
 // Gets the item data
-long wxListCtrl::GetItemData(long item) const
+long wxListCtrl::GetItemData (
+  long                              lItem
+) const
 {
-       wxListItem info;
+    wxListItem                      vInfo;
 
-       info.m_mask = wxLIST_MASK_DATA ;
-       info.m_itemId = item;
-
-       if (!GetItem(info))
-               return 0;
-       return info.m_data;
-}
+    vInfo.m_mask   = wxLIST_MASK_DATA;
+    vInfo.m_itemId = lItem;
+    if (!GetItem(vInfo))
+        return 0;
+    return vInfo.m_data;
+} // end of wxListCtrl::GetItemData
 
 // Sets the item data
-bool wxListCtrl::SetItemData(long item, long data)
+bool wxListCtrl::SetItemPtrData (
+  long                              lItem
+, wxUIntPtr                         lData
+)
 {
-       wxListItem info;
+    wxListItem                      vInfo;
 
-       info.m_mask = wxLIST_MASK_DATA ;
-       info.m_itemId = item;
-       info.m_data = data;
-
-       return SetItem(info);
-}
+    vInfo.m_mask   = wxLIST_MASK_DATA;
+    vInfo.m_itemId = lItem;
+    vInfo.m_data   = lData;
+    return SetItem(vInfo);
+} // end of wxListCtrl::SetItemPtrData
 
 // Gets the item rectangle
-bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const
+bool wxListCtrl::GetItemRect ( long lItem,
+                               wxRect& rRect,
+                               int nCode ) const
 {
-       // TODO
-    return FALSE;
-}
+    bool bSuccess;
+    PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), lItem );
+    QUERYRECORDRECT vQueryRect;
+    RECTL vRect;
+    int nHeight;
+
+    if (!pRecord)
+        return false;
+    vQueryRect.cb                = sizeof(QUERYRECORDRECT);
+    vQueryRect.pRecord           = &pRecord->m_vRecord;
+    vQueryRect.fRightSplitWindow = TRUE;
+    vQueryRect.fsExtent          = CMA_ICON | CMA_TEXT;
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYRECORDRECT
+                 ,MPFROMP(&vRect)
+                 ,MPFROMP(&vQueryRect)
+                );
+    //
+    // remember OS/2 is backwards
+    //
+    GetClientSize( NULL, &nHeight );
+    rRect.x      = vRect.xLeft;
+    rRect.y      = nHeight - vRect.yTop;
+    rRect.width  = vRect.xRight;
+    rRect.height = nHeight - vRect.yBottom;
+    bSuccess = true;
+    return bSuccess;
+} // end of wxListCtrl::GetItemRect
 
 // Gets the item position
-bool wxListCtrl::GetItemPosition(long item, wxPoint& pos) const
+bool wxListCtrl::GetItemPosition ( long lItem, wxPoint& rPos ) const
 {
-       // TODO
-    return FALSE;
-}
+    bool bSuccess;
+    PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND() , lItem );
+    QUERYRECORDRECT vQueryRect;
+    RECTL vRect;
+    int nHeight;
+
+    if (!pRecord)
+        return false;
+    vQueryRect.cb                = sizeof(QUERYRECORDRECT);
+    vQueryRect.pRecord           = &pRecord->m_vRecord;
+    vQueryRect.fRightSplitWindow = TRUE;
+    vQueryRect.fsExtent          = CMA_ICON | CMA_TEXT;
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYRECORDRECT
+                 ,MPFROMP(&vRect)
+                 ,MPFROMP(&vQueryRect)
+                );
+    //
+    // remember OS/2 is backwards
+    //
+    GetClientSize( NULL, &nHeight );
+    rPos.x   = vRect.xLeft;
+    rPos.y   = nHeight - vRect.yTop;
+    bSuccess = true;
+    return bSuccess;
+} // end of wxListCtrl::GetItemPosition
 
 // Sets the item position.
-bool wxListCtrl::SetItemPosition(long item, const wxPoint& pos)
+bool wxListCtrl::SetItemPosition ( long lItem, const wxPoint& rPos )
 {
-       // TODO
-    return FALSE;
-}
+    //
+    // Items cannot be positioned in X/Y coord in OS/2
+    //
+    return false;
+} // end of wxListCtrl::SetItemPosition
 
 // Gets the number of items in the list control
-int wxListCtrl::GetItemCount() const
+int wxListCtrl::GetItemCount () const
 {
-       // TODO
-    return FALSE;
-}
+    CNRINFO                         vCnrInfo;
+
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                     ))
+        return -1;
+    return vCnrInfo.cRecords;
+} // end of wxListCtrl::GetItemCount
 
 // Retrieves the spacing between icons in pixels.
-// If small is TRUE, gets the spacing for the small icon
+// If bIsSmall is true, gets the spacing for the small icon
 // view, otherwise the large icon view.
-int wxListCtrl::GetItemSpacing(bool isSmall) const
+int wxListCtrl::GetItemSpacing ( bool bIsSmall ) const
 {
-       // TODO
-    return FALSE;
-}
+    CNRINFO                         vCnrInfo;
+
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                     ))
+        return -1;
+    return vCnrInfo.cyLineSpacing;
+} // end of wxListCtrl::GetItemSpacing
+
+void wxListCtrl::SetItemTextColour (
+  long                              lItem
+, const wxColour&                   rCol
+)
+{
+    wxListItem                      vInfo;
+
+    vInfo.m_itemId = lItem;
+    vInfo.SetTextColour(rCol);
+    SetItem(vInfo);
+} // end of wxListCtrl::SetItemTextColour
+
+wxColour wxListCtrl::GetItemTextColour (
+  long                              lItem
+) const
+{
+    wxListItem                      vInfo;
+
+    vInfo.m_itemId = lItem;
+    GetItem(vInfo);
+    return vInfo.GetTextColour();
+} // end of wxListCtrl::GetItemTextColour
+
+void wxListCtrl::SetItemBackgroundColour (
+  long                              lItem
+, const wxColour&                   rCol
+)
+{
+    wxListItem                      vInfo;
+
+    vInfo.m_itemId = lItem;
+    vInfo.SetBackgroundColour(rCol);
+    SetItem(vInfo);
+} // end of wxListCtrl::SetItemBackgroundColour
+
+wxColour wxListCtrl::GetItemBackgroundColour (
+  long                              lItem
+) const
+{
+    wxListItem                      vInfo;
+
+    vInfo.m_itemId = lItem;
+    GetItem(vInfo);
+    return vInfo.GetBackgroundColour();
+} // end of wxListCtrl::GetItemBackgroundColour
 
 // Gets the number of selected items in the list control
-int wxListCtrl::GetSelectedItemCount() const
+int wxListCtrl::GetSelectedItemCount () const
 {
-       // TODO
-    return FALSE;
-}
+    PMYRECORD                       pRecord = NULL;
+    int                             nCount = 0;
+    pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                  ,CM_QUERYRECORDEMPHASIS
+                                                  ,(MPARAM)CMA_FIRST
+                                                  ,(MPARAM)CRA_SELECTED
+                                                 ));
+    if (pRecord)
+        nCount++;
+    else
+        return 0;
+    while (pRecord)
+    {
+        pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                      ,CM_QUERYRECORDEMPHASIS
+                                                      ,MPFROMP(pRecord)
+                                                      ,(MPARAM)CRA_SELECTED
+                                                     ));
+        if (pRecord)
+            nCount++;
+    }
+    return nCount;
+} // end of wxListCtrl::GetSelectedItemCount
 
 // Gets the text colour of the listview
-wxColour wxListCtrl::GetTextColour() const
+wxColour wxListCtrl::GetTextColour () const
 {
-       // TODO
-    return wxColour();
-}
+    wxColour                        vCol;
+    ULONG                           ulColor;
+
+    ::WinQueryPresParam( GetHWND()
+                        ,PP_FOREGROUNDCOLOR
+                        ,0
+                        ,NULL
+                        ,sizeof(ULONG)
+                        ,&ulColor
+                        ,QPF_PURERGBCOLOR
+                       );
+    vCol.Set(ulColor);
+    return vCol;
+} // end of wxListCtrl::GetTextColour
 
 // Sets the text colour of the listview
-void wxListCtrl::SetTextColour(const wxColour& col)
+void wxListCtrl::SetTextColour (
+  const wxColour&                   rCol
+)
 {
-       // TODO
-}
+    ULONG                           ulColor = wxColourToRGB(rCol);
+
+    ::WinSetPresParam( GetHWND()
+                      ,PP_FOREGROUNDCOLOR
+                      ,sizeof(ULONG)
+                      ,&ulColor
+                     );
+} // end of wxListCtrl::SetTextColour
 
 // Gets the index of the topmost visible item when in
 // list or report view
-long wxListCtrl::GetTopItem() const
+long wxListCtrl::GetTopItem () const
 {
-       // TODO
-    return 0;
-}
+    PMYRECORD                       pRecord = NULL;
+    QUERYRECFROMRECT                vQueryRect;
+    RECTL                           vRect;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYVIEWPORTRECT
+                 ,MPFROMP(&vRect)
+                 ,MPFROM2SHORT(CMA_WINDOW, TRUE)
+                );
+    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 (long)pRecord->m_ulItemId;
+} // end of wxListCtrl::GetTopItem
 
 // Searches for an item, starting from 'item'.
 // 'geometry' is one of
@@ -338,259 +1767,989 @@ long wxListCtrl::GetTopItem() const
 // item can be -1 to find the first item that matches the
 // specified flags.
 // Returns the item or -1 if unsuccessful.
-long wxListCtrl::GetNextItem(long item, int geom, int state) const
+long wxListCtrl::GetNextItem (
+  long                              lItem
+, int                               WXUNUSED(nGeom)
+, int                               WXUNUSED(nState)
+) const
 {
-       // TODO
-    return 0;
-}
-
-wxImageList *wxListCtrl::GetImageList(int which) const
+    PMYRECORD                       pRecord = FindOS2ListRecordByID( GetHWND()
+                                                                    ,lItem
+                                                                   );
+
+    pRecord = (PMYRECORD)pRecord->m_vRecord.preccNextRecord;
+    if (pRecord)
+        return((long)pRecord->m_ulItemId);
+    return -1L;
+} // end of wxListCtrl::GetNextItem
+
+wxImageList* wxListCtrl::GetImageList (
+  int                               nWhich
+) const
 {
-       if ( which == wxIMAGE_LIST_NORMAL )
+    if (nWhich == wxIMAGE_LIST_NORMAL )
     {
-               return m_imageListNormal;
-       }
-       else if ( which == wxIMAGE_LIST_SMALL )
+        return m_pImageListNormal;
+    }
+    else if (nWhich == wxIMAGE_LIST_SMALL )
     {
-               return m_imageListSmall;
-       }
-       else if ( which == wxIMAGE_LIST_STATE )
+        return m_pImageListSmall;
+    }
+    else if (nWhich == wxIMAGE_LIST_STATE )
     {
-               return m_imageListState;
-       }
-       return NULL;
-}
+        return m_pImageListState;
+    }
+    return NULL;
+} // end of wxListCtrl::GetImageList
 
-void wxListCtrl::SetImageList(wxImageList *imageList, int which)
+void wxListCtrl::SetImageList ( wxImageList* pImageList,
+                                int nWhich )
 {
-       int flags = 0;
-       if ( which == wxIMAGE_LIST_NORMAL )
+    if (nWhich == wxIMAGE_LIST_NORMAL)
     {
-               m_imageListNormal = imageList;
-       }
-       else if ( which == wxIMAGE_LIST_SMALL )
+        if (m_bOwnsImageListNormal)
+            delete m_pImageListNormal;
+        m_pImageListNormal     = pImageList;
+        m_bOwnsImageListNormal = false;
+    }
+    else if (nWhich == wxIMAGE_LIST_SMALL)
     {
-               m_imageListSmall = imageList;
-       }
-       else if ( which == wxIMAGE_LIST_STATE )
+        if (m_bOwnsImageListSmall)
+            delete m_pImageListSmall;
+        m_pImageListSmall    = pImageList;
+        m_bOwnsImageListSmall = false;
+    }
+    else if (nWhich == wxIMAGE_LIST_STATE)
     {
-               m_imageListState = imageList;
-       }
-       // TODO set image list
-}
+        if (m_bOwnsImageListState)
+            delete m_pImageListState;
+        m_pImageListState     = pImageList;
+        m_bOwnsImageListState = false;
+    }
+} // end of wxListCtrl::SetImageList
+
+void wxListCtrl::AssignImageList ( wxImageList* pImageList, int nWhich )
+{
+    SetImageList( pImageList, nWhich );
+
+    if (nWhich == wxIMAGE_LIST_NORMAL )
+        m_bOwnsImageListNormal = true;
+    else if (nWhich == wxIMAGE_LIST_SMALL )
+        m_bOwnsImageListSmall = true;
+    else if (nWhich == wxIMAGE_LIST_STATE )
+        m_bOwnsImageListState = true;
+} // end of wxListCtrl::AssignImageList
 
+// ----------------------------------------------------------------------------
 // Operations
-////////////////////////////////////////////////////////////////////////////
+// ----------------------------------------------------------------------------
 
 // Arranges the items
-bool wxListCtrl::Arrange(int flag)
+bool wxListCtrl::Arrange ( int nFlag )
 {
-       // TODO
-    return FALSE;
-}
+    ULONG ulType = 0L;
+    ULONG ulFlags = 0L;
+
+    if (nFlag == wxLIST_ALIGN_SNAP_TO_GRID)
+    {
+        ulType = CMA_ARRANGEGRID;
+        if (nFlag == wxLIST_ALIGN_LEFT)
+            ulFlags |= CMA_LEFT;
+        else if (nFlag == wxLIST_ALIGN_TOP)
+            ulFlags |= CMA_TOP;
+        else if (nFlag == wxLIST_ALIGN_DEFAULT)
+            ulFlags |= CMA_LEFT;
+    }
+    else
+        ulType = CMA_ARRANGESTANDARD;
+    ::WinSendMsg( GetHWND()
+                 ,CM_ARRANGE
+                 ,(MPARAM)ulType
+                 ,(MPARAM)ulFlags
+                );
+    //
+    // We do not support CMA_ARRANGESELECTED
+    //
+    return true;
+} // end of wxListCtrl::Arrange
 
 // Deletes an item
-bool wxListCtrl::DeleteItem(long item)
+bool wxListCtrl::DeleteItem ( long lItem )
 {
-       // TODO
-    return FALSE;
-}
+    PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), lItem );
+    if (LONGFROMMR(::WinSendMsg( GetHWND()
+                                ,CM_REMOVERECORD
+                                ,(MPARAM)pRecord
+                                ,MPFROM2SHORT(1, CMA_FREE)
+                               )) == -1L)
+    {
+        return false;
+    }
+
+    //
+    // The virtual list control doesn't refresh itself correctly, help it
+    //
+    if (IsVirtual())
+    {
+        //
+        // We need to refresh all the lines below the one which was deleted
+        //
+        wxRect                      vRectItem;
+
+        if (lItem > 0 && GetItemCount())
+        {
+            GetItemRect( lItem - 1
+                        ,vRectItem
+                       );
+        }
+        else
+        {
+            vRectItem.y = vRectItem.height = 0;
+        }
+        wxRect                      vRectWin = GetRect();
+
+        vRectWin.height = vRectWin.GetBottom() - vRectItem.GetBottom();
+        vRectWin.y      = vRectItem.GetBottom();
+        RefreshRect(vRectWin);
+    }
+    return true;
+} // end of wxListCtrl::DeleteItem
 
 // Deletes all items
-bool wxListCtrl::DeleteAllItems()
+bool wxListCtrl::DeleteAllItems ()
 {
-       // TODO
-    return FALSE;
-}
+    return((LONG)::WinSendMsg( GetHWND()
+                              ,CM_REMOVERECORD
+                              ,NULL
+                              ,MPFROM2SHORT(0, CMA_FREE)
+                             ) != -1L);
+} // end of wxListCtrl::DeleteAllItems
 
 // Deletes all items
-bool wxListCtrl::DeleteAllColumns()
+bool wxListCtrl::DeleteAllColumns ()
 {
-       // TODO
-    return FALSE;
-}
+    while (m_nColCount > 0)
+    {
+        DeleteColumn(m_nColCount - 1);
+        m_nColCount--;
+    }
+
+    wxASSERT_MSG(m_nColCount == 0, wxT("no columns should be left"));
+    return true;
+} // end of wxListCtrl::DeleteAllColumns
 
 // Deletes a column
-bool wxListCtrl::DeleteColumn(int col)
+bool wxListCtrl::DeleteColumn ( int nCol )
 {
-       // TODO
-    return FALSE;
-}
+    bool bSuccess = false;
+    PFIELDINFO pField = FindOS2ListFieldByColNum( GetHWND(), nCol );
+    bSuccess = ((LONG)::WinSendMsg( GetHWND()
+                                   ,CM_REMOVEDETAILFIELDINFO
+                                   ,MPFROMP(pField)
+                                   ,MPFROM2SHORT((SHORT)1, CMA_FREE)
+                                  ) == -1L);
+    if (bSuccess && (m_nColCount > 0))
+        m_nColCount--;
+    return bSuccess;
+} // end of wxListCtrl::DeleteColumn
 
 // Clears items, and columns if there are any.
-void wxListCtrl::ClearAll()
+void wxListCtrl::ClearAll ()
 {
     DeleteAllItems();
-    if ( m_colCount > 0 )
+    if (m_nColCount > 0)
         DeleteAllColumns();
-}
-
-// Edit the label
-wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
+} // end of wxListCtrl::ClearAll
+
+//
+// OS/2 does not use a text control for its container labels.  You merely
+// "open" a record for editting.
+//
+wxTextCtrl* wxListCtrl::EditLabel (
+  long                              lItem
+, wxClassInfo*                      WXUNUSED(pTextControlClass)
+)
 {
-    // TODO
-    return NULL;
-}
-
-// End label editing, optionally cancelling the edit
-bool wxListCtrl::EndEditLabel(bool cancel)
+    CNREDITDATA                     vEdit;
+    PMYRECORD                       pRecord = FindOS2ListRecordByID( GetHWND()
+                                                                    ,lItem
+                                                                   );
+
+    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 m_pTextCtrl;
+} // end of wxListCtrl::EditLabel
+
+// End label editing, optionally cancelling the edit.  Under OS/2 you close
+// the record for editting
+bool wxListCtrl::EndEditLabel ( bool WXUNUSED(bCancel) )
 {
-    // TODO
-    return FALSE;
-}
+    ::WinSendMsg( GetHWND()
+                 ,CM_CLOSEEDIT
+                 ,(MPARAM)0
+                 ,(MPARAM)0
+                );
+    return true;
+} // end of wxListCtrl::EndEditLabel
 
 // Ensures this item is visible
-bool wxListCtrl::EnsureVisible(long item)
+bool wxListCtrl::EnsureVisible ( long lItem )
 {
-    // TODO
-    return FALSE;
-}
+    PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), lItem );
+    ::WinSendMsg( GetHWND()
+                 ,CM_INVALIDATERECORD
+                 ,MPFROMP(pRecord)
+                 ,MPFROM2SHORT((SHORT)1, CMA_NOREPOSITION)
+                );
+    return true;
+} // end of wxListCtrl::EnsureVisible
 
 // Find an item whose label matches this string, starting from the item after 'start'
 // or the beginning if 'start' is -1.
-long wxListCtrl::FindItem(long start, const wxString& str, bool partial)
+long wxListCtrl::FindItem (
+  long                              lStart
+, const wxString&                   rsStr
+, bool                              bPartial
+)
 {
-    // TODO
-    return FALSE;
-}
+    CNRINFO                         vCnrInfo;
+    SEARCHSTRING                    vSearch;
+    PMYRECORD                       pRecord = FindOS2ListRecordByID( GetHWND()
+                                                                    ,lStart
+                                                                   );
+    ULONG                           ulFlag;
+
+
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                     ))
+        return -1L;
+
+    if (vCnrInfo.flWindowAttr & CV_ICON)
+        ulFlag = CV_ICON;
+    if (vCnrInfo.flWindowAttr & CV_NAME)
+        ulFlag = CV_NAME;
+    if (vCnrInfo.flWindowAttr & CV_TEXT)
+        ulFlag = CV_TEXT;
+    if (vCnrInfo.flWindowAttr & CV_DETAIL)
+        ulFlag = CV_DETAIL;
+    if (!bPartial)
+        ulFlag |= CV_EXACTLENGTH;
+
+    vSearch.cb              = sizeof(SEARCHSTRING);
+    vSearch.pszSearch       = (char*)rsStr.c_str();
+    vSearch.fsPrefix        = TRUE;
+    vSearch.fsCaseSensitive = TRUE;
+    vSearch.usView          = ulFlag;
+
+    if (lStart == -1)
+    {
+        pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+                                          ,CM_SEARCHSTRING
+                                          ,MPFROMP(&vSearch)
+                                          ,(MPARAM)CMA_FIRST
+                                         );
+    }
+    else
+    {
+        pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+                                          ,CM_SEARCHSTRING
+                                          ,MPFROMP(&vSearch)
+                                          ,MPFROMP(pRecord)
+                                         );
+    }
+    if (!pRecord)
+        return -1L;
+    return pRecord->m_ulItemId;
+} // end of wxListCtrl::FindItem
 
 // Find an item whose data matches this data, starting from the item after 'start'
 // or the beginning if 'start' is -1.
-long wxListCtrl::FindItem(long start, long data)
+long wxListCtrl::FindItem (
+  long                              lStart
+, long                              lData
+)
 {
-    // TODO
-    return 0;
-}
+    long                            lIdx = lStart + 1;
+    long                            lCount = GetItemCount();
+
+    while (lIdx < lCount)
+    {
+        if (GetItemData(lIdx) == lData)
+            return lIdx;
+        lIdx++;
+    };
+    return -1;
+} // end of wxListCtrl::FindItem
 
 // Find an item nearest this position in the specified direction, starting from
 // the item after 'start' or the beginning if 'start' is -1.
-long wxListCtrl::FindItem(long start, const wxPoint& pt, int direction)
+long wxListCtrl::FindItem (
+  long                              lStart
+, const wxPoint&                    rPoint
+, int                               nDirection
+)
 {
-    // TODO
-    return 0;
-}
+    RECTL                           vRect;
+    QUERYRECORDRECT                 vQueryRect;
+    PMYRECORD                       pRecord = FindOS2ListRecordByID( GetHWND()
+                                                                    ,lStart
+                                                                   );
+    CNRINFO                         vCnrInfo;
+    ULONG                           i;
+    wxRect                          vLibRect;
+
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_QUERYCNRINFO
+                      ,MPFROMP(&vCnrInfo)
+                      ,(MPARAM)(USHORT)sizeof(CNRINFO)
+                     ))
+        return -1L;
+
+    vQueryRect.cb                = sizeof(QUERYRECORDRECT);
+    vQueryRect.pRecord           = &pRecord->m_vRecord;
+    vQueryRect.fRightSplitWindow = TRUE;
+    vQueryRect.fsExtent          = CMA_ICON | CMA_TEXT;
+
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYRECORDRECT
+                 ,MPFROMP(&vRect)
+                 ,MPFROMP(&vQueryRect)
+                );
+    vLibRect.SetLeft(vRect.xLeft);
+    vLibRect.SetTop(vRect.yTop);
+    vLibRect.SetRight(vRect.xRight);
+    vLibRect.SetBottom(vRect.yBottom);
+    if (vLibRect.Contains(rPoint))
+        return pRecord->m_ulItemId;
+
+    for (i = lStart + 1; i < vCnrInfo.cRecords; i++)
+    {
+        pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+                                                      ,CM_QUERYRECORD
+                                                      ,MPFROMP(pRecord)
+                                                      ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+                                                     ));
+        vQueryRect.pRecord = (PRECORDCORE)pRecord;
+        ::WinSendMsg( GetHWND()
+                     ,CM_QUERYRECORDRECT
+                     ,MPFROMP(&vRect)
+                     ,MPFROMP(&vQueryRect)
+                    );
+        vLibRect.SetLeft(vRect.xLeft);
+        vLibRect.SetTop(vRect.yTop);
+        vLibRect.SetRight(vRect.xRight);
+        vLibRect.SetBottom(vRect.yBottom);
+        if (vLibRect.Contains(rPoint))
+            return pRecord->m_ulItemId;
+    }
+    return -1L;
+} // end of wxListCtrl::FindItem
 
 // Determines which item (if any) is at the specified point,
 // giving details in 'flags' (see wxLIST_HITTEST_... flags above)
-long wxListCtrl::HitTest(const wxPoint& point, int& flags)
+long wxListCtrl::HitTest (
+  const wxPoint&                    rPoint
+, int&                              WXUNUSED(rFlags)
+)
 {
-    // TODO
-    return 0;
-}
+    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 pRecord->m_ulItemId;
+} // end of wxListCtrl::HitTest
 
 // Inserts an item, returning the index of the new item if successful,
 // -1 otherwise.
-long wxListCtrl::InsertItem(wxListItem& info)
+long wxListCtrl::InsertItem (
+  wxListItem&                       rInfo
+)
 {
-    // TODO
-    return 0;
-}
-
-long wxListCtrl::InsertItem(long index, const wxString& label)
+    wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual controls") );
+
+    PFIELDINFO                      pFieldInfo = FindOS2ListFieldByColNum ( GetHWND()
+                                                                           ,rInfo.GetColumn()
+                                                                          );
+    PMYRECORD                       pRecordAfter = NULL;
+    PMYRECORD                       pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+                                                                      ,CM_ALLOCRECORD
+                                                                      ,MPFROMLONG(sizeof(MYRECORD) - sizeof(RECORDCORE))
+                                                                      ,MPFROMSHORT(1)
+                                                                     );
+
+    ConvertToOS2ListItem( this
+                         ,rInfo
+                         ,pRecord
+                         ,pFieldInfo
+                        );
+
+    if (rInfo.GetId() > 0)
+        pRecordAfter = FindOS2ListRecordByID( GetHWND()
+                                             ,rInfo.GetId() - 1
+                                            );
+
+    RECORDINSERT                    vInsert;
+
+    vInsert.cb                = sizeof(RECORDINSERT);
+    vInsert.pRecordParent     = NULL;
+    if (!pRecordAfter)
+        vInsert.pRecordOrder  = (PRECORDCORE)CMA_FIRST;
+    else
+        vInsert.pRecordOrder  = (PRECORDCORE)pRecordAfter;
+    vInsert.zOrder            = CMA_TOP;
+    vInsert.cRecordsInsert    = 1;
+    vInsert.fInvalidateRecord = TRUE;
+
+    //
+    // Check whether we need to allocate our internal data
+    //
+    bool                            bNeedInternalData = ((rInfo.GetMask() & wxLIST_MASK_DATA) ||
+                                                          rInfo.HasAttributes()
+                                                        );
+    if (bNeedInternalData)
+    {
+        m_bAnyInternalData = true;
+
+        //
+        // Internal stucture that manages data
+        //
+        CListItemInternalData*      pData = new CListItemInternalData();
+
+        pRecord->m_ulUserData = (unsigned long)pData;
+        if (rInfo.GetMask() & wxLIST_MASK_DATA)
+            pData->m_lParam = (WXLPARAM)rInfo.GetData();
+
+        //
+        // Check whether it has any custom attributes
+        //
+        if (rInfo.HasAttributes())
+        {
+            //
+            // Take copy of attributes
+            //
+            pData->m_pAttr = new wxListItemAttr(*rInfo.GetAttributes());
+        }
+    }
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_INSERTRECORD
+                      ,MPFROMP(pRecord)
+                      ,MPFROMP(&vInsert)
+                     ))
+        return -1;
+    //
+    // OS/2 must mannually bump the index's of following records
+    //
+    BumpRecordIds( GetHWND()
+                  ,pRecord
+                 );
+    ::WinSendMsg( GetHWND()
+                 ,CM_INVALIDATEDETAILFIELDINFO
+                 ,NULL
+                 ,NULL
+                );
+    return pRecord->m_ulItemId;
+} // end of wxListCtrl::InsertItem
+
+long wxListCtrl::InsertItem (
+  long                              lIndex
+, const wxString&                   rsLabel
+)
 {
-       wxListItem info;
-       info.m_text = label;
-       info.m_mask = wxLIST_MASK_TEXT;
-       info.m_itemId = index;
-       return InsertItem(info);
-}
+    wxListItem                      vInfo;
+
+    memset(&vInfo, '\0', sizeof(wxListItem));
+    vInfo.m_text   = rsLabel;
+    vInfo.m_mask   = wxLIST_MASK_TEXT;
+    vInfo.m_itemId = lIndex;
+    return InsertItem(vInfo);
+} // end of wxListCtrl::InsertItem
 
 // Inserts an image item
-long wxListCtrl::InsertItem(long index, int imageIndex)
+long wxListCtrl::InsertItem (
+  long                              lIndex
+, int                               nImageIndex
+)
 {
-       wxListItem info;
-       info.m_image = imageIndex;
-       info.m_mask = wxLIST_MASK_IMAGE;
-       info.m_itemId = index;
-       return InsertItem(info);
-}
+    wxListItem                      vInfo;
 
-// Inserts an image/string item
-long wxListCtrl::InsertItem(long index, const wxString& label, int imageIndex)
-{
-       wxListItem info;
-       info.m_image = imageIndex;
-       info.m_text = label;
-       info.m_mask = wxLIST_MASK_IMAGE | wxLIST_MASK_TEXT;
-       info.m_itemId = index;
-       return InsertItem(info);
-}
+    vInfo.m_image  = nImageIndex;
+    vInfo.m_mask   = wxLIST_MASK_IMAGE;
+    vInfo.m_itemId = lIndex;
+    return InsertItem(vInfo);
+} // end of wxListCtrl::InsertItem
 
-// For list view mode (only), inserts a column.
-long wxListCtrl::InsertColumn(long col, wxListItem& item)
+// Inserts an image/string item
+long wxListCtrl::InsertItem (
+  long                              lIndex
+, const wxString&                   rsLabel
+, int                               nImageIndex
+)
 {
-    // TODO
-    return 0;
-}
+    wxListItem                      vInfo;
+
+    vInfo.m_image  = nImageIndex;
+    vInfo.m_text   = rsLabel;
+    vInfo.m_mask   = wxLIST_MASK_IMAGE | wxLIST_MASK_TEXT;
+    vInfo.m_itemId = lIndex;
+    return InsertItem(vInfo);
+} // end of wxListCtrl::InsertItem
+
+// For details view mode (only), inserts a column.
+long wxListCtrl::InsertColumn (
+  long                              lCol
+, wxListItem&                       rItem
+)
+{
+    bool                            bSuccess;
+    PFIELDINFO                      pField = (PFIELDINFO)::WinSendMsg( GetHWND()
+                                                                      ,CM_ALLOCDETAILFIELDINFO
+                                                                      ,MPFROMLONG(1)
+                                                                      ,NULL
+                                                                     );
+    PFIELDINFO                      pFieldAfter = FindOS2ListFieldByColNum ( GetHWND()
+                                                                            ,lCol - 1
+                                                                           );
+    FIELDINFOINSERT                 vInsert;
+
+    ConvertToOS2ListCol ( lCol
+                         ,rItem
+                         ,pField
+                        );
+
+    vInsert.cb                   = sizeof(FIELDINFOINSERT);
+    vInsert.pFieldInfoOrder      = pFieldAfter;
+    vInsert.fInvalidateFieldInfo = TRUE;
+    vInsert.cFieldInfoInsert     = 1;
+
+    bSuccess = ::WinSendMsg( GetHWND()
+                            ,CM_INSERTDETAILFIELDINFO
+                            ,MPFROMP(pField)
+                            ,MPFROMP(&vInsert)
+                           ) != (MRESULT)0;
+    return bSuccess;
+} // end of wxListCtrl::InsertColumn
+
+long wxListCtrl::InsertColumn (
+  long                              lCol
+, const wxString&                   rsHeading
+, int                               nFormat
+, int                               nWidth
+)
+{
+    wxListItem                      vItem;
 
-long wxListCtrl::InsertColumn(long col, const wxString& heading, int format,
-    int width)
+    vItem.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
+    vItem.m_text = rsHeading;
+    if (nWidth > -1)
+    {
+        vItem.m_mask |= wxLIST_MASK_WIDTH;
+        vItem.m_width = nWidth;
+    }
+    vItem.m_format = nFormat;
+
+    return InsertColumn( lCol
+                        ,vItem
+                       );
+} // end of wxListCtrl::InsertColumn
+
+// scroll the control by the given number of pixels (exception: in list view,
+// dx is interpreted as number of columns)
+bool wxListCtrl::ScrollList ( int nDx, int nDy )
+{
+    if (nDx > 0)
+        ::WinSendMsg( GetHWND()
+                     ,CM_SCROLLWINDOW
+                     ,(MPARAM)CMA_HORIZONTAL
+                     ,(MPARAM)nDx
+                    );
+    if (nDy > 0)
+        ::WinSendMsg( GetHWND()
+                     ,CM_SCROLLWINDOW
+                     ,(MPARAM)CMA_VERTICAL
+                     ,(MPARAM)nDy
+                    );
+    return true;
+} // end of wxListCtrl::ScrollList
+
+bool wxListCtrl::SortItems ( wxListCtrlCompare fn, long lData )
 {
-       wxListItem item;
-       item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
-       item.m_text = heading;
-       if ( width > -1 )
-       {
-               item.m_mask |= wxLIST_MASK_WIDTH;
-               item.m_width = width;
-       }
-       item.m_format = format;
+    SInternalDataSort vInternalData;
 
-       return InsertColumn(col, item);
-}
+    vInternalData.m_fnUser = fn;
+    vInternalData.m_lData  = lData;
+
+    // WPARAM cast is needed for mingw/cygwin
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_SORTRECORD
+                      ,(PFN)InternalDataCompareFunc
+                      ,(PVOID)&vInternalData
+                     ))
+    {
+        wxLogDebug(wxT("CM_SORTRECORD failed"));
+        return false;
+    }
+    return true;
+} // end of wxListCtrl::SortItems
 
-// Scrolls the list control. If in icon, small icon or report view mode,
-// x specifies the number of pixels to scroll. If in list view mode, x
-// specifies the number of columns to scroll.
-// If in icon, small icon or list view mode, y specifies the number of pixels
-// to scroll. If in report view mode, y specifies the number of lines to scroll.
-bool wxListCtrl::ScrollList(int dx, int dy)
+// ----------------------------------------------------------------------------
+// message processing
+// ----------------------------------------------------------------------------
+
+bool wxListCtrl::OS2Command ( WXUINT uCmd, WXWORD wId )
 {
-    // TODO
-    return FALSE;
-}
+    if (uCmd == CN_ENDEDIT)
+    {
+        wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED, wId );
 
-// Sort items.
+        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 wxListCtrl::OS2Command
+
+// Necessary for drawing hrules and vrules, if specified
+void wxListCtrl::OnPaint ( wxPaintEvent& rEvent )
+{
+    wxPaintDC                       vDc(this);
+    wxPen                           vPen(wxSystemSettings::GetColour( wxSYS_COLOUR_3DLIGHT)
+                                                                     ,1
+                                                                     ,wxSOLID
+                                                                    );
+    wxSize                          vClientSize = GetClientSize();
+    wxRect                          vItemRect;
+    int                             nItemCount = GetItemCount();
+    int                             nCy = 0;
+    int                             i;
+    bool                            bDrawHRules = ((GetWindowStyle() & wxLC_HRULES) != 0);
+    bool                            bDrawVRules = ((GetWindowStyle() & wxLC_VRULES) != 0);
+
+    wxControl::OnPaint(rEvent);
+
+    //
+    // Reset the device origin since it may have been set
+    //
+    vDc.SetDeviceOrigin(0, 0);
+    if (!bDrawHRules && !bDrawVRules)
+        return;
+    if ((GetWindowStyle() & wxLC_REPORT) == 0)
+        return;
+    vDc.SetPen(vPen);
+    vDc.SetBrush(*wxTRANSPARENT_BRUSH);
+
+    if (bDrawHRules)
+    {
+        long                        lTop = GetTopItem();
+
+        for (i = lTop; i < lTop + GetCountPerPage() + 1; i++)
+        {
+            if (GetItemRect( i
+                            ,vItemRect
+                           ))
+            {
+                nCy = vItemRect.GetTop();
+                if (i != 0) // Don't draw the first one
+                {
+                    vDc.DrawLine( 0
+                                 ,nCy
+                                 ,vClientSize.x
+                                 ,nCy
+                                );
+                }
+                // Draw last line
+                if (i == nItemCount - 1)
+                {
+                    nCy = vItemRect.GetBottom();
+                    vDc.DrawLine( 0
+                                 ,nCy
+                                 ,vClientSize.x
+                                 ,nCy
+                                );
+                }
+            }
+        }
+    }
+    i = nItemCount - 1;
+    if (bDrawVRules && (i > -1))
+    {
+        wxRect                      vFirstItemRect;
+
+        GetItemRect( 0
+                    ,vFirstItemRect
+                   );
+        if (GetItemRect( i
+                        ,vItemRect
+                       ))
+        {
+            int                     nCol;
+            int                     nX = vItemRect.GetX();
+
+            for (nCol = 0; nCol < GetColumnCount(); nCol++)
+            {
+                int                 nColWidth = GetColumnWidth(nCol);
+
+                nX += nColWidth ;
+                vDc.DrawLine( nX - 1
+                             ,vFirstItemRect.GetY() - 2
+                             ,nX - 1
+                             ,vItemRect.GetBottom()
+                            );
+            }
+        }
+    }
+} // end of wxListCtrl::OnPaint
 
-// fn is a function which takes 3 long arguments: item1, item2, data.
-// item1 is the long data associated with a first item (NOT the index).
-// item2 is the long data associated with a second item (NOT the index).
-// data is the same value as passed to SortItems.
-// The return value is a negative number if the first item should precede the second
-// item, a positive number of the second item should precede the first,
-// or zero if the two items are equivalent.
+// ----------------------------------------------------------------------------
+// virtual list controls
+// ----------------------------------------------------------------------------
 
-// data is arbitrary data to be passed to the sort function.
-bool wxListCtrl::SortItems(wxListCtrlCompare fn, long data)
+wxString wxListCtrl::OnGetItemText (
+  long                              WXUNUSED(lItem)
+, long                              WXUNUSED(lCol)
+) const
 {
-    // TODO
-    return FALSE;
-}
+    // this is a pure virtual function, in fact - which is not really pure
+    // because the controls which are not virtual don't need to implement it
+    wxFAIL_MSG( wxT("not supposed to be called") );
+    return wxEmptyString;
+} // end of wxListCtrl::OnGetItemText
+
+int wxListCtrl::OnGetItemImage (
+  long                              WXUNUSED(lItem)
+) const
+{
+    // same as above
+    wxFAIL_MSG( wxT("not supposed to be called") );
+    return -1;
+} // end of wxListCtrl::OnGetItemImage
+
+int wxListCtrl::OnGetItemColumnImage (
+  long                              lItem,
+  long                              lColumn
+) const
+{
+    if (!lColumn)
+        return OnGetItemImage(lItem);
+
+    return -1;
+} // end of wxListCtrl::OnGetItemColumnImage
 
-// List item structure
-wxListItem::wxListItem()
+wxListItemAttr* wxListCtrl::OnGetItemAttr (
+  long                              WXUNUSED_UNLESS_DEBUG(lItem)
+) const
 {
-    m_mask = 0;
-    m_itemId = 0;
-    m_col = 0;
-    m_state = 0;
-    m_stateMask = 0;
-    m_image = 0;
-       m_data = 0;
+    wxASSERT_MSG( lItem >= 0 && lItem < GetItemCount(),
+                  wxT("invalid item index in OnGetItemAttr()") );
 
-       m_format = wxLIST_FORMAT_CENTRE;
-       m_width = 0;
-}
+    //
+    // No attributes by default
+    //
+    return NULL;
+} // end of wxListCtrl::OnGetItemAttr
+
+void wxListCtrl::SetItemCount (
+  long                              lCount
+)
+{
+    wxASSERT_MSG( IsVirtual(), wxT("this is for virtual controls only") );
 
-// List event
-IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxCommandEvent)
+    //
+    // Cannot explicitly set the record count in OS/2
+    //
+} // end of wxListCtrl::SetItemCount
 
-wxListEvent::wxListEvent(wxEventType commandType, int id):
-  wxCommandEvent(commandType, id)
+void wxListCtrl::RefreshItem (
+  long                              lItem
+)
 {
-       m_code = 0;
-       m_itemIndex = 0;
-       m_col = 0;
-       m_cancelled = FALSE;
-}
+    wxRect                          vRect;
+
+    GetItemRect( lItem
+                ,vRect
+               );
+    RefreshRect(vRect);
+} // end of wxListCtrl::RefreshItem
+
+void wxListCtrl::RefreshItems ( long lItemFrom, long lItemTo )
+{
+    wxRect vRect1;
+    wxRect vRect2;
+
+    GetItemRect( lItemFrom , vRect1 );
+    GetItemRect( lItemTo , vRect2 );
 
+    wxRect vRect = vRect1;
+
+    vRect.height = vRect2.GetBottom() - vRect1.GetTop();
+    RefreshRect(vRect);
+} // end of wxListCtrl::RefreshItems
+
+MRESULT wxListCtrl::OS2WindowProc( WXUINT uMsg,
+                                   WXWPARAM wParam,
+                                   WXLPARAM lParam )
+{
+    bool                            bProcessed = false;
+    MRESULT                         lRc;
+    wxListEvent                     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:
+            //
+            // First off let's set some internal data
+            //
+            switch(SHORT2FROMMP(wParam))
+            {
+                case CN_INITDRAG:
+                case CN_DRAGOVER:
+                case CN_DRAGAFTER:
+                    {
+                        CListItemInternalData*  pInternaldata = (CListItemInternalData *)lParam;
+
+                        if (pInternaldata)
+                        {
+                            wxListItem*     pItem = (wxListItem*)&vEvent.GetItem();
+
+                            pItem->SetData((long)pInternaldata->m_lParam);
+                        }
+                    }
+                    break;
+            }
+            //
+            // Now let's go through the codes we're interested in
+            //
+            switch(SHORT2FROMMP(wParam))
+            {
+                case CN_INITDRAG:
+                    pDragInit = (PCNRDRAGINIT)lParam;
+                    if (pDragInit)
+                    {
+                        PMYRECORD       pRecord = (PMYRECORD)pDragInit->pRecord;
+
+                        vEventType = wxEVT_COMMAND_LIST_BEGIN_RDRAG;
+                        vEvent.m_itemIndex   = pRecord->m_ulItemId;
+                        vEvent.m_pointDrag.x = pDragInit->x;
+                        vEvent.m_pointDrag.y = pDragInit->y;
+                    }
+                    break;
+
+                case CN_BEGINEDIT:
+                    pEditData = (PCNREDITDATA)lParam;
+                    if (pEditData)
+                    {
+                        vEventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
+                        ConvertFromOS2ListItem( GetHWND()
+                                               ,(wxListItem &)vEvent.GetItem()
+                                               ,(PMYRECORD)pEditData->pRecord
+                                              );
+                        vEvent.m_itemIndex = vEvent.GetItem().GetId();
+                    }
+                    break;
+
+                case CN_ENDEDIT:
+                    pEditData = (PCNREDITDATA)lParam;
+                    if (pEditData)
+                    {
+                        vEventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
+                        ConvertFromOS2ListItem( GetHWND()
+                                               ,(wxListItem &)vEvent.GetItem()
+                                               ,(PMYRECORD)pEditData->pRecord
+                                              );
+                        if (pEditData->cbText == 0)
+                            return (MRESULT)FALSE;
+                        vEvent.m_itemIndex = vEvent.GetItem().GetId();
+                    }
+                    break;
+
+                case CN_ENTER:
+                    pNotifyEnter = (PNOTIFYRECORDENTER)lParam;
+                    if (pNotifyEnter)
+                    {
+                        wxListItem*     pItem = (wxListItem*)&vEvent.GetItem();
+                        PMYRECORD       pMyRecord = (PMYRECORD)pNotifyEnter->pRecord;
+
+                        vEventType             = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
+                        vEvent.m_itemIndex = pMyRecord->m_ulItemId;
+                        pItem->SetText(GetItemText(pMyRecord->m_ulItemId));
+                        pItem->SetData(GetItemData(pMyRecord->m_ulItemId));
+                    }
+                    break;
+
+                    //
+                    // Add the CN_DROP messages for Direct Manipulation
+                    //
+            }
+            vEvent.SetEventType(vEventType);
+            bProcessed = HandleWindowEvent(vEvent);
+            break;
+    }
+    if (!bProcessed)
+        lRc = wxControl::OS2WindowProc( uMsg
+                                       ,wParam
+                                       ,lParam
+                                      );
+    return lRc;
+} // end of wxListCtrl::WindowProc
+
+#endif // wxUSE_LISTCTRL