ensure row >= GetRowCount() if GetLineAt reaches invalid item

refactored method structure for better readability
This commit is contained in:
jensgoe
2018-12-19 20:45:00 +01:00
parent 1f0e32e485
commit 7ab9e992b6
2 changed files with 56 additions and 48 deletions

View File

@@ -134,6 +134,7 @@ public:
bool GetLineStart(unsigned int row, int& start); bool GetLineStart(unsigned int row, int& start);
bool GetLineHeight(unsigned int row, int& height); bool GetLineHeight(unsigned int row, int& height);
bool GetLineAt(int y, unsigned int& row); bool GetLineAt(int y, unsigned int& row);
bool GetLineInfo(unsigned int row, int &start, int &height);
void Put(unsigned int row, int height); void Put(unsigned int row, int height);
@@ -146,8 +147,6 @@ public:
void Clear(); void Clear();
private: private:
bool GetLineInfo(unsigned int row, int &start, int &height);
HeightToRowRangesMap m_heightToRowRange; HeightToRowRangesMap m_heightToRowRange;
}; };

View File

@@ -3346,8 +3346,10 @@ wxRect wxDataViewMainWindow::GetLinesRect( unsigned int rowFrom, unsigned int ro
int wxDataViewMainWindow::GetLineStart( unsigned int row ) const int wxDataViewMainWindow::GetLineStart( unsigned int row ) const
{ {
if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT) // check for the easy case first
{ if (!GetOwner()->HasFlag(wxDV_VARIABLE_LINE_HEIGHT))
return row * m_lineHeight;
int start = 0; int start = 0;
if ( m_rowHeightCache->GetLineStart(row, start) ) if ( m_rowHeightCache->GetLineStart(row, start) )
return start; return start;
@@ -3356,27 +3358,20 @@ int wxDataViewMainWindow::GetLineStart( unsigned int row ) const
for (r = 0; r < row; r++) for (r = 0; r < row; r++)
{ {
int height = 0; int height = 0;
if ( m_rowHeightCache->GetLineHeight(r, height) ) if ( !m_rowHeightCache->GetLineHeight(r, height) )
{ {
start += height; // row height not in cache -> get it from the renderer...
continue;
}
wxDataViewItem item = GetItemByRow(r); wxDataViewItem item = GetItemByRow(r);
if ( !item ) if (!item)
break; break;
height = QueryAndCacheLineHeight(r, item); height = QueryAndCacheLineHeight(r, item);
}
start += height; start += height;
} }
return start; return start;
}
else
{
return row * m_lineHeight;
}
} }
int wxDataViewMainWindow::GetLineAt( unsigned int y ) const int wxDataViewMainWindow::GetLineAt( unsigned int y ) const
@@ -3386,37 +3381,57 @@ int wxDataViewMainWindow::GetLineAt( unsigned int y ) const
return y / m_lineHeight; return y / m_lineHeight;
unsigned int row = 0; unsigned int row = 0;
unsigned int yy = 0;
if ( m_rowHeightCache->GetLineAt(y, row) ) if ( m_rowHeightCache->GetLineAt(y, row) )
return row; return row;
// OnPaint asks GetLineAt for the very last y position and this is always
// below the last item (--> an invalid item). To prevent iterating over all
// items, check if y is below the last row.
// Because this is done very often (for each repaint) its worth to handle
// this special case separately.
int height = 0;
int start = 0;
unsigned int rowCount = GetRowCount();
if (rowCount == 0 ||
(m_rowHeightCache->GetLineInfo(rowCount - 1, start, height) &&
y >= start + height))
{
return rowCount;
}
// sum all item heights until y is reached
unsigned int yy = 0;
for (;;) for (;;)
{ {
int height = 0; height = 0;
if ( !m_rowHeightCache->GetLineHeight(row, height) ) if ( !m_rowHeightCache->GetLineHeight(row, height) )
{ {
// row height not in cache -> get it from the renderer... // row height not in cache -> get it from the renderer...
wxDataViewItem item = GetItemByRow(row); wxDataViewItem item = GetItemByRow(row);
if ( !item ) if ( !item )
return row; // should be the last row {
wxASSERT(row >= GetRowCount());
break;
}
height = QueryAndCacheLineHeight(row, item); height = QueryAndCacheLineHeight(row, item);
} }
yy += height; yy += height;
if (y < yy) if (y < yy)
return row; break;
row++; row++;
} }
return row;
} }
int wxDataViewMainWindow::GetLineHeight( unsigned int row ) const int wxDataViewMainWindow::GetLineHeight( unsigned int row ) const
{ {
if (GetOwner()->GetWindowStyle() & wxDV_VARIABLE_LINE_HEIGHT) // check for the easy case first
{ if (!GetOwner()->HasFlag(wxDV_VARIABLE_LINE_HEIGHT))
return m_lineHeight;
int height = 0; int height = 0;
if ( m_rowHeightCache->GetLineHeight(row, height) ) if ( m_rowHeightCache->GetLineHeight(row, height) )
return height; return height;
@@ -3427,14 +3442,8 @@ int wxDataViewMainWindow::GetLineHeight( unsigned int row ) const
height = QueryAndCacheLineHeight(row, item); height = QueryAndCacheLineHeight(row, item);
return height; return height;
}
else
{
return m_lineHeight;
}
} }
int wxDataViewMainWindow::QueryAndCacheLineHeight(unsigned int row, wxDataViewItem item) const int wxDataViewMainWindow::QueryAndCacheLineHeight(unsigned int row, wxDataViewItem item) const
{ {
const wxDataViewModel *model = GetModel(); const wxDataViewModel *model = GetModel();