]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/listctrl.cpp
fixes SetFirstItem, Thanks to David Wright
[wxWidgets.git] / src / msw / listctrl.cpp
index 9d49a3be1031cf23610edcbe74f15372f8ca9b0c..1b0a6c74ac70e41cc28d4cbdc271f44a87a9aa4a 100644 (file)
@@ -226,8 +226,9 @@ public:
     wxDECLARE_NO_COPY_CLASS(wxMSWListItemData);
 };
 
-BEGIN_EVENT_TABLE(wxListCtrl, wxControl)
+BEGIN_EVENT_TABLE(wxListCtrl, wxListCtrlBase)
     EVT_PAINT(wxListCtrl::OnPaint)
+    EVT_CHAR_HOOK(wxListCtrl::OnCharHook)
 END_EVENT_TABLE()
 
 // ============================================================================
@@ -308,7 +309,7 @@ void wxListCtrl::MSWSetExListStyles()
 
 WXDWORD wxListCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
 {
-    WXDWORD wstyle = wxControl::MSWGetStyle(style, exstyle);
+    WXDWORD wstyle = wxListCtrlBase::MSWGetStyle(style, exstyle);
 
     wstyle |= LVS_SHAREIMAGELISTS | LVS_SHOWSELALWAYS;
 
@@ -477,7 +478,7 @@ void wxListCtrl::SetWindowStyleFlag(long flag)
 {
     if ( flag != m_windowStyle )
     {
-        wxControl::SetWindowStyleFlag(flag);
+        wxListCtrlBase::SetWindowStyleFlag(flag);
 
         UpdateStyle();
 
@@ -1332,6 +1333,29 @@ void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
         m_ownsImageListState = true;
 }
 
+// ----------------------------------------------------------------------------
+// Geometry
+// ----------------------------------------------------------------------------
+
+wxSize wxListCtrl::MSWGetBestViewRect(int x, int y) const
+{
+    const DWORD rc = ListView_ApproximateViewRect(GetHwnd(), x, y, -1);
+
+    wxSize size(LOWORD(rc), HIWORD(rc));
+
+    // We have to add space for the scrollbars ourselves, they're not taken
+    // into account by ListView_ApproximateViewRect(), at least not with
+    // commctrl32.dll v6.
+    const DWORD mswStyle = ::GetWindowLong(GetHwnd(), GWL_STYLE);
+
+    if ( mswStyle & WS_HSCROLL )
+        size.y += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
+    if ( mswStyle & WS_VSCROLL )
+        size.x += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
+
+    return size;
+}
+
 // ----------------------------------------------------------------------------
 // Operations
 // ----------------------------------------------------------------------------
@@ -1490,21 +1514,15 @@ bool wxListCtrl::EndEditLabel(bool cancel)
     if ( !hwnd )
         return false;
 
-    // Newer versions of Windows have a special message for cancelling editing,
-    // use it if available.
-#ifdef ListView_CancelEditLabel
-    if ( cancel && (wxApp::GetComCtl32Version() >= 600) )
-    {
-        ListView_CancelEditLabel(GetHwnd());
-    }
-    else
-#endif // ListView_CancelEditLabel
-    {
-        // We shouldn't destroy the control ourselves according to MSDN, which
-        // proposes WM_CANCELMODE to do this, but it doesn't seem to work so
-        // emulate the corresponding user action instead.
-        ::SendMessage(hwnd, WM_KEYDOWN, cancel ? VK_ESCAPE : VK_RETURN, 0);
-    }
+    // Newer versions of Windows have a special ListView_CancelEditLabel()
+    // message for cancelling editing but it, rather counter-intuitively, keeps
+    // the last text entered in the dialog while cancelling as we do it below
+    // restores the original text which is the more expected behaviour.
+
+    // We shouldn't destroy the control ourselves according to MSDN, which
+    // proposes WM_CANCELMODE to do this, but it doesn't seem to work so
+    // emulate the corresponding user action instead.
+    ::SendMessage(hwnd, WM_KEYDOWN, cancel ? VK_ESCAPE : VK_RETURN, 0);
 
     return true;
 }
@@ -1661,6 +1679,12 @@ long wxListCtrl::InsertItem(const wxListItem& info)
 {
     wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual controls") );
 
+    // In 2.8 it was possible to succeed inserting an item without initializing
+    // its ID as it defaulted to 0. This was however never supported and in 2.9
+    // the ID is -1 by default and inserting it simply fails, but it might be
+    // not obvious why does it happen, so check it proactively.
+    wxASSERT_MSG( info.m_itemId != -1, wxS("Item ID must be set.") );
+
     LV_ITEM item;
     wxConvertToMSWListItem(this, info, item);
     item.mask &= ~LVIF_PARAM;
@@ -1727,18 +1751,27 @@ long wxListCtrl::InsertItem(long index, const wxString& label, int imageIndex)
     wxListItem info;
     info.m_image = imageIndex;
     info.m_text = label;
-    info.m_mask = wxLIST_MASK_IMAGE | wxLIST_MASK_TEXT;
+    info.m_mask = wxLIST_MASK_TEXT;
+    if (imageIndex > -1)
+        info.m_mask |= wxLIST_MASK_IMAGE;
     info.m_itemId = index;
     return InsertItem(info);
 }
 
 // For list view mode (only), inserts a column.
-long wxListCtrl::InsertColumn(long col, const wxListItem& item)
+long wxListCtrl::DoInsertColumn(long col, const wxListItem& item)
 {
     LV_COLUMN lvCol;
     wxConvertToMSWListCol(GetHwnd(), col, item, lvCol);
 
-    if ( !(lvCol.mask & LVCF_WIDTH) )
+    // LVSCW_AUTOSIZE_USEHEADER is not supported when inserting new column,
+    // we'll deal with it below instead. Plain LVSCW_AUTOSIZE is not supported
+    // neither but it doesn't need any special handling as we use fixed value
+    // for it here, both because we can't do anything else (there are no items
+    // with values in this column to compute the size from yet) and for
+    // compatibility as wxLIST_AUTOSIZE == -1 and -1 as InsertColumn() width
+    // parameter used to mean "arbitrary fixed width".
+    if ( !(lvCol.mask & LVCF_WIDTH) || lvCol.cx < 0 )
     {
         // always give some width to the new column: this one is compatible
         // with the generic version
@@ -1747,35 +1780,23 @@ long wxListCtrl::InsertColumn(long col, const wxListItem& item)
     }
 
     long n = ListView_InsertColumn(GetHwnd(), col, &lvCol);
-    if ( n != -1 )
-    {
-        m_colCount++;
-    }
-    else // failed to insert?
+    if ( n == -1 )
     {
         wxLogDebug(wxT("Failed to insert the column '%s' into listview!"),
                    lvCol.pszText);
+        return -1;
     }
 
-    return n;
-}
+    m_colCount++;
 
-long wxListCtrl::InsertColumn(long col,
-                              const wxString& heading,
-                              int format,
-                              int width)
-{
-    wxListItem item;
-    item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
-    item.m_text = heading;
-    if ( width > -1 )
+    // Now adjust the new column size.
+    if ( (item.GetMask() & wxLIST_MASK_WIDTH) &&
+            (item.GetWidth() == wxLIST_AUTOSIZE_USEHEADER) )
     {
-        item.m_mask |= wxLIST_MASK_WIDTH;
-        item.m_width = width;
+        SetColumnWidth(n, wxLIST_AUTOSIZE_USEHEADER);
     }
-    item.m_format = format;
 
-    return InsertColumn(col, item);
+    return n;
 }
 
 // scroll the control by the given number of pixels (exception: in list view,
@@ -1865,7 +1886,7 @@ bool wxListCtrl::MSWShouldPreProcessMessage(WXMSG* msg)
             return false;
         }
     }
