Merge branch 'dvc-null-values'

Improve handling of null values in wxDataViewCtrl to be more compatible
with the earlier versions.

See https://github.com/wxWidgets/wxWidgets/pull/2602

See #18934.

Closes #19333.
This commit is contained in:
Vadim Zeitlin 2021-12-09 20:00:50 +01:00
commit 933ac7afbb
7 changed files with 70 additions and 28 deletions

View File

@ -268,7 +268,17 @@ public:
/**
Override this to indicate the value of @a item.
A wxVariant is used to store the data.
This function should fill the provided @a variant with the value to be
shown for the specified item in the given column. The value returned in
this wxVariant must have the appropriate type, e.g. string for the text
columns, boolean for the columns using wxDataViewToggleRenderer etc,
and if there is a type mismatch, nothing will be shown and a debug
error message will be logged.
It is also possible to not return any value, in which case nothing will
be shown in the corresponding cell, in the same way as if HasValue()
returned @false.
*/
virtual void GetValue(wxVariant& variant, const wxDataViewItem& item,
unsigned int col) const = 0;

View File

@ -40,6 +40,8 @@ MyMusicTreeModel::MyMusicTreeModel()
m_pop = new MyMusicTreeModelNode( m_root, "Pop music" );
m_pop->Append(
new MyMusicTreeModelNode( m_pop, "You are not alone", "Michael Jackson", 1995 ) );
m_pop->Append(
new MyMusicTreeModelNode( m_pop, "Yesterday", "The Beatles", -1 /* not specified */ ) );
m_pop->Append(
new MyMusicTreeModelNode( m_pop, "Take a bow", "Madonna", 1994 ) );
m_root->Append( m_pop );
@ -193,7 +195,8 @@ void MyMusicTreeModel::GetValue( wxVariant &variant,
variant = node->m_artist;
break;
case 2:
variant = (long) node->m_year;
if (node->m_year != -1)
variant = (long) node->m_year;
break;
case 3:
variant = node->m_quality;
@ -202,7 +205,9 @@ void MyMusicTreeModel::GetValue( wxVariant &variant,
variant = 80L; // all music is very 80% popular
break;
case 5:
if (GetYear(item) < 1900)
if (node->m_year == -1)
variant = "n/a";
else if (node->m_year < 1900)
variant = "old";
else
variant = "new";
@ -248,7 +253,16 @@ bool MyMusicTreeModel::IsEnabled( const wxDataViewItem &item,
MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
// disable Beethoven's ratings, his pieces can only be good
return !(col == 3 && node->m_artist.EndsWith("Beethoven"));
if (col == 3 && node->m_artist.EndsWith("Beethoven"))
return false;
// also disable editing the year when it's not specified, this doesn't work
// because the editor needs some initial value
if (col == 2 && node->m_year == -1)
return false;
// otherwise allow editing
return true;
}
wxDataViewItem MyMusicTreeModel::GetParent( const wxDataViewItem &item ) const

View File

@ -26,7 +26,7 @@ class MyMusicTreeModelNode
public:
MyMusicTreeModelNode( MyMusicTreeModelNode* parent,
const wxString &title, const wxString &artist,
unsigned int year )
int year )
{
m_parent = parent;

View File

@ -913,16 +913,15 @@ wxDataViewRendererBase::PrepareForItem(const wxDataViewModel *model,
// empty cells.
SetEnabled(model->IsEnabled(item, column));
return !value.IsNull();
}
wxCATCH_ALL
(
// There is not much we can do about it here, just log it and don't
// show anything in this cell.
wxLogDebug("Retrieving the value from the model threw an exception");
SetValue(wxVariant());
return false;
)
return true;
}

View File

@ -2463,14 +2463,15 @@ wxBitmap wxDataViewMainWindow::CreateItemBitmap( unsigned int row, int &indent )
width -= indent;
wxDataViewItem item = GetItemByRow( row );
cell->PrepareForItem(model, item, column->GetModelColumn());
if ( cell->PrepareForItem(model, item, column->GetModelColumn()) )
{
wxRect item_rect(x, 0, width, height);
item_rect.Deflate(PADDING_RIGHTLEFT, 0);
wxRect item_rect(x, 0, width, height);
item_rect.Deflate(PADDING_RIGHTLEFT, 0);
// dc.SetClippingRegion( item_rect );
cell->WXCallRender(item_rect, &dc, 0);
// dc.DestroyClippingRegion();
// dc.SetClippingRegion( item_rect );
cell->WXCallRender(item_rect, &dc, 0);
// dc.DestroyClippingRegion();
}
x += width;
}
@ -2836,7 +2837,7 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
cell->SetState(state);
if (hasValue)
cell->PrepareForItem(model, dataitem, col->GetModelColumn());
hasValue = cell->PrepareForItem(model, dataitem, col->GetModelColumn());
// draw the background
if ( !selected )
@ -3789,9 +3790,8 @@ int wxDataViewMainWindow::QueryAndCacheLineHeight(unsigned int row, wxDataViewIt
wxDataViewRenderer *renderer =
const_cast<wxDataViewRenderer*>(column->GetRenderer());
renderer->PrepareForItem(model, item, column->GetModelColumn());
height = wxMax(height, renderer->GetSize().y);
if ( renderer->PrepareForItem(model, item, column->GetModelColumn()) )
height = wxMax(height, renderer->GetSize().y);
}
// ... and store the height in the cache
@ -5998,8 +5998,8 @@ public:
if ( m_model->HasValue(item, GetColumn()) )
{
m_renderer->PrepareForItem(m_model, item, GetColumn());
width += m_renderer->GetSize().x;
if ( m_renderer->PrepareForItem(m_model, item, GetColumn()) )
width += m_renderer->GetSize().x;
}
UpdateWithWidth(width);
@ -6747,7 +6747,9 @@ wxAccStatus wxDataViewCtrlAccessible::GetName(int childId, wxString* name)
continue; // Skip non-textual items
wxDataViewRenderer* r = dvCol->GetRenderer();
r->PrepareForItem(model, item, dvCol->GetModelColumn());
if ( !r->PrepareForItem(model, item, dvCol->GetModelColumn()) )
continue;
wxString vs = r->GetAccessibleDescription();
if ( !vs.empty() )
{
@ -6905,7 +6907,9 @@ wxAccStatus wxDataViewCtrlAccessible::GetDescription(int childId, wxString* desc
model->GetValue(value, item, dvCol->GetModelColumn());
wxDataViewRenderer* r = dvCol->GetRenderer();
r->PrepareForItem(model, item, dvCol->GetModelColumn());
if ( !r->PrepareForItem(model, item, dvCol->GetModelColumn()) )
continue;
wxString valStr = r->GetAccessibleDescription();
// Skip first textual item
if ( !firstTextSkipped && !value.IsNull() && !value.IsType(wxS("bool")) && !valStr.empty() )

View File

@ -3171,6 +3171,14 @@ gtk_dataview_header_button_press_callback( GtkWidget *WXUNUSED(widget),
return FALSE;
}
// Helper for wxGtkTreeCellDataFunc() below.
static void wxGtkTreeSetVisibleProp(GtkCellRenderer *renderer, gboolean visible)
{
wxGtkValue gvalue( G_TYPE_BOOLEAN );
g_value_set_boolean( gvalue, visible );
g_object_set_property( G_OBJECT(renderer), "visible", gvalue );
}
extern "C"
{
@ -3200,16 +3208,22 @@ static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column),
if (!wx_model->IsVirtualListModel())
{
gboolean visible = wx_model->HasValue(item, column);
wxGtkValue gvalue( G_TYPE_BOOLEAN );
g_value_set_boolean( gvalue, visible );
g_object_set_property( G_OBJECT(renderer), "visible", gvalue );
wxGtkTreeSetVisibleProp(renderer, visible);
if ( !visible )
return;
}
cell->GtkSetCurrentItem(item);
cell->PrepareForItem(wx_model, item, column);
if (!cell->PrepareForItem(wx_model, item, column))
{
// We don't have any value in this cell, after all, so hide it.
if (!wx_model->IsVirtualListModel())
{
wxGtkTreeSetVisibleProp(renderer, FALSE);
}
}
}
} // extern "C"

View File

@ -626,7 +626,8 @@ outlineView:(NSOutlineView*)outlineView
{
wxVariant value;
model->GetValue(value,dataViewItem, colIdx);
col->GetRenderer()->SetValue(value);
if ( !value.IsNull() )
col->GetRenderer()->SetValue(value);
}
return nil;