]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/listctrl.cpp
fixed bug with lower-case colours in wxColourDatabase::AddColour() (patch 1074865)
[wxWidgets.git] / src / os2 / listctrl.cpp
index 7d8aa47552abeea1db9694171928c61d5fa1ebcc..701d27f3c8a344e5aef02e18e1d5c55c58c3a4b3 100644 (file)
 /////////////////////////////////////////////////////////////////////////////
-// Name:        listctrl.cpp
-// Purpose:     wxListCtrl. See also Robert's generic wxListCtrl
+// Name:        src/os2/listctrl.cpp
+// Purpose:     wxListCtrl
 // Author:      David Webster
 // Modified by:
-// Created:     10/10/99
+// Created:     01/21/03
 // RCS-ID:      $Id$
 // Copyright:   (c) David Webster
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+    #pragma implementation "listctrl.h"
+    #pragma implementation "listctrlbase.h"
+#endif
+
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#if wxUSE_LISTCTRL
+
 #ifndef WX_PRECOMP
-    #include "wx/wx.h"
+    #include "wx/app.h"
+    #include "wx/intl.h"
+    #include "wx/log.h"
+    #include "wx/settings.h"
 #endif
 
+#include "wx/textctrl.h"
+#include "wx/imaglist.h"
 #include "wx/listctrl.h"
-#include "wx/log.h"
+#include "wx/dcclient.h"
 
 #include "wx/os2/private.h"
 
-// TODO: not sure if we will need these
-/*
-static void wxConvertToOS2ListItem(const wxListCtrl *ctrl, wxListItem& info, LV_ITEM& tvItem);
-static void wxConvertFromOS2ListItem(const wxListCtrl *ctrl, wxListItem& info, LV_ITEM& tvItem, HWND getFullInfo = 0);
-*/
+//
+// 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))
 
-#if !USE_SHARED_LIBRARY
-IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
-IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
-#endif
+// ----------------------------------------------------------------------------
+// private helper classes
+// ----------------------------------------------------------------------------
 
-wxListCtrl::wxListCtrl()
+/////////////////////////////////////////////////////////////////////////////
+// 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
+{
+    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;
+
+/////////////////////////////////////////////////////////////////////////////
+// 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 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 independant 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_baseStyle = 0;
-    m_colCount = 0;
-    m_textCtrl = NULL;
-}
+public:
+
+    CListItemInternalData(): m_pAttr(NULL)
+                            ,m_lParam(0)
+    {}
 
-bool wxListCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
-            long style, const wxValidator& validator, const wxString& name)
+    ~CListItemInternalData()
+    {
+        delete m_pAttr;
+        m_pAttr = NULL;
+    }
+
+    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
+
+/////////////////////////////////////////////////////////////////////////////
+// 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
 {
-    m_imageListNormal = NULL;
-    m_imageListSmall = NULL;
-    m_imageListState = NULL;
-    m_colCount = 0;
+    wxListCtrlCompare               m_fnUser;
+    long                            m_lData;
+} SInternalDataSort; // end of STRUCT SInternalDataSort
 
-    SetValidator(validator);
-    SetName(name);
+// ----------------------------------------------------------------------------
+// private helper functions
+// ----------------------------------------------------------------------------
 
-    int x = pos.x;
-    int y = pos.y;
-    int width = size.x;
-    int height = size.y;
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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
 
-    m_windowStyle = style;
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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
 
-    SetParent(parent);
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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
 
-    m_windowId = (id == -1) ? NewControlId() : id;
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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
 
-    if (parent) parent->AddChild(this);
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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
 
-    // TODO create list control
-//  DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |
-//                 LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;
-//  if ( wxStyleHasBorder(m_windowStyle) )
-//      wstyle |= WS_BORDER;
-//  m_baseStyle = wstyle;
+/////////////////////////////////////////////////////////////////////////////
 //
-//  if ( !DoCreateControl(x, y, width, height) )
-//      return FALSE;
+// DeleteInternalData
 //
-//  if (parent)
-//      parent->AddChild(this);
-    return TRUE;
-}
+//  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
 