-    return wxControl::MSWShouldPreProcessMessage(msg);
+    return wxListCtrlBase::MSWShouldPreProcessMessage(msg);
 }
 
 bool wxListCtrl::MSWCommand(WXUINT cmd, WXWORD id_)
@@ -1903,9 +1924,8 @@ int WXDLLIMPEXP_CORE wxMSWGetColumnClicked(NMHDR *nmhdr, POINT *ptClick)
     }
     else
 #endif //__WXWINCE__
-    if ( !::GetCursorPos(ptClick) )
     {
-        wxLogLastError(wxT("GetCursorPos"));
+       wxGetCursorPosMSW(ptClick);
     }
 
     // we need to use listctrl coordinates for the event point so this is what
@@ -2051,7 +2071,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
         }
 
         if ( ignore )
-            return wxControl::MSWOnNotify(idCtrl, lParam, result);
+            return wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result);
     }
     else
 #endif // defined(HDN_BEGINTRACKA)
@@ -2279,7 +2299,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             case NM_DBLCLK:
                 // if the user processes it in wxEVT_COMMAND_LEFT_CLICK(), don't do
                 // anything else
-                if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
+                if ( wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result) )
                 {
                     return true;
                 }
@@ -2304,7 +2324,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
             case NM_RCLICK:
                 // if the user processes it in wxEVT_COMMAND_RIGHT_CLICK(),
                 // don't do anything else
