+ 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 independent of its position in the list is to store a pointer
+// to it in its lParam attribute. However user programs are already using
+// this (via the SetItemData() GetItemData() calls).
+//
+// However what we can do is store a pointer to a structure which contains
+// the attributes we want *and* a lParam for the users data, e.g.
+//
+// class CListItemInternalData
+// {
+// public:
+// GuiAdvCtrl_CListItemAttr* pAttr;
+// long lParam; // user data
+// };
+//
+// To conserve memory, a CListItemInternalData is only allocated for a
+// LV_ITEM if text attributes or user data(lparam) are being set.
+//
+// For OS/2, the lParam value points to whatever actual data we have
+/////////////////////////////////////////////////////////////////////////////
+class CListItemInternalData
+{
+public:
+
+ CListItemInternalData(): m_pAttr(NULL)
+ ,m_lParam(0)
+ {}
+
+ ~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
+{
+ wxListCtrlCompare m_fnUser;
+ long m_lData;
+} SInternalDataSort; // end of STRUCT SInternalDataSort
+
+// ----------------------------------------------------------------------------
+// private helper functions
+// ----------------------------------------------------------------------------
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// 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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// BumpRecordIds
+//
+// Since OS/2 does not keep native record id's but wx insists on inserting
+// and selecting via ID's, when we insert a record in the middle we need
+// to bump the id's of each record after the one we just inserted.
+//
+// PARAMETERS
+// hWnd -- window handle of container to search
+// pRecord -- record after which we starting bumping id's
+//
+// RETURN VALUE
+// none
+//
+/////////////////////////////////////////////////////////////////////////////
+void BumpRecordIds (
+ HWND hWnd
+, PMYRECORD pRecord
+)
+{
+ while(pRecord)
+ {
+ pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
+ ,CM_QUERYRECORD
+ ,MPFROMP(pRecord)
+ ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+ ));
+ if (pRecord)
+ pRecord->m_ulItemId++;
+ }
+} // end of BumpRecordIds
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GetInternalData
+//
+// Get the internal data given a handle and an id
+//
+// PARAMETERS
+// hWnd -- window handle to the control in which item is located
+// lItemId -- ID to get
+//
+// RETURN VALUE
+// pointer to the internal data
+//
+// Note:
+// Under OS/2 PM a container item cannot be obtained via a simple index or
+// id retrieval. We have to walk the record list if we are looking for
+// a record at a specific index location
+/////////////////////////////////////////////////////////////////////////////
+CListItemInternalData* GetInternalData (
+ HWND hWnd
+, long lItemId
+)
+{
+ PMYRECORD pRecord = FindOS2ListRecordByID( hWnd
+ ,lItemId
+ );
+ //
+ // Internal user data is stored AFTER the last field of the RECORDCORE
+ //
+ if (!pRecord)
+ return NULL;
+ return((CListItemInternalData *)(pRecord->m_ulUserData));
+} // end of GetInternalData
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GetInternalData
+//
+// Get the internal data given a pointer to a list control and an id
+//
+// PARAMETERS
+// pCtl -- pointer to control inwhich item is located
+// lItemId -- ID to get
+//
+// RETURN VALUE
+// pointer to the internal data
+//
+/////////////////////////////////////////////////////////////////////////////
+CListItemInternalData* GetInternalData (
+ wxListCtrl* pCtl
+, long lItemId
+)
+{
+ return(GetInternalData( (HWND)pCtl->GetHWND()
+ ,lItemId
+ ));
+} // end of GetInternalData
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DeleteInternalData
+//
+// Delete the internal data for a record
+//
+// PARAMETERS
+// pCtl -- pointer to the list control containing the record
+// lItemId -- the record index to delete the internal data from
+//
+// RETURN VALUE
+// pointer to the internal data attribute
+//
+/////////////////////////////////////////////////////////////////////////////
+void DeleteInternalData (
+ wxListCtrl* pCtl
+, long lItemId
+)
+{
+ CListItemInternalData* pData = GetInternalData( pCtl
+ ,lItemId
+ );
+ if (pData)
+ {
+ if (pData->m_pMyRecord)
+ pData->m_pMyRecord->m_ulUserData = 0;
+ delete pData;
+ }
+} // end of DeleteInternalData
+
+// #pragma page "GetInternalDataAttr"
+/////////////////////////////////////////////////////////////////////////////
+//
+// GetInternalDataAttr
+//
+// Get the internal data item attribute given a pointer to a list control
+// and an id
+//
+// PARAMETERS
+// pCtl -- pointer to control to set
+// lItemId -- ID to set
+//
+// RETURN VALUE
+// pointer to the internal data attribute
+//
+/////////////////////////////////////////////////////////////////////////////
+wxListItemAttr* GetInternalDataAttr (
+ wxListCtrl* pCtl
+, long lItemId
+)
+{
+ CListItemInternalData* pData = GetInternalData( pCtl
+ ,lItemId
+ );
+
+ if (pData)
+ return(pData->m_pAttr);
+ else
+ return NULL;
+} // end of GetInternalDataAttr
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// InternalDataCompareFunc
+//
+// This is compare function we pass to PM. It wraps the real compare
+// function in SInternalDataSort
+//
+// PARAMETERS
+// p1 -- is the first record structure to compare
+// p2 -- is the second record structure to compare
+// lStorage -- is the same value as passed to SortItems.
+//
+// RETURN VALUE
+// pointer to the internal data attribute
+//
+/////////////////////////////////////////////////////////////////////////////
+SHORT EXPENTRY InternalDataCompareFunc (
+ PMYRECORD p1
+, PMYRECORD p2
+, PVOID pStorage
+)
+{
+ SInternalDataSort* pInternalData = (SInternalDataSort *)pStorage;
+ CListItemInternalData* pData1 = (CListItemInternalData *)p1->m_ulUserData;
+ CListItemInternalData* pData2 = (CListItemInternalData *)p2->m_ulUserData;
+ long lD1 = (pData1 == NULL ? 0 : (long)pData1->m_lParam);
+ long lD2 = (pData2 == NULL ? 0 : (long)pData2->m_lParam);
+
+ return(pInternalData->m_fnUser( lD1
+ ,lD2
+ ,pInternalData->m_lData
+ ));
+} // end of InternalDataCompareFunc
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ConvertFromOS2ListItem
+//
+// Convert from an internal PM List item to a Toolkit List item
+//
+// PARAMETERS
+// hWndListCtrl -- the control's windows handle
+// rInfo -- the library list control to convert to
+// pRecord -- the OS list control to convert from
+//
+// RETURN VALUE
+// none
+//
+/////////////////////////////////////////////////////////////////////////////
+void ConvertFromOS2ListItem (
+ HWND hWndListCtrl
+, wxListItem& rInfo
+, PMYRECORD pRecord
+)
+{
+ CListItemInternalData* pInternaldata = (CListItemInternalData *)pRecord->m_ulUserData;
+ bool bNeedText = FALSE;
+
+ if (pInternaldata)
+ rInfo.SetData(pInternaldata->m_lParam);
+
+ rInfo.SetMask(0);
+ rInfo.SetState(0);
+ rInfo.SetStateMask(0);
+ rInfo.SetId((long)pRecord->m_ulItemId);
+ if (hWndListCtrl != 0)
+ {
+ pRecord = FindOS2ListRecordByID( hWndListCtrl
+ ,rInfo.GetId()
+ );
+ }
+
+ //
+ // The wxListItem class is really set up to handle the WIN32 list item
+ // and OS/2 are not as complicated. Just set both state members to the
+ // same thing under OS/2
+ //
+ if (pRecord->m_vRecord.flRecordAttr & CRA_DROPONABLE)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_DROPHILITED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_DROPHILITED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_SELECTED)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_SELECTED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_SELECTED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_DISABLED)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_DISABLED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_DISABLED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_FILTERED)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_FILTERED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_FILTERED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_INUSE)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_INUSE);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_INUSE);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_PICKED)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_PICKED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_PICKED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_SOURCE)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_SOURCE);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_SOURCE);
+ }
+
+ if (pRecord->m_vRecord.pszText != (PSZ)NULL)
+ {
+ rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_TEXT);
+ rInfo.SetText(pRecord->m_vRecord.pszText);
+ }
+ if (pRecord->m_vRecord.pszIcon != (PSZ)NULL ||
+ pRecord->m_vRecord.pszName != (PSZ)NULL)
+ {
+ rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_IMAGE);
+ rInfo.SetImage(pRecord->m_vRecord.hptrIcon);
+ }
+ if (pRecord->m_ulUserData)
+ rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_DATA);
+} // end of ConvertFromOS2ListItem