-bool wxListCtrl::DoCreateControl(int x, int y, int w, int h)
-{
-    DWORD wstyle = m_baseStyle;
-
-    bool want3D;
-// TODO
-//    WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D);
-
-    // Even with extended styles, need to combine with WS_BORDER
-    // for them to look right.
-//    if ( want3D )
-//        wstyle |= WS_BORDER;
-
-//    long oldStyle = 0; // Dummy
-//    wstyle |= ConvertToMSWStyle(oldStyle, m_windowStyle);
-
-    // Create the ListView control.
-//    m_hWnd = (WXHWND)CreateWindowEx(exStyle,
-//                                    WC_LISTVIEW,
-//                                    wxT(""),
-//                                    wstyle,
-//                                    x, y, w, h,
-//                                    GetWinHwnd(GetParent()),
-//                                    (HMENU)m_windowId,
-//                                    wxGetInstance(),
-//                                    NULL);
-
-//    if ( !m_hWnd )
-//    {
-//        wxLogError(wxT("Can't create list control window."));
-//
-//        return FALSE;
-//    }
-
-    // for comctl32.dll v 4.70+ we want to have this attribute because it's
-    // prettier (and also because wxGTK does it like this)
-#ifdef ListView_SetExtendedListViewStyle
-//    if ( wstyle & LVS_REPORT )
-//    {
-//        ListView_SetExtendedListViewStyle(GetHwnd(),
-//                                          LVS_EX_FULLROWSELECT);
-//    }
-#endif // ListView_SetExtendedListViewStyle
-
-    SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
-    SetForegroundColour(GetParent()->GetForegroundColour());
+// #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
 
-//    SubclassWin(m_hWnd);
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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( _T("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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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
+
+// ----------------------------------------------------------------------------
+// events
+// ----------------------------------------------------------------------------
+
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
+
+IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
+IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
+
+IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
+
+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()
+void wxListCtrl::UpdateStyle ()
 {
-/*
-    if ( GetHWND() )
+    if (GetHWND())
     {
-        // The new window view style
-        long dummy;
-        DWORD dwStyleNew = ConvertToMSWStyle(dummy, m_windowStyle);
-        dwStyleNew |= m_baseStyle;
+        long                        lDummy;
+        DWORD                       dwStyleNew = ConvertToOS2Style( lDummy
+                                                                   ,GetWindowStyleFlag()
+                                                                  );
+
+        dwStyleNew |= m_lBaseStyle;
 
+        //
         // Get the current window style.
-        DWORD dwStyleOld = ::GetWindowLong(GetHwnd(), GWL_STYLE);
+        //
+        ULONG                       dwStyleOld = ::WinQueryWindowULong(GetHWND(), QWL_STYLE);
 
+        //
         // Only set the window style if the view bits have changed.
-        if ( dwStyleOld != dwStyleNew )
+        //
+        if (dwStyleOld != dwStyleNew)
         {
-            ::SetWindowLong(GetHwnd(), GWL_STYLE, dwStyleNew);
+            ::WinSetWindowULong(GetHWND(), QWL_STYLE, dwStyleNew);
         }
     }
-*/
-}
-wxListCtrl::~wxListCtrl()
+} // end of wxListCtrl::UpdateStyle
+
+void wxListCtrl::FreeAllInternalData ()
 {
-    if (m_textCtrl)
+    if (m_bAnyInternalData)
     {
-        m_textCtrl->UnsubclassWin();
-        m_textCtrl->SetHWND(0);
-        delete m_textCtrl;
-        m_textCtrl = NULL;
+        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();
+        delete m_pTextCtrl;
+        m_pTextCtrl = NULL;
     }
-}
+
+    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 style, bool add)
+void wxListCtrl::SetSingleStyle (
+  long                              lStyle
+, bool                              bAdd
+)
 {
-    long flag = GetWindowStyleFlag();
+    long                            lFlag = GetWindowStyleFlag();
 
+    //
     // Get rid of conflicting styles
-    if ( add )
+    //
+    if (bAdd)
     {
-        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 ;
+        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 ( flag & style )
+    if (lFlag & lStyle)
     {
-        if ( !add )
-            flag -= style;
+        if (!bAdd)
+            lFlag -= lStyle;
     }
     else
     {
-        if ( add )
+        if (bAdd)
         {
-            flag |= style;
+            lFlag |= lStyle;
         }
     }
-
-    m_windowStyle = flag;
-
+    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 = flag;
-
+    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
 
-// Can be just a single style, or a bitlist
-long wxListCtrl::ConvertToOS2Style(long& oldStyle, long style) const
+long wxListCtrl::ConvertArrangeToOS2Style (
+  long                              lStyle
+)
 {
-    long wstyle = 0;
-/*
-    if ( style & wxLC_ICON )
+    long                            lWstyle = 0;
+
+    if (lStyle & wxLC_ALIGN_LEFT)
     {
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_SMALLICON )
-            oldStyle -= LVS_SMALLICON;
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_REPORT )
-            oldStyle -= LVS_REPORT;
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_LIST )
-            oldStyle -= LVS_LIST;
-        wstyle |= LVS_ICON;
+        lWstyle |= CMA_LEFT;
     }
 
-    if ( style & wxLC_SMALL_ICON )
+    if (lStyle & wxLC_ALIGN_TOP)
     {
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_ICON )
-            oldStyle -= LVS_ICON;
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_REPORT )
-            oldStyle -= LVS_REPORT;
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_LIST )
-            oldStyle -= LVS_LIST;
-        wstyle |= LVS_SMALLICON;
+        lWstyle |= CMA_TOP;
     }
+    return lWstyle;
+} // end of wxListCtrl::ConvertArrangeToOS2Style
+
+long wxListCtrl::ConvertViewToOS2Style (
+  long                              lStyle
+)
+{
+    long                            lWstyle = CA_DRAWICON; // we will only use icons
 
-    if ( style & wxLC_LIST )
+    if (lStyle & wxLC_ICON)
     {
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_ICON )
-            oldStyle -= LVS_ICON;
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_REPORT )
-            oldStyle -= LVS_REPORT;
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_SMALLICON )
-            oldStyle -= LVS_SMALLICON;
-        wstyle |= LVS_LIST;
+        lWstyle |= CV_ICON;
     }
-
-    if ( style & wxLC_REPORT )
+    if (lStyle & wxLC_SMALL_ICON)
     {
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_ICON )
-            oldStyle -= LVS_ICON;
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_LIST )
-            oldStyle -= LVS_LIST;
-        if ( (oldStyle & LVS_TYPEMASK) == LVS_SMALLICON )
-            oldStyle -= LVS_SMALLICON;
-
-        wstyle |= LVS_REPORT;
+        lWstyle |= (CV_ICON | CV_MINI);
     }
-
-    if ( style & wxLC_ALIGN_LEFT )
+    if (lStyle & wxLC_LIST)
     {
-        if ( oldStyle & LVS_ALIGNTOP )
-            oldStyle -= LVS_ALIGNTOP;
-        wstyle |= LVS_ALIGNLEFT;
+        lWstyle |= CV_TEXT;
     }
-
-    if ( style & wxLC_ALIGN_TOP )
+    if (lStyle & wxLC_REPORT)
     {
-        if ( oldStyle & LVS_ALIGNLEFT )
-            oldStyle -= LVS_ALIGNLEFT;
-        wstyle |= LVS_ALIGNTOP;
+        lWstyle |= CV_DETAIL;
     }
-
-    if ( style & wxLC_AUTOARRANGE )
-        wstyle |= LVS_AUTOARRANGE;
-
-    // Apparently, no such style (documentation wrong?)
-    //   if ( style & wxLC_BUTTON )
-    //   wstyle |= LVS_BUTTON;
-
-    if ( style & wxLC_NO_SORT_HEADER )
-        wstyle |= LVS_NOSORTHEADER;
-
-    if ( style & wxLC_NO_HEADER )
-        wstyle |= LVS_NOCOLUMNHEADER;
-
-    if ( style & wxLC_EDIT_LABELS )
-        wstyle |= LVS_EDITLABELS;
-
-    if ( style & wxLC_SINGLE_SEL )
-        wstyle |= LVS_SINGLESEL;
-
-    if ( style & wxLC_SORT_ASCENDING )
+    if (lStyle & wxLC_VIRTUAL)
     {
-        if ( oldStyle & LVS_SORTDESCENDING )
-            oldStyle -= LVS_SORTDESCENDING;
-        wstyle |= LVS_SORTASCENDING;
+        lWstyle |= CA_OWNERDRAW;
     }
-
-    if ( style & wxLC_SORT_DESCENDING )
+    if (lStyle & wxLC_AUTOARRANGE)
     {
-        if ( oldStyle & LVS_SORTASCENDING )
-            oldStyle -= LVS_SORTASCENDING;
-        wstyle |= LVS_SORTDESCENDING;
+        lWstyle |= CV_FLOW;
     }
-*/
-    return wstyle;
-}
+    if (!(lStyle & wxLC_NO_HEADER))
+    {
+        lWstyle |= CA_DETAILSVIEWTITLES;
+    }
+    return lWstyle;
+} // end of wxListCtrl::ConvertViewToOS2Style
+
+// ----------------------------------------------------------------------------
+// accessors
+// ----------------------------------------------------------------------------
 
-// Sets the background colour (GetBackgroundColour already implicit in
-// wxWindow class)
-bool wxListCtrl::SetBackgroundColour(const wxColour& col)
+// Sets the foreground, i.e. text, colour
+bool wxListCtrl::SetForegroundColour (
+  const wxColour&                   rCol)
 {
-    if ( !wxWindow::SetBackgroundColour(col) )
+    ULONG                           ulColor = wxColourToRGB(rCol);
+
+    if (!wxWindow::SetForegroundColour(rCol))
         return FALSE;
 
-//    ListView_SetBkColor(GetHwnd(), PALETTERGB(col.Red(), col.Green(), col.Blue()));
 
+    ::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)
-{
-    // TODO
-    return FALSE;
-}
+bool wxListCtrl::SetColumn (
+  int                               nCol
+, wxListItem&                       rItem
+)
+{
+    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)
-{
-    // TODO
-    return FALSE;
-}
+bool wxListCtrl::SetColumnWidth (
+  int                               nCol
+, int                               nWidth
+)
+{
+    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
-{
-    // TODO
-    return 0;
-}
+int wxListCtrl::GetCountPerPage () const
+{
+    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
-{
-    // TODO
-    return FALSE;
-}
+bool wxListCtrl::GetItem (
+  wxListItem&                       rInfo
+) const
+{
+    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)
-{
-    // 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 )
+bool wxListCtrl::SetItem (
+  wxListItem&                       rInfo
+)
+{
+    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))
     {
-        info.m_image = imageId;
-        info.m_mask |= wxLIST_MASK_IMAGE;
+        //
+        // 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
     }
-    return SetItem(info);
-}
 
+    //
+    // 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;
+    wxListItem                      vInfo;
 
-    info.m_mask = wxLIST_MASK_STATE ;
-    info.m_stateMask = stateMask;
-    info.m_itemId = item;
+    vInfo.m_mask      = wxLIST_MASK_STATE;
+    vInfo.m_stateMask = lStateMask;
+    vInfo.m_itemId    = lItem;
 
-    if (!GetItem(info))
+    if (!GetItem(vInfo))
         return 0;
-
-    return info.m_state;
-}
+    return vInfo.m_state;
+} // end of wxListCtrl::GetItemState
 
 // Sets the item state
-bool wxListCtrl::SetItemState(long item, long state, long stateMask)
-{
-    wxListItem info;
-
-    info.m_mask = wxLIST_MASK_STATE ;
-    info.m_state = state;
-    info.m_stateMask = stateMask;
-    info.m_itemId = item;
+bool wxListCtrl::SetItemState (
+  long                              lItem
+, long                              lState
+, long                              lStateMask
+)
+{
+    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)
+                );
 
-    return SetItem(info);
-}
+    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;
+    wxListItem                      vInfo;
 
-    info.m_mask = wxLIST_MASK_IMAGE ;
-    info.m_image = image;
-    info.m_itemId = item;
-
-    return SetItem(info);
-}
+    vInfo.m_mask   = wxLIST_MASK_IMAGE;
+    vInfo.m_image  = nImage;
+    vInfo.m_itemId = lItem;
+    return SetItem(vInfo);
+} // end of wxListCtrl::SetItemImage
 
 // 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;
+    wxListItem                      vInfo;
 
-    info.m_mask = wxLIST_MASK_TEXT ;
-    info.m_itemId = item;
-    info.m_text = str;
-
-    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;
-
-    info.m_mask = wxLIST_MASK_DATA ;
-    info.m_itemId = item;
+    wxListItem                      vInfo;
 
-    if (!GetItem(info))
+    vInfo.m_mask   = wxLIST_MASK_DATA;
+    vInfo.m_itemId = lItem;
+    if (!GetItem(vInfo))
         return 0;
-    return info.m_data;
-}
+    return vInfo.m_data;
+} // end of wxListCtrl::GetItemData
 
 // Sets the item data
-bool wxListCtrl::SetItemData(long item, long data)
+bool wxListCtrl::SetItemData (
+  long                              lItem
+, long                              lData
+)
 {
-    wxListItem info;
-
-    info.m_mask = wxLIST_MASK_DATA ;
-    info.m_itemId = item;
-    info.m_data = data;
+    wxListItem                      vInfo;
 
-    return SetItem(info);
-}
+    vInfo.m_mask   = wxLIST_MASK_DATA;
+    vInfo.m_itemId = lItem;
+    vInfo.m_data   = lData;
+    return SetItem(vInfo);
+} // end of wxListCtrl::SetItemData
 
 // Gets the item rectangle