-                if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
+                if ( wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result) )
                 {
                     return true;
                 }
@@ -2321,7 +2341,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
                 else
 #endif //__WXWINCE__
                 {
-                    ::GetCursorPos(&(lvhti.pt));
+                    wxGetCursorPosMSW(&(lvhti.pt));
                 }
 
                 ::ScreenToClient(GetHwnd(), &lvhti.pt);
@@ -2517,7 +2537,7 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
         }
 
         if ( !processed )
-            return wxControl::MSWOnNotify(idCtrl, lParam, result);
+            return wxListCtrlBase::MSWOnNotify(idCtrl, lParam, result);
     }
     else
     {
@@ -2532,7 +2552,11 @@ bool wxListCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
     // fill in the item before passing it to the event handler if we do have a
     // valid item index and haven't filled it yet (e.g. for LVN_ITEMCHANGED)
-    if ( event.m_itemIndex != -1 && !event.m_item.GetMask() )
+    // and we're not using a virtual control as in this case the program
+    // already has the data anyhow and we don't want to call GetItem() for
+    // potentially many items
+    if ( event.m_itemIndex != -1 && !event.m_item.GetMask()
+            && !IsVirtual() )
     {
         wxListItem& item = event.m_item;
 
@@ -2903,7 +2927,7 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
 
     wxPaintDC dc(this);
 
-    wxControl::OnPaint(event);
+    wxListCtrlBase::OnPaint(event);
 
     // Reset the device origin since it may have been set
     dc.SetDeviceOrigin(0, 0);
@@ -2978,6 +3002,27 @@ void wxListCtrl::OnPaint(wxPaintEvent& event)
     }
 }
 
+void wxListCtrl::OnCharHook(wxKeyEvent& event)
+{
+    if ( GetEditControl() )
+    {
+        // We need to ensure that Escape is not stolen from the in-place editor
+        // by the containing dialog.
+        //
+        // Notice that we don't have to care about Enter key here as we return
+        // false from MSWShouldPreProcessMessage() for it.
+        if ( event.GetKeyCode() == WXK_ESCAPE )
+        {
+            EndEditLabel(true /* cancel */);
+
+            // Don't call Skip() below.
+            return;
+        }
+    }
+
+    event.Skip();
+}
+
 WXLRESULT
 wxListCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 {
@@ -3001,7 +3046,7 @@ wxListCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
             //else: break
     }
 
-    return wxControl::MSWWindowProc(nMsg, wParam, lParam);
+    return wxListCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
 }
 
 // ----------------------------------------------------------------------------