// it until the matching DecRef() is called
void IncRef() { m_nRef++; }
void DecRef() { if ( !--m_nRef ) delete this; }
+ void SafeIncRef() { if ( this ) IncRef(); }
void SafeDecRef() { if ( this ) DecRef(); }
// setters
// doesn't have any yet or the existing one if it does
//
// DecRef() must be called on the returned pointer, as usual
+ wxGridCellAttr *GetOrCreateCellAttr(int row, int col) const;
+
+ // cell attribute cache (currently we only cache 1, may be will do
+ // more/better later)
+ struct CachedAttr
+ {
+ int row, col;
+ wxGridCellAttr *attr;
+ } m_attrCache;
+
+ // invalidates the attribute cache
+ void ClearAttrCache();
+
+ // adds an attribute to cache
+ void CacheAttr(int row, int col, wxGridCellAttr *attr) const;
+
+ // looks for an attr in cache, returns TRUE if found
+ bool LookupAttr(int row, int col, wxGridCellAttr **attr) const;
+
+ // looks for the attr in cache, if not found asks the table and caches the
+ // result
wxGridCellAttr *GetCellAttr(int row, int col) const;
wxGridCellCoordsArray m_cellsExposed;
#define WXGRID_DRAW_LINES 1
#endif
-//////////////////////////////////////////////////////////////////////
+// ----------------------------------------------------------------------------
+// globals
+// ----------------------------------------------------------------------------
+
+//#define DEBUG_ATTR_CACHE
+#ifdef DEBUG_ATTR_CACHE
+ static size_t gs_nAttrCacheHits = 0;
+ static size_t gs_nAttrCacheMisses = 0;
+#endif // DEBUG_ATTR_CACHE
wxGridCellCoords wxGridNoCellCoords( -1, -1 );
wxRect wxGridNoCellRect( -1, -1, -1, -1 );
wxGrid::~wxGrid()
{
+ ClearAttrCache();
+
+#ifdef DEBUG_ATTR_CACHE
+ size_t total = gs_nAttrCacheHits + gs_nAttrCacheMisses;
+ wxPrintf(_T("wxGrid attribute cache statistics: "
+ "total: %u, hits: %u (%u%%)\n"),
+ total, gs_nAttrCacheHits,
+ total ? (gs_nAttrCacheHits*100) / total : 0);
+#endif
+
delete m_defaultRenderer;
delete m_table;
}
m_labelTextColour = wxColour( _T("BLACK") );
+ // init attr cache
+ m_attrCache.row = -1;
+
// TODO: something better than this ?
//
m_labelFont = this->GetFont();
// access to cell attributes
// ----------------------------------------------------------------------------
-// TODO VZ: we must cache the attr to allow only retrieveing it once!
-
wxColour wxGrid::GetCellBackgroundColour(int row, int col)
{
- wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
+ wxGridCellAttr *attr = GetCellAttr(row, col);
wxColour colour;
if ( attr && attr->HasBackgroundColour() )
wxColour wxGrid::GetCellTextColour( int row, int col )
{
- wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
+ wxGridCellAttr *attr = GetCellAttr(row, col);
wxColour colour;
if ( attr && attr->HasTextColour() )
wxFont wxGrid::GetCellFont( int row, int col )
{
- wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
+ wxGridCellAttr *attr = GetCellAttr(row, col);
wxFont font;
if ( attr && attr->HasFont() )
void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert )
{
- wxGridCellAttr *attr = m_table ? m_table->GetAttr(row, col) : NULL;
+ wxGridCellAttr *attr = GetCellAttr(row, col);
if ( attr && attr->HasAlignment() )
attr->GetAlignment(horiz, vert);
return TRUE;
}
+void wxGrid::ClearAttrCache()
+{
+ if ( m_attrCache.row != -1 )
+ {
+ m_attrCache.attr->SafeDecRef();
+ m_attrCache.row = -1;
+ }
+}
+
+void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
+{
+ wxGrid *self = (wxGrid *)this; // const_cast
+
+ self->ClearAttrCache();
+ self->m_attrCache.row = row;
+ self->m_attrCache.col = col;
+ self->m_attrCache.attr = attr;
+ attr->SafeIncRef();
+}
+
+bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
+{
+ if ( row == m_attrCache.row && col == m_attrCache.col )
+ {
+ *attr = m_attrCache.attr;
+ (*attr)->SafeIncRef();
+
+#ifdef DEBUG_ATTR_CACHE
+ gs_nAttrCacheHits++;
+#endif
+
+ return TRUE;
+ }
+ else
+ {
+#ifdef DEBUG_ATTR_CACHE
+ gs_nAttrCacheMisses++;
+#endif
+ return FALSE;
+ }
+}
+
wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
{
- wxGridCellAttr *attr = m_table->GetAttr(row, col);
- if ( !attr )
+ wxGridCellAttr *attr;
+ if ( !LookupAttr(row, col, &attr) )
{
- attr = new wxGridCellAttr;
+ attr = m_table ? m_table->GetAttr(row, col) : (wxGridCellAttr *)NULL;
+ CacheAttr(row, col, attr);
+ }
- // artificially inc the ref count to match DecRef() in caller
- attr->IncRef();
+ return attr;
+}
+
+wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
+{
+ wxGridCellAttr *attr;
+ if ( !LookupAttr(row, col, &attr) || !attr )
+ {
+ wxASSERT_MSG( m_table,
+ _T("we may only be called if CanHaveAttributes() "
+ "returned TRUE and then m_table should be !NULL") );
+
+ attr = m_table->GetAttr(row, col);
+ if ( !attr )
+ {
+ attr = new wxGridCellAttr;
+
+ // artificially inc the ref count to match DecRef() in caller
+ attr->IncRef();
+
+ m_table->SetAttr(attr, row, col);
+ }
- m_table->SetAttr(attr, row, col);
+ CacheAttr(row, col, attr);
}
return attr;
{
if ( CanHaveAttributes() )
{
- wxGridCellAttr *attr = GetCellAttr(row, col);
+ wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
attr->SetBackgroundColour(colour);
attr->DecRef();
}
{
if ( CanHaveAttributes() )
{
- wxGridCellAttr *attr = GetCellAttr(row, col);
+ wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
attr->SetTextColour(colour);
attr->DecRef();
}
{
if ( CanHaveAttributes() )
{
- wxGridCellAttr *attr = GetCellAttr(row, col);
+ wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
attr->SetFont(font);
attr->DecRef();
}
{
if ( CanHaveAttributes() )
{
- wxGridCellAttr *attr = GetCellAttr(row, col);
+ wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
attr->SetAlignment(horiz, vert);
attr->DecRef();
}
{
if ( CanHaveAttributes() )
{
- wxGridCellAttr *attr = GetCellAttr(row, col);
+ wxGridCellAttr *attr = GetOrCreateCellAttr(row, col);
attr->SetRenderer(renderer);
attr->DecRef();
}