]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/listctrl.cpp
Fix tracking rectangles in 64-bit build by remembering the tag as the 64-bit integer...
[wxWidgets.git] / src / generic / listctrl.cpp
index 40a79102d5a9defeaaacebcd9cf5965bfe4a9fc6..e8cfa298625f92e603b623fa2d64912939dd1adc 100644 (file)
@@ -42,6 +42,7 @@
     #include "wx/dcclient.h"
     #include "wx/dcscreen.h"
     #include "wx/math.h"
+    #include "wx/settings.h"
 #endif
 
 #include "wx/imaglist.h"
@@ -83,8 +84,8 @@ static const int EXTRA_BORDER_X = 2;
 static const int EXTRA_BORDER_Y = 2;
 
 // offset for the header window
-static const int HEADER_OFFSET_X = 1;
-static const int HEADER_OFFSET_Y = 1;
+static const int HEADER_OFFSET_X = 0;
+static const int HEADER_OFFSET_Y = 0;
 
 // margin between rows of icons in [small] icon view
 static const int MARGIN_BETWEEN_ROWS = 6;
@@ -98,6 +99,9 @@ static const int WIDTH_COL_DEFAULT = 80;
 // the space between the image and the text in the report mode
 static const int IMAGE_MARGIN_IN_REPORT_MODE = 5;
 
+// the space between the image and the text in the report mode in header
+static const int HEADER_IMAGE_MARGIN_IN_REPORT_MODE = 2;
+
 // ============================================================================
 // private classes
 // ============================================================================
@@ -460,7 +464,7 @@ public:
 
     wxTextCtrl *GetText() const { return m_text; }
 
-    void AcceptChangesAndFinish();
+    void EndEdit( bool discardChanges );
 
 protected:
     void OnChar( wxKeyEvent &event );
@@ -468,14 +472,13 @@ protected:
     void OnKillFocus( wxFocusEvent &event );
 
     bool AcceptChanges();
-    void Finish();
+    void Finish( bool setfocus );
 
 private:
     wxListMainWindow   *m_owner;
     wxTextCtrl         *m_text;
     wxString            m_startValue;
     size_t              m_itemEdited;
-    bool                m_finished;
     bool                m_aboutToFinish;
 
     DECLARE_EVENT_TABLE()
@@ -576,6 +579,8 @@ public:
     // bring the selected item into view, scrolling to it if necessary
     void MoveToItem(size_t item);
 
+    bool ScrollList( int WXUNUSED(dx), int dy );
+
     // bring the current item into view
     void MoveToFocus() { MoveToItem(m_current); }
 
@@ -587,16 +592,15 @@ public:
         return m_textctrlWrapper ? m_textctrlWrapper->GetText() : NULL;
     }
 
-    void FinishEditing(wxTextCtrl *text)
+    void ResetTextControl(wxTextCtrl *text)
     {
         delete text;
         m_textctrlWrapper = NULL;
-        SetFocusIgnoringChildren();
     }
 
-    // suspend/resume redrawing the control
-    void Freeze();
-    void Thaw();
+    // we don't draw anything while we're frozen so we must refresh ourselves
+    // when we're thawed to make sure the changes are displayed correctly
+    virtual void DoThaw() { Refresh(); }
 
     void OnRenameTimer();
     bool OnRenameAccept(size_t itemEdit, const wxString& value);
@@ -695,7 +699,7 @@ public:
 
     // send out a wxListEvent
     void SendNotify( size_t line,
-                     wxEventType command, 
+                     wxEventType command,
                      const wxPoint& point = wxDefaultPosition );
 
     // override base class virtual to reset m_lineHeight when the font changes
@@ -728,7 +732,7 @@ public:
     {
         return m_hasFocus ? m_highlightBrush : m_highlightUnfocusedBrush;
     }
-    
+
     bool HasFocus() const
     {
         return m_hasFocus;
@@ -844,9 +848,6 @@ private:
     wxBrush *m_highlightBrush,
             *m_highlightUnfocusedBrush;
 
-    // if this is > 0, the control is frozen and doesn't redraw itself
-    size_t m_freezeCount;
-
     // wrapper around the text control currently used for in place editing or
     // NULL if no item is being edited
     wxListTextCtrlWrapper *m_textctrlWrapper;
@@ -1036,7 +1037,7 @@ void wxListHeaderData::SetItem( const wxListItem &item )
 
     if ( m_mask & wxLIST_MASK_WIDTH )
         SetWidth(item.m_width);
-        
+
     if ( m_mask & wxLIST_MASK_STATE )
         SetState(item.m_state);
 }