-bool wxListCtrl::GetItemRect(long item, wxRect& rect, int code) const
-{
-    // TODO
-    return FALSE;
-}
+bool wxListCtrl::GetItemRect (
+  long                              lItem
+, wxRect&                           rRect
+, int                               nCode
+) const
+{
+    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
-{
-    // TODO
-    return FALSE;
-}
+bool wxListCtrl::GetItemPosition (
+  long                              lItem
+, wxPoint&                          rPos
+) const
+{
+    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)
-{
-    // TODO
+bool wxListCtrl::SetItemPosition (
+  long                              lItem
+, const wxPoint&                    rPos
+)
+{
+    //
+    // 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
 // view, otherwise the large icon view.
-int wxListCtrl::GetItemSpacing(bool isSmall) const
+int wxListCtrl::GetItemSpacing (
+  bool                              bIsSmall
+) const
+{
+    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
 {
-    // TODO
-    return FALSE;
-}
+    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
-{
-    // TODO
-    return FALSE;
-}
+int wxListCtrl::GetSelectedItemCount () const
+{
+    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
-{
-    // TODO
-    return wxColour();
-}
+wxColour wxListCtrl::GetTextColour () const
+{
+    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
-{
-    // TODO
-    return 0;
-}
+long wxListCtrl::GetTopItem () const
+{
+    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
@@ -556,635 +1876,1024 @@ 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
-{
-    // TODO
-    return 0;
-}
-
-wxImageList *wxListCtrl::GetImageList(int which) const
-{
-    if ( which == wxIMAGE_LIST_NORMAL )
+long wxListCtrl::GetNextItem (
+  long                              lItem
+, int                               WXUNUSED(nGeom)
+, int                               WXUNUSED(nState)
+) 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 (nWhich == wxIMAGE_LIST_NORMAL )
     {
-        return m_imageListNormal;
+        return m_pImageListNormal;
     }
-    else if ( which == wxIMAGE_LIST_SMALL )
+    else if (nWhich == wxIMAGE_LIST_SMALL )
     {
-        return m_imageListSmall;
+        return m_pImageListSmall;
     }
-    else if ( which == wxIMAGE_LIST_STATE )
+    else if (nWhich == wxIMAGE_LIST_STATE )
     {
-        return m_imageListState;
+        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;
+        if (m_bOwnsImageListNormal)
+            delete m_pImageListNormal;
+        m_pImageListNormal     = pImageList;
+        m_bOwnsImageListNormal = FALSE;
     }
-    else if ( which == wxIMAGE_LIST_SMALL )
+    else if (nWhich == wxIMAGE_LIST_SMALL)
     {
-        m_imageListSmall = imageList;
+        if (m_bOwnsImageListSmall)
+            delete m_pImageListSmall;
+        m_pImageListSmall    = pImageList;
+        m_bOwnsImageListSmall = FALSE;
     }
-    else if ( which == wxIMAGE_LIST_STATE )
+    else if (nWhich == wxIMAGE_LIST_STATE)
     {
-        m_imageListState = imageList;
+        if (m_bOwnsImageListState)
+            delete m_pImageListState;
+        m_pImageListState     = pImageList;
+        m_bOwnsImageListState = FALSE;
     }
-    // TODO set image list
-}
-
+} // 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)
-{
-    // TODO
-    return FALSE;
-}
+bool wxListCtrl::DeleteItem (
+  long                              lItem
+)
+{
+    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)
-{
-    // TODO
-    return FALSE;
-}
+bool wxListCtrl::DeleteColumn (
+  int                               nCol
+)
+{
+    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)
-{
-    // TODO
-    return NULL;
-}
+} // end of wxListCtrl::ClearAll
 
-// End label editing, optionally cancelling the edit
-bool wxListCtrl::EndEditLabel(bool cancel)
-{
-    // TODO
-    return FALSE;
-}
+//
+// 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)
+)
+{
+    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)
+)
+{
+    ::WinSendMsg( GetHWND()
+                 ,CM_CLOSEEDIT
+                 ,(MPARAM)0
+                 ,(MPARAM)0
+                );
+    return TRUE;
+} // end of wxListCtrl::EndEditLabel
 
 // Ensures this item is visible
-bool wxListCtrl::EnsureVisible(long item)
-{
-    // TODO
-    return FALSE;
-}
+bool wxListCtrl::EnsureVisible (
+  long                              lItem
+)
+{
+    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)
-{
-    // TODO
-    return FALSE;
-}
+long wxListCtrl::FindItem (
+  long                              lStart
+, const wxString&                   rsStr
+, bool                              bPartial
+)
+{
+    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)
-{
-    // TODO
-    return 0;
-}
+long wxListCtrl::FindItem (
+  long                              lStart
+, const wxPoint&                    rPoint
+, int                               nDirection
+)
+{
+    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.Inside(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.Inside(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)
-{
-    // TODO
-    return 0;
-}
+long wxListCtrl::HitTest (
+  const wxPoint&                    rPoint
+, int&                              WXUNUSED(rFlags)
+)
+{
+    PMYRECORD                       pRecord = NULL;
+    QUERYRECFROMRECT                vQueryRect;
+    RECTL                           vRect;
+    long                            lHeight;
+
+    //
+    // Get height for OS/2 point conversion
+    //
+    ::WinSendMsg( GetHWND()
+                 ,CM_QUERYVIEWPORTRECT
+                 ,MPFROMP(&vRect)
+                 ,MPFROM2SHORT(CMA_WINDOW, TRUE)
+                );
+    lHeight = vRect.yTop - vRect.yBottom;
+
+    //
+    // For now just try and get a record in the general vicinity and forget
+    // the flag
+    //
+    vRect.xLeft   = rPoint.x - 2;
+    vRect.xRight  = rPoint.x + 2;
+    vRect.yTop    = (lHeight - rPoint.y) + 2;
+    vRect.yBottom = (lHeight - rPoint.y) - 2;
+
+    vQueryRect.cb = sizeof(QUERYRECFROMRECT);
+    vQueryRect.rect = vRect;
+    vQueryRect.fsSearch = CMA_PARTIAL;
+
+    pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+                                      ,CM_QUERYRECORDFROMRECT
+                                      ,(MPARAM)CMA_FIRST
+                                      ,MPFROMP(&vQueryRect)
+                                    );
+
+    if (!pRecord)
+        return -1L;
+    return 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)
-{
-    // TODO
-    return 0;
-}
+long wxListCtrl::InsertItem (
+  wxListItem&                       rInfo
+)
+{
+    wxASSERT_MSG( !IsVirtual(), _T("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 wether we need to allocate our internal data
+    //
+    bool                            bNeedInternalData = ((rInfo.GetMask() & wxLIST_MASK_DATA) ||
+                                                          rInfo.HasAttributes()
+                                                        );
+    if (bNeedInternalData)
+    {
+        m_bAnyInternalData = TRUE;
 
-long wxListCtrl::InsertItem(long index, const wxString& label)
-{
-    wxListItem info;
-    info.m_text = label;
-    info.m_mask = wxLIST_MASK_TEXT;
-    info.m_itemId = index;
-    return InsertItem(info);
-}
+        //
+        // Internal stucture that manages data
+        //
+        CListItemInternalData*      pData = new CListItemInternalData();
 
-// Inserts an image item
-long wxListCtrl::InsertItem(long index, int imageIndex)
-{
-    wxListItem info;
-    info.m_image = imageIndex;
-    info.m_mask = wxLIST_MASK_IMAGE;
-    info.m_itemId = index;
-    return InsertItem(info);
-}
+        pRecord->m_ulUserData = (unsigned long)pData;
+        if (rInfo.GetMask() & wxLIST_MASK_DATA)
+            pData->m_lParam = (WXLPARAM)rInfo.GetData();
 
-// 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);
-}
+        //
+        // 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                      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
 
-// For list view mode (only), inserts a column.
-long wxListCtrl::InsertColumn(long col, wxListItem& item)
+// Inserts an image item
+long wxListCtrl::InsertItem (
+  long                              lIndex
+, int                               nImageIndex
+)
 {
-    // TODO
-    return 0;
-}
+    wxListItem                      vInfo;
 
-long wxListCtrl::InsertColumn(long col, const wxString& heading, int format,
-    int width)
-{
-    wxListItem item;
-    item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
-    item.m_text = heading;
-    if ( width > -1 )
+    vInfo.m_image  = nImageIndex;
+    vInfo.m_mask   = wxLIST_MASK_IMAGE;
+    vInfo.m_itemId = lIndex;
+    return InsertItem(vInfo);
+} // end of wxListCtrl::InsertItem
+
+// Inserts an image/string item
+long wxListCtrl::InsertItem (
+  long                              lIndex
+, const wxString&                   rsLabel
+, int                               nImageIndex
+)
+{
+    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;
+
+    vItem.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
+    vItem.m_text = rsHeading;
+    if (nWidth > -1)
     {
-        item.m_mask |= wxLIST_MASK_WIDTH;
-        item.m_width = width;
+        vItem.m_mask |= wxLIST_MASK_WIDTH;
+        vItem.m_width = nWidth;
     }
-    item.m_format = format;
-
-    return InsertColumn(col, item);
-}
+    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
 
-// 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)
+bool wxListCtrl::SortItems (
+  wxListCtrlCompare                 fn
+, long                              lData
+)
 {
-    // TODO
-    return FALSE;
-}
+    SInternalDataSort               vInternalData;
 
-// Sort items.
+    vInternalData.m_fnUser = fn;
+    vInternalData.m_lData  = lData;
 
-// 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.
+    // WPARAM cast is needed for mingw/cygwin
+    if (!::WinSendMsg( GetHWND()
+                      ,CM_SORTRECORD
+                      ,(PFN)InternalDataCompareFunc
+                      ,(PVOID)&vInternalData
+                     ))
+    {
+        wxLogDebug(_T("CM_SORTRECORD failed"));
+        return FALSE;
+    }
+    return TRUE;
+} // end of wxListCtrl::SortItems
 
-// data is arbitrary data to be passed to the sort function.
-bool wxListCtrl::SortItems(wxListCtrlCompare fn, long data)
-{
-    // TODO
-    return FALSE;
-}
+// ----------------------------------------------------------------------------
+// message processing
+// ----------------------------------------------------------------------------
 
-bool wxListCtrl::OS2Command(WXUINT cmd, WXWORD id)
+bool wxListCtrl::OS2Command (
+  WXUINT                            uCmd
+, WXWORD                            wId
+)
 {
-/*
-    if (cmd == EN_UPDATE)
+    if (uCmd == CN_ENDEDIT)
     {
-        wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
-        event.SetEventObject( this );
-        ProcessCommand(event);
+        wxCommandEvent              vEvent( wxEVT_COMMAND_TEXT_UPDATED
+                                           ,wId
+                                          );
+
+        vEvent.SetEventObject( this );
+        ProcessCommand(vEvent);
         return TRUE;
     }
-    else if (cmd == EN_KILLFOCUS)
+    else if (uCmd == CN_KILLFOCUS)
     {
-        wxCommandEvent event(wxEVT_KILL_FOCUS, id);
-        event.SetEventObject( this );
-        ProcessCommand(event);
+        wxCommandEvent              vEvent( wxEVT_KILL_FOCUS
+                                           ,wId
+                                          );
+        vEvent.SetEventObject( this );
+        ProcessCommand(vEvent);
         return TRUE;
     }
     else
         return FALSE;
-*/
-    return FALSE;
-}
-
-bool wxListCtrl::OS2OnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
-{
-    // TODO
-/*
-    wxListEvent event(wxEVT_NULL, m_windowId);
-    wxEventType eventType = wxEVT_NULL;
-    NMHDR *hdr1 = (NMHDR *) lParam;
-    switch ( hdr1->code )
+} // 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)
     {
-        case LVN_BEGINRDRAG:
-            eventType = wxEVT_COMMAND_LIST_BEGIN_RDRAG;
-            // fall through
-
-        case LVN_BEGINDRAG:
-            if ( eventType == wxEVT_NULL )
-            {
-                eventType = wxEVT_COMMAND_LIST_BEGIN_DRAG;
-            }
-
-            {
-                NM_LISTVIEW *hdr = (NM_LISTVIEW *)lParam;
-                event.m_itemIndex = hdr->iItem;
-                event.m_pointDrag.x = hdr->ptAction.x;
-                event.m_pointDrag.y = hdr->ptAction.y;
-            }
-            break;
-
-        case LVN_BEGINLABELEDIT:
-            {
-                eventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
-                LV_DISPINFO *info = (LV_DISPINFO *)lParam;
-                wxConvertFromMSWListItem(this, event.m_item, info->item, GetHwnd());
-                break;
-            }
-
-        case LVN_COLUMNCLICK:
-            {
-                eventType = wxEVT_COMMAND_LIST_COL_CLICK;
-                NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam;
-                event.m_itemIndex = -1;
-                event.m_col = hdr->iSubItem;
-                break;
-            }
-
-        case LVN_DELETEALLITEMS:
-            // what's the sense of generating a wxWin event for this when
-            // it's absolutely not portable?
-#if 0
-            eventType = wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS;
-            event.m_itemIndex = -1;
-#endif // 0
-
-            // return TRUE to suppress all additional LVN_DELETEITEM
-            // notifications - this makes deleting all items from a list ctrl
-            // much faster
-            *result = TRUE;
-            return TRUE;
-
-        case LVN_DELETEITEM:
-            {
-                eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
-                NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam;
-                event.m_itemIndex = hdr->iItem;
-                break;
-            }
-        case LVN_ENDLABELEDIT:
-            {
-                eventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
-                LV_DISPINFO *info = (LV_DISPINFO *)lParam;
-                wxConvertFromMSWListItem(this, event.m_item, info->item, GetHwnd());
-                if ( info->item.pszText == NULL || info->item.iItem == -1 )
-                    event.m_cancelled = TRUE;
-                break;
-            }
-        case LVN_GETDISPINFO:
-                return FALSE;
-
-                // this provokes stack overflow: indeed, wxConvertFromMSWListItem()
-                // sends us WM_NOTIFY! As it doesn't do anything for now, just leave
-                // it out.
-#if 0
-            {
-                // TODO: some text buffering here, I think
-                // TODO: API for getting Windows to retrieve values
-                // on demand.
-                eventType = wxEVT_COMMAND_LIST_GET_INFO;
-                LV_DISPINFO *info = (LV_DISPINFO *)lParam;
-                wxConvertFromMSWListItem(this, event.m_item, info->item, GetHwnd());
-                break;
-            }
-#endif // 0
-
-        case LVN_INSERTITEM:
-            {
-                eventType = wxEVT_COMMAND_LIST_INSERT_ITEM;
-                NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam;
-                event.m_itemIndex = hdr->iItem;
-                break;
-            }
-        case LVN_ITEMCHANGED:
-            {
-                // This needs to be sent to wxListCtrl as a rather more
-                // concrete event. For now, just detect a selection
-                // or deselection.
-                NM_LISTVIEW* hdr = (NM_LISTVIEW*)lParam;
-                if ( (hdr->uNewState & LVIS_SELECTED) && !(hdr->uOldState & LVIS_SELECTED) )
-                {
-                    eventType = wxEVT_COMMAND_LIST_ITEM_SELECTED;
-                    event.m_itemIndex = hdr->iItem;
-                }
-                else if ( !(hdr->uNewState & LVIS_SELECTED) && (hdr->uOldState & LVIS_SELECTED) )
-                {
-                    eventType = wxEVT_COMMAND_LIST_ITEM_DESELECTED;
-                    event.m_itemIndex = hdr->iItem;
-                }
-                else
-                    return FALSE;
-                break;
-            }
+        long                        lTop = GetTopItem();
 
-        case LVN_KEYDOWN:
+        for (i = lTop; i < lTop + GetCountPerPage() + 1; i++)
+        {
+            if (GetItemRect( i
+                            ,vItemRect
+                           ))
             {
-                LV_KEYDOWN *info = (LV_KEYDOWN *)lParam;
-                WORD wVKey = info->wVKey;
-
-                // get the current selection
-                long lItem = GetNextItem(-1,
-                                         wxLIST_NEXT_ALL,
-                                         wxLIST_STATE_SELECTED);
-
-                // <Enter> or <Space> activate the selected item if any
-                if ( lItem != -1 && (wVKey == VK_RETURN || wVKey == VK_SPACE) )
+                nCy = vItemRect.GetTop();
+                if (i != 0) // Don't draw the first one
                 {
-                    // TODO this behaviour probably should be optional
-                    eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
-                    event.m_itemIndex = lItem;
+                    vDc.DrawLine( 0
+                                 ,nCy
+                                 ,vClientSize.x
+                                 ,nCy
+                                );
                 }
-                else
+                // Draw last line
+                if (i == nItemCount - 1)
                 {
-                    eventType = wxEVT_COMMAND_LIST_KEY_DOWN;
-                    event.m_code = wxCharCodeMSWToWX(wVKey);
+                    nCy = vItemRect.GetBottom();
+                    vDc.DrawLine( 0
+                                 ,nCy
+                                 ,vClientSize.x
+                                 ,nCy
+                                );
                 }
-                break;
-            }
-
-        case NM_DBLCLK:
-            // if the user processes it in wxEVT_COMMAND_LEFT_CLICK(), don't do
-            // anything else
-            if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
-            {
-                return TRUE;
-            }
-
-            // else translate it into wxEVT_COMMAND_LIST_ITEM_ACTIVATED event
-            eventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
-            break;
-
-        case LVN_SETDISPINFO:
-            {
-                eventType = wxEVT_COMMAND_LIST_SET_INFO;
-                LV_DISPINFO *info = (LV_DISPINFO *)lParam;
-                wxConvertFromMSWListItem(this, event.m_item, info->item, GetHwnd());
-                break;
             }
-
-        default:
-            return wxControl::MSWOnNotify(idCtrl, lParam, result);
-    }
-
-    event.SetEventObject( this );
-    event.SetEventType(eventType);
-
-    if ( !GetEventHandler()->ProcessEvent(event) )
-        return FALSE;
-
-    if (hdr1->code == LVN_GETDISPINFO)
-    {
-        LV_DISPINFO *info = (LV_DISPINFO *)lParam;
-        if ( info->item.mask & LVIF_TEXT )
-        {
-            if ( !event.m_item.m_text.IsNull() )
-            {
-                info->item.pszText = AddPool(event.m_item.m_text);
-                info->item.cchTextMax = wxStrlen(info->item.pszText) + 1;
-            }
-        }
-        //    wxConvertToMSWListItem(this, event.m_item, info->item);
-    }
-
-    *result = !event.IsAllowed();
-*/
-    return TRUE;
-}
-
-wxChar *wxListCtrl::AddPool(const wxString& str)
-{
-    // Remove the first element if 3 strings exist
-    if ( m_stringPool.Number() == 3 )
-    {
-        wxNode *node = m_stringPool.First();
-        delete[] (char *)node->Data();
-        delete node;
-    }
-    wxNode *node = m_stringPool.Add(WXSTRINGCAST str);
-    return (wxChar *)node->Data();
-}
-// List item structure
-wxListItem::wxListItem()
-{
-    m_mask = 0;
-    m_itemId = 0;
-    m_col = 0;
-    m_state = 0;
-    m_stateMask = 0;
-    m_image = 0;
-    m_data = 0;
-
-    m_format = wxLIST_FORMAT_CENTRE;
-    m_width = 0;
-}
-
-// TODO see if we need these
-/*
-static void wxConvertFromOS2ListItem(const wxListCtrl *ctrl, wxListItem& info, LV_ITEM& lvItem, HWND getFullInfo)
-{
-    info.m_data = lvItem.lParam;
-    info.m_mask = 0;
-    info.m_state = 0;
-    info.m_stateMask = 0;
-    info.m_itemId = lvItem.iItem;
-
-    long oldMask = lvItem.mask;
-
-    bool needText = FALSE;
-    if (getFullInfo != 0)
-    {
-        if ( lvItem.mask & LVIF_TEXT )
-            needText = FALSE;
-        else
-            needText = TRUE;
-
-        if ( needText )
-        {
-            lvItem.pszText = new wxChar[513];
-            lvItem.cchTextMax = 512;
         }
-        //    lvItem.mask |= TVIF_HANDLE | TVIF_STATE | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM;
-        lvItem.mask |= LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
-        ::SendMessage(getFullInfo, LVM_GETITEM, 0, (LPARAM)& lvItem);
     }
-
-    if ( lvItem.mask & LVIF_STATE )
+    i = nItemCount - 1;
+    if (bDrawVRules && (i > -1))
     {
-        info.m_mask |= wxLIST_MASK_STATE;
-
-        if ( lvItem.stateMask & LVIS_CUT)
-        {
-            info.m_stateMask |= wxLIST_STATE_CUT;
-            if ( lvItem.state & LVIS_CUT )
-                info.m_state |= wxLIST_STATE_CUT;
-        }
-        if ( lvItem.stateMask & LVIS_DROPHILITED)
-        {
-            info.m_stateMask |= wxLIST_STATE_DROPHILITED;
-            if ( lvItem.state & LVIS_DROPHILITED )
-                info.m_state |= wxLIST_STATE_DROPHILITED;
-        }
-        if ( lvItem.stateMask & LVIS_FOCUSED)
-        {
-            info.m_stateMask |= wxLIST_STATE_FOCUSED;
-            if ( lvItem.state & LVIS_FOCUSED )
-                info.m_state |= wxLIST_STATE_FOCUSED;
-        }
-        if ( lvItem.stateMask & LVIS_SELECTED)
+        wxRect                      vFirstItemRect;
+
+        GetItemRect( 0
+                    ,vFirstItemRect
+                   );
+        if (GetItemRect( i
+                        ,vItemRect
+                       ))
         {
-            info.m_stateMask |= wxLIST_STATE_SELECTED;
-            if ( lvItem.state & LVIS_SELECTED )
-                info.m_state |= wxLIST_STATE_SELECTED;
-        }
-    }
-
-    if ( lvItem.mask & LVIF_TEXT )
-    {
-        info.m_mask |= wxLIST_MASK_TEXT;
-        info.m_text = lvItem.pszText;
-    }
-    if ( lvItem.mask & LVIF_IMAGE )
-    {
-        info.m_mask |= wxLIST_MASK_IMAGE;
-        info.m_image = lvItem.iImage;
-    }
-    if ( lvItem.mask & LVIF_PARAM )
-        info.m_mask |= wxLIST_MASK_DATA;
-    if ( lvItem.mask & LVIF_DI_SETITEM )
-        info.m_mask |= wxLIST_SET_ITEM;
-    info.m_col = lvItem.iSubItem;
-
-    if (needText)
-    {
-        if (lvItem.pszText)
-            delete[] lvItem.pszText;
-    }
-    lvItem.mask = oldMask;
-}
+            int                     nCol;
+            int                     nX = vItemRect.GetX();
 
-static void wxConvertToOS2ListItem(const wxListCtrl *ctrl, wxListItem& info, LV_ITEM& lvItem)
-{
-    lvItem.iItem = (int) info.m_itemId;
-
-    lvItem.iImage = info.m_image;
-    lvItem.lParam = info.m_data;
-    lvItem.stateMask = 0;
-    lvItem.state = 0;
-    lvItem.mask = 0;
-    lvItem.iSubItem = info.m_col;
-
-    if (info.m_mask & wxLIST_MASK_STATE)
-    {
-        lvItem.mask |= LVIF_STATE;
-        if (info.m_stateMask & wxLIST_STATE_CUT)
-        {
-            lvItem.stateMask |= LVIS_CUT;
-            if (info.m_state & wxLIST_STATE_CUT)
-                lvItem.state |= LVIS_CUT;
-        }
-        if (info.m_stateMask & wxLIST_STATE_DROPHILITED)
-        {
-            lvItem.stateMask |= LVIS_DROPHILITED;
-            if (info.m_state & wxLIST_STATE_DROPHILITED)
-                lvItem.state |= LVIS_DROPHILITED;
-        }
-        if (info.m_stateMask & wxLIST_STATE_FOCUSED)
-        {
-            lvItem.stateMask |= LVIS_FOCUSED;
-            if (info.m_state & wxLIST_STATE_FOCUSED)
-                lvItem.state |= LVIS_FOCUSED;
-        }
-        if (info.m_stateMask & wxLIST_STATE_SELECTED)
-        {
-            lvItem.stateMask |= LVIS_SELECTED;
-            if (info.m_state & wxLIST_STATE_SELECTED)
-                lvItem.state |= LVIS_SELECTED;
+            for (nCol = 0; nCol < GetColumnCount(); nCol++)
+            {
+                int                 nColWidth = GetColumnWidth(nCol);
+
+                nX += nColWidth ;
+                vDc.DrawLine( nX - 1
+                             ,vFirstItemRect.GetY() - 2
+                             ,nX - 1
+                             ,vItemRect.GetBottom()
+                            );
+            }
         }
     }
-
-    if (info.m_mask & wxLIST_MASK_TEXT)
+} // end of wxListCtrl::OnPaint
+
+// ----------------------------------------------------------------------------
+// virtual list controls
+// ----------------------------------------------------------------------------
+
+wxString wxListCtrl::OnGetItemText (
+  long                              WXUNUSED(lItem)
+, long                              WXUNUSED(lCol)
+) const
+{
+    // 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( _T("not supposed to be called") );
+    return wxEmptyString;
+} // end of wxListCtrl::OnGetItemText
+
+int wxListCtrl::OnGetItemImage (
+  long                              WXUNUSED(lItem)
+) const
+{
+    // same as above
+    wxFAIL_MSG( _T("not supposed to be called") );
+    return -1;
+} // end of wxListCtrl::OnGetItemImage
+
+wxListItemAttr* wxListCtrl::OnGetItemAttr (
+  long                              WXUNUSED_UNLESS_DEBUG(lItem)
+) const
+{
+    wxASSERT_MSG( lItem >= 0 && lItem < GetItemCount(),
+                  _T("invalid item index in OnGetItemAttr()") );
+
+    //
+    // No attributes by default
+    //
+    return NULL;
+} // end of wxListCtrl::OnGetItemAttr
+
+void wxListCtrl::SetItemCount (
+  long                              lCount
+)
+{
+    wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
+
+    //
+    // Cannot explicitly set the record count in OS/2
+    //
+} // end of wxListCtrl::SetItemCount
+
+void wxListCtrl::RefreshItem (
+  long                              lItem
+)
+{
+    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)
     {
-        lvItem.mask |= LVIF_TEXT;
-        if ( ctrl->GetWindowStyleFlag() & wxLC_USER_TEXT )
-        {
-            lvItem.pszText = LPSTR_TEXTCALLBACK;
-        }
-        else
-        {
-            lvItem.pszText = WXSTRINGCAST info.m_text;
-            if ( lvItem.pszText )
-                lvItem.cchTextMax = info.m_text.Length();
-            else
-                lvItem.cchTextMax = 0;
-        }
+        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 = GetEventHandler()->ProcessEvent(vEvent);
+            break;
     }
-    if (info.m_mask & wxLIST_MASK_IMAGE)
-        lvItem.mask |= LVIF_IMAGE;
-    if (info.m_mask & wxLIST_MASK_DATA)
-        lvItem.mask |= LVIF_PARAM;
-}
-*/
-
-// List event
-IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxCommandEvent)
-
-wxListEvent::wxListEvent(wxEventType commandType, int id)
-           : wxNotifyEvent(commandType, id)
-{
-    m_code = 0;
-    m_itemIndex = 0;
-    m_col = 0;
-    m_cancelled = FALSE;
-}
-
+    if (!bProcessed)
+        lRc = wxControl::OS2WindowProc( uMsg
+                                       ,wParam
+                                       ,lParam
+                                      );
+    return lRc;
+} // end of wxListCtrl::WindowProc
+
+#endif // wxUSE_LISTCTRL