]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/listctrl.cpp
update for digital mars - resolve externals in shell and winsock libs
[wxWidgets.git] / src / msw / listctrl.cpp
index 943a87ae8da8bd59c2a6cbde8d6b2aa0e798236a..c369f92b0fc2e7aa0a3881e36eb77f06f4e28c23 100644 (file)
@@ -5,8 +5,8 @@
 // Modified by:
 // Created:     04/01/98
 // RCS-ID:      $Id$
 // Modified by:
 // Created:     04/01/98
 // RCS-ID:      $Id$
-// Copyright:   (c) Julian Smart and Markus Holzem
-// Licence:     wxWindows license
+// Copyright:   (c) Julian Smart
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // ============================================================================
 /////////////////////////////////////////////////////////////////////////////
 
 // ============================================================================
@@ -244,6 +244,8 @@ void wxListCtrl::Init()
     m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = FALSE;
     m_baseStyle = 0;
     m_colCount = 0;
     m_ownsImageListNormal = m_ownsImageListSmall = m_ownsImageListState = FALSE;
     m_baseStyle = 0;
     m_colCount = 0;
+    m_count = 0;
+    m_ignoreChangeMessages = FALSE;
     m_textCtrl = NULL;
     m_AnyInternalData = FALSE;
     m_hasAnyAttr = FALSE;
     m_textCtrl = NULL;
     m_AnyInternalData = FALSE;
     m_hasAnyAttr = FALSE;
@@ -289,8 +291,11 @@ bool wxListCtrl::Create(wxWindow *parent,
     if ( m_windowStyle & wxCLIP_SIBLINGS )
         wstyle |= WS_CLIPSIBLINGS;
 
     if ( m_windowStyle & wxCLIP_SIBLINGS )
         wstyle |= WS_CLIPSIBLINGS;
 
+/*
     if ( wxStyleHasBorder(m_windowStyle) )
         wstyle |= WS_BORDER;
     if ( wxStyleHasBorder(m_windowStyle) )
         wstyle |= WS_BORDER;
+*/
+
     m_baseStyle = wstyle;
 
     if ( !DoCreateControl(x, y, width, height) )
     m_baseStyle = wstyle;
 
     if ( !DoCreateControl(x, y, width, height) )
@@ -306,13 +311,8 @@ bool wxListCtrl::DoCreateControl(int x, int y, int w, int h)
 {
     DWORD wstyle = m_baseStyle;
 
 {
     DWORD wstyle = m_baseStyle;
 
-    bool want3D;
-    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;
+    WXDWORD exStyle = 0;
+    (void) MSWGetStyle(GetWindowStyle(), & exStyle) ;
 
     long oldStyle = 0; // Dummy
     wstyle |= ConvertToMSWStyle(oldStyle, m_windowStyle);
 
     long oldStyle = 0; // Dummy
     wstyle |= ConvertToMSWStyle(oldStyle, m_windowStyle);
@@ -378,8 +378,10 @@ void wxListCtrl::FreeAllInternalData()
         int n = GetItemCount();
         int i = 0;
 
         int n = GetItemCount();
         int i = 0;
 
+        m_ignoreChangeMessages = TRUE;
         for (i = 0; i < n; i++)
             wxDeleteInternalData(this, i);
         for (i = 0; i < n; i++)
             wxDeleteInternalData(this, i);
+        m_ignoreChangeMessages = FALSE;
 
         m_AnyInternalData = FALSE;
     }
 
         m_AnyInternalData = FALSE;
     }
@@ -391,8 +393,8 @@ wxListCtrl::~wxListCtrl()
 
     if ( m_textCtrl )
     {
 
     if ( m_textCtrl )
     {
-        m_textCtrl->SetHWND(0);
         m_textCtrl->UnsubclassWin();
         m_textCtrl->UnsubclassWin();
+        m_textCtrl->SetHWND(0);
         delete m_textCtrl;
         m_textCtrl = NULL;
     }
         delete m_textCtrl;
         m_textCtrl = NULL;
     }
@@ -1014,7 +1016,7 @@ bool wxListCtrl::SetItemPosition(long item, const wxPoint& pos)
 // Gets the number of items in the list control
 int wxListCtrl::GetItemCount() const
 {
 // Gets the number of items in the list control
 int wxListCtrl::GetItemCount() const
 {
-    return ListView_GetItemCount(GetHwnd());
+    return m_count;
 }
 
 // Retrieves the spacing between icons in pixels.
 }
 
 // Retrieves the spacing between icons in pixels.
@@ -1204,6 +1206,10 @@ bool wxListCtrl::DeleteItem(long item)
         return FALSE;
     }
 
         return FALSE;
     }
 
+    m_count -= 1;
+    wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
+                  wxT("m_count should match ListView_GetItemCount"));
+
     // the virtual list control doesn't refresh itself correctly, help it
     if ( IsVirtual() )
     {
     // the virtual list control doesn't refresh itself correctly, help it
     if ( IsVirtual() )
     {
@@ -1232,6 +1238,7 @@ bool wxListCtrl::DeleteItem(long item)
 // Deletes all items
 bool wxListCtrl::DeleteAllItems()
 {
 // Deletes all items
 bool wxListCtrl::DeleteAllItems()
 {
+    FreeAllInternalData();
     return ListView_DeleteAllItems(GetHwnd()) != 0;
 }
 
     return ListView_DeleteAllItems(GetHwnd()) != 0;
 }
 
@@ -1290,8 +1297,8 @@ wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
     // [re]create the text control wrapping the HWND we got
     if ( m_textCtrl )
     {
     // [re]create the text control wrapping the HWND we got
     if ( m_textCtrl )
     {
-        m_textCtrl->SetHWND(0);
         m_textCtrl->UnsubclassWin();
         m_textCtrl->UnsubclassWin();
+        m_textCtrl->SetHWND(0);
         delete m_textCtrl;
     }
 
         delete m_textCtrl;
     }
 
@@ -1448,8 +1455,12 @@ long wxListCtrl::InsertItem(wxListItem& info)
     }
     };
 
     }
     };
 
+    long rv = ListView_InsertItem(GetHwnd(), & item);
+    m_count += 1;
+    wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
+                  wxT("m_count should match ListView_GetItemCount"));
 
 
-    return (long) ListView_InsertItem(GetHwnd(), & item);
+    return rv;
 }
 
 long wxListCtrl::InsertItem(long index, const wxString& label)
 }
 
 long wxListCtrl::InsertItem(long index, const wxString& label)
@@ -1641,6 +1652,7 @@ bool wxListCtrl::MSWCommand(WXUINT cmd, WXWORD id)
 
 bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 {
 
 bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 {
+
     // prepare the event
     // -----------------
 
     // prepare the event
     // -----------------
 
@@ -1770,53 +1782,29 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
         const int iItem = nmLV->iItem;
 
 
         const int iItem = nmLV->iItem;
 
-        // set the data event field for all messages for which the system gives
-        // us a valid NM_LISTVIEW::lParam
-        switch ( nmLV->hdr.code )
+
+        // FreeAllInternalData will cause LVN_ITEMCHANG* messages, which can be
+        // ignored for efficiency.  It is done here because the internal data is in the
+        // process of being deleted so we don't want to try and access it below.
+        if ( m_ignoreChangeMessages &&
+             ( (nmLV->hdr.code == LVN_ITEMCHANGED) || (nmLV->hdr.code == LVN_ITEMCHANGING)))
         {
         {
-            case LVN_BEGINDRAG:
-            case LVN_BEGINRDRAG:
-            case LVN_COLUMNCLICK:
-            case LVN_ITEMCHANGED:
-            case LVN_ITEMCHANGING:
-                if ( iItem != -1 )
-                {
-                    if ( iItem >= GetItemCount() )
-                    {
-                        // there is apparently a bug in comctl32.dll version
-                        // 5.50.4704.1100 (note that the MS DLL database
-                        // doesn't say what this version is, it's not the one
-                        // shipped with W2K although the bug was reported under
-                        // that system) and it sends us LVN_ITEMCHANGING
-                        // notifications with the item out of range -- and as
-                        // we access the items client data, we crash below
-                        //
-                        // see
-                        //
-                        //  http://lists.wxwindows.org/cgi-bin/ezmlm-cgi?8:mss:29852:knlihdmadhaljafjajei
-                        //
-                        // and the thread continuation for more details
-                        // (although note that the bug may be present in other
-                        // versions of comctl32.dll as well as it has been
-                        // reported quite a few times)
-                        //
-                        // to fix this, simply ignore these "bad" events (as
-                        // above with HDN_GETDISPINFOW)
-                        return TRUE;
-                    }
+            return TRUE;
+        }
 
 
-                    wxListItemInternalData *internaldata =
-                        (wxListItemInternalData *) nmLV->lParam;
 
 
-                    if ( internaldata )
-                        event.m_item.m_data = internaldata->lParam;
-                }
+        // If we have a valid item then check if there is a data value
+        // associated with it and put it in the event.
+        if ( iItem >= 0 && iItem < GetItemCount() )
+        {
+            wxListItemInternalData *internaldata =
+                wxGetInternalData(GetHwnd(), iItem);
 
 
-            default:
-                // fall through
-                ;
+            if ( internaldata )
+                event.m_item.m_data = internaldata->lParam;
         }
 
         }
 
+
         switch ( nmhdr->code )
         {
             case LVN_BEGINRDRAG:
         switch ( nmhdr->code )
         {
             case LVN_BEGINRDRAG:
@@ -1885,11 +1873,17 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 break;
 
             case LVN_DELETEALLITEMS:
                 break;
 
             case LVN_DELETEALLITEMS:
+                m_count = 0;
                 eventType = wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS;
                 event.m_itemIndex = -1;
                 break;
 
             case LVN_DELETEITEM:
                 eventType = wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS;
                 event.m_itemIndex = -1;
                 break;
 
             case LVN_DELETEITEM:
+                if (m_count == 0)
+                    // this should be prevented by the post-processing code below,
+                    // but "just in case"
+                    return FALSE;
+
                 eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
                 event.m_itemIndex = iItem;
                 // delete the assoicated internal data
                 eventType = wxEVT_COMMAND_LIST_DELETE_ITEM;
                 event.m_itemIndex = iItem;
                 // delete the assoicated internal data
@@ -2133,12 +2127,10 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
     event.SetEventType(eventType);
 
 
     event.SetEventType(eventType);
 
-    if ( !GetEventHandler()->ProcessEvent(event) )
-        return FALSE;
+    bool processed = GetEventHandler()->ProcessEvent(event);
 
     // post processing
     // ---------------
 
     // post processing
     // ---------------
-
     switch ( nmhdr->code )
     {
         case LVN_DELETEALLITEMS:
     switch ( nmhdr->code )
     {
         case LVN_DELETEALLITEMS:
@@ -2146,7 +2138,6 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             // notifications - this makes deleting all items from a list ctrl
             // much faster
             *result = TRUE;
             // notifications - this makes deleting all items from a list ctrl
             // much faster
             *result = TRUE;
-
             return TRUE;
 
         case LVN_ENDLABELEDITA:
             return TRUE;
 
         case LVN_ENDLABELEDITA:
@@ -2159,8 +2150,8 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             {
                 // EDIT control will be deleted by the list control itself so
                 // prevent us from deleting it as well
             {
                 // EDIT control will be deleted by the list control itself so
                 // prevent us from deleting it as well
-                m_textCtrl->SetHWND(0);
                 m_textCtrl->UnsubclassWin();
                 m_textCtrl->UnsubclassWin();
+                m_textCtrl->SetHWND(0);
                 delete m_textCtrl;
                 m_textCtrl = NULL;
             }
                 delete m_textCtrl;
                 m_textCtrl = NULL;
             }
@@ -2168,9 +2159,10 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             return TRUE;
     }
 
             return TRUE;
     }
 
-    *result = !event.IsAllowed();
+    if ( processed )
+        *result = !event.IsAllowed();
 
 
-    return TRUE;
+    return processed;
 }
 
 #if defined(_WIN32_IE) && _WIN32_IE >= 0x300
 }
 
 #if defined(_WIN32_IE) && _WIN32_IE >= 0x300
@@ -2340,7 +2332,7 @@ wxString wxListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) cons
 {
     // 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
 {
     // 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") );
+    wxFAIL_MSG( _T("wxListCtrl::OnGetItemText not supposed to be called") );
 
     return wxEmptyString;
 }
 
     return wxEmptyString;
 }
@@ -2348,7 +2340,7 @@ wxString wxListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) cons
 int wxListCtrl::OnGetItemImage(long WXUNUSED(item)) const
 {
     // same as above
 int wxListCtrl::OnGetItemImage(long WXUNUSED(item)) const
 {
     // same as above
-    wxFAIL_MSG( _T("not supposed to be called") );
+    wxFAIL_MSG( _T("wxListCtrl::OnGetItemImage not supposed to be called") );
 
     return -1;
 }
 
     return -1;
 }
@@ -2370,6 +2362,9 @@ void wxListCtrl::SetItemCount(long count)
     {
         wxLogLastError(_T("ListView_SetItemCount"));
     }
     {
         wxLogLastError(_T("ListView_SetItemCount"));
     }
+    m_count = count;
+    wxASSERT_MSG( m_count == ListView_GetItemCount(GetHwnd()),
+                  wxT("m_count should match ListView_GetItemCount"));
 }
 
 void wxListCtrl::RefreshItem(long item)
 }
 
 void wxListCtrl::RefreshItem(long item)
@@ -2432,13 +2427,13 @@ static void wxDeleteInternalData(wxListCtrl* ctl, long itemId)
     wxListItemInternalData *data = wxGetInternalData(ctl, itemId);
     if (data)
     {
     wxListItemInternalData *data = wxGetInternalData(ctl, itemId);
     if (data)
     {
-        delete data;
         LV_ITEM item;
         memset(&item, 0, sizeof(item));
         item.iItem = itemId;
         item.mask = LVIF_PARAM;
         item.lParam = (LPARAM) 0;
         ListView_SetItem((HWND)ctl->GetHWND(), &item);
         LV_ITEM item;
         memset(&item, 0, sizeof(item));
         item.iItem = itemId;
         item.mask = LVIF_PARAM;
         item.lParam = (LPARAM) 0;
         ListView_SetItem((HWND)ctl->GetHWND(), &item);
+        delete data;
     }
 }
 
     }
 }