@@ -1410,7 +1411,11 @@ bool wxListLineData::SetAttributes(wxDC *dc,
     if ( highlighted )
 #ifdef __WXMAC__
     {
-        if (m_owner->HasFocus())
+        if (m_owner->HasFocus()
+#if !defined(__WXUNIVERSAL__)
+                && IsControlActive( (ControlRef)m_owner->GetHandle() )
+#endif
+        )
             colText = *wxWHITE;
         else
             colText = *wxBLACK;
@@ -1470,10 +1475,14 @@ void wxListLineData::Draw( wxDC *dc )
         if (highlighted)
         {
             int flags = wxCONTROL_SELECTED;
-            if (m_owner->HasFocus())
+            if (m_owner->HasFocus()
+#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__)
+                && IsControlActive( (ControlRef)m_owner->GetHandle() )
+#endif
+            )
                 flags |= wxCONTROL_FOCUSED;
             wxRendererNative::Get().DrawItemSelectionRect( m_owner, *dc, m_gi->m_rectHighlight, flags );
-            
+
         }
         else
         {
@@ -1578,12 +1587,17 @@ void wxListLineData::DrawInReportMode( wxDC *dc,
 }
 
 void wxListLineData::DrawTextFormatted(wxDC *dc,
-                                       const wxString &text,
+                                       const wxString& textOrig,
                                        int col,
                                        int x,
                                        int yMid,
                                        int width)
 {
+    // we don't support displaying multiple lines currently (and neither does
+    // wxMSW FWIW) so just merge all the lines
+    wxString text(textOrig);
+    text.Replace(_T("\n"), _T(" "));
+
     wxCoord w, h;
     dc->GetTextExtent(text, &w, &h);
 
@@ -1788,26 +1802,19 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
         m_owner->GetColumn( i, item );
         int wCol = item.m_width;
 
-        // the width of the rect to draw: make it smaller to fit entirely
-        // inside the column rect
-#ifdef __WXMAC__
         int cw = wCol;
         int ch = h;
-#else
-        int cw = wCol - 2;
-        int ch = h - 2;
-#endif
 
         int flags = 0;
         if (!m_parent->IsEnabled())
             flags |= wxCONTROL_DISABLED;
 
-// NB: The code below is not really Mac-specific, but since we are close 
+// NB: The code below is not really Mac-specific, but since we are close
 // to 2.8 release and I don't have time to test on other platforms, I
 // defined this only for wxMac. If this behavior is desired on
 // other platforms, please go ahead and revise or remove the #ifdef.
 #ifdef __WXMAC__
-        if ( !m_owner->IsVirtual() && (item.m_mask & wxLIST_MASK_STATE) && 
+        if ( !m_owner->IsVirtual() && (item.m_mask & wxLIST_MASK_STATE) &&
                 (item.m_state & wxLIST_STATE_SELECTED) )
             flags |= wxCONTROL_SELECTED;
 #endif
@@ -1829,7 +1836,6 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
         wLabel += 2 * EXTRA_WIDTH;
 
         // and the width of the icon, if any
-        static const int MARGIN_BETWEEN_TEXT_AND_ICON = 2;
         int ix = 0, iy = 0;    // init them just to suppress the compiler warnings
         const int image = item.m_image;
         wxImageList *imageList;
@@ -1839,7 +1845,7 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
             if ( imageList )
             {
                 imageList->GetSize(image, ix, iy);
-                wLabel += ix + MARGIN_BETWEEN_TEXT_AND_ICON;
+                wLabel += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE;
             }
         }
         else
@@ -1868,6 +1874,10 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
                 break;
         }
 
+        // draw the text and image clipping them so that they
+        // don't overwrite the column boundary
+        wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
+
         // if we have an image, draw it on the right of the label
         if ( imageList )
         {
@@ -1875,18 +1885,12 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
                        (
                         image,
                         dc,
-                        xAligned + wLabel - ix - MARGIN_BETWEEN_TEXT_AND_ICON,
+                        xAligned + wLabel - ix - HEADER_IMAGE_MARGIN_IN_REPORT_MODE,
                         HEADER_OFFSET_Y + (h - 4 - iy)/2,
                         wxIMAGELIST_DRAW_TRANSPARENT
                        );
-
-            cw -= ix + MARGIN_BETWEEN_TEXT_AND_ICON;
         }
 
-        // draw the text clipping it so that it doesn't overwrite the column
-        // boundary
-        wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
-
         dc.DrawText( item.GetText(),
                      xAligned + EXTRA_WIDTH, h / 2 - hLabel / 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT );
 
@@ -1896,6 +1900,9 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
 
 void wxListHeaderWindow::DrawCurrent()
 {
+#if 1
+    m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
+#else
     int x1 = m_currentX;
     int y1 = 0;
     m_owner->ClientToScreen( &x1, &y1 );
@@ -1918,6 +1925,7 @@ void wxListHeaderWindow::DrawCurrent()
 
     dc.SetPen( wxNullPen );
     dc.SetBrush( wxNullBrush );
+#endif
 }
 
 void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
@@ -2020,7 +2028,7 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
                     {
                         wxListItem colItem;
                         m_owner->GetColumn(i, colItem);
-                        long state = colItem.GetState(); 
+                        long state = colItem.GetState();
                         if (i == m_column)
                             colItem.SetState(state | wxLIST_STATE_SELECTED);
                         else
@@ -2028,7 +2036,7 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
                         m_owner->SetColumn(i, colItem);
                     }
                 }
-                
+
                 SendListEvent( event.LeftDown()
                                     ? wxEVT_COMMAND_LIST_COL_CLICK
                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK,
@@ -2110,7 +2118,6 @@ wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow *owner,
 {
     m_owner = owner;
     m_text = text;
-    m_finished = false;
     m_aboutToFinish = false;
 
     wxRect rectLabel = owner->GetLineLabelRect(itemEdit);
@@ -2126,59 +2133,66 @@ wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow *owner,
     m_text->PushEventHandler(this);
 }
 
-void wxListTextCtrlWrapper::Finish()
+void wxListTextCtrlWrapper::EndEdit(bool discardChanges)
 {
-    if ( !m_finished )
+    m_aboutToFinish = true;
+    
+    if ( discardChanges )
     {
-        m_finished = true;
-
-        m_text->RemoveEventHandler(this);
-        m_owner->FinishEditing(m_text);
+        m_owner->OnRenameCancelled(m_itemEdited);
+           
+        Finish( true );
+    }
+    else
+    {
+        // Notify the owner about the changes
+        AcceptChanges();
 
-        wxPendingDelete.Append( this );
+        // Even if vetoed, close the control (consistent with MSW)
+        Finish( true );
     }
 }
 
+void wxListTextCtrlWrapper::Finish( bool setfocus )
+{
+    m_text->RemoveEventHandler(this);
+    m_owner->ResetTextControl( m_text );
+
+    wxPendingDelete.Append( this );
+    
+    if (setfocus)
+        m_owner->SetFocusIgnoringChildren();
+}
+
 bool wxListTextCtrlWrapper::AcceptChanges()
 {
     const wxString value = m_text->GetValue();
 
-    if ( value == m_startValue )
-        // nothing changed, always accept
-        return true;
-
+    // notice that we should always call OnRenameAccept() to generate the "end
+    // label editing" event, even if the user hasn't really changed anything
     if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
+    {
         // vetoed by the user
         return false;
+    }
 
-    // accepted, do rename the item
-    m_owner->SetItemText(m_itemEdited, value);
+    // accepted, do rename the item (unless nothing changed)
+    if ( value != m_startValue )
+        m_owner->SetItemText(m_itemEdited, value);
 
     return true;
 }
 
-void wxListTextCtrlWrapper::AcceptChangesAndFinish()
-{
-    m_aboutToFinish = true;
-
-    // Notify the owner about the changes
-    AcceptChanges();
-
-    // Even if vetoed, close the control (consistent with MSW)
-    Finish();
-}
-
 void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event )
 {
     switch ( event.m_keyCode )
     {
         case WXK_RETURN:
-            AcceptChangesAndFinish();
+            EndEdit( false );
             break;
 
         case WXK_ESCAPE:
-            m_owner->OnRenameCancelled( m_itemEdited );
-            Finish();
+            EndEdit( true );
             break;
 
         default:
@@ -2188,35 +2202,32 @@ void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event )
 
 void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent &event )
 {
-    if (m_finished)
+    if (m_aboutToFinish)
     {
-        event.Skip();
-        return;
+        // auto-grow the textctrl:
+        wxSize parentSize = m_owner->GetSize();
+        wxPoint myPos = m_text->GetPosition();
+        wxSize mySize = m_text->GetSize();
+        int sx, sy;
+        m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
+        if (myPos.x + sx > parentSize.x)
+            sx = parentSize.x - myPos.x;
+       if (mySize.x > sx)
+            sx = mySize.x;
+       m_text->SetSize(sx, wxDefaultCoord);
     }
-
-    // auto-grow the textctrl:
-    wxSize parentSize = m_owner->GetSize();
-    wxPoint myPos = m_text->GetPosition();
-    wxSize mySize = m_text->GetSize();
-    int sx, sy;
-    m_text->GetTextExtent(m_text->GetValue() + _T("MM"), &sx, &sy);
-    if (myPos.x + sx > parentSize.x)
-        sx = parentSize.x - myPos.x;
-    if (mySize.x > sx)
-        sx = mySize.x;
-    m_text->SetSize(sx, wxDefaultCoord);
-
+    
     event.Skip();
 }
 
 void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent &event )
 {
-    if ( !m_finished && !m_aboutToFinish )
+    if ( !m_aboutToFinish )
     {
         if ( !AcceptChanges() )
             m_owner->OnRenameCancelled( m_itemEdited );
 
-        Finish();
+        Finish( false );
     }
 
     // We must let the native text control handle focus
@@ -2234,7 +2245,7 @@ BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow)
   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse)
   EVT_CHAR           (wxListMainWindow::OnChar)
   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown)
-  EVT_KEY_UP         (wxListMainWindow::OnKeyUp)      
+  EVT_KEY_UP         (wxListMainWindow::OnKeyUp)
   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus)
   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus)
   EVT_SCROLLWIN      (wxListMainWindow::OnScroll)
@@ -2269,8 +2280,6 @@ void wxListMainWindow::Init()
     m_lineLastClicked =
     m_lineSelectSingleOnUp =
     m_lineBeforeLastClicked = (size_t)-1;
-
-    m_freezeCount = 0;
 }
 
 wxListMainWindow::wxListMainWindow()
@@ -2300,7 +2309,7 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent,
                             ),
                             wxSOLID
                          );
-                         
+
     m_highlightUnfocusedBrush = new wxBrush
                               (
                                  wxSystemSettings::GetColour
@@ -2432,10 +2441,24 @@ wxRect wxListMainWindow::GetLineLabelRect(size_t line) const
     if ( !InReportView() )
         return GetLine(line)->m_gi->m_rectLabel;
 
+    int image_x = 0;
+    wxListLineData *data = GetLine(line);
+    wxListItemDataList::compatibility_iterator node = data->m_items.GetFirst();
+    if (node)
+    {
+        wxListItemData *item = node->GetData();
+        if ( item->HasImage() )
+        {
+            int ix, iy;
+            GetImageSize( item->GetImage(), ix, iy );
+            image_x = 3 + ix + IMAGE_MARGIN_IN_REPORT_MODE;
+        }
+    }
+
     wxRect rect;
-    rect.x = HEADER_OFFSET_X;
+    rect.x = image_x + HEADER_OFFSET_X;
     rect.y = GetLineY(line);
-    rect.width = GetColumnWidth(0);
+    rect.width = GetColumnWidth(0) - image_x;
     rect.height = GetLineHeight();
 
     return rect;
@@ -2675,32 +2698,23 @@ void wxListMainWindow::RefreshSelected()
     }
 }
 
-void wxListMainWindow::Freeze()
-{
-    m_freezeCount++;
-}
-
-void wxListMainWindow::Thaw()
-{
-    wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen list control?") );
-
-    if ( --m_freezeCount == 0 )
-        Refresh();
-}
-
 void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
 {
     // Note: a wxPaintDC must be constructed even if no drawing is
     // done (a Windows requirement).
     wxPaintDC dc( this );
 
-    if ( IsEmpty() || m_freezeCount )
+    if ( IsEmpty() || IsFrozen() )
+    {
         // nothing to draw or not the moment to draw it
         return;
+    }
 
     if ( m_dirty )
+    {
         // delay the repainting until we calculate all the items positions
         return;
+    }
 
     PrepareDC( dc );
 
@@ -2719,7 +2733,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
         wxRect rectLine;
         int xOrig = dc.LogicalToDeviceX( 0 );
         int yOrig = dc.LogicalToDeviceY( 0 );
-        
+
         // tell the caller cache to cache the data
         if ( IsVirtual() )
         {
@@ -2754,8 +2768,9 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
             wxPen pen(GetRuleColour(), 1, wxSOLID);
             wxSize clientSize = GetClientSize();
 
-            // Don't draw the first one
-            for ( size_t i = visibleFrom + 1; i <= visibleTo; i++ )
+            size_t i = visibleFrom;
+            if (i == 0) i = 1; // Don't draw the first one
+            for ( ; i <= visibleTo; i++ )
             {
                 dc.SetPen(pen);
                 dc.SetBrush( *wxTRANSPARENT_BRUSH );
@@ -2789,8 +2804,10 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
             {
                 int colWidth = GetColumnWidth(col);
                 x += colWidth;
-                dc.DrawLine(x - dev_x - 2, firstItemRect.GetY() - 1 - dev_y,
-                            x - dev_x - 2, lastItemRect.GetBottom() + 1 - dev_y);
+                int x_pos = x - dev_x;
+                if (col < GetColumnCount()-1) x_pos -= 2;
+                dc.DrawLine(x_pos, firstItemRect.GetY() - 1 - dev_y,
+                            x_pos, lastItemRect.GetBottom() + 1 - dev_y);
             }
         }
     }
@@ -2816,7 +2833,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
             dc.DrawRectangle( rect );
 #else
             wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, wxCONTROL_CURRENT|wxCONTROL_FOCUSED );
-            
+
 #endif
         }
     }
@@ -2836,9 +2853,10 @@ void wxListMainWindow::HighlightAll( bool on )
             RefreshLine(m_current);
         }
     }
-    else // multi sel
+    else // multi selection
     {
-        HighlightLines(0, GetItemCount() - 1, on);
+        if ( !IsEmpty() )
+            HighlightLines(0, GetItemCount() - 1, on);
     }
 }
 
@@ -2848,7 +2866,7 @@ void wxListMainWindow::SendNotify( size_t line,
 {
     wxListEvent le( command, GetParent()->GetId() );
     le.SetEventObject( GetParent() );
-    
+
     le.m_itemIndex = line;
 
     // set only for events which have position
@@ -2876,6 +2894,11 @@ void wxListMainWindow::ChangeCurrent(size_t current)
 {
     m_current = current;
 
+    // as the current item changed, we shouldn't start editing it when the
+    // "slow click" timer expires as the click happened on another item
+    if ( m_renameTimer->IsRunning() )
+        m_renameTimer->Stop();
+
     SendNotify(current, wxEVT_COMMAND_LIST_ITEM_FOCUSED);
 }
 
@@ -2905,8 +2928,15 @@ wxTextCtrl *wxListMainWindow::EditLabel(long item, wxClassInfo* textControlClass
     // We have to call this here because the label in question might just have
     // been added and no screen update taken place.
     if ( m_dirty )
+    {
         wxSafeYield();
 
+        // Pending events dispatched by wxSafeYield might have changed the item
+        // count
+        if ( (size_t)item >= GetItemCount() )
+            return NULL;
+    }
+
     wxTextCtrl * const text = (wxTextCtrl *)textControlClass->CreateObject();
     m_textctrlWrapper = new wxListTextCtrlWrapper(this, text, item);
     return m_textctrlWrapper->GetText();
@@ -2961,9 +2991,12 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
     // listctrl because the order of events is different (or something like
     // that), so explicitly end the edit if it is active.
     if ( event.LeftDown() && m_textctrlWrapper )
-        m_textctrlWrapper->AcceptChangesAndFinish();
+        m_textctrlWrapper->EndEdit( false );
 #endif // __WXMAC__
 
+    if ( event.LeftDown() )
+        SetFocusIgnoringChildren();
+
     event.SetEventObject( GetParent() );
     if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
         return;
@@ -2980,8 +3013,13 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
         if (event.RightDown())
         {
             SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
-            // Allow generation of context menu event
-            event.Skip();
+
+            wxContextMenuEvent evtCtx(
+                wxEVT_CONTEXT_MENU,
+                GetParent()->GetId(),
+                ClientToScreen(event.GetPosition()));
+            evtCtx.SetEventObject(GetParent());
+            GetParent()->GetEventHandler()->ProcessEvent(evtCtx);
         }
         return;
     }
@@ -3058,8 +3096,13 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
         if (event.RightDown())
         {
             SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
-            // Allow generation of context menu event
-            event.Skip();
+
+            wxContextMenuEvent evtCtx(
+                wxEVT_CONTEXT_MENU,
+                GetParent()->GetId(),
+                ClientToScreen(event.GetPosition()));
+            evtCtx.SetEventObject(GetParent());
+            GetParent()->GetEventHandler()->ProcessEvent(evtCtx);
         }
         else
         {
@@ -3073,7 +3116,9 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
     bool forceClick = false;
     if (event.ButtonDClick())
     {
-        m_renameTimer->Stop();
+        if ( m_renameTimer->IsRunning() )
+            m_renameTimer->Stop();
+
         m_lastOnSame = false;
 
         if ( current == m_lineLastClicked )
@@ -3105,7 +3150,12 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event )
                 (hitResult == wxLIST_HITTEST_ONITEMLABEL) &&
                 HasFlag(wxLC_EDIT_LABELS) )
             {
-                m_renameTimer->Start( 100, true );
+                if ( !InReportView() ||
+                        GetLineLabelRect(current).Contains(x, y) )
+                {
+                    int dclick = wxSystemSettings::GetMetric(wxSYS_DCLICK_MSEC);
+                    m_renameTimer->Start(dclick > 0 ? dclick : 250, true);
+                }
             }
         }
 
@@ -3231,16 +3281,65 @@ void wxListMainWindow::MoveToItem(size_t item)
             Scroll( -1, rect.y / hLine );
         if (rect.y + rect.height + 5 > view_y + client_h)
             Scroll( -1, (rect.y + rect.height - client_h + hLine) / hLine );
+
+#ifdef __WXMAC__
+        // At least on Mac the visible lines value will get reset inside of
+        // Scroll *before* it actually scrolls the window because of the
+        // Update() that happens there, so it will still have the wrong value.
+        // So let's reset it again and wait for it to be recalculated in the
+        // next paint event.  I would expect this problem to show up in wxGTK
+        // too but couldn't duplicate it there.  Perhaps the order of events
+        // is different...  --Robin
+        ResetVisibleLinesRange();
+#endif
     }
     else // !report
     {
+        int sx = -1,
+            sy = -1;
+
         if (rect.x-view_x < 5)
-            Scroll( (rect.x - 5) / SCROLL_UNIT_X, -1 );
+            sx = (rect.x - 5) / SCROLL_UNIT_X;
         if (rect.x + rect.width - 5 > view_x + client_w)
-            Scroll( (rect.x + rect.width - client_w + SCROLL_UNIT_X) / SCROLL_UNIT_X, -1 );
+            sx = (rect.x + rect.width - client_w + SCROLL_UNIT_X) / SCROLL_UNIT_X;
+
+        if (rect.y-view_y < 5)
+            sy = (rect.y - 5) / hLine;
+        if (rect.y + rect.height - 5 > view_y + client_h)
+            sy = (rect.y + rect.height - client_h + hLine) / hLine;
+
+        Scroll(sx, sy);
     }
 }
 
+bool wxListMainWindow::ScrollList(int WXUNUSED(dx), int dy)
+{
+    if ( !InReportView() )
+    {
+        // TODO: this should work in all views but is not implemented now
+        return false;
+    }
+
+    size_t top, bottom;
+    GetVisibleLinesRange(&top, &bottom);
+
+    if ( bottom == (size_t)-1 )
+        return 0;
+
+    ResetVisibleLinesRange();
+
+    int hLine = GetLineHeight();
+
+    Scroll(-1, top + dy / hLine);
+
+#ifdef __WXMAC__
+    // see comment in MoveToItem() for why we do this
+    ResetVisibleLinesRange();
+#endif
+
+    return true;
+}
+
 // ----------------------------------------------------------------------------
 // keyboard handling
 // ----------------------------------------------------------------------------
@@ -3273,7 +3372,8 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
     else // !shift
     {
         // all previously selected items are unselected unless ctrl is held
-        if ( !event.ControlDown() )
+        // in a multiselection control
+        if ( !event.ControlDown() || IsSingleSel() )
             HighlightAll(false);
 
         ChangeCurrent(newCurrent);
@@ -3281,10 +3381,9 @@ void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
         // refresh the old focus to remove it
         RefreshLine( oldCurrent );
 
-        if ( !event.ControlDown() )
-        {
+        // in single selection mode we must always have a selected item
+        if ( !event.ControlDown() || IsSingleSel() )
             HighlightLine( m_current, true );
-        }
     }
 
     RefreshLine( m_current );
@@ -3464,17 +3563,19 @@ void wxListMainWindow::OnChar( wxKeyEvent &event )
         case WXK_SPACE:
             if ( IsSingleSel() )
             {
-                SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
-
-                if ( IsHighlighted(m_current) )
+                if ( event.ControlDown() )
                 {
-                    // don't unselect the item in single selection mode
-                    break;
+                    ReverseHighlight(m_current);
+                }
+                else // normal space press
+                {
+                    SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
                 }
-                //else: select it in ReverseHighlight() below if unselected
             }
-
-            ReverseHighlight(m_current);
+            else // multiple selection
+            {
+                ReverseHighlight(m_current);
+            }
             break;
 
         case WXK_RETURN:
@@ -3670,6 +3771,19 @@ void wxListMainWindow::SetColumnWidth( int col, int width )
     if (width == wxLIST_AUTOSIZE_USEHEADER)
     {
         width = GetTextLength(column->GetText());
+        width += 2*EXTRA_WIDTH;
+
+        // check for column header's image availability
+        const int image = column->GetImage();
+        if ( image != -1 )
+        {
+            if ( m_small_image_list )
+            {
+                int ix = 0, iy = 0;
+                m_small_image_list->GetSize(image, ix, iy);
+                width += ix + HEADER_IMAGE_MARGIN_IN_REPORT_MODE;
+            }
+        }
     }
     else if ( width == wxLIST_AUTOSIZE )
     {
@@ -4358,7 +4472,7 @@ void wxListMainWindow::DeleteItem( long lindex )
         if ( m_current != index || m_current == count - 1 )
             m_current--;
     }
+
     if ( InReportView() )
     {
         //  mark the Column Max Width cache as dirty if the items in the line
@@ -4501,10 +4615,13 @@ void wxListMainWindow::EnsureVisible( long index )
     MoveToItem((size_t)index);
 }
 
-long wxListMainWindow::FindItem(long start, const wxString& str, bool WXUNUSED(partial) )
+long wxListMainWindow::FindItem(long start, const wxString& str, bool partial )
 {
+    if (str.empty())
+        return wxNOT_FOUND;
+
     long pos = start;
-    wxString tmp = str;
+    wxString str_upper = str.Upper();
     if (pos < 0)
         pos = 0;
 
@@ -4512,8 +4629,17 @@ long wxListMainWindow::FindItem(long start, const wxString& str, bool WXUNUSED(p
     for ( size_t i = (size_t)pos; i < count; i++ )
     {
         wxListLineData *line = GetLine(i);
-        if ( line->GetText(0) == tmp )
-            return i;
+        wxString line_upper = line->GetText(0).Upper();
+        if (!partial)
+        {
+            if (line_upper == str_upper )
+                return i;
+        }
+        else
+        {
+            if (line_upper.find(str_upper) == 0)
+                return i;
+        }
     }
 
     return wxNOT_FOUND;
@@ -4724,6 +4850,11 @@ int LINKAGEMODE list_ctrl_compare_func_1( wxListLineData **arg1, wxListLineData
 
 void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data )
 {
+    // selections won't make sense any more after sorting the items so reset
+    // them
+    HighlightAll(false);
+    ResetCurrent();
+
     list_ctrl_compare_func_2 = fn;
     list_ctrl_compare_data = data;
     m_lines.Sort( list_ctrl_compare_func_1 );
@@ -4736,10 +4867,6 @@ void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data )
 
 void wxListMainWindow::OnScroll(wxScrollWinEvent& event)
 {
-    // update our idea of which lines are shown when we redraw the window the
-    // next time
-    ResetVisibleLinesRange();
-
     // FIXME
 #if ( defined(__WXGTK__) || defined(__WXMAC__) ) && !defined(__WXUNIVERSAL__)
     wxScrolledWindow::OnScroll(event);
@@ -4747,6 +4874,10 @@ void wxListMainWindow::OnScroll(wxScrollWinEvent& event)
     HandleOnScroll( event );
 #endif
 
+    // update our idea of which lines are shown when we redraw the window the
+    // next time
+    ResetVisibleLinesRange();
+
     if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() )
     {
         wxGenericListCtrl* lc = GetListCtrl();
@@ -4908,17 +5039,20 @@ bool wxGenericListCtrl::Create(wxWindow *parent,
     if ( !wxControl::Create( parent, id, pos, size, style, validator, name ) )
         return false;
 
+    // this window itself shouldn't get the focus, only m_mainWin should
+    SetCanFocus(false);
+
     // don't create the inner window with the border
     style &= ~wxBORDER_MASK;
 
     m_mainWin = new wxListMainWindow( this, wxID_ANY, wxPoint(0, 0), size, style );
 
-#ifdef  __WXMAC_CARBON__
+#ifdef __WXMAC__
     // Human Interface Guidelines ask us for a special font in this case
     if ( GetWindowVariant() == wxWINDOW_VARIANT_NORMAL )
     {
         wxFont font;
-        font.MacCreateThemeFont( kThemeViewsFont );
+        font.MacCreateFromThemeFont( kThemeViewsFont );
         SetFont( font );
     }
 #endif
@@ -4927,11 +5061,11 @@ bool wxGenericListCtrl::Create(wxWindow *parent,
     {
         CreateHeaderWindow();
 
-#ifdef  __WXMAC_CARBON__
+#ifdef __WXMAC__
         if (m_headerWin)
         {
             wxFont font;
-            font.MacCreateThemeFont( kThemeSmallSystemFont );
+            font.MacCreateFromThemeFont( kThemeSmallSystemFont );
             m_headerWin->SetFont( font );
             CalculateAndSetHeaderHeight();
         }
@@ -5118,7 +5252,7 @@ wxUIntPtr wxGenericListCtrl::GetItemData( long item ) const
     return info.m_data;
 }
 
-bool wxGenericListCtrl::SetItemData( long item, long data )
+bool wxGenericListCtrl::SetItemPtrData( long item, wxUIntPtr data )
 {
     wxListItem info;
     info.m_mask = wxLIST_MASK_DATA;
@@ -5213,6 +5347,16 @@ wxColour wxGenericListCtrl::GetItemBackgroundColour( long item ) const
     return info.GetBackgroundColour();
 }
 
+int wxGenericListCtrl::GetScrollPos( int orient ) const
+{
+    return m_mainWin->GetScrollPos( orient );
+}
+
+void wxGenericListCtrl::SetScrollPos( int orient, int pos, bool refresh )
+{
+    m_mainWin->SetScrollPos( orient, pos, refresh );
+}
+
 void wxGenericListCtrl::SetItemFont( long item, const wxFont &f )
 {
     wxListItem info;
@@ -5452,9 +5596,9 @@ long wxGenericListCtrl::InsertColumn( long col, const wxString &heading,
     return InsertColumn( col, item );
 }
 
-bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) )
+bool wxGenericListCtrl::ScrollList( int dx, int dy )
 {
-    return 0;
+    return m_mainWin->ScrollList(dx, dy);
 }
 
 // Sort items.
@@ -5762,12 +5906,12 @@ void wxGenericListCtrl::Refresh(bool eraseBackground, const wxRect *rect)
     }
 }
 
-void wxGenericListCtrl::Freeze()
+void wxGenericListCtrl::DoFreeze()
 {
     m_mainWin->Freeze();
 }
 
-void wxGenericListCtrl::Thaw()
+void wxGenericListCtrl::DoThaw()
 {
     m_mainWin->Thaw();
 }