Use virtual functions to convert NSObject to the correct type in wxDVC.

Instead of trying to determine the type of the value which should be extracted
from the NSObject we receive from NSOutlineView, just pass it to a virtual
method in the renderer which knows which type does it need.

This fixes the problem with editing boolean/checkbox columns and makes the
code more elegant.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62490 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2009-10-23 23:49:26 +00:00
parent 795dac4c86
commit 9461dd8c71
2 changed files with 160 additions and 40 deletions

View File

@ -85,7 +85,7 @@ public:
#if wxOSX_USE_COCOA
// called when a value was edited by user
virtual void OSXOnCellChanged(const wxVariant& value,
virtual void OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col);
#endif // Cocoa
@ -197,7 +197,12 @@ public:
//
virtual bool MacRender();
protected:
#if wxOSX_USE_COCOA
virtual void OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col);
#endif // Cocoa
private:
DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewTextRenderer)
};
@ -281,8 +286,7 @@ public:
virtual bool MacRender();
#if wxOSX_USE_COCOA
// called when a value was edited by user
virtual void OSXOnCellChanged(const wxVariant& value,
virtual void OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col);
#endif // Cocoa
@ -306,7 +310,12 @@ public:
//
virtual bool MacRender();
protected:
#if wxOSX_USE_COCOA
virtual void OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col);
#endif // Cocoa
private:
DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewToggleRenderer)
};
@ -326,7 +335,12 @@ public:
//
virtual bool MacRender();
protected:
#if wxOSX_USE_COCOA
virtual void OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col);
#endif // Cocoa
private:
DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewProgressRenderer)
};
@ -345,7 +359,12 @@ public:
//
virtual bool MacRender();
protected:
#if wxOSX_USE_COCOA
virtual void OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col);
#endif // Cocoa
private:
DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewDateRenderer)
};

View File

@ -84,6 +84,71 @@
namespace
{
// convert from NSObject to different C++ types: all these functions check
// that the conversion really makes sense and assert if it doesn't
wxString ObjectToString(NSObject *object)
{
wxCHECK_MSG( [object isKindOfClass:[NSString class]], "",
wxString::Format
(
"string expected but got %s",
wxCFStringRef::AsString([object className])
));
return wxCFStringRef([((NSString*) object) retain]).AsString();
}
bool ObjectToBool(NSObject *object)
{
// actually the value must be of NSCFBoolean class but it's private so we
// can't check for it directly
wxCHECK_MSG( [object isKindOfClass:[NSNumber class]], false,
wxString::Format
(
"number expected but got %s",
wxCFStringRef::AsString([object className])
));
return [(NSNumber *)object boolValue];
}
long ObjectToLong(NSObject *object)
{
wxCHECK_MSG( [object isKindOfClass:[NSNumber class]], -1,
wxString::Format
(
"number expected but got %s",
wxCFStringRef::AsString([object className])
));
return [(NSNumber *)object longValue];
}
wxDateTime ObjectToDate(NSObject *object)
{
wxCHECK_MSG( [object isKindOfClass:[NSDate class]], wxInvalidDateTime,
wxString::Format
(
"date expected but got %s",
wxCFStringRef::AsString([object className])
));
// get the number of seconds since 1970-01-01 UTC and this is the only
// way to convert a double to a wxLongLong
const wxLongLong seconds = [((NSDate*) object) timeIntervalSince1970];
wxDateTime dt(1, wxDateTime::Jan, 1970);
dt.Add(wxTimeSpan(0,0,seconds));
// the user has entered a date in the local timezone but seconds
// contains the number of seconds from date in the local timezone
// since 1970-01-01 UTC; therefore, the timezone information has to be
// transferred to wxWidgets, too:
dt.MakeFromTimezone(wxDateTime::UTC);
return dt;
}
NSInteger CompareItems(id item1, id item2, void* context)
{
NSArray* const sortDescriptors = (NSArray*) context;
@ -516,31 +581,8 @@ outlineView:(NSOutlineView*)outlineView
wxDataViewItem dataViewItem([((wxPointerObject*) item) pointer]);
wxVariant value;
if ( [object isKindOfClass:[NSString class]] )
value = wxCFStringRef([((NSString*) object) retain]).AsString();
else if ( [object isKindOfClass:[NSNumber class]] )
value = (long)[((NSNumber *)object) intValue];
else if ( [object isKindOfClass:[NSDate class]] )
{
// get the number of seconds since 1970-01-01 UTC and this is the only
// way to convert a double to a wxLongLong
const wxLongLong seconds = [((NSDate*) object) timeIntervalSince1970];
wxDateTime dt(1, wxDateTime::Jan, 1970);
dt.Add(wxTimeSpan(0,0,seconds));
// the user has entered a date in the local timezone but seconds
// contains the number of seconds from date in the local timezone
// since 1970-01-01 UTC; therefore, the timezone information has to be
// transferred to wxWidgets, too:
dt.MakeFromTimezone(wxDateTime::UTC);
value = dt;
}
col->GetRenderer()->
OSXOnCellChanged(value, dataViewItem, col->GetModelColumn());
OSXOnCellChanged(object, dataViewItem, col->GetModelColumn());
}
-(void) outlineView:(NSOutlineView*)outlineView sortDescriptorsDidChange:(NSArray*)oldDescriptors
@ -2231,10 +2273,35 @@ wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const
return GetNativeData()->GetEllipsizeMode();
}
void wxDataViewRenderer::OSXOnCellChanged(const wxVariant& value,
const wxDataViewItem& item,
unsigned col)
void
wxDataViewRenderer::OSXOnCellChanged(NSObject *object,
const wxDataViewItem& item,
unsigned col)
{
// TODO: we probably should get rid of this code entirely and make this
// function pure virtual, but currently we still have some native
// renderers (wxDataViewChoiceRenderer) which don't override it and
// there is also wxDataViewCustomRenderer for which it's not obvious
// how it should be implemented so keep this "auto-deduction" of
// variant type from NSObject for now
wxVariant value;
if ( [object isKindOfClass:[NSString class]] )
value = ObjectToString(object);
else if ( [object isKindOfClass:[NSNumber class]] )
value = ObjectToLong(object);
else if ( [object isKindOfClass:[NSDate class]] )
value = ObjectToDate(object);
else
{
wxFAIL_MSG( wxString::Format
(
"unknown value type %s",
wxCFStringRef::AsString([object className])
));
return;
}
wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
model->ChangeValue(value, item, col);
}
@ -2293,6 +2360,15 @@ bool wxDataViewTextRenderer::MacRender()
}
}
void
wxDataViewTextRenderer::OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col)
{
wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
model->ChangeValue(ObjectToString(value), item, col);
}
IMPLEMENT_CLASS(wxDataViewTextRenderer,wxDataViewRenderer)
// ---------------------------------------------------------
@ -2434,6 +2510,15 @@ bool wxDataViewDateRenderer::MacRender()
}
}
void
wxDataViewDateRenderer::OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col)
{
wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
model->ChangeValue(ObjectToDate(value), item, col);
}
IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer,wxDataViewRenderer)
// ---------------------------------------------------------
@ -2476,17 +2561,15 @@ bool wxDataViewIconTextRenderer::MacRender()
}
void
wxDataViewIconTextRenderer::OSXOnCellChanged(const wxVariant& value,
wxDataViewIconTextRenderer::OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col)
{
// we receive just the text (because it's the only component which can be
// edited by user) from the native control but we need wxDataViewIconText
// for the model, so construct it here
wxVariant valueIconText;
valueIconText << wxDataViewIconText(value.GetString());
valueIconText << wxDataViewIconText(ObjectToString(value));
wxDataViewRenderer::OSXOnCellChanged(valueIconText, item, col);
wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
model->ChangeValue(valueIconText, item, col);
}
IMPLEMENT_ABSTRACT_CLASS(wxDataViewIconTextRenderer,wxDataViewRenderer)
@ -2524,6 +2607,15 @@ bool wxDataViewToggleRenderer::MacRender()
}
}
void
wxDataViewToggleRenderer::OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col)
{
wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
model->ChangeValue(ObjectToBool(value), item, col);
}
IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer,wxDataViewRenderer)
// ---------------------------------------------------------
@ -2558,6 +2650,15 @@ bool wxDataViewProgressRenderer::MacRender()
}
}
void
wxDataViewProgressRenderer::OSXOnCellChanged(NSObject *value,
const wxDataViewItem& item,
unsigned col)
{
wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
model->ChangeValue(ObjectToLong(value), item, col);
}
IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer,wxDataViewRenderer)
// ---------------------------------------------------------