X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/705c4d13d9fe789db114bd8116186a268b819b62..7d6a4d96961eac84d05db8bb24c64d39003f6e54:/src/generic/listctrl.cpp diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index c9915b198e..de34935ced 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -25,15 +25,6 @@ #include "wx/listctrl.h" -#if ((!defined(__WXMSW__) && !(defined(__WXMAC__) && wxOSX_USE_CARBON)) || defined(__WXUNIVERSAL__)) - // if we have a native version, its implementation file does all this - IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject) - IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl) - IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent) - - IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxGenericListCtrl) -#endif - #ifndef WX_PRECOMP #include "wx/scrolwin.h" #include "wx/timer.h" @@ -351,12 +342,23 @@ bool wxListHeaderData::IsHit( int x, int y ) const void wxListHeaderData::GetItem( wxListItem& item ) { - item.m_mask = m_mask; - item.m_text = m_text; - item.m_image = m_image; - item.m_format = m_format; - item.m_width = m_width; - item.m_state = m_state; + long mask = item.m_mask; + if ( !mask ) + { + // by default, get everything for backwards compatibility + mask = -1; + } + + if ( mask & wxLIST_MASK_STATE ) + item.m_state = m_state; + if ( mask & wxLIST_MASK_TEXT ) + item.m_text = m_text; + if ( mask & wxLIST_MASK_IMAGE ) + item.m_image = m_image; + if ( mask & wxLIST_MASK_WIDTH ) + item.m_width = m_width; + if ( mask & wxLIST_MASK_FORMAT ) + item.m_format = m_format; } int wxListHeaderData::GetImage() const @@ -667,11 +669,20 @@ void wxListLineData::SetAttr(wxListItemAttr *attr) item->SetAttr(attr); } -bool wxListLineData::SetAttributes(wxDC *dc, - const wxListItemAttr *attr, - bool highlighted) +void wxListLineData::ApplyAttributes(wxDC *dc, + const wxRect& rectHL, + bool highlighted, + bool current) { - wxWindow *listctrl = m_owner->GetParent(); + const wxListItemAttr * const attr = GetAttr(); + + wxWindow * const listctrl = m_owner->GetParent(); + + const bool hasFocus = listctrl->HasFocus() +#if defined(__WXMAC__) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON + && IsControlActive( (ControlRef)listctrl->GetHandle() ) +#endif + ; // fg colour @@ -680,20 +691,19 @@ bool wxListLineData::SetAttributes(wxDC *dc, // arithmetics on wxColour, unfortunately) wxColour colText; if ( highlighted ) -#ifdef __WXMAC__ { - if (m_owner->HasFocus() -#if !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON - && IsControlActive( (ControlRef)m_owner->GetHandle() ) -#endif - ) +#ifdef __WXMAC__ + if ( hasFocus ) colText = *wxWHITE; else colText = *wxBLACK; - } #else - colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + if ( hasFocus ) + colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + else + colText = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT); #endif + } else if ( attr && attr->HasTextColour() ) colText = attr->GetTextColour(); else @@ -710,45 +720,25 @@ bool wxListLineData::SetAttributes(wxDC *dc, dc->SetFont(font); - // bg colour - bool hasBgCol = attr && attr->HasBackgroundColour(); - if ( highlighted || hasBgCol ) - { - if ( highlighted ) - dc->SetBrush( *m_owner->GetHighlightBrush() ); - else - dc->SetBrush(wxBrush(attr->GetBackgroundColour(), wxBRUSHSTYLE_SOLID)); - - dc->SetPen( *wxTRANSPARENT_PEN ); - - return true; - } - - return false; -} - -void wxListLineData::Draw( wxDC *dc ) -{ - wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); - wxCHECK_RET( node, wxT("no subitems at all??") ); - - bool highlighted = IsHighlighted(); - - wxListItemAttr *attr = GetAttr(); - - if ( SetAttributes(dc, attr, highlighted) ) + // background + if ( highlighted ) { - int flags = 0; - if (highlighted) - flags |= wxCONTROL_SELECTED; - if (m_owner->HasFocus() -#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON - && IsControlActive( (ControlRef)m_owner->GetHandle() ) -#endif - ) + // Use the renderer method to ensure that the selected items use the + // native look. + int flags = wxCONTROL_SELECTED; + if ( hasFocus ) flags |= wxCONTROL_FOCUSED; + if (current) + flags |= wxCONTROL_CURRENT; wxRendererNative::Get(). - DrawItemSelectionRect( m_owner, *dc, m_gi->m_rectHighlight, flags ); + DrawItemSelectionRect( m_owner, *dc, rectHL, flags ); + } + else if ( attr && attr->HasBackgroundColour() ) + { + // Draw the background using the items custom background colour. + dc->SetBrush(attr->GetBackgroundColour()); + dc->SetPen(*wxTRANSPARENT_PEN); + dc->DrawRectangle(rectHL); } // just for debugging to better see where the items are @@ -759,6 +749,14 @@ void wxListLineData::Draw( wxDC *dc ) dc->SetPen(*wxGREEN_PEN); dc->DrawRectangle( m_gi->m_rectIcon ); #endif +} + +void wxListLineData::Draw(wxDC *dc, bool current) +{ + wxListItemDataList::compatibility_iterator node = m_items.GetFirst(); + wxCHECK_RET( node, wxT("no subitems at all??") ); + + ApplyAttributes(dc, m_gi->m_rectHighlight, IsHighlighted(), current); wxListItemData *item = node->GetData(); if (item->HasImage()) @@ -788,18 +786,8 @@ void wxListLineData::DrawInReportMode( wxDC *dc, // TODO: later we should support setting different attributes for // different columns - to do it, just add "col" argument to // GetAttr() and move these lines into the loop below - wxListItemAttr *attr = GetAttr(); - if ( SetAttributes(dc, attr, highlighted) ) - { - int flags = 0; - if (highlighted) - flags |= wxCONTROL_SELECTED; - if (m_owner->HasFocus()) - flags |= wxCONTROL_FOCUSED; - if (current) - flags |= wxCONTROL_CURRENT; - wxRendererNative::Get().DrawItemSelectionRect( m_owner, *dc, rectHL, flags ); - } + + ApplyAttributes(dc, rectHL, highlighted, current); wxCoord x = rect.x + HEADER_OFFSET_X, yMid = rect.y + rect.height/2; @@ -821,7 +809,8 @@ void wxListLineData::DrawInReportMode( wxDC *dc, int xOld = x; x += width; - const int wText = width - 8; + width -= 8; + const int wText = width; wxDCClipper clipper(*dc, xOld, rect.y, wText, rect.height); if ( item->HasImage() ) @@ -837,7 +826,7 @@ void wxListLineData::DrawInReportMode( wxDC *dc, } if ( item->HasText() ) - DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, wText); + DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, width); } } @@ -945,7 +934,6 @@ void wxListLineData::ReverseHighlight( void ) BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow) EVT_PAINT (wxListHeaderWindow::OnPaint) EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse) - EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus) END_EVENT_TABLE() void wxListHeaderWindow::Init() @@ -1068,7 +1056,7 @@ void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) // 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 +// defined this only for wxMac. If this behaviour 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) && @@ -1352,12 +1340,6 @@ void wxListHeaderWindow::OnMouse( wxMouseEvent &event ) } } -void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) -{ - m_owner->SetFocus(); - m_owner->Update(); -} - bool wxListHeaderWindow::SendListEvent(wxEventType type, const wxPoint& pos) { wxWindow *parent = GetParent(); @@ -1424,23 +1406,31 @@ wxListTextCtrlWrapper::wxListTextCtrlWrapper(wxListMainWindow *owner, m_text->PushEventHandler(this); } -void wxListTextCtrlWrapper::EndEdit(bool discardChanges) +void wxListTextCtrlWrapper::EndEdit(EndReason reason) { m_aboutToFinish = true; - if ( discardChanges ) + switch ( reason ) { - m_owner->OnRenameCancelled(m_itemEdited); + case End_Accept: + // Notify the owner about the changes + AcceptChanges(); - Finish( true ); - } - else - { - // Notify the owner about the changes - AcceptChanges(); + // Even if vetoed, close the control (consistent with MSW) + Finish( true ); + break; + + case End_Discard: + m_owner->OnRenameCancelled(m_itemEdited); - // Even if vetoed, close the control (consistent with MSW) - Finish( true ); + Finish( true ); + break; + + case End_Destroy: + // Don't generate any notifications for the control being destroyed + // and don't set focus to it neither. + Finish(false); + break; } } @@ -1475,20 +1465,28 @@ bool wxListTextCtrlWrapper::AcceptChanges() } void wxListTextCtrlWrapper::OnChar( wxKeyEvent &event ) +{ + if ( !CheckForEndEditKey(event) ) + event.Skip(); +} + +bool wxListTextCtrlWrapper::CheckForEndEditKey(const wxKeyEvent& event) { switch ( event.m_keyCode ) { case WXK_RETURN: - EndEdit( false ); + EndEdit( End_Accept ); break; case WXK_ESCAPE: - EndEdit( true ); + EndEdit( End_Discard ); break; default: - event.Skip(); + return false; } + + return true; } void wxListTextCtrlWrapper::OnKeyUp( wxKeyEvent &event ) @@ -1532,6 +1530,7 @@ void wxListTextCtrlWrapper::OnKillFocus( wxFocusEvent &event ) BEGIN_EVENT_TABLE(wxListMainWindow, wxWindow) EVT_PAINT (wxListMainWindow::OnPaint) EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse) + EVT_CHAR_HOOK (wxListMainWindow::OnCharHook) EVT_CHAR (wxListMainWindow::OnChar) EVT_KEY_DOWN (wxListMainWindow::OnKeyDown) EVT_KEY_UP (wxListMainWindow::OnKeyUp) @@ -1583,10 +1582,9 @@ wxListMainWindow::wxListMainWindow() wxListMainWindow::wxListMainWindow( wxWindow *parent, wxWindowID id, const wxPoint& pos, - const wxSize& size, - long style, - const wxString &name ) - : wxWindow( parent, id, pos, size, style, name ) + const wxSize& size ) + : wxWindow( parent, id, pos, size, + wxWANTS_CHARS | wxBORDER_NONE ) { Init(); @@ -1617,6 +1615,9 @@ wxListMainWindow::wxListMainWindow( wxWindow *parent, wxListMainWindow::~wxListMainWindow() { + if ( m_textctrlWrapper ) + m_textctrlWrapper->EndEdit(wxListTextCtrlWrapper::End_Destroy); + DoDeleteAllItems(); WX_CLEAR_LIST(wxListHeaderDataList, m_columns); WX_CLEAR_ARRAY(m_aColWidths); @@ -2034,6 +2035,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) GetParent()->GetId()); evCache.SetEventObject( GetParent() ); evCache.m_oldItemIndex = visibleFrom; + evCache.m_item.m_itemId = evCache.m_itemIndex = visibleTo; GetParent()->GetEventHandler()->ProcessEvent( evCache ); } @@ -2110,7 +2112,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) size_t count = GetItemCount(); for ( size_t i = 0; i < count; i++ ) { - GetLine(i)->Draw( &dc ); + GetLine(i)->Draw( &dc, i == m_current ); } } @@ -2164,6 +2166,7 @@ void wxListMainWindow::SendNotify( size_t line, wxListEvent le( command, GetParent()->GetId() ); le.SetEventObject( GetParent() ); + le.m_item.m_itemId = le.m_itemIndex = line; // set only for events which have position @@ -2204,13 +2207,14 @@ wxTextCtrl *wxListMainWindow::EditLabel(long item, wxClassInfo* textControlClass wxCHECK_MSG( (item >= 0) && ((size_t)item < GetItemCount()), NULL, wxT("wrong index in wxGenericListCtrl::EditLabel()") ); - wxASSERT_MSG( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)), + wxASSERT_MSG( textControlClass->IsKindOf(wxCLASSINFO(wxTextCtrl)), wxT("EditLabel() needs a text control") ); size_t itemEdit = (size_t)item; wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() ); le.SetEventObject( GetParent() ); + le.m_item.m_itemId = le.m_itemIndex = item; wxListLineData *data = GetLine(itemEdit); wxCHECK_MSG( data, NULL, wxT("invalid index in EditLabel()") ); @@ -2253,6 +2257,7 @@ bool wxListMainWindow::OnRenameAccept(size_t itemEdit, const wxString& value) { wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() ); le.SetEventObject( GetParent() ); + le.m_item.m_itemId = le.m_itemIndex = itemEdit; wxListLineData *data = GetLine(itemEdit); @@ -2273,6 +2278,7 @@ void wxListMainWindow::OnRenameCancelled(size_t itemEdit) le.SetEditCanceled(true); le.SetEventObject( GetParent() ); + le.m_item.m_itemId = le.m_itemIndex = itemEdit; wxListLineData *data = GetLine(itemEdit); @@ -2290,7 +2296,7 @@ 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->EndEdit( false ); + m_textctrlWrapper->EndEdit(wxListTextCtrlWrapper::End_Accept); #endif // __WXMAC__ if ( event.LeftDown() ) @@ -2357,37 +2363,19 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) } } + // Update drag events counter first as we must do it even if the mouse is + // not on any item right now as we must keep count in case we started + // dragging from the empty control area but continued to do it over a valid + // item -- in this situation we must not start dragging this item. if (event.Dragging()) - { - if (m_dragCount == 0) - { - // we have to report the raw, physical coords as we want to be - // able to call HitTest(event.m_pointDrag) from the user code to - // get the item being dragged - m_dragStart = event.GetPosition(); - } - m_dragCount++; - - if (m_dragCount != 3) - return; - - int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG - : wxEVT_COMMAND_LIST_BEGIN_DRAG; - - wxListEvent le( command, GetParent()->GetId() ); - le.SetEventObject( GetParent() ); - le.m_itemIndex = m_lineLastClicked; - le.m_pointDrag = m_dragStart; - GetParent()->GetEventHandler()->ProcessEvent( le ); - - return; - } else - { m_dragCount = 0; - } + // The only mouse event that can be generated without any valid item is + // wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK as it can be useful to have a global + // popup menu for the list control itself which should be shown even when + // the user clicks outside of any item. if ( !hitResult ) { // outside of any item @@ -2411,6 +2399,27 @@ void wxListMainWindow::OnMouse( wxMouseEvent &event ) return; } + if ( event.Dragging() ) + { + if (m_dragCount == 1) + { + // we have to report the raw, physical coords as we want to be + // able to call HitTest(event.m_pointDrag) from the user code to + // get the item being dragged + m_dragStart = event.GetPosition(); + } + + if (m_dragCount != 3) + return; + + int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG + : wxEVT_COMMAND_LIST_BEGIN_DRAG; + + SendNotify( m_lineLastClicked, command, m_dragStart ); + + return; + } + bool forceClick = false; if (event.ButtonDClick()) { @@ -2699,6 +2708,17 @@ void wxListMainWindow::OnKeyDown( wxKeyEvent &event ) if (parent->GetEventHandler()->ProcessEvent( ke )) return; + // send a list event + wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, parent->GetId() ); + le.m_item.m_itemId = + le.m_itemIndex = m_current; + if (HasCurrent()) + GetLine(m_current)->GetItem( 0, le.m_item ); + le.m_code = event.GetKeyCode(); + le.SetEventObject( parent ); + if (parent->GetEventHandler()->ProcessEvent( le )) + return; + event.Skip(); } @@ -2714,21 +2734,26 @@ void wxListMainWindow::OnKeyUp( wxKeyEvent &event ) event.Skip(); } -void wxListMainWindow::OnChar( wxKeyEvent &event ) +void wxListMainWindow::OnCharHook( wxKeyEvent &event ) { - wxWindow *parent = GetParent(); - - // send a list_key event up - if ( HasCurrent() ) + if ( m_textctrlWrapper ) { - wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, GetParent()->GetId() ); - le.m_itemIndex = m_current; - GetLine(m_current)->GetItem( 0, le.m_item ); - le.m_code = event.GetKeyCode(); - le.SetEventObject( parent ); - parent->GetEventHandler()->ProcessEvent( le ); + // When an in-place editor is active we should ensure that it always + // gets the key events that are special to it. + if ( m_textctrlWrapper->CheckForEndEditKey(event) ) + { + // Skip the call to wxEvent::Skip() below. + return; + } } + event.Skip(); +} + +void wxListMainWindow::OnChar( wxKeyEvent &event ) +{ + wxWindow *parent = GetParent(); + // propagate the char event upwards wxKeyEvent ke(event); ke.SetEventObject( parent ); @@ -2944,17 +2969,6 @@ void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const } } -int wxListMainWindow::GetTextLength( const wxString &s ) const -{ - wxClientDC dc( wxConstCast(this, wxListMainWindow) ); - dc.SetFont( GetFont() ); - - wxCoord lw; - dc.GetTextExtent( s, &lw, NULL ); - - return lw + AUTOSIZE_COL_MARGIN; -} - void wxListMainWindow::SetImageList( wxImageList *imageList, int which ) { m_dirty = true; @@ -2997,18 +3011,42 @@ int wxListMainWindow::GetItemSpacing( bool isSmall ) // columns // ---------------------------------------------------------------------------- -void wxListMainWindow::SetColumn( int col, wxListItem &item ) +int +wxListMainWindow::ComputeMinHeaderWidth(const wxListHeaderData* column) const +{ + wxClientDC dc(const_cast(this)); + + int width = dc.GetTextExtent(column->GetText()).x + AUTOSIZE_COL_MARGIN; + + 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; + } + } + + return width; +} + +void wxListMainWindow::SetColumn( int col, const wxListItem &item ) { wxListHeaderDataList::compatibility_iterator node = m_columns.Item( col ); wxCHECK_RET( node, wxT("invalid column index in SetColumn") ); - if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER ) - item.m_width = GetTextLength( item.m_text ); - wxListHeaderData *column = node->GetData(); column->SetItem( item ); + if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER ) + column->SetWidth(ComputeMinHeaderWidth(column)); + wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin; if ( headerWin ) headerWin->m_dirty = true; @@ -3042,29 +3080,13 @@ 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; - } - } + width = ComputeMinHeaderWidth(column); } else if ( width == wxLIST_AUTOSIZE ) { - if ( IsVirtual() ) - { - // TODO: determine the max width somehow... - width = WIDTH_COL_DEFAULT; - } - else // !virtual + width = ComputeMinHeaderWidth(column); + + if ( !IsVirtual() ) { wxClientDC dc(this); dc.SetFont( GetFont() ); @@ -3094,8 +3116,9 @@ void wxListMainWindow::SetColumnWidth( int col, int width ) m_aColWidths.Item(col)->nMaxWidth = max; } - max = m_aColWidths.Item(col)->nMaxWidth; - width = max + AUTOSIZE_COL_MARGIN; + max = m_aColWidths.Item(col)->nMaxWidth + AUTOSIZE_COL_MARGIN; + if ( width < max ) + width = max; } } @@ -3168,10 +3191,14 @@ void wxListMainWindow::SetItem( wxListItem &item ) } } - // update the item on screen - wxRect rectItem; - GetItemRect(id, rectItem); - RefreshRect(rectItem); + // update the item on screen unless we're going to update everything soon + // anyhow + if ( !m_dirty ) + { + wxRect rectItem; + GetItemRect(id, rectItem); + RefreshRect(rectItem); + } } void wxListMainWindow::SetItemStateAll(long state, long stateMask) @@ -3616,6 +3643,9 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) int x = EXTRA_BORDER_X; int y = EXTRA_BORDER_Y; + + // Note that "row" here is vertical, i.e. what is called + // "column" in many other places in wxWidgets. int maxWidthInThisRow = 0; m_linesPerPage = 0; @@ -3637,8 +3667,24 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) if (currentlyVisibleLines > m_linesPerPage) m_linesPerPage = currentlyVisibleLines; - if ( y + sizeLine.y >= clientHeight ) + // Have we reached the end of the row either because no + // more items would fit or because there are simply no more + // items? + if ( y + sizeLine.y >= clientHeight + || i == count - 1) { + // Adjust all items in this row to have the same + // width to ensure that they all align horizontally in + // icon view. + if ( HasFlag(wxLC_ICON) || HasFlag(wxLC_SMALL_ICON) ) + { + size_t firstRowLine = i - currentlyVisibleLines + 1; + for (size_t j = firstRowLine; j <= i; j++) + { + GetLine(j)->m_gi->ExtendWidth(maxWidthInThisRow); + } + } + currentlyVisibleLines = 0; y = EXTRA_BORDER_Y; maxWidthInThisRow += MARGIN_BETWEEN_ROWS; @@ -3647,10 +3693,6 @@ void wxListMainWindow::RecalculatePositions(bool noRefresh) maxWidthInThisRow = 0; } - // We have reached the last item. - if ( i == count - 1 ) - entireWidth += maxWidthInThisRow; - if ( (tries == 0) && (entireWidth + SCROLL_UNIT_X > clientWidth) ) { @@ -3823,6 +3865,21 @@ void wxListMainWindow::DeleteColumn( int col ) for ( size_t i = 0; i < m_lines.GetCount(); i++ ) { wxListLineData * const line = GetLine(i); + + // In the following atypical but possible scenario it can be + // legal to call DeleteColumn() but the items may not have any + // values for it: + // 1. In report view, insert a second column. + // 2. Still in report view, add an item with 2 values. + // 3. Switch to an icon (or list) view. + // 4. Add an item -- necessarily with 1 value only. + // 5. Switch back to report view. + // 6. Call DeleteColumn(). + // So we need to check for this as otherwise we would simply crash + // if this happens. + if ( line->m_items.GetCount() <= static_cast(col) ) + continue; + wxListItemDataList::compatibility_iterator n = line->m_items.Item( col ); delete n->GetData(); line->m_items.Erase(n); @@ -4039,6 +4096,19 @@ void wxListMainWindow::InsertItem( wxListItem &item ) wxListLineData *line = new wxListLineData(this); line->SetItem( item.m_col, item ); + if ( item.m_mask & wxLIST_MASK_IMAGE ) + { + // Reset the buffered height if it's not big enough for the new image. + int image = item.GetImage(); + if ( m_small_image_list && image != -1 && InReportView() ) + { + int imageWidth, imageHeight; + m_small_image_list->GetSize(image, imageWidth, imageHeight); + + if ( imageHeight > m_lineHeight ) + m_lineHeight = 0; + } + } m_lines.Insert( line, id ); @@ -4055,15 +4125,15 @@ void wxListMainWindow::InsertItem( wxListItem &item ) RefreshLines(id, GetItemCount() - 1); } -void wxListMainWindow::InsertColumn( long col, wxListItem &item ) +void wxListMainWindow::InsertColumn( long col, const wxListItem &item ) { m_dirty = true; if ( InReportView() ) { + wxListHeaderData *column = new wxListHeaderData( item ); if (item.m_width == wxLIST_AUTOSIZE_USEHEADER) - item.m_width = GetTextLength( item.m_text ); + column->SetWidth(ComputeMinHeaderWidth(column)); - wxListHeaderData *column = new wxListHeaderData( item ); wxColWidthInfo *colWidthInfo = new wxColWidthInfo(); bool insert = (col >= 0) && ((size_t)col < m_columns.GetCount()); @@ -4233,7 +4303,7 @@ void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to) IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl, wxControl) -BEGIN_EVENT_TABLE(wxGenericListCtrl,wxControl) +BEGIN_EVENT_TABLE(wxGenericListCtrl,wxListCtrlBase) EVT_SIZE(wxGenericListCtrl::OnSize) EVT_SCROLLWIN(wxGenericListCtrl::OnScroll) END_EVENT_TABLE() @@ -4313,15 +4383,12 @@ bool wxGenericListCtrl::Create(wxWindow *parent, wxASSERT_MSG( (style & wxLC_MASK_TYPE), wxT("wxListCtrl style should have exactly one mode bit set") ); - if ( !wxControl::Create( parent, id, pos, size, style|wxVSCROLL|wxHSCROLL, validator, name ) ) + if ( !wxListCtrlBase::Create( parent, id, pos, size, + style | wxVSCROLL | wxHSCROLL, + validator, name ) ) return false; -#ifdef __WXGTK__ - style &= ~wxBORDER_MASK; - style |= wxBORDER_THEME; -#endif - - m_mainWin = new wxListMainWindow( this, wxID_ANY, wxPoint(0, 0), size, style ); + m_mainWin = new wxListMainWindow(this, wxID_ANY, wxPoint(0, 0), size); SetTargetWindow( m_mainWin ); @@ -4351,7 +4418,7 @@ WXLRESULT wxGenericListCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) { - WXLRESULT rc = wxControl::MSWWindowProc(nMsg, wParam, lParam); + WXLRESULT rc = wxListCtrlBase::MSWWindowProc(nMsg, wParam, lParam); // we need to process arrows ourselves for scrolling if ( nMsg == WM_GETDLGCODE ) @@ -4459,7 +4526,7 @@ bool wxGenericListCtrl::GetColumn(int col, wxListItem &item) const return true; } -bool wxGenericListCtrl::SetColumn( int col, wxListItem& item ) +bool wxGenericListCtrl::SetColumn( int col, const wxListItem& item ) { m_mainWin->SetColumn( col, item ); return true; @@ -4794,6 +4861,10 @@ bool wxGenericListCtrl::DeleteColumn( int col ) // if we don't have the header any longer, we need to relayout the window // if ( !GetColumnCount() ) + + // Ensure that the non-existent columns are really removed from display. + Refresh(); + return true; } @@ -4865,12 +4936,14 @@ long wxGenericListCtrl::InsertItem( long index, const wxString &label, int image wxListItem info; info.m_text = label; info.m_image = imageIndex; - info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE; + info.m_mask = wxLIST_MASK_TEXT; + if (imageIndex > -1) + info.m_mask |= wxLIST_MASK_IMAGE; info.m_itemId = index; return InsertItem( info ); } -long wxGenericListCtrl::InsertColumn( long col, wxListItem &item ) +long wxGenericListCtrl::DoInsertColumn( long col, const wxListItem &item ) { wxCHECK_MSG( InReportView(), -1, wxT("can't add column in non report mode") ); @@ -4884,23 +4957,6 @@ long wxGenericListCtrl::InsertColumn( long col, wxListItem &item ) return 0; } -long wxGenericListCtrl::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 >= -2) - { - item.m_mask |= wxLIST_MASK_WIDTH; - item.m_width = width; - } - - item.m_format = format; - - return InsertColumn( col, item ); -} - bool wxGenericListCtrl::ScrollList( int dx, int dy ) { return m_mainWin->ScrollList(dx, dy); @@ -5067,26 +5123,28 @@ bool wxGenericListCtrl::DoPopupMenu( wxMenu *menu, int x, int y ) void wxGenericListCtrl::DoClientToScreen( int *x, int *y ) const { - m_mainWin->DoClientToScreen(x, y); + // It's not clear whether this can be called before m_mainWin is created + // but it seems better to be on the safe side and check. + if ( m_mainWin ) + m_mainWin->DoClientToScreen(x, y); + else + wxListCtrlBase::DoClientToScreen(x, y); } void wxGenericListCtrl::DoScreenToClient( int *x, int *y ) const { - m_mainWin->DoScreenToClient(x, y); -} - -void wxGenericListCtrl::SetFocus() -{ - // The test in window.cpp fails as we are a composite - // window, so it checks against "this", but not m_mainWin. - if ( DoFindFocus() != this ) - m_mainWin->SetFocus(); + // At least in wxGTK/Univ build this method can be called before m_mainWin + // is created so avoid crashes in this case. + if ( m_mainWin ) + m_mainWin->DoScreenToClient(x, y); + else + wxListCtrlBase::DoScreenToClient(x, y); } wxSize wxGenericListCtrl::DoGetBestClientSize() const { - // Something is better than nothing even if this is completely arbitrary. - wxSize sizeBest(100, 80); + // The base class version can compute the best size in report view only. + wxSize sizeBest = wxListCtrlBase::DoGetBestClientSize(); if ( !InReportView() ) {