wxDataViewCtrl: always update the header when col best width changes.

Have an explicit per-column dirty flag and use that to determine whether
we need to call wxHeaderCtrl::UpdateColumn(). Previously, the lack of
computed best width was used as an indicator, but this didn't work
correctly if some code called GetWidth() after invalidation but before
wxDataViewCtrl::UpdateColWidths() was called at idle time. This resulted
in header's column widths getting out of sync with the control itself.

Fixes #14167.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71335 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík
2012-04-30 09:33:30 +00:00
parent b6b171522b
commit 840fc4d170
2 changed files with 34 additions and 14 deletions

View File

@@ -242,10 +242,18 @@ private:
void UpdateColWidths(); void UpdateColWidths();
wxDataViewColumnList m_cols; wxDataViewColumnList m_cols;
// cached column best widths or 0 if not computed, values are for // cached column best widths information, values are for
// respective columns from m_cols and the arrays have same size // respective columns from m_cols and the arrays have same size
wxVector<int> m_colsBestWidths; struct CachedColWidthInfo
// m_colsBestWidths partially invalid, needs recomputing {
CachedColWidthInfo() : width(0), dirty(true) {}
int width; // cached width or 0 if not computed
bool dirty; // column was invalidated, header needs updating
};
wxVector<CachedColWidthInfo> m_colsBestWidths;
// This indicates that at least one entry in m_colsBestWidths has 'dirty'
// flag set. It's cheaper to check one flag in OnInternalIdle() than to
// iterate over m_colsBestWidths to check if anything needs to be done.
bool m_colsDirty; bool m_colsDirty;
wxDataViewModelNotifier *m_notifier; wxDataViewModelNotifier *m_notifier;

View File

@@ -4547,7 +4547,7 @@ bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )
return false; return false;
m_cols.Append( col ); m_cols.Append( col );
m_colsBestWidths.push_back(0); m_colsBestWidths.push_back(CachedColWidthInfo());
OnColumnsCountChanged(); OnColumnsCountChanged();
return true; return true;
} }
@@ -4558,7 +4558,7 @@ bool wxDataViewCtrl::PrependColumn( wxDataViewColumn *col )
return false; return false;
m_cols.Insert( col ); m_cols.Insert( col );
m_colsBestWidths.insert(m_colsBestWidths.begin(), 0); m_colsBestWidths.insert(m_colsBestWidths.begin(), CachedColWidthInfo());
OnColumnsCountChanged(); OnColumnsCountChanged();
return true; return true;
} }
@@ -4569,7 +4569,7 @@ bool wxDataViewCtrl::InsertColumn( unsigned int pos, wxDataViewColumn *col )
return false; return false;
m_cols.Insert( pos, col ); m_cols.Insert( pos, col );
m_colsBestWidths.insert(m_colsBestWidths.begin() + pos, 0); m_colsBestWidths.insert(m_colsBestWidths.begin() + pos, CachedColWidthInfo());
OnColumnsCountChanged(); OnColumnsCountChanged();
return true; return true;
} }
@@ -4644,8 +4644,8 @@ int wxDataViewCtrl::GetColumnIndex(const wxDataViewColumn *column) const
unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx) const unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx) const
{ {
if ( m_colsBestWidths[idx] != 0 ) if ( m_colsBestWidths[idx].width != 0 )
return m_colsBestWidths[idx]; return m_colsBestWidths[idx].width;
const int count = m_clientArea->GetRowCount(); const int count = m_clientArea->GetRowCount();
wxDataViewColumn *column = GetColumn(idx); wxDataViewColumn *column = GetColumn(idx);
@@ -4795,7 +4795,7 @@ unsigned int wxDataViewCtrl::GetBestColumnWidth(int idx) const
if ( max_width > 0 ) if ( max_width > 0 )
max_width += 2 * PADDING_RIGHTLEFT; max_width += 2 * PADDING_RIGHTLEFT;
const_cast<wxDataViewCtrl*>(this)->m_colsBestWidths[idx] = max_width; const_cast<wxDataViewCtrl*>(this)->m_colsBestWidths[idx].width = max_width;
return max_width; return max_width;
} }
@@ -4840,12 +4840,14 @@ bool wxDataViewCtrl::ClearColumns()
void wxDataViewCtrl::InvalidateColBestWidth(int idx) void wxDataViewCtrl::InvalidateColBestWidth(int idx)
{ {
m_colsBestWidths[idx] = 0; m_colsBestWidths[idx].width = 0;
m_colsBestWidths[idx].dirty = true;
m_colsDirty = true; m_colsDirty = true;
} }
void wxDataViewCtrl::InvalidateColBestWidths() void wxDataViewCtrl::InvalidateColBestWidths()
{ {
// mark all columns as dirty:
m_colsBestWidths.clear(); m_colsBestWidths.clear();
m_colsBestWidths.resize(m_cols.size()); m_colsBestWidths.resize(m_cols.size());
m_colsDirty = true; m_colsDirty = true;
@@ -4853,14 +4855,27 @@ void wxDataViewCtrl::InvalidateColBestWidths()
void wxDataViewCtrl::UpdateColWidths() void wxDataViewCtrl::UpdateColWidths()
{ {
m_colsDirty = false;
if ( !m_headerArea ) if ( !m_headerArea )
return; return;
const unsigned len = m_colsBestWidths.size(); const unsigned len = m_colsBestWidths.size();
for ( unsigned i = 0; i < len; i++ ) for ( unsigned i = 0; i < len; i++ )
{ {
if ( m_colsBestWidths[i] == 0 ) // Note that we have to have an explicit 'dirty' flag here instead of
// checking if the width==0, as is done in GetBestColumnWidth().
//
// Testing width==0 wouldn't work correctly if some code called
// GetWidth() after col. width invalidation but before
// wxDataViewCtrl::UpdateColWidths() was called at idle time. This
// would result in the header's column width getting out of sync with
// the control itself.
if ( m_colsBestWidths[i].dirty )
{
m_headerArea->UpdateColumn(i); m_headerArea->UpdateColumn(i);
m_colsBestWidths[i].dirty = false;
}
} }
} }
@@ -4869,11 +4884,8 @@ void wxDataViewCtrl::OnInternalIdle()
wxDataViewCtrlBase::OnInternalIdle(); wxDataViewCtrlBase::OnInternalIdle();
if ( m_colsDirty ) if ( m_colsDirty )
{
m_colsDirty = false;
UpdateColWidths(); UpdateColWidths();
} }
}
int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const
{ {