]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/listctrl.cpp
Copyright cleanup
[wxWidgets.git] / src / msw / listctrl.cpp
index 15356ad7d985ae2b1e1eafc3096e0f6231b954c0..e47b10a13d9cb589901378b3de4ac2d3b0a633d1 100644 (file)
@@ -5,8 +5,8 @@
 // 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_count = 0;
+    m_ignoreChangeMessages = FALSE;
     m_textCtrl = NULL;
     m_AnyInternalData = FALSE;
     m_hasAnyAttr = FALSE;
@@ -378,8 +380,10 @@ void wxListCtrl::FreeAllInternalData()
         int n = GetItemCount();
         int i = 0;
 
+        m_ignoreChangeMessages = TRUE;
         for (i = 0; i < n; i++)
             wxDeleteInternalData(this, i);
+        m_ignoreChangeMessages = FALSE;
 
         m_AnyInternalData = FALSE;
     }
@@ -391,8 +395,8 @@ wxListCtrl::~wxListCtrl()
 
     if ( m_textCtrl )
     {
-        m_textCtrl->SetHWND(0);
         m_textCtrl->UnsubclassWin();
+        m_textCtrl->SetHWND(0);
         delete m_textCtrl;
         m_textCtrl = NULL;
     }
@@ -1014,7 +1018,7 @@ bool wxListCtrl::SetItemPosition(long item, const wxPoint& pos)
 // 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.
@@ -1204,6 +1208,10 @@ bool wxListCtrl::DeleteItem(long item)
         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() )
     {
@@ -1232,6 +1240,7 @@ bool wxListCtrl::DeleteItem(long item)
 // Deletes all items
 bool wxListCtrl::DeleteAllItems()
 {
+    FreeAllInternalData();
     return ListView_DeleteAllItems(GetHwnd()) != 0;
 }
 
@@ -1290,8 +1299,8 @@ wxTextCtrl* wxListCtrl::EditLabel(long item, wxClassInfo* textControlClass)
     // [re]create the text control wrapping the HWND we got
     if ( m_textCtrl )
     {
-        m_textCtrl->SetHWND(0);
         m_textCtrl->UnsubclassWin();
+        m_textCtrl->SetHWND(0);
         delete m_textCtrl;
     }
 
@@ -1448,8 +1457,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)
@@ -1641,6 +1654,7 @@ bool wxListCtrl::MSWCommand(WXUINT cmd, WXWORD id)
 
 bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 {
+
     // prepare the event
     // -----------------
 
@@ -1752,7 +1766,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                     // there's a GPF in Windows.
                     // By returning TRUE here, we avoid further processing
                     // of this strange message.
-                    if (info->iItem > GetColumnCount())
+                    if ( info->iItem >= GetColumnCount() )
                         return TRUE;
                 }
                 // fall through
@@ -1770,29 +1784,29 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
         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 )
-                {
-                    wxListItemInternalData *internaldata =
-                        (wxListItemInternalData *) nmLV->lParam;
+            return TRUE;
+        }
 
-                    if ( internaldata )
-                        event.m_item.m_data = internaldata->lParam;
-                }
 
-            default:
-                // fall through
-                ;
+        // 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);
+
+            if ( internaldata )
+                event.m_item.m_data = internaldata->lParam;
         }
 
+
         switch ( nmhdr->code )
         {
             case LVN_BEGINRDRAG:
@@ -1861,11 +1875,17 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 break;
 
             case LVN_DELETEALLITEMS:
+                m_count = 0;
                 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
@@ -2109,12 +2129,10 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
     event.SetEventType(eventType);
 
-    if ( !GetEventHandler()->ProcessEvent(event) )
-        return FALSE;
+    bool processed = GetEventHandler()->ProcessEvent(event);
 
     // post processing
     // ---------------
-
     switch ( nmhdr->code )
     {
         case LVN_DELETEALLITEMS:
@@ -2122,7 +2140,6 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             // notifications - this makes deleting all items from a list ctrl
             // much faster
             *result = TRUE;
-
             return TRUE;
 
         case LVN_ENDLABELEDITA:
@@ -2135,8 +2152,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
-                m_textCtrl->SetHWND(0);
                 m_textCtrl->UnsubclassWin();
+                m_textCtrl->SetHWND(0);
                 delete m_textCtrl;
                 m_textCtrl = NULL;
             }
@@ -2144,9 +2161,10 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             return TRUE;
     }
 
-    *result = !event.IsAllowed();
+    if ( processed )
+        *result = !event.IsAllowed();
 
-    return TRUE;
+    return processed;
 }
 
 #if defined(_WIN32_IE) && _WIN32_IE >= 0x300
@@ -2316,7 +2334,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
-    wxFAIL_MSG( _T("not supposed to be called") );
+    wxFAIL_MSG( _T("wxListCtrl::OnGetItemText not supposed to be called") );
 
     return wxEmptyString;
 }
@@ -2324,7 +2342,7 @@ wxString wxListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) cons
 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;
 }
@@ -2346,6 +2364,9 @@ void wxListCtrl::SetItemCount(long count)
     {
         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)