[4/7] comctl32/listview: Implement LVM_MAPIDTOINDEX/LVM_MAPINDEXTOID

Nikolay Sivov bunglehead at gmail.com
Sun Jun 21 17:50:13 CDT 2009


Changelog:
    - Implement LVM_MAPIDTOINDEX/LVM_MAPINDEXTOID

>From 264b5eaac9eab18fd6aa708f619cfc5e00be070b Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <bunglehead at gmail.com>
Date: Sun, 21 Jun 2009 00:48:07 +0400
Subject: Implement LVM_MAPIDTOINDEX/LVM_MAPINDEXTOID

---
 dlls/comctl32/listview.c       |  120 +++++++++++++++++++++++++++++++++++++++-
 dlls/comctl32/tests/listview.c |   33 ++++++++++-
 2 files changed, 147 insertions(+), 6 deletions(-)

diff --git a/dlls/comctl32/listview.c b/dlls/comctl32/listview.c
index c56d294..3bc90fd 100644
--- a/dlls/comctl32/listview.c
+++ b/dlls/comctl32/listview.c
@@ -124,7 +124,6 @@
  *   -- LVM_INSERTGROUPSORTED
  *   -- LVM_INSERTMARKHITTEST
  *   -- LVM_ISGROUPVIEWENABLED
- *   -- LVM_MAPIDTOINDEX, LVM_MAPINDEXTOID
  *   -- LVM_MOVEGROUP
  *   -- LVM_MOVEITEMTOGROUP
  *   -- LVM_SETINFOTIP
@@ -194,14 +193,23 @@ typedef struct tagSUBITEM_INFO
   INT iSubItem;
 } SUBITEM_INFO;
 
+typedef struct tagITEM_ID ITEM_ID;
+
 typedef struct tagITEM_INFO
 {
   ITEMHDR hdr;
   UINT state;
   LPARAM lParam;
   INT iIndent;
+  ITEM_ID *id;
 } ITEM_INFO;
 
+struct tagITEM_ID
+{
+  UINT id;   /* item id */
+  HDPA item; /* link to item data */
+};
+
 typedef struct tagRANGE
 {
   INT lower;
@@ -278,6 +286,7 @@ typedef struct tagLISTVIEW_INFO
   DWORD uView;			/* current view available through LVM_[G,S]ETVIEW */
   INT nItemCount;		/* the number of items in the list */
   HDPA hdpaItems;               /* array ITEM_INFO pointers */
+  HDPA hdpaItemIds;             /* array of ITEM_ID pointers */
   HDPA hdpaPosX;		/* maintains the (X, Y) coordinates of the */
   HDPA hdpaPosY;		/* items in LVS_ICON, and LVS_SMALLICON modes */
   HDPA hdpaColumns;		/* array of COLUMN_INFO pointers */
@@ -1430,6 +1439,19 @@ static inline void map_style_view(LISTVIEW_INFO *infoPtr)
     }
 }
 
+/* computes next item id value */
+static DWORD get_next_itemid(const LISTVIEW_INFO *infoPtr)
+{
+    INT count = DPA_GetPtrCount(infoPtr->hdpaItemIds);
+
+    if (count > 0)
+    {
+        ITEM_ID *lpID = DPA_GetPtr(infoPtr->hdpaItemIds, count - 1);
+        return lpID->id + 1;
+    }
+    return 0;
+}
+
 /******** Internal API functions ************************************/
 
 static inline COLUMN_INFO * LISTVIEW_GetColumnInfo(const LISTVIEW_INFO *infoPtr, INT nSubItem)
@@ -2310,6 +2332,76 @@ static void LISTVIEW_GetItemBox(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT
         OffsetRect(lprcBox, Position.x + Origin.x, Position.y + Origin.y);
 }
 
+/* LISTVIEW_MapIdToIndex helper */
+INT CALLBACK MapIdSearchCompare(LPVOID p1, LPVOID p2, LPARAM lParam)
+{
+    ITEM_ID *id1 = (ITEM_ID*)p1;
+    ITEM_ID *id2 = (ITEM_ID*)p2;
+
+    if (id1->id == id2->id) return 0;
+
+    return (id1->id < id2->id) ? -1 : 1;
+}
+
+/***
+ * DESCRIPTION:
+ * Returns the item index for id specified.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] iID : item id to get index for
+ *
+ * RETURN:
+ * Item index, or -1 on failure.
+ */
+static INT LISTVIEW_MapIdToIndex(const LISTVIEW_INFO *infoPtr, UINT iID)
+{
+    ITEM_ID ID;
+    INT index;
+
+    TRACE("iID=%d\n", iID);
+
+    if (infoPtr->dwStyle & LVS_OWNERDATA) return -1;
+    if (infoPtr->nItemCount == 0) return -1;
+
+    ID.id = iID;
+    index = DPA_Search(infoPtr->hdpaItemIds, &ID, -1, &MapIdSearchCompare, 0, DPAS_SORTED);
+
+    if (index != -1)
+    {
+        ITEM_ID *lpID = DPA_GetPtr(infoPtr->hdpaItemIds, index);
+        return DPA_GetPtrIndex(infoPtr->hdpaItems, lpID->item);
+    }
+
+    return -1;
+}
+
+/***
+ * DESCRIPTION:
+ * Returns the item id for index given.
+ *
+ * PARAMETER(S):
+ * [I] infoPtr : valid pointer to the listview structure
+ * [I] iItem : item index to get id for
+ *
+ * RETURN:
+ * Item id.
+ */
+static DWORD LISTVIEW_MapIndexToId(const LISTVIEW_INFO *infoPtr, INT iItem)
+{
+    ITEM_INFO *lpItem;
+    HDPA hdpaSubItems;
+
+    TRACE("iItem=%d\n", iItem);
+
+    if (infoPtr->dwStyle & LVS_OWNERDATA) return -1;
+    if (iItem < 0 || iItem >= infoPtr->nItemCount) return -1;
+
+    hdpaSubItems = DPA_GetPtr(infoPtr->hdpaItems, iItem);
+    lpItem = DPA_GetPtr(hdpaSubItems, 0);
+
+    return lpItem->id->id;
+}
 
 /***
  * DESCRIPTION:
@@ -4988,9 +5080,18 @@ static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem)
     {
         HDPA hdpaSubItems;
 	ITEMHDR *hdrItem;
+	ITEM_INFO *lpItem;
+	ITEM_ID *lpID;
 	INT i;
 
 	hdpaSubItems = DPA_DeletePtr(infoPtr->hdpaItems, nItem);
+	lpItem = DPA_GetPtr(hdpaSubItems, 0);
+
+	/* free id struct */
+	i = DPA_GetPtrIndex(infoPtr->hdpaItemIds, lpItem->id);
+	lpID = DPA_GetPtr(infoPtr->hdpaItemIds, i);
+	DPA_DeletePtr(infoPtr->hdpaItemIds, i);
+	Free(lpID);
 	for (i = 0; i < DPA_GetPtrCount(hdpaSubItems); i++)
     	{
             hdrItem = DPA_GetPtr(hdpaSubItems, i);
@@ -6815,6 +6916,7 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
     HDPA hdpaSubItems;
     NMLISTVIEW nmlv;
     ITEM_INFO *lpItem;
+    ITEM_ID *lpID;
     BOOL is_sorted, has_changed;
     LVITEMW item;
     HWND hwndSelf = infoPtr->hwndSelf;
@@ -6834,6 +6936,13 @@ static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem,
     if ( !(hdpaSubItems = DPA_Create(8)) ) goto fail;
     if ( !DPA_SetPtr(hdpaSubItems, 0, lpItem) ) assert (FALSE);
 
+    /* link with id struct */
+    if (!(lpID = Alloc(sizeof(ITEM_ID)))) goto fail;
+    lpItem->id = lpID;
+    lpID->item = hdpaSubItems;
+    lpID->id = get_next_itemid(infoPtr);
+    if ( DPA_InsertPtr(infoPtr->hdpaItemIds, infoPtr->nItemCount, lpID) == -1) goto fail;
+
     is_sorted = (infoPtr->dwStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) &&
 	        !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (LPSTR_TEXTCALLBACKW != lpLVItem->pszText);
 
@@ -8483,6 +8592,7 @@ static LRESULT LISTVIEW_NCCreate(HWND hwnd, const CREATESTRUCTW *lpcs)
   /* allocate memory for the data structure */
   if (!(infoPtr->selectionRanges = ranges_create(10))) goto fail;
   if (!(infoPtr->hdpaItems = DPA_Create(10))) goto fail;
+  if (!(infoPtr->hdpaItemIds = DPA_Create(10))) goto fail;
   if (!(infoPtr->hdpaPosX  = DPA_Create(10))) goto fail;
   if (!(infoPtr->hdpaPosY  = DPA_Create(10))) goto fail;
   if (!(infoPtr->hdpaColumns = DPA_Create(10))) goto fail;
@@ -8492,6 +8602,7 @@ fail:
     DestroyWindow(infoPtr->hwndHeader);
     ranges_destroy(infoPtr->selectionRanges);
     DPA_Destroy(infoPtr->hdpaItems);
+    DPA_Destroy(infoPtr->hdpaItemIds);
     DPA_Destroy(infoPtr->hdpaPosX);
     DPA_Destroy(infoPtr->hdpaPosY);
     DPA_Destroy(infoPtr->hdpaColumns);
@@ -9264,6 +9375,7 @@ static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr)
 
   /* destroy data structure */
   DPA_Destroy(infoPtr->hdpaItems);
+  DPA_Destroy(infoPtr->hdpaItemIds);
   DPA_Destroy(infoPtr->hdpaPosX);
   DPA_Destroy(infoPtr->hdpaPosY);
   DPA_Destroy(infoPtr->hdpaColumns);
@@ -10381,9 +10493,11 @@ LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   case LVM_ISITEMVISIBLE:
     return LISTVIEW_IsItemVisible(infoPtr, (INT)wParam);
 
-  /* case LVM_MAPIDTOINDEX: */
+  case LVM_MAPIDTOINDEX:
+    return LISTVIEW_MapIdToIndex(infoPtr, (UINT)wParam);
 
-  /* case LVM_MAPINDEXTOID: */
+  case LVM_MAPINDEXTOID:
+    return LISTVIEW_MapIndexToId(infoPtr, (INT)wParam);
 
   /* case LVM_MOVEGROUP: */
 
diff --git a/dlls/comctl32/tests/listview.c b/dlls/comctl32/tests/listview.c
index a97a8dc..3f182e8 100644
--- a/dlls/comctl32/tests/listview.c
+++ b/dlls/comctl32/tests/listview.c
@@ -3588,24 +3588,51 @@ static void test_mapidindex(void)
     HWND hwnd;
     DWORD ret;
 
+    /* LVM_MAPINDEXTOID unsupported with LVS_OWNERDATA */
+    hwnd = create_listview_control(LVS_OWNERDATA);
+    ok(hwnd != NULL, "failed to create a listview window\n");
+    insert_item(hwnd, 0);
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
+    expect(-1, ret);
+    DestroyWindow(hwnd);
+
     hwnd = create_listview_control(0);
     ok(hwnd != NULL, "failed to create a listview window\n");
 
+    /* LVM_MAPINDEXTOID with invalid index */
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
+    expect(-1, ret);
+
     insert_item(hwnd, 0);
     insert_item(hwnd, 1);
 
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, -1, 0);
+    expect(-1, ret);
+    ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 2, 0);
+    expect(-1, ret);
+
     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
     expect(0, ret);
     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
-    todo_wine expect(1, ret);
+    expect(1, ret);
     /* remove 0 indexed item, id retained */
     SendMessage(hwnd, LVM_DELETEITEM, 0, 0);
     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 0, 0);
-    todo_wine expect(1, ret);
+    expect(1, ret);
     /* new id starts from previous value */
     insert_item(hwnd, 1);
     ret = SendMessage(hwnd, LVM_MAPINDEXTOID, 1, 0);
-    todo_wine expect(2, ret);
+    expect(2, ret);
+
+    /* get index by id */
+    ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, -1, 0);
+    expect(-1, ret);
+    ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 0, 0);
+    expect(-1, ret);
+    ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 1, 0);
+    expect(0, ret);
+    ret = SendMessage(hwnd, LVM_MAPIDTOINDEX, 2, 0);
+    expect(1, ret);
 
     DestroyWindow(hwnd);
 }
-- 
1.5.6.5







More information about the wine-patches mailing list