Consistently check for type mismatch in all ports in wxDataViewCtrl.

Move the checks for the type mismatch between the type of the value returned
by wxDataViewModel and the type expected by wxDataViewRenderer into common
code. This avoids duplicating the same code in wxGTK and wxOSX and, more
importantly, means that this check is also performed in wxMSW when using the
generic version, so that the problems such as the one fixed in 3ff8c3c ("add
missing wxDataViewDateRenderer::GetDefaultType()") would be visible there too.
This commit is contained in:
Vadim Zeitlin
2015-08-28 23:58:10 +02:00
parent e8647b4751
commit a49567109a
5 changed files with 78 additions and 41 deletions

View File

@@ -121,7 +121,27 @@ public:
wxString GetVariantType() const { return m_variantType; } wxString GetVariantType() const { return m_variantType; }
// helper that calls SetValue and SetAttr: // Prepare for rendering the value of the corresponding item in the given
// column taken from the provided non-null model.
//
// Notice that the column must be the same as GetOwner()->GetModelColumn(),
// it is only passed to this method because the existing code already has
// it and should probably be removed in the future.
//
// Returns false if the value is missing (or invalid, i.e. has a wrong type
// differing from GetVariantType() of this renderer, in which case a debug
// error is also logged as it indicates an error in the user code).
bool PrepareValue(const wxDataViewModel* model,
const wxDataViewItem& item,
unsigned column);
// Prepare for rendering the given item by both calling PrepareValue() and
// setting up the attributes.
//
// This is currently only used in the generic version but should really be
// used everywhere, i.e. SetEnabled() and SetAttr() should be overridden in
// the native versions instead of adding platform-specific equivalents for
// them as it's done currently.
void PrepareForItem(const wxDataViewModel *model, void PrepareForItem(const wxDataViewModel *model,
const wxDataViewItem& item, unsigned column); const wxDataViewItem& item, unsigned column);
@@ -178,6 +198,12 @@ protected:
// Called from {Cancel,Finish}Editing() to cleanup m_editorCtrl // Called from {Cancel,Finish}Editing() to cleanup m_editorCtrl
void DestroyEditControl(); void DestroyEditControl();
// Helper of PrepareValue() also used in StartEditing(): returns the value
// checking that its type matches our GetVariantType().
wxVariant CheckedGetValue(const wxDataViewModel* model,
const wxDataViewItem& item,
unsigned column) const;
wxString m_variantType; wxString m_variantType;
wxDataViewColumn *m_owner; wxDataViewColumn *m_owner;
wxWeakRef<wxWindow> m_editorCtrl; wxWeakRef<wxWindow> m_editorCtrl;

View File

@@ -683,8 +683,7 @@ bool wxDataViewRendererBase::StartEditing( const wxDataViewItem &item, wxRect la
m_item = item; // remember for later m_item = item; // remember for later
unsigned int col = GetOwner()->GetModelColumn(); unsigned int col = GetOwner()->GetModelColumn();
wxVariant value; const wxVariant& value = CheckedGetValue(dv_ctrl->GetModel(), item, col);
dv_ctrl->GetModel()->GetValue( value, item, col );
m_editorCtrl = CreateEditorCtrl( dv_ctrl->GetMainWindow(), labelRect, value ); m_editorCtrl = CreateEditorCtrl( dv_ctrl->GetMainWindow(), labelRect, value );
@@ -778,13 +777,57 @@ bool wxDataViewRendererBase::FinishEditing()
return false; return false;
} }
wxVariant
wxDataViewRendererBase::CheckedGetValue(const wxDataViewModel* model,
const wxDataViewItem& item,
unsigned column) const
{
wxVariant value;
model->GetValue(value, item, column);
// We always allow the cell to be null, regardless of the renderer type.
if ( !value.IsNull() )
{
if ( value.GetType() != GetVariantType() )
{
// If you're seeing this message, this indicates that either your
// renderer is using the wrong type, or your model returns values
// of the wrong type.
wxLogDebug("Wrong type returned from the model for column %u: "
"%s required but actual type is %s",
column,
GetVariantType(),
value.GetType());
// Don't return data of mismatching type, this could be unexpected.
value.MakeNull();
}
}
return value;
}
bool
wxDataViewRendererBase::PrepareValue(const wxDataViewModel* model,
const wxDataViewItem& item,
unsigned column)
{
const wxVariant& value = CheckedGetValue(model, item, column);
if ( value.IsNull() )
return false;
SetValue(value);
return true;
}
void wxDataViewRendererBase::PrepareForItem(const wxDataViewModel *model, void wxDataViewRendererBase::PrepareForItem(const wxDataViewModel *model,
const wxDataViewItem& item, const wxDataViewItem& item,
unsigned column) unsigned column)
{ {
wxVariant value; if ( !PrepareValue(model, item, column) )
model->GetValue(value, item, column); return;
SetValue(value);
wxDataViewItemAttr attr; wxDataViewItemAttr attr;
model->GetAttr(item, column, attr); model->GetAttr(item, column, attr);

View File

@@ -2923,23 +2923,7 @@ static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column),
return; return;
} }
wxVariant value; cell->PrepareValue(wx_model, item, column);
wx_model->GetValue( value, item, column );
// It is always possible to leave a cell empty, don't warn about type
// mismatch in this case.
if (!value.IsNull())
{
if (value.GetType() != cell->GetVariantType())
{
wxLogDebug("Wrong type returned from the model: "
"%s required but actual type is %s",
cell->GetVariantType(),
value.GetType());
}
}
cell->SetValue( value );
// deal with disabled items // deal with disabled items
bool enabled = wx_model->IsEnabled( item, column ); bool enabled = wx_model->IsEnabled( item, column );

View File

@@ -1410,7 +1410,6 @@ OSStatus wxMacDataViewDataBrowserListViewControl::DataBrowserGetSetItemDataProc(
if (propertyID >= kMinPropertyID) // in case data columns set the data if (propertyID >= kMinPropertyID) // in case data columns set the data
{ {
// variable definitions: // variable definitions:
wxVariant variant;
wxDataViewColumn* dataViewColumnPtr; wxDataViewColumn* dataViewColumnPtr;
wxDataViewCtrl* dataViewCtrlPtr; wxDataViewCtrl* dataViewCtrlPtr;
@@ -1420,11 +1419,9 @@ OSStatus wxMacDataViewDataBrowserListViewControl::DataBrowserGetSetItemDataProc(
dataViewColumnPtr = GetColumnPtr(propertyID); dataViewColumnPtr = GetColumnPtr(propertyID);
wxCHECK_MSG(dataViewColumnPtr != NULL,errDataBrowserNotConfigured,_("No column for the specified column position existing.")); wxCHECK_MSG(dataViewColumnPtr != NULL,errDataBrowserNotConfigured,_("No column for the specified column position existing."));
wxCHECK_MSG(dataViewColumnPtr->GetRenderer() != NULL,errDataBrowserNotConfigured,_("No renderer specified for column.")); wxCHECK_MSG(dataViewColumnPtr->GetRenderer() != NULL,errDataBrowserNotConfigured,_("No renderer specified for column."));
dataViewCtrlPtr->GetModel()->GetValue(variant,wxDataViewItem(reinterpret_cast<void*>(itemID)),dataViewColumnPtr->GetModelColumn()); if (dataViewColumnPtr->GetRenderer()->PrepareValue(dataViewCtrlPtr->GetModel(),wxDataViewItem(reinterpret_cast<void*>(itemID)),dataViewColumnPtr->GetModelColumn()))
if (!(variant.IsNull()))
{ {
dataViewColumnPtr->GetRenderer()->GetNativeData()->SetItemDataRef(itemData); dataViewColumnPtr->GetRenderer()->GetNativeData()->SetItemDataRef(itemData);
dataViewColumnPtr->GetRenderer()->SetValue(variant);
wxCHECK_MSG(dataViewColumnPtr->GetRenderer()->MacRender(),errDataBrowserNotConfigured,_("Rendering failed.")); wxCHECK_MSG(dataViewColumnPtr->GetRenderer()->MacRender(),errDataBrowserNotConfigured,_("Rendering failed."));
} }
return noErr; return noErr;

View File

@@ -1814,26 +1814,13 @@ outlineView:(NSOutlineView*)outlineView
renderer->OSXApplyEnabled(enabled); renderer->OSXApplyEnabled(enabled);
// check if we have anything to render // check if we have anything to render
wxVariant value; if ( !renderer->PrepareValue(model, dvItem, colIdx) )
model->GetValue(value, dvItem, colIdx);
if ( value.IsNull() )
{ {
// for consistency with the generic implementation, just handle missing // for consistency with the generic implementation, just handle missing
// values as blank // values as blank
return; return;
} }
if ( value.GetType() != renderer->GetVariantType() )
{
wxLogDebug("Wrong type returned from the model: "
"%s required but actual type is %s",
renderer->GetVariantType(),
value.GetType());
// we can't use the value of wrong type
return;
}
// use the attributes: notice that we need to do this whether we have them // use the attributes: notice that we need to do this whether we have them
// or not as even if this cell doesn't have any attributes, the previous // or not as even if this cell doesn't have any attributes, the previous
// one might have had some and then we need to reset them back to default // one might have had some and then we need to reset them back to default