[COMCTL32]
[reactos.git] / reactos / dll / win32 / comctl32 / treeview.c
index d1ace57..a4800d0 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(treeview);
 
-enum StateListType
-{
-  OriginInternal,
-  OriginUser
-};
-
 /* internal structures */
-
-typedef struct _TREEITEM    /* HTREEITEM is a _TREEINFO *. */
-{
-  HTREEITEM parent;         /* handle to parent or 0 if at root */
-  HTREEITEM nextSibling;    /* handle to next item in list, 0 if last */
-  HTREEITEM firstChild;     /* handle to first child or 0 if no child */
-
-  UINT      callbackMask;
-  UINT      state;
-  UINT      stateMask;
-  LPWSTR    pszText;
-  int       cchTextMax;
-  int       iImage;
-  int       iSelectedImage;
-  int       iExpandedImage;
-  int       cChildren;
-  LPARAM    lParam;
-  int       iIntegral;      /* item height multiplier (1 is normal) */
-  int       iLevel;         /* indentation level:0=root level */
-  HTREEITEM lastChild;
-  HTREEITEM prevSibling;    /* handle to prev item in list, 0 if first */
-  RECT      rect;
-  LONG      linesOffset;
-  LONG      stateOffset;
-  LONG      imageOffset;
-  LONG      textOffset;
-  LONG      textWidth;      /* horizontal text extent for pszText */
-  LONG      visibleOrder;   /* visible ordering, 0 is first visible item */
-} TREEVIEW_ITEM;
-
-
 typedef struct tagTREEVIEW_INFO
 {
   HWND          hwnd;
@@ -162,7 +125,6 @@ typedef struct tagTREEVIEW_INFO
   HIMAGELIST    himlState;
   int           stateImageHeight;
   int           stateImageWidth;
-  enum StateListType statehimlType;
   HDPA          items;
 
   DWORD lastKeyPressTimestamp;
@@ -171,6 +133,35 @@ typedef struct tagTREEVIEW_INFO
   WCHAR szSearchParam[ MAX_PATH ];
 } TREEVIEW_INFO;
 
+typedef struct _TREEITEM    /* HTREEITEM is a _TREEINFO *. */
+{
+  HTREEITEM parent;         /* handle to parent or 0 if at root */
+  HTREEITEM nextSibling;    /* handle to next item in list, 0 if last */
+  HTREEITEM firstChild;     /* handle to first child or 0 if no child */
+
+  UINT      callbackMask;
+  UINT      state;
+  UINT      stateMask;
+  LPWSTR    pszText;
+  int       cchTextMax;
+  int       iImage;
+  int       iSelectedImage;
+  int       iExpandedImage;
+  int       cChildren;
+  LPARAM    lParam;
+  int       iIntegral;      /* item height multiplier (1 is normal) */
+  int       iLevel;         /* indentation level:0=root level */
+  HTREEITEM lastChild;
+  HTREEITEM prevSibling;    /* handle to prev item in list, 0 if first */
+  RECT      rect;
+  LONG      linesOffset;
+  LONG      stateOffset;
+  LONG      imageOffset;
+  LONG      textOffset;
+  LONG      textWidth;      /* horizontal text extent for pszText */
+  LONG      visibleOrder;   /* visible ordering, 0 is first visible item */
+  const TREEVIEW_INFO *infoPtr; /* tree data this item belongs to */
+} TREEVIEW_ITEM;
 
 /******** Defines that TREEVIEW_ProcessLetterKeys uses ****************/
 #define KEY_DELAY       450
@@ -217,7 +208,6 @@ static VOID TREEVIEW_Invalidate(const TREEVIEW_INFO *, const TREEVIEW_ITEM *);
 static LRESULT TREEVIEW_DoSelectItem(TREEVIEW_INFO *, INT, HTREEITEM, INT);
 static VOID TREEVIEW_SetFirstVisible(TREEVIEW_INFO *, TREEVIEW_ITEM *, BOOL);
 static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *, HTREEITEM, BOOL);
-static LRESULT TREEVIEW_RButtonUp(const TREEVIEW_INFO *, const POINT *);
 static LRESULT TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel);
 static VOID TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr);
 static LRESULT TREEVIEW_HScroll(TREEVIEW_INFO *, WPARAM);
@@ -858,7 +848,9 @@ static INT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, HWND hwndFrom, UINT nC
     format = SendMessageW(hwndFrom, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwnd, NF_QUERY);
     TRACE("format=%d\n", format);
 
-    if (format != NFR_ANSI && format != NFR_UNICODE) return 0;
+    /* Invalid format returned by NF_QUERY defaults to ANSI*/
+    if (format != NFR_ANSI && format != NFR_UNICODE)
+        format = NFR_ANSI;
 
     infoPtr->bNtfUnicode = (format == NFR_UNICODE);
 
@@ -1020,6 +1012,7 @@ TREEVIEW_AllocateItem(const TREEVIEW_INFO *infoPtr)
     newItem->iImage = 0;
     newItem->iSelectedImage = 0;
     newItem->iExpandedImage = (WORD)I_IMAGENONE;
+    newItem->infoPtr = infoPtr;
 
     if (DPA_InsertPtr(infoPtr->items, INT_MAX, newItem) == -1)
     {
@@ -1621,7 +1614,7 @@ TREEVIEW_DeleteItem(TREEVIEW_INFO *infoPtr, HTREEITEM item)
 static LRESULT
 TREEVIEW_SetRedraw(TREEVIEW_INFO* infoPtr, WPARAM wParam)
 {
-    infoPtr->bRedraw = wParam ? TRUE : FALSE;
+    infoPtr->bRedraw = wParam != 0;
 
     if (infoPtr->bRedraw)
     {
@@ -1793,11 +1786,8 @@ TREEVIEW_SetImageList(TREEVIEW_INFO *infoPtr, UINT type, HIMAGELIST himlNew)
        infoPtr->himlState = himlNew;
 
        if (himlNew)
-       {
            ImageList_GetIconSize(himlNew, &infoPtr->stateImageWidth,
                                  &infoPtr->stateImageHeight);
-           infoPtr->statehimlType = OriginUser;
-       }
        else
        {
            infoPtr->stateImageWidth = 0;
@@ -2093,7 +2083,13 @@ TREEVIEW_GetItemT(const TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW)
     TREEVIEW_ITEM *item = tvItem->hItem;
 
     if (!TREEVIEW_ValidItem(infoPtr, item))
-       return FALSE;
+    {
+        if (!item) return FALSE;
+
+        TRACE("got item from different tree %p, called from %p\n", item->infoPtr, infoPtr);
+        infoPtr = item->infoPtr;
+        if (!TREEVIEW_ValidItem(infoPtr, item)) return FALSE;
+    }
 
     TREEVIEW_UpdateDispInfo(infoPtr, item, tvItem->mask);
 
@@ -3243,21 +3239,23 @@ TREEVIEW_Collapse(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item,
     RECT scrollRect;
     LONG scrollDist = 0;
     TREEVIEW_ITEM *nextItem = NULL, *tmpItem;
+    BOOL wasExpanded;
 
     TRACE("TVE_COLLAPSE %p %s\n", item, TREEVIEW_ItemName(item));
 
-    if (!(item->state & TVIS_EXPANDED))
+    if (!TREEVIEW_HasChildren(infoPtr, item))
        return FALSE;
 
-    if (bUser || !(item->state & TVIS_EXPANDEDONCE))
+    if (bUser)
        TREEVIEW_SendExpanding(infoPtr, item, action);
 
     if (item->firstChild == NULL)
        return FALSE;
 
+    wasExpanded = (item->state & TVIS_EXPANDED) != 0;
     item->state &= ~TVIS_EXPANDED;
 
-    if (bUser || !(item->state & TVIS_EXPANDEDONCE))
+    if (wasExpanded && bUser)
        TREEVIEW_SendExpanded(infoPtr, item, action);
 
     bSetSelection = (infoPtr->selectedItem != NULL
@@ -3338,7 +3336,7 @@ TREEVIEW_Collapse(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item,
                              bSetFirstVisible ? item : infoPtr->firstVisible,
                              TRUE);
 
-    return TRUE;
+    return wasExpanded;
 }
 
 static BOOL
@@ -3353,8 +3351,8 @@ TREEVIEW_Expand(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item,
 
     TRACE("(%p, %p, partial=%d, %d\n", infoPtr, item, partial, user);
 
-    if (item->state & TVIS_EXPANDED)
-       return TRUE;
+    if (!TREEVIEW_HasChildren(infoPtr, item))
+       return FALSE;
 
     tmpItem = item; nextItem = NULL;
     while (tmpItem)
@@ -3820,6 +3818,9 @@ TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr, HTREEITEM hItem)
     TEXTMETRICW textMetric;
 
     TRACE("%p %p\n", hwnd, hItem);
+    if (!(infoPtr->dwStyle & TVS_EDITLABELS))
+        return NULL;
+
     if (!TREEVIEW_ValidItem(infoPtr, hItem))
        return NULL;
 
@@ -4050,8 +4051,6 @@ TREEVIEW_TrackMouse(const TREEVIEW_INFO *infoPtr, POINT pt)
            else if (msg.message >= WM_LBUTTONDOWN &&
                     msg.message <= WM_RBUTTONDBLCLK)
            {
-               if (msg.message == WM_RBUTTONUP)
-                   TREEVIEW_RButtonUp(infoPtr, &pt);
                break;
            }
 
@@ -4267,34 +4266,17 @@ TREEVIEW_RButtonDown(TREEVIEW_INFO *infoPtr, LPARAM lParam)
     else
     {
        SetFocus(infoPtr->hwnd);
-       TREEVIEW_SendSimpleNotify(infoPtr, NM_RCLICK);
+       if(!TREEVIEW_SendSimpleNotify(infoPtr, NM_RCLICK))
+       {
+           /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
+           SendMessageW(infoPtr->hwndNotify, WM_CONTEXTMENU,
+               (WPARAM)infoPtr->hwnd, (LPARAM)GetMessagePos());
+       }
     }
 
     return 0;
 }
 
-static LRESULT
-TREEVIEW_RButtonUp(const TREEVIEW_INFO *infoPtr, const POINT *pPt)
-{
-    TVHITTESTINFO ht;
-
-    ht.pt = *pPt;
-
-    TREEVIEW_HitTest(infoPtr, &ht);
-
-    if (ht.hItem)
-    {
-        /* Change to screen coordinate for WM_CONTEXTMENU */
-        ClientToScreen(infoPtr->hwnd, &ht.pt);
-
-        /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */
-        SendMessageW(infoPtr->hwnd, WM_CONTEXTMENU,
-            (WPARAM)infoPtr->hwnd, MAKELPARAM(ht.pt.x, ht.pt.y));
-    }
-    return 0;
-}
-
-
 static LRESULT
 TREEVIEW_CreateDragImage(TREEVIEW_INFO *infoPtr, LPARAM lParam)
 {
@@ -4975,7 +4957,6 @@ TREEVIEW_InitCheckboxes(TREEVIEW_INFO *infoPtr)
     int nIndex;
 
     infoPtr->himlState = ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 3, 0);
-    infoPtr->statehimlType = OriginInternal;
 
     hdcScreen = GetDC(0);
 
@@ -5095,10 +5076,7 @@ TREEVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs)
     infoPtr->hwndNotify = lpcs->hwndParent;
     infoPtr->hwndToolTip = 0;
 
-    infoPtr->bNtfUnicode = IsWindowUnicode (hwnd);
-
-    /* Determine what type of notify should be issued */
-    /* sets infoPtr->bNtfUnicode */
+    /* Determine what type of notify should be issued (sets infoPtr->bNtfUnicode) */
     TREEVIEW_NotifyFormat(infoPtr, infoPtr->hwndNotify, NF_REQUERY);
 
     if (!(infoPtr->dwStyle & TVS_NOTOOLTIPS))
@@ -5139,8 +5117,6 @@ TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr)
 
     CloseThemeData (GetWindowTheme (infoPtr->hwnd));
 
-    if (infoPtr->statehimlType == OriginInternal)
-        ImageList_Destroy(infoPtr->himlState);
     /* Deassociate treeview from the window before doing anything drastic. */
     SetWindowLongPtrW(infoPtr->hwnd, 0, 0);
 
@@ -5269,13 +5245,11 @@ TREEVIEW_KeyDown(TREEVIEW_INFO *infoPtr, WPARAM wParam)
        break;
 
     case VK_ADD:
-       if (!(prevItem->state & TVIS_EXPANDED))
-           TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE);
+       TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE);
        break;
 
     case VK_SUBTRACT:
-       if (prevItem->state & TVIS_EXPANDED)
-           TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE);
+       TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE);
        break;
 
     case VK_PRIOR: