]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/cocoa/dataview.mm
Fix bug in wxMBConv_cf::FromWChar() in OS X.
[wxWidgets.git] / src / osx / cocoa / dataview.mm
index c5b3635ad9d0c936f6767eea23b9263209227fd0..be4074a36e004b33f7b43b4d08f0618697c7ae43 100644 (file)
@@ -21,8 +21,8 @@
     #include "wx/utils.h"
 #endif
 
-#include "wx/osx/cocoa/dataview.h"
 #include "wx/osx/private.h"
+#include "wx/osx/cocoa/dataview.h"
 #include "wx/renderer.h"
 
 // ============================================================================
 // ============================================================================
 // Classes used locally in dataview.mm
 // ============================================================================
+
+// ============================================================================
+// wxPointerObject
+// ============================================================================
+
+@implementation wxPointerObject
+
+-(id) init
+{
+    self = [super init];
+    if (self != nil)
+        self->pointer = NULL;
+    return self;
+}
+
+-(id) initWithPointer:(void*) initPointer
+{
+    self = [super init];
+    if (self != nil)
+        self->pointer = initPointer;
+    return self;
+}
+
+//
+// inherited methods from NSObject
+//
+-(BOOL) isEqual:(id)object
+{
+    return (object != nil) &&
+             ([object isKindOfClass:[wxPointerObject class]]) &&
+                 (pointer == [((wxPointerObject*) object) pointer]);
+}
+
+-(NSUInteger) hash
+{
+    return (NSUInteger) pointer;
+}
+
+-(void*) pointer
+{
+    return pointer;
+}
+
+-(void) setPointer:(void*) newPointer
+{
+    pointer = newPointer;
+}
+
+@end
+
+namespace
+{
+
+inline wxDataViewItem wxDataViewItemFromItem(id item)
+{
+    return wxDataViewItem([static_cast<wxPointerObject *>(item) pointer]);
+}
+
+inline wxDataViewItem wxDataViewItemFromMaybeNilItem(id item)
+{
+    return item == nil ? wxDataViewItem() : wxDataViewItemFromItem(item);
+}
+
+} // anonymous namespace
+
+// ----------------------------------------------------------------------------
+// wxCustomRendererObject
+// ----------------------------------------------------------------------------
+
 @interface wxCustomRendererObject : NSObject <NSCopying>
 {
 @public
 }
 @end
 
+// ----------------------------------------------------------------------------
+// wxDVCNSTableColumn: exists only to override NSTableColumn:dataCellForRow:
+// ----------------------------------------------------------------------------
+
+@interface wxDVCNSTableColumn : NSTableColumn
+{
+}
+
+    -(id) dataCellForRow:(NSInteger)row;
+@end
+
+@implementation wxDVCNSTableColumn
+
+-(id) dataCellForRow:(NSInteger)row
+{
+    // what we want to do here is to simply return nil for the cells which
+    // shouldn't show anything as otherwise we would show e.g. empty combo box
+    // or progress cells in the columns using the corresponding types even for
+    // the container rows which is wrong
+
+    // half of the problem is just finding the objects we need from the column
+    // pointer which is itself stashed inside wxPointerObject which we use as
+    // our identifier
+    const wxDataViewColumn * const
+        dvCol = static_cast<wxDataViewColumn *>(
+                    [(wxPointerObject *)[self identifier] pointer]
+                );
+
+    const wxDataViewCtrl * const dvc = dvCol->GetOwner();
+    const wxCocoaDataViewControl * const
+        peer = static_cast<wxCocoaDataViewControl *>(dvc->GetPeer());
+
+
+    // once we do have everything, simply ask NSOutlineView for the item...
+    const id item = peer->GetItemAtRow(row);
+    if ( item )
+    {
+        // ... and if it succeeded, ask the model whether it has any value
+        wxDataViewItem dvItem(wxDataViewItemFromItem(item));
+
+        if ( !dvc->GetModel()->HasValue(dvItem, dvCol->GetModelColumn()) )
+            return nil;
+    }
+
+    return [super dataCellForRow:row];
+}
+
+@end
+
 // ============================================================================
 // local helpers
 // ============================================================================
 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;
@@ -93,15 +276,14 @@ NSInteger CompareItems(id item1, id item2, void* context)
     NSInteger result = NSOrderedSame;
     for ( NSUInteger i = 0; i < count && result == NSOrderedSame; ++i )
     {
-        // constant definition for abbreviational purposes:
         wxSortDescriptorObject* const
             sortDescriptor = (wxSortDescriptorObject*)
                 [sortDescriptors objectAtIndex:i];
 
         int rc = [sortDescriptor modelPtr]->Compare
                  (
-                     wxDataViewItem([((wxPointerObject*) item1) pointer]),
-                     wxDataViewItem([((wxPointerObject*) item2) pointer]),
+                     wxDataViewItemFromItem(item1),
+                     wxDataViewItemFromItem(item2),
                      [sortDescriptor columnPtr]->GetModelColumn(),
                      [sortDescriptor ascending] == YES
                  );
@@ -131,27 +313,34 @@ NSTableColumn* CreateNativeColumn(const wxDataViewColumn *column)
 
     wxCHECK_MSG( renderer, NULL, "column should have a renderer" );
 
-    NSTableColumn * const nativeColumn(
-        [[NSTableColumn alloc] initWithIdentifier:
+    wxDVCNSTableColumn * const nativeColumn(
+        [[wxDVCNSTableColumn alloc] initWithIdentifier:
             [[[wxPointerObject alloc] initWithPointer:
                 const_cast<wxDataViewColumn*>(column)]
              autorelease]]
     );
 
     // setting the size related parameters:
+    const int width = column->GetWidthVariable();
+    int resizingMask;
     if (column->IsResizeable())
     {
-        [nativeColumn setResizingMask:NSTableColumnUserResizingMask];
+        resizingMask = NSTableColumnUserResizingMask;
         [nativeColumn setMinWidth:column->GetMinWidth()];
         [nativeColumn setMaxWidth:column->GetMaxWidth()];
     }
-    else
+    else // column is not resizeable [by user]
     {
-        [nativeColumn setResizingMask:NSTableColumnNoResizing];
-        [nativeColumn setMinWidth:column->GetWidth()];
-        [nativeColumn setMaxWidth:column->GetWidth()];
+        // if the control doesn't show a header, make the columns resize
+        // automatically, this is particularly important for the single column
+        // controls (such as wxDataViewTreeCtrl) as their unique column should
+        // always take up all the available splace
+        resizingMask = column->GetOwner()->HasFlag(wxDV_NO_HEADER)
+                            ? NSTableColumnAutoresizingMask
+                            : NSTableColumnNoResizing;
     }
-    [nativeColumn setWidth:column->GetWidth()];
+    [nativeColumn setResizingMask:resizingMask];
+    [nativeColumn setWidth:width];
 
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
     // setting the visibility:
@@ -197,55 +386,6 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer,
     return new wxCocoaDataViewControl(wxpeer,pos,size,style);
 }
 
-// ============================================================================
-// wxPointerObject
-// ============================================================================
-
-@implementation wxPointerObject
-
--(id) init
-{
-    self = [super init];
-    if (self != nil)
-        self->pointer = NULL;
-    return self;
-}
-
--(id) initWithPointer:(void*) initPointer
-{
-    self = [super init];
-    if (self != nil)
-        self->pointer = initPointer;
-    return self;
-}
-
-//
-// inherited methods from NSObject
-//
--(BOOL) isEqual:(id)object
-{
-    return (object != nil) &&
-             ([object isKindOfClass:[wxPointerObject class]]) &&
-                 (pointer == [((wxPointerObject*) object) pointer]);
-}
-
--(NSUInteger) hash
-{
-    return (NSUInteger) pointer;
-}
-
--(void*) pointer
-{
-    return pointer;
-}
-
--(void) setPointer:(void*) newPointer
-{
-    pointer = newPointer;
-}
-
-@end
-
 // ============================================================================
 // wxSortDescriptorObject
 // ============================================================================
@@ -375,19 +515,22 @@ outlineView:(NSOutlineView*)outlineView
 
     wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_DROP, dvc->GetId());
     event.SetEventObject(dvc);
-    event.SetItem(wxDataViewItem([((wxPointerObject*) item) pointer]));
+    event.SetItem(wxDataViewItemFromItem(item));
     event.SetModel(dvc->GetModel());
 
     BOOL dragSuccessful;
     if ( [bestType compare:DataViewPboardType] == NSOrderedSame )
     {
-        NSArray*   dataArray((NSArray*)[pasteboard propertyListForType:DataViewPboardType]);
+        NSArray* dataArray((NSArray*)
+                      [pasteboard propertyListForType:DataViewPboardType]);
         NSUInteger indexDraggedItem, noOfDraggedItems([dataArray count]);
 
         indexDraggedItem = 0;
         while (indexDraggedItem < noOfDraggedItems)
         {
-            wxDataObjectComposite* dataObjects(implementation->GetDnDDataObjects((NSData*)[dataArray objectAtIndex:indexDraggedItem]));
+            wxDataObjectComposite* dataObjects(
+                implementation->GetDnDDataObjects((NSData*)
+                    [dataArray objectAtIndex:indexDraggedItem]));
 
             if (dataObjects && (dataObjects->GetFormatCount() > 0))
             {
@@ -395,9 +538,12 @@ outlineView:(NSOutlineView*)outlineView
 
                 // copy data into data object:
                 event.SetDataObject(dataObjects);
-                event.SetDataFormat(implementation->GetDnDDataFormat(dataObjects));
+                event.SetDataFormat(
+                    implementation->GetDnDDataFormat(dataObjects));
                 // copy data into buffer:
-                dataObjects->GetDataHere(event.GetDataFormat().GetType(),buffer.GetWriteBuf(event.GetDataSize()));
+                dataObjects->GetDataHere(
+                    event.GetDataFormat().GetType(),
+                    buffer.GetWriteBuf(event.GetDataSize()));
                 buffer.UngetWriteBuf(event.GetDataSize());
                 event.SetDataBuffer(buffer.GetData());
                 // finally, send event:
@@ -423,12 +569,21 @@ outlineView:(NSOutlineView*)outlineView
     }
     else
     {
-        CFDataRef              osxData; // needed to convert internally used UTF-16 representation to a UTF-8 representation
+        // needed to convert internally used UTF-16 representation to a UTF-8
+        // representation
+        CFDataRef              osxData;
         wxDataObjectComposite* dataObjects   (new wxDataObjectComposite());
         wxTextDataObject*      textDataObject(new wxTextDataObject());
 
-        osxData = ::CFStringCreateExternalRepresentation(kCFAllocatorDefault,(CFStringRef)[pasteboard stringForType:NSStringPboardType],kCFStringEncodingUTF8,32);
-        if (textDataObject->SetData(::CFDataGetLength(osxData),::CFDataGetBytePtr(osxData)))
+        osxData = ::CFStringCreateExternalRepresentation
+                    (
+                     kCFAllocatorDefault,
+                     (CFStringRef)[pasteboard stringForType:NSStringPboardType],
+                     kCFStringEncodingUTF8,
+                     32
+                    );
+        if (textDataObject->SetData(::CFDataGetLength(osxData),
+                                    ::CFDataGetBytePtr(osxData)))
             dataObjects->Add(textDataObject);
         else
             delete textDataObject;
@@ -448,29 +603,31 @@ outlineView:(NSOutlineView*)outlineView
         ::CFRelease(osxData);
         delete dataObjects;
     }
+    return dragSuccessful;
 }
 
--(id) outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(id)item
+-(id) outlineView:(NSOutlineView*)outlineView
+    child:(NSInteger)index
+    ofItem:(id)item
 {
-    if ((item == currentParentItem) && (index < ((NSInteger) [self getChildCount])))
+    if ((item == currentParentItem) &&
+            (index < ((NSInteger) [self getChildCount])))
         return [self getChild:index];
-    else
-    {
-        wxDataViewItemArray dataViewChildren;
 
-        wxCHECK_MSG( model, 0, "Valid model in data source does not exist." );
-        (void) model->GetChildren((item == nil) ? wxDataViewItem() : wxDataViewItem([((wxPointerObject*) item) pointer]),dataViewChildren);
-        [self bufferItem:item withChildren:&dataViewChildren];
-        if ([sortDescriptors count] > 0)
-            [children sortUsingFunction:CompareItems context:sortDescriptors];
-        return [self getChild:index];
-    }
+    wxDataViewItemArray dataViewChildren;
+
+    wxCHECK_MSG( model, 0, "Valid model in data source does not exist." );
+    model->GetChildren(wxDataViewItemFromMaybeNilItem(item), dataViewChildren);
+    [self bufferItem:item withChildren:&dataViewChildren];
+    if ([sortDescriptors count] > 0)
+        [children sortUsingFunction:CompareItems context:sortDescriptors];
+    return [self getChild:index];
 }
 
 -(BOOL) outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item
 {
     wxCHECK_MSG( model, 0, "Valid model in data source does not exist." );
-    return model->IsContainer(wxDataViewItem([((wxPointerObject*) item) pointer]));
+    return model->IsContainer(wxDataViewItemFromItem(item));
 }
 
 -(NSInteger) outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(id)item
@@ -481,7 +638,8 @@ outlineView:(NSOutlineView*)outlineView
 
 
     wxCHECK_MSG( model, 0, "Valid model in data source does not exist." );
-    noOfChildren = model->GetChildren((item == nil) ? wxDataViewItem() : wxDataViewItem([((wxPointerObject*) item) pointer]),dataViewChildren);
+    noOfChildren = model->GetChildren(wxDataViewItemFromMaybeNilItem(item),
+                                      dataViewChildren);
     [self bufferItem:item withChildren:&dataViewChildren];
     if ([sortDescriptors count] > 0)
         [children sortUsingFunction:CompareItems context:sortDescriptors];
@@ -493,16 +651,20 @@ outlineView:(NSOutlineView*)outlineView
     objectValueForTableColumn:(NSTableColumn*)tableColumn
     byItem:(id)item
 {
-    wxDataViewColumn* col(static_cast<wxDataViewColumn*>([[tableColumn identifier] pointer]));
+    wxCHECK_MSG( model, nil, "Valid model in data source does not exist." );
 
-    wxDataViewItem dataViewItem([((wxPointerObject*) item) pointer]);
+    wxDataViewColumn* col(static_cast<wxDataViewColumn*>([[tableColumn identifier] pointer]));
+    const unsigned colIdx = col->GetModelColumn();
 
-    wxVariant value;
+    wxDataViewItem dataViewItem(wxDataViewItemFromItem(item));
 
+    if ( model->HasValue(dataViewItem, colIdx) )
+    {
+        wxVariant value;
+        model->GetValue(value,dataViewItem, colIdx);
+        col->GetRenderer()->SetValue(value);
+    }
 
-    wxCHECK_MSG( model, 0, "Valid model in data source does not exist." );
-    model->GetValue(value,dataViewItem,col->GetModelColumn());
-    col->GetRenderer()->SetValue(value);
     return nil;
 }
 
@@ -514,55 +676,15 @@ outlineView:(NSOutlineView*)outlineView
 {
     wxDataViewColumn* col(static_cast<wxDataViewColumn*>([[tableColumn identifier] pointer]));
 
-    wxDataViewItem dataViewItem([((wxPointerObject*) item) pointer]);
-
-
-    if (((dynamic_cast<wxDataViewTextRenderer*>(col->GetRenderer()) != NULL) || (dynamic_cast<wxDataViewIconTextRenderer*>(col->GetRenderer()) != NULL)) &&
-            ([object isKindOfClass:[NSString class]] == YES))
-    {
-        model->SetValue(wxVariant(wxCFStringRef([((NSString*) object) retain]).AsString()),dataViewItem,col->GetModelColumn()); // the string has to be retained before being passed to wxCFStringRef
-        model->ValueChanged(dataViewItem,col->GetModelColumn());
-    }
-    else if (dynamic_cast<wxDataViewChoiceRenderer*>(col->GetRenderer()) != NULL)
-    {
-        if ([object isKindOfClass:[NSNumber class]] == YES)
-        {
-            model->SetValue(wxVariant(dynamic_cast<wxDataViewChoiceRenderer*>(col->GetRenderer())->GetChoice([((NSNumber*) object) intValue])),
-                    dataViewItem,col->GetModelColumn());
-            model->ValueChanged(dataViewItem,col->GetModelColumn());
-        }
-        else if ([object isKindOfClass:[NSString class]] == YES) // do not know if this case can occur but initializing using strings works
-        {
-            model->SetValue(wxVariant(wxCFStringRef((NSString*) object).AsString()),dataViewItem,col->GetModelColumn());
-            model->ValueChanged(dataViewItem,col->GetModelColumn());
-        }
-    }
-    else if ((dynamic_cast<wxDataViewDateRenderer*>(col->GetRenderer()) != NULL) && ([object isKindOfClass:[NSDate class]] == YES))
-    {
-        wxDateTime wxDateTimeValue(1,wxDateTime::Jan,1970);
-
-        wxLongLong seconds;
-
-        seconds.Assign([((NSDate*) object) timeIntervalSince1970]); // get the number of seconds since 1970-01-01 UTC and this is
-        // the only way to convert a double to a wxLongLong
-        // 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:
-        wxDateTimeValue.Add(wxTimeSpan(0,0,seconds));
-        wxDateTimeValue.MakeFromTimezone(wxDateTime::UTC);
-        model->SetValue(wxVariant(wxDateTimeValue),dataViewItem,col->GetModelColumn());
-        model->ValueChanged(dataViewItem,col->GetModelColumn());
-    }
-    else if ((dynamic_cast<wxDataViewToggleRenderer*>(col->GetRenderer()) != NULL) && ([object isKindOfClass:[NSNumber class]] == YES))
-    {
-        model->SetValue(wxVariant((bool) [((NSNumber*) object) boolValue]),dataViewItem,col->GetModelColumn());
-        model->ValueChanged(dataViewItem,col->GetModelColumn());
-    }
+    col->GetRenderer()->
+        OSXOnCellChanged(object, wxDataViewItemFromItem(item), col->GetModelColumn());
 }
 
 -(void) outlineView:(NSOutlineView*)outlineView sortDescriptorsDidChange:(NSArray*)oldDescriptors
-// Warning: the new sort descriptors are guaranteed to be only of type NSSortDescriptor! Therefore, the
-// sort descriptors for the data source have to be converted.
 {
+    // Warning: the new sort descriptors are guaranteed to be only of type
+    // NSSortDescriptor! Therefore, the sort descriptors for the data source
+    // have to be converted.
     NSArray* newDescriptors;
 
     NSMutableArray* wxSortDescriptors;
@@ -578,23 +700,21 @@ outlineView:(NSOutlineView*)outlineView
     wxSortDescriptors = [NSMutableArray arrayWithCapacity:noOfDescriptors];
     for (NSUInteger i=0; i<noOfDescriptors; ++i)
     {
-        // constant definition for abbreviational purposes:
         NSSortDescriptor* const newDescriptor = [newDescriptors objectAtIndex:i];
 
         [wxSortDescriptors addObject:[[[wxSortDescriptorObject alloc] initWithModelPtr:model
             sortingColumnPtr:dvc->GetColumn([[newDescriptor key] intValue])
             ascending:[newDescriptor ascending]] autorelease]];
     }
-    [[outlineView dataSource] setSortDescriptors:wxSortDescriptors];
+    [(wxCocoaOutlineDataSource*)[outlineView dataSource] setSortDescriptors:wxSortDescriptors];
 
-    // send first the event to wxWidgets that the sorting has changed so that the program can do special actions before
-    // the sorting actually starts:
+    // send first the event to wxWidgets that the sorting has changed so that
+    // the program can do special actions before the sorting actually starts:
     wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED,dvc->GetId()); // variable defintion
 
     event.SetEventObject(dvc);
     if (noOfDescriptors > 0)
     {
-        // constant definition for abbreviational purposes:
         wxDataViewColumn* const col = [[wxSortDescriptors objectAtIndex:0] columnPtr];
 
         event.SetColumn(dvc->GetColumnPosition(col));
@@ -629,7 +749,7 @@ outlineView:(NSOutlineView*)outlineView
         event(wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE,dvc->GetId());
 
     event.SetEventObject(dvc);
-    event.SetItem(wxDataViewItem([((wxPointerObject*) item) pointer]));
+    event.SetItem(wxDataViewItemFromItem(item));
     event.SetModel(dvc->GetModel());
     if ([bestType compare:DataViewPboardType] == NSOrderedSame)
     {
@@ -675,7 +795,9 @@ outlineView:(NSOutlineView*)outlineView
     }
     else
     {
-        CFDataRef              osxData; // needed to convert internally used UTF-16 representation to a UTF-8 representation
+        // needed to convert internally used UTF-16 representation to a UTF-8
+        // representation
+        CFDataRef              osxData;
         wxDataObjectComposite* dataObjects   (new wxDataObjectComposite());
         wxTextDataObject*      textDataObject(new wxTextDataObject());
 
@@ -705,10 +827,11 @@ outlineView:(NSOutlineView*)outlineView
 }
 
 -(BOOL) outlineView:(NSOutlineView*)outlineView writeItems:(NSArray*)writeItems toPasteboard:(NSPasteboard*)pasteboard
-// the pasteboard will be filled up with an array containing the data as returned by the events (including the data type)
-// and a concatenation of text (string) data; the text data will only be put onto the pasteboard if for all items a
-// string representation exists
 {
+    // the pasteboard will be filled up with an array containing the data as
+    // returned by the events (including the data type) and a concatenation of
+    // text (string) data; the text data will only be put onto the pasteboard
+    // if for all items a string representation exists
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
     wxDataViewItemArray dataViewItems;
@@ -723,7 +846,8 @@ outlineView:(NSOutlineView*)outlineView
         NSMutableArray* dataArray = [[NSMutableArray arrayWithCapacity:[writeItems count]] retain]; // data of all items
         wxString        dataString; // contains the string data of all items
 
-        // send a begin drag event for all selected items and proceed with dragging unless the event is vetoed:
+        // send a begin drag event for all selected items and proceed with
+        // dragging unless the event is vetoed:
         wxDataViewEvent
             event(wxEVT_COMMAND_DATAVIEW_ITEM_BEGIN_DRAG,dvc->GetId());
 
@@ -735,16 +859,15 @@ outlineView:(NSOutlineView*)outlineView
             wxDataObjectComposite* itemObject(new wxDataObjectComposite()); // data object for current item
             wxString               itemString;                              // contains the TAB concatenated data of an item
 
-            event.SetItem(wxDataViewItem([((wxPointerObject*) [writeItems objectAtIndex:itemCounter]) pointer]));
+            event.SetItem(
+                wxDataViewItemFromItem([writeItems objectAtIndex:itemCounter]));
             itemString = ::ConcatenateDataViewItemValues(dvc,event.GetItem());
             itemObject->Add(new wxTextDataObject(itemString));
             event.SetDataObject(itemObject);
             // check if event has not been vetoed:
             if (dvc->HandleWindowEvent(event) && event.IsAllowed() && (event.GetDataObject()->GetFormatCount() > 0))
             {
-                // constant definition for abbreviational purposes:
                 size_t const noOfFormats = event.GetDataObject()->GetFormatCount();
-                // variable definition and initialization:
                 wxDataFormat* dataFormats(new wxDataFormat[noOfFormats]);
 
                 event.GetDataObject()->GetAllFormats(dataFormats,wxDataObject::Get);
@@ -761,7 +884,10 @@ outlineView:(NSOutlineView*)outlineView
                     switch (idDataFormat)
                     {
                         case wxDF_TEXT:
-                            if (!itemStringAvailable) // otherwise wxDF_UNICODETEXT already filled up the string; and the UNICODE representation has priority
+                            // otherwise wxDF_UNICODETEXT already filled up
+                            // the string; and the UNICODE representation has
+                            // priority
+                            if (!itemStringAvailable)
                             {
                                 event.GetDataObject()->GetDataHere(wxDF_TEXT,dataBuffer.GetAppendBuf(dataSize));
                                 dataBuffer.UngetAppendBuf(dataSize);
@@ -1010,14 +1136,17 @@ outlineView:(NSOutlineView*)outlineView
 {
     wxCustomRendererObject * const
         obj = static_cast<wxCustomRendererObject *>([self objectValue]);
-    wxDataViewCustomRenderer * const renderer = obj->customRenderer;
+    if ( !obj )
+    {
+        // this may happen for the custom cells in container rows: they don't
+        // have any values
+        return;
+    }
 
-    // draw its own background:
-    [[self backgroundColor] set];
-    NSRectFill(cellFrame);
+    wxDataViewCustomRenderer * const renderer = obj->customRenderer;
 
-    // TODO: attributes support
-    renderer->Render(wxFromNSRect(controlView, cellFrame), renderer->GetDC(), 0);
+    wxDC * const dc = renderer->GetDC();
+    renderer->WXCallRender(wxFromNSRect(controlView, cellFrame), dc, 0);
     renderer->SetDC(NULL);
 }
 
@@ -1165,7 +1294,9 @@ outlineView:(NSOutlineView*)outlineView
             {
                 CGFloat const cellSpace = cellFrame.size.width-[self cellSize].width;
 
-                if (cellSpace <= 0) // if the cell's frame is smaller than its contents (at least in x-direction) make sure that the image is visible:
+                // if the cell's frame is smaller than its contents (at least
+                // in x-direction) make sure that the image is visible:
+                if (cellSpace <= 0)
                     NSDivideRect(cellFrame,imageFrame,textFrame,xImageShift+imageSize.width+spaceImageText,NSMinXEdge);
                 else // otherwise center the image and text in the cell's frame
                     NSDivideRect(cellFrame,imageFrame,textFrame,xImageShift+imageSize.width+spaceImageText+0.5*cellSpace,NSMinXEdge);
@@ -1180,7 +1311,9 @@ outlineView:(NSOutlineView*)outlineView
             {
                 CGFloat const cellSpace = cellFrame.size.width-[self cellSize].width;
 
-                if (cellSpace <= 0) // if the cell's frame is smaller than its contents (at least in x-direction) make sure that the image is visible:
+                // if the cell's frame is smaller than its contents (at least
+                // in x-direction) make sure that the image is visible:
+                if (cellSpace <= 0)
                     NSDivideRect(cellFrame,imageFrame,textFrame,xImageShift+imageSize.width+spaceImageText,NSMinXEdge);
                 else // otherwise right align the image and text in the cell's frame
                     NSDivideRect(cellFrame,imageFrame,textFrame,xImageShift+imageSize.width+spaceImageText+cellSpace,NSMinXEdge);
@@ -1200,7 +1333,8 @@ outlineView:(NSOutlineView*)outlineView
 
     [self determineCellParts:cellFrame imagePart:&imageFrame textPart:&textFrame];
     // draw the image part by ourselves;
-    // check if the cell has to draw its own background (checking is done by the parameter of the textfield's cell):
+    // check if the cell has to draw its own background (checking is done by
+    // the parameter of the textfield's cell):
     if ([self drawsBackground])
     {
         [[self backgroundColor] set];
@@ -1208,8 +1342,10 @@ outlineView:(NSOutlineView*)outlineView
     }
     if (image != nil)
     {
-        // the image is slightly shifted (xImageShift) and has a fixed size but the image's frame might be larger and starts
-        // currently on the left side of the cell's frame; therefore, the origin and the image's frame size have to be adjusted:
+        // the image is slightly shifted (xImageShift) and has a fixed size
+        // but the image's frame might be larger and starts currently on the
+        // left side of the cell's frame; therefore, the origin and the
+        // image's frame size have to be adjusted:
         if (imageFrame.size.width >= xImageShift+imageSize.width+spaceImageText)
         {
             imageFrame.origin.x += imageFrame.size.width-imageSize.width-spaceImageText;
@@ -1225,8 +1361,10 @@ outlineView:(NSOutlineView*)outlineView
             imageFrame.size.height = imageSize.height;
         imageFrame.origin.y += ceil(0.5*(cellFrame.size.height-imageFrame.size.height));
 
-        // according to the documentation the coordinate system should be flipped for NSTableViews (y-coordinate goes from top to bottom);
-        // to draw an image correctly the coordinate system has to be transformed to a bottom-top coordinate system, otherwise the image's
+        // according to the documentation the coordinate system should be
+        // flipped for NSTableViews (y-coordinate goes from top to bottom); to
+        // draw an image correctly the coordinate system has to be transformed
+        // to a bottom-top coordinate system, otherwise the image's
         // content is flipped:
         NSAffineTransform* coordinateTransform([NSAffineTransform transform]);
 
@@ -1238,14 +1376,21 @@ outlineView:(NSOutlineView*)outlineView
         }
         [image drawInRect:imageFrame fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; // suggested method to draw the image
         // instead of compositeToPoint:operation:
-        // take back previous transformation (if the view is not flipped the coordinate transformation matrix contains the identity matrix
-        // and the next two operations do not change the content's transformation matrix):
+        // take back previous transformation (if the view is not flipped the
+        // coordinate transformation matrix contains the identity matrix and
+        // the next two operations do not change the content's transformation
+        // matrix):
         [coordinateTransform invert];
         [coordinateTransform concat];
     }
     // let the textfield cell draw the text part:
-    if (textFrame.size.width > [self cellTextSize].width) // for unknown reasons the alignment of the text cell is ignored; therefore change the size so that
-        textFrame.size.width = [self cellTextSize].width;   // alignment does not influence the visualization anymore
+    if (textFrame.size.width > [self cellTextSize].width)
+    {
+        // for unknown reasons the alignment of the text cell is ignored;
+        // therefore change the size so that alignment does not influence the
+        // visualization anymore
+        textFrame.size.width = [self cellTextSize].width;
+    }
     [super drawWithFrame:textFrame inView:controlView];
 }
 
@@ -1284,13 +1429,20 @@ outlineView:(NSOutlineView*)outlineView
         if (imageFrame.size.height > imageSize.height)
             imageFrame.size.height = imageSize.height;
         imageFrame.origin.y += ceil(0.5*(cellFrame.size.height-imageFrame.size.height));
-        // If the point is in the image rect, then it is a content hit (see documentation for hitTestForEvent:inRect:ofView):
+        // If the point is in the image rect, then it is a content hit (see
+        // documentation for hitTestForEvent:inRect:ofView):
         if (NSMouseInRect(point, imageFrame, [controlView isFlipped]))
             return NSCellHitContentArea;
     }
     // if the image was not hit let's try the text part:
-    if (textFrame.size.width > [self cellTextSize].width) // for unknown reasons the alignment of the text cell is ignored; therefore change the size so that
-        textFrame.size.width = [self cellTextSize].width;   // alignment does not influence the visualization anymore
+    if (textFrame.size.width > [self cellTextSize].width)
+    {
+        // for unknown reasons the alignment of the text cell is ignored;
+        // therefore change the size so that alignment does not influence the
+        // visualization anymore
+        textFrame.size.width = [self cellTextSize].width;
+    }
+
     return [super hitTestForEvent:event inRect:textFrame ofView:controlView];
 }
 #endif
@@ -1382,16 +1534,17 @@ outlineView:(NSOutlineView*)outlineView
 // actions
 //
 -(void) actionDoubleClick:(id)sender
-// actually the documentation (NSTableView 2007-10-31) for doubleAction: and setDoubleAction: seems to be wrong as this action message is always sent
-// whether the cell is editable or not
 {
+    // actually the documentation (NSTableView 2007-10-31) for doubleAction:
+    // and setDoubleAction: seems to be wrong as this action message is always
+    // sent whether the cell is editable or not
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
-    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED,dvc->GetId()); // variable definition
+    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED,dvc->GetId());
 
 
     event.SetEventObject(dvc);
-    event.SetItem(wxDataViewItem([((wxPointerObject*) [self itemAtRow:[self clickedRow]]) pointer]));
+    event.SetItem(wxDataViewItemFromItem([self itemAtRow:[self clickedRow]]));
     dvc->GetEventHandler()->ProcessEvent(event);
 }
 
@@ -1400,9 +1553,10 @@ outlineView:(NSOutlineView*)outlineView
 // contextual menus
 //
 -(NSMenu*) menuForEvent:(NSEvent*)theEvent
-// this method does not do any special menu event handling but only sends an event message; therefore, the user
-// has full control if a context menu should be shown or not
 {
+    // this method does not do any special menu event handling but only sends
+    // an event message; therefore, the user has full control if a context
+    // menu should be shown or not
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
     wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU,dvc->GetId());
@@ -1413,8 +1567,9 @@ outlineView:(NSOutlineView*)outlineView
     event.SetEventObject(dvc);
     event.SetModel(dvc->GetModel());
     // get the item information;
-    // theoretically more than one ID can be returned but the event can only handle one item, therefore only the first
-    // item of the array is returned:
+    // theoretically more than one ID can be returned but the event can only
+    // handle one item, therefore only the first item of the array is
+    // returned:
     if (dvc->GetSelections(selectedItems) > 0)
         event.SetItem(selectedItems[0]);
     dvc->GetEventHandler()->ProcessEvent(event);
@@ -1442,13 +1597,15 @@ outlineView:(NSOutlineView*)outlineView
     dvc->HandleWindowEvent(event);
 
     // now, check if the click may have had an influence on sorting, too;
-    // the sorting setup has to be done only if the clicked table column is sortable and has not been used for
-    // sorting before the click; if the column is already responsible for sorting the native control changes
-    // the sorting direction automatically and informs the data source via outlineView:sortDescriptorsDidChange:
+    // the sorting setup has to be done only if the clicked table column is
+    // sortable and has not been used for sorting before the click; if the
+    // column is already responsible for sorting the native control changes
+    // the sorting direction automatically and informs the data source via
+    // outlineView:sortDescriptorsDidChange:
     if (col->IsSortable() && ([tableColumn sortDescriptorPrototype] == nil))
     {
-        // remove the sort order from the previously sorted column table (it can also be that
-        // no sorted column table exists):
+        // remove the sort order from the previously sorted column table (it
+        // can also be that no sorted column table exists):
         UInt32 const noOfColumns = [outlineView numberOfColumns];
 
         for (UInt32 i=0; i<noOfColumns; ++i)
@@ -1470,11 +1627,11 @@ outlineView:(NSOutlineView*)outlineView
 {
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
-    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING,dvc->GetId()); // variable definition
+    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING,dvc->GetId());
 
 
     event.SetEventObject(dvc);
-    event.SetItem       (wxDataViewItem([((wxPointerObject*) item) pointer]));
+    event.SetItem       (wxDataViewItemFromItem(item));
     event.SetModel      (dvc->GetModel());
     // finally send the equivalent wxWidget event:
     dvc->GetEventHandler()->ProcessEvent(event);
@@ -1486,11 +1643,11 @@ outlineView:(NSOutlineView*)outlineView
 {
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
-    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING,dvc->GetId()); // variable definition
+    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING,dvc->GetId());
 
 
     event.SetEventObject(dvc);
-    event.SetItem       (wxDataViewItem([((wxPointerObject*) item) pointer]));
+    event.SetItem       (wxDataViewItemFromItem(item));
     event.SetModel      (dvc->GetModel());
     // finally send the equivalent wxWidget event:
     dvc->GetEventHandler()->ProcessEvent(event);
@@ -1504,9 +1661,9 @@ outlineView:(NSOutlineView*)outlineView
 }
 
 -(void) outlineView:(wxCocoaOutlineView*)outlineView
-willDisplayCell:(id)cell
-forTableColumn:(NSTableColumn*)tableColumn
-item:(id)item
+    willDisplayCell:(id)cell
+    forTableColumn:(NSTableColumn*)tableColumn
+    item:(id)item
 {
     wxDataViewCtrl * const dvc = implementation->GetDataViewCtrl();
     wxDataViewModel * const model = dvc->GetModel();
@@ -1516,83 +1673,29 @@ item:(id)item
                     [[tableColumn identifier] pointer]
                     )
              );
+    const unsigned colIdx = dvCol->GetModelColumn();
 
-    wxDataViewRenderer * const renderer = dvCol->GetRenderer();
-    wxDataViewRendererNativeData * const data = renderer->GetNativeData();
-
-    wxDataViewItem dvItem([static_cast<wxPointerObject *>(item) pointer]);
+    wxDataViewItem dvItem(wxDataViewItemFromItem(item));
 
-    // set the font and text colour to use: we need to do it if we had ever
-    // changed them before, even if this item itself doesn't have any special
-    // attributes as otherwise it would reuse the attributes from the previous
-    // cell rendered using the same renderer
-    NSFont *font = NULL;
-    NSColor *colText = NULL;
-
-    wxDataViewItemAttr attr;
-    if ( model && model->GetAttr(dvItem, dvCol->GetModelColumn(), attr) )
-    {
-        if ( attr.HasFont() )
-        {
-            font = data->GetOriginalFont();
-            if ( !font )
-            {
-                // this is the first time we're setting the font, remember the
-                // original one before changing it
-                font = [cell font];
-                data->SaveOriginalFont(font);
-            }
-
-            if ( font )
-            {
-                // FIXME: using wxFont methods here doesn't work for some reason
-                NSFontManager * const fm = [NSFontManager sharedFontManager];
-                if ( attr.GetBold() )
-                    font = [fm convertFont:font toHaveTrait:NSBoldFontMask];
-                if ( attr.GetItalic() )
-                    font = [fm convertFont:font toHaveTrait:NSItalicFontMask];
-            }
-            //else: can't change font if the cell doesn't have any
-        }
-
-        if ( attr.HasColour() )
-        {
-            // we can set font for any cell but only NSTextFieldCell provides
-            // a method for setting text colour so check that this method is
-            // available before using it
-            if ( [cell respondsToSelector:@selector(setTextColor:)] &&
-                    [cell respondsToSelector:@selector(textColor)] )
-            {
-                if ( !data->GetOriginalTextColour() )
-                {
-                    data->SaveOriginalTextColour([cell textColor]);
-                }
-
-                const wxColour& c = attr.GetColour();
-                colText = [NSColor colorWithDeviceRed:c.Red() / 255.
-                    green:c.Green() / 255.
-                    blue:c.Blue() / 255.
-                    alpha:c.Alpha() / 255.];
-            }
-        }
-    }
-
-    if ( !font )
-        font = data->GetOriginalFont();
-    if ( !colText )
-        colText = data->GetOriginalTextColour();
-
-    if ( font )
-        [cell setFont:font];
-
-    if ( colText )
-        [cell setTextColor:colText];
+    if ( !model->HasValue(dvItem, colIdx) )
+        return;
 
+    wxDataViewRenderer * const renderer = dvCol->GetRenderer();
+    wxDataViewRendererNativeData * const data = renderer->GetNativeData();
 
+    // let the renderer know about what it's going to render next
     data->SetColumnPtr(tableColumn);
     data->SetItem(item);
     data->SetItemCell(cell);
 
+    // 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
+    // one might have had some and then we need to reset them back to default
+    wxDataViewItemAttr attr;
+    model->GetAttr(dvItem, colIdx, attr);
+    renderer->OSXApplyAttr(attr);
+
+    // and finally do draw it
     renderer->MacRender();
 }
 
@@ -1624,7 +1727,8 @@ item:(id)item
 
 
     event.SetEventObject(dvc);
-    event.SetItem(wxDataViewItem([((wxPointerObject*) [[notification userInfo] objectForKey:@"NSObject"]) pointer]));
+    event.SetItem(wxDataViewItemFromItem(
+                    [[notification userInfo] objectForKey:@"NSObject"]));
     dvc->GetEventHandler()->ProcessEvent(event);
 }
 
@@ -1636,7 +1740,8 @@ item:(id)item
 
 
     event.SetEventObject(dvc);
-    event.SetItem(wxDataViewItem([((wxPointerObject*) [[notification userInfo] objectForKey:@"NSObject"]) pointer]));
+    event.SetItem(wxDataViewItemFromItem(
+                    [[notification userInfo] objectForKey:@"NSObject"]));
     dvc->GetEventHandler()->ProcessEvent(event);
 }
 
@@ -1644,20 +1749,22 @@ item:(id)item
 {
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
-    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED,dvc->GetId()); // variable definition
-
+    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED,dvc->GetId());
 
     event.SetEventObject(dvc);
-    event.SetModel      (dvc->GetModel());
+    event.SetModel(dvc->GetModel());
+    event.SetItem(dvc->GetSelection());
     dvc->GetEventHandler()->ProcessEvent(event);
 }
 
 -(void) textDidBeginEditing:(NSNotification*)notification
-// this notification is only sent if the user started modifying the cell (not when the user clicked into the cell
-// and the cell's editor is called!)
 {
-    // call method of superclass (otherwise editing does not work correctly - the outline data source class is not
-    // informed about a change of data):
+    // this notification is only sent if the user started modifying the cell
+    // (not when the user clicked into the cell and the cell's editor is
+    // called!)
+
+    // call method of superclass (otherwise editing does not work correctly -
+    // the outline data source class is not informed about a change of data):
     [super textDidBeginEditing:notification];
 
     // remember the column being edited, it will be used in textDidEndEditing:
@@ -1676,11 +1783,11 @@ item:(id)item
 
     // now, send the event:
     wxDataViewEvent
-        event(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED,dvc->GetId()); // variable definition
+        event(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED,dvc->GetId());
 
     event.SetEventObject(dvc);
     event.SetItem(
-            wxDataViewItem([((wxPointerObject*) [self itemAtRow:currentlyEditedRow]) pointer]));
+            wxDataViewItemFromItem([self itemAtRow:currentlyEditedRow]));
     event.SetColumn(dvc->GetColumnPosition(col));
     event.SetDataViewColumn(col);
     dvc->GetEventHandler()->ProcessEvent(event);
@@ -1688,15 +1795,18 @@ item:(id)item
 
 -(void) textDidEndEditing:(NSNotification*)notification
 {
-    // call method of superclass (otherwise editing does not work correctly - the outline data source class is not
-    // informed about a change of data):
+    // call method of superclass (otherwise editing does not work correctly -
+    // the outline data source class is not informed about a change of data):
     [super textDidEndEditing:notification];
 
-    // under OSX an event indicating the end of an editing session can be sent even if no event indicating a start of an
-    // editing session has been sent (see Documentation for NSControl controlTextDidEndEditing:); this is not expected by a user
-    // of the wxWidgets library and therefore an wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE event is only sent if a corresponding
-    // wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED has been sent before; to check if a wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED
-    // has been sent the last edited column/row are valid:
+    // under OSX an event indicating the end of an editing session can be sent
+    // even if no event indicating a start of an editing session has been sent
+    // (see Documentation for NSControl controlTextDidEndEditing:); this is
+    // not expected by a user of the wxWidgets library and therefore an
+    // wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE event is only sent if a
+    // corresponding wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED has been sent
+    // before; to check if a wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED has
+    // been sent the last edited column/row are valid:
     if ( currentlyEditedColumn != -1 && currentlyEditedRow != -1 )
     {
         wxDataViewColumn* const col =
@@ -1707,11 +1817,11 @@ item:(id)item
 
         // send event to wxWidgets:
         wxDataViewEvent
-            event(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE,dvc->GetId()); // variable definition
+            event(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE,dvc->GetId());
 
         event.SetEventObject(dvc);
         event.SetItem(
-                wxDataViewItem([((wxPointerObject*) [self itemAtRow:currentlyEditedRow]) pointer]));
+                wxDataViewItemFromItem([self itemAtRow:currentlyEditedRow]));
         event.SetColumn(dvc->GetColumnPosition(col));
         event.SetDataViewColumn(col);
         dvc->GetEventHandler()->ProcessEvent(event);
@@ -1724,19 +1834,25 @@ item:(id)item
 }
 
 @end
+
 // ============================================================================
 // wxCocoaDataViewControl
 // ============================================================================
-//
-// constructors / destructor
-//
-    wxCocoaDataViewControl::wxCocoaDataViewControl(wxWindow* peer, const wxPoint& pos, const wxSize& size, long style)
-:wxWidgetCocoaImpl(peer,[[NSScrollView alloc] initWithFrame:wxOSXGetFrameForControl(peer,pos,size)]),
-    m_DataSource(NULL), m_OutlineView([[wxCocoaOutlineView alloc] init])
+
+wxCocoaDataViewControl::wxCocoaDataViewControl(wxWindow* peer,
+                                               const wxPoint& pos,
+                                               const wxSize& size,
+                                               long style)
+    : wxWidgetCocoaImpl
+      (
+        peer,
+        [[NSScrollView alloc] initWithFrame:wxOSXGetFrameForControl(peer,pos,size)]
+      ),
+      m_DataSource(NULL),
+      m_OutlineView([[wxCocoaOutlineView alloc] init])
 {
     // initialize scrollview (the outline view is part of a scrollview):
-    NSScrollView* scrollview = (NSScrollView*) GetWXWidget(); // definition for abbreviational purposes
-
+    NSScrollView* scrollview = (NSScrollView*) GetWXWidget();
 
     [scrollview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
     [scrollview setBorderType:NSNoBorder];
@@ -1745,12 +1861,16 @@ item:(id)item
     [scrollview setAutohidesScrollers:YES];
     [scrollview setDocumentView:m_OutlineView];
 
-    // setting up the native control itself
-    NSUInteger maskGridStyle(NSTableViewGridNone);
+    // initialize the native control itself too
+    InitOutlineView(style);
+}
 
+void wxCocoaDataViewControl::InitOutlineView(long style)
+{
     [m_OutlineView setImplementation:this];
     [m_OutlineView setColumnAutoresizingStyle:NSTableViewSequentialColumnAutoresizingStyle];
     [m_OutlineView setIndentationPerLevel:GetDataViewCtrl()->GetIndent()];
+    NSUInteger maskGridStyle(NSTableViewGridNone);
     if (style & wxDV_HORIZ_RULES)
         maskGridStyle |= NSTableViewSolidHorizontalGridLineMask;
     if (style & wxDV_VERT_RULES)
@@ -1758,6 +1878,9 @@ item:(id)item
     [m_OutlineView setGridStyleMask:maskGridStyle];
     [m_OutlineView setAllowsMultipleSelection:           (style & wxDV_MULTIPLE)  != 0];
     [m_OutlineView setUsesAlternatingRowBackgroundColors:(style & wxDV_ROW_LINES) != 0];
+
+    if ( style & wxDV_NO_HEADER )
+        [m_OutlineView setHeaderView:nil];
 }
 
 wxCocoaDataViewControl::~wxCocoaDataViewControl()
@@ -1771,23 +1894,16 @@ wxCocoaDataViewControl::~wxCocoaDataViewControl()
 //
 bool wxCocoaDataViewControl::ClearColumns()
 {
-    bool const bufAllowsMultipleSelection = [m_OutlineView allowsMultipleSelection];
-
-
-    // as there is a bug in NSOutlineView version (OSX 10.5.6 #6555162) the columns cannot be deleted if there is an outline column in the view;
+    // as there is a bug in NSOutlineView version (OSX 10.5.6 #6555162) the
+    // columns cannot be deleted if there is an outline column in the view;
     // therefore, the whole view is deleted and newly constructed:
     [m_OutlineView release];
     m_OutlineView = [[wxCocoaOutlineView alloc] init];
     [((NSScrollView*) GetWXWidget()) setDocumentView:m_OutlineView];
-
-    // setting up the native control itself
-    [m_OutlineView setImplementation:this];
-    [m_OutlineView setColumnAutoresizingStyle:NSTableViewSequentialColumnAutoresizingStyle];
-    [m_OutlineView setIndentationPerLevel:GetDataViewCtrl()->GetIndent()];
-    if (bufAllowsMultipleSelection)
-        [m_OutlineView setAllowsMultipleSelection:YES];
     [m_OutlineView setDataSource:m_DataSource];
-    // done:
+
+    InitOutlineView(GetDataViewCtrl()->GetWindowStyle());
+
     return true;
 }
 
@@ -1820,8 +1936,9 @@ bool wxCocoaDataViewControl::InsertColumn(unsigned int pos, wxDataViewColumn* co
     // create column and set the native data of the dataview column:
     NSTableColumn *nativeColumn = ::CreateNativeColumn(columnPtr);
     columnPtr->GetNativeData()->SetNativeColumnPtr(nativeColumn);
-    // as the native control does not allow the insertion of a column at a specified position the column is first appended and
-    // - if necessary - moved to its final position:
+    // as the native control does not allow the insertion of a column at a
+    // specified position the column is first appended and - if necessary -
+    // moved to its final position:
     [m_OutlineView addTableColumn:nativeColumn];
     if (pos != static_cast<unsigned int>([m_OutlineView numberOfColumns]-1))
         [m_OutlineView moveColumn:[m_OutlineView numberOfColumns]-1 toColumn:pos];
@@ -2152,6 +2269,11 @@ wxDataObjectComposite* wxCocoaDataViewControl::GetDnDDataObjects(NSData* dataObj
     }
 }
 
+id wxCocoaDataViewControl::GetItemAtRow(int row) const
+{
+    return [m_OutlineView itemAtRow:row];
+}
+
 // ----------------------------------------------------------------------------
 // wxDataViewRendererNativeData
 // ----------------------------------------------------------------------------
@@ -2196,8 +2318,14 @@ void wxDataViewRendererNativeData::ApplyLineBreakMode(NSCell *cell)
 // ---------------------------------------------------------
 // wxDataViewRenderer
 // ---------------------------------------------------------
-    wxDataViewRenderer::wxDataViewRenderer(const wxString& varianttype, wxDataViewCellMode mode, int align)
-:wxDataViewRendererBase(varianttype,mode,align), m_alignment(align), m_mode(mode), m_NativeDataPtr(NULL)
+
+wxDataViewRenderer::wxDataViewRenderer(const wxString& varianttype,
+                                       wxDataViewCellMode mode,
+                                       int align)
+    : wxDataViewRendererBase(varianttype, mode, align),
+      m_alignment(align),
+      m_mode(mode),
+      m_NativeDataPtr(NULL)
 {
 }
 
@@ -2241,6 +2369,108 @@ wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const
     return GetNativeData()->GetEllipsizeMode();
 }
 
+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);
+}
+
+void wxDataViewRenderer::OSXApplyAttr(const wxDataViewItemAttr& attr)
+{
+    wxDataViewRendererNativeData * const data = GetNativeData();
+    NSCell * const cell = data->GetItemCell();
+
+    // set the font and text colour to use: we need to do it if we had ever
+    // changed them before, even if this item itself doesn't have any special
+    // attributes as otherwise it would reuse the attributes from the previous
+    // cell rendered using the same renderer
+    NSFont *font = NULL;
+    NSColor *colText = NULL;
+
+    if ( attr.HasFont() )
+    {
+        font = data->GetOriginalFont();
+        if ( !font )
+        {
+            // this is the first time we're setting the font, remember the
+            // original one before changing it
+            font = [cell font];
+            data->SaveOriginalFont(font);
+        }
+
+        if ( font )
+        {
+            // FIXME: using wxFont methods here doesn't work for some reason
+            NSFontManager * const fm = [NSFontManager sharedFontManager];
+            if ( attr.GetBold() )
+                font = [fm convertFont:font toHaveTrait:NSBoldFontMask];
+            if ( attr.GetItalic() )
+                font = [fm convertFont:font toHaveTrait:NSItalicFontMask];
+        }
+        //else: can't change font if the cell doesn't have any
+    }
+
+    if ( attr.HasColour() )
+    {
+        // we can set font for any cell but only NSTextFieldCell provides
+        // a method for setting text colour so check that this method is
+        // available before using it
+        if ( [cell respondsToSelector:@selector(setTextColor:)] &&
+                [cell respondsToSelector:@selector(textColor)] )
+        {
+            if ( !data->GetOriginalTextColour() )
+            {
+                // the cast to (untyped) id is safe because of the check above
+                data->SaveOriginalTextColour([(id)cell textColor]);
+            }
+
+            const wxColour& c = attr.GetColour();
+            colText = [NSColor colorWithDeviceRed:c.Red() / 255.
+                green:c.Green() / 255.
+                blue:c.Blue() / 255.
+                alpha:c.Alpha() / 255.];
+        }
+    }
+
+    if ( !font )
+        font = data->GetOriginalFont();
+    if ( !colText )
+        colText = data->GetOriginalTextColour();
+
+    if ( font )
+        [cell setFont:font];
+
+    if ( colText )
+        [(id)cell setTextColor:colText];
+}
+
 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer,wxDataViewRendererBase)
 
 // ---------------------------------------------------------
@@ -2249,7 +2479,7 @@ IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer,wxDataViewRendererBase)
 wxDataViewCustomRenderer::wxDataViewCustomRenderer(const wxString& varianttype,
                                                    wxDataViewCellMode mode,
                                                    int align)
-    : wxDataViewRenderer(varianttype, mode, align),
+    : wxDataViewCustomRendererBase(varianttype, mode, align),
       m_editorCtrlPtr(NULL),
       m_DCPtr(NULL)
 {
@@ -2262,6 +2492,18 @@ bool wxDataViewCustomRenderer::MacRender()
     return true;
 }
 
+void wxDataViewCustomRenderer::OSXApplyAttr(const wxDataViewItemAttr& attr)
+{
+    // simply save the attribute so that it could be reused from our Render()
+    SetAttr(attr);
+
+    // it's not necessary to call the base class version which sets the cell
+    // properties to correspond to this attribute because we currently don't
+    // use any NSCell methods in custom renderers anyhow but if we ever start
+    // doing this (e.g. override RenderText() here to use NSTextFieldCell
+    // methods), then we should pass it on to wxDataViewRenderer here
+}
+
 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
 
 // ---------------------------------------------------------
@@ -2295,6 +2537,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)
 
 // ---------------------------------------------------------
@@ -2313,11 +2564,13 @@ wxDataViewBitmapRenderer::wxDataViewBitmapRenderer(const wxString& varianttype,
     [cell release];
 }
 
+// This method returns 'true' if
+//  - the passed bitmap is valid and it could be assigned to the native data
+//  browser;
+//  - the passed bitmap is invalid (or is not initialized); this case
+//  simulates a non-existing bitmap.
+// In all other cases the method returns 'false'.
 bool wxDataViewBitmapRenderer::MacRender()
-    // This method returns 'true' if
-    //  - the passed bitmap is valid and it could be assigned to the native data browser;
-    //  - the passed bitmap is invalid (or is not initialized); this case simulates a non-existing bitmap.
-    // In all other cases the method returns 'false'.
 {
     wxCHECK_MSG(GetValue().GetType() == GetVariantType(),false,wxString("Bitmap renderer cannot render value; value type: ") << GetValue().GetType());
 
@@ -2337,7 +2590,8 @@ IMPLEMENT_CLASS(wxDataViewBitmapRenderer,wxDataViewRenderer)
 wxDataViewChoiceRenderer::wxDataViewChoiceRenderer(const wxArrayString& choices,
                                                    wxDataViewCellMode mode,
                                                    int alignment)
-    : wxDataViewRenderer(wxT("string"),mode,alignment), m_Choices(choices)
+    : wxDataViewRenderer(wxT("string"), mode, alignment),
+      m_choices(choices)
 {
     NSPopUpButtonCell* cell;
 
@@ -2398,33 +2652,47 @@ bool wxDataViewDateRenderer::MacRender()
         if (GetValue().GetDateTime().IsValid())
         {
             // -- find best fitting style to show the date --
-            // as the style should be identical for all cells a reference date instead of the actual cell's date
-            // value is used for all cells; this reference date is stored in the renderer's native data section
-            // for speed purposes; otherwise, the reference date's string has to be recalculated for each item that
-            // may become timewise long if a lot of rows using dates exist;
-            // the algorithm has the preference to display as much information as possible in the first instance;
-            // but as this is often impossible due to space restrictions the style is shortened per loop; finally,
-            // if the shortest time and date format does not fit into the cell the time part is dropped;
-            // remark: the time part itself is not modified per iteration loop and only uses the short style,
-            //         means that only the hours and minutes are being shown
-            [GetNativeData()->GetItemCell() setObjectValue:GetNativeData()->GetObject()]; // GetObject() returns a date for testing the size of a date object
+            // as the style should be identical for all cells a reference date
+            // instead of the actual cell's date value is used for all cells;
+            // this reference date is stored in the renderer's native data
+            // section for speed purposes; otherwise, the reference date's
+            // string has to be recalculated for each item that may become
+            // timewise long if a lot of rows using dates exist; the algorithm
+            // has the preference to display as much information as possible
+            // in the first instance; but as this is often impossible due to
+            // space restrictions the style is shortened per loop; finally, if
+            // the shortest time and date format does not fit into the cell
+            // the time part is dropped; remark: the time part itself is not
+            // modified per iteration loop and only uses the short style,
+            // means that only the hours and minutes are being shown
+
+            // GetObject() returns a date for testing the size of a date object
+            [GetNativeData()->GetItemCell() setObjectValue:GetNativeData()->GetObject()];
             [[GetNativeData()->GetItemCell() formatter] setTimeStyle:NSDateFormatterShortStyle];
             for (int dateFormatterStyle=4; dateFormatterStyle>0; --dateFormatterStyle)
             {
                 [[GetNativeData()->GetItemCell() formatter] setDateStyle:(NSDateFormatterStyle)dateFormatterStyle];
                 if (dateFormatterStyle == 1)
                 {
-                    // if the shortest style for displaying the date and time is too long to be fully visible remove the time part of the date:
+                    // if the shortest style for displaying the date and time
+                    // is too long to be fully visible remove the time part of
+                    // the date:
                     if ([GetNativeData()->GetItemCell() cellSize].width > [GetNativeData()->GetColumnPtr() width])
                         [[GetNativeData()->GetItemCell() formatter] setTimeStyle:NSDateFormatterNoStyle];
-                    break; // basically not necessary as the loop would end anyway but let's save the last comparison
+                    {
+                        // basically not necessary as the loop would end anyway
+                        // but let's save the last comparison
+                        break;
+                    }
                 }
                 else if ([GetNativeData()->GetItemCell() cellSize].width <= [GetNativeData()->GetColumnPtr() width])
                     break;
             }
-            // set data (the style is set by the previous loop);
-            // on OSX the date has to be specified with respect to UTC; in wxWidgets the date is always entered in the local timezone; so, we have to do a conversion
-            // from the local to UTC timezone when adding the seconds to 1970-01-01 UTC:
+            // set data (the style is set by the previous loop); on OSX the
+            // date has to be specified with respect to UTC; in wxWidgets the
+            // date is always entered in the local timezone; so, we have to do
+            // a conversion from the local to UTC timezone when adding the
+            // seconds to 1970-01-01 UTC:
             [GetNativeData()->GetItemCell() setObjectValue:[NSDate dateWithTimeIntervalSince1970:GetValue().GetDateTime().ToUTC().Subtract(wxDateTime(1,wxDateTime::Jan,1970)).GetSeconds().ToDouble()]];
         }
         return true;
@@ -2436,6 +2704,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)
 
 // ---------------------------------------------------------
@@ -2477,6 +2754,18 @@ bool wxDataViewIconTextRenderer::MacRender()
     }
 }
 
+void
+wxDataViewIconTextRenderer::OSXOnCellChanged(NSObject *value,
+                                             const wxDataViewItem& item,
+                                             unsigned col)
+{
+    wxVariant valueIconText;
+    valueIconText << wxDataViewIconText(ObjectToString(value));
+
+    wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
+    model->ChangeValue(valueIconText, item, col);
+}
+
 IMPLEMENT_ABSTRACT_CLASS(wxDataViewIconTextRenderer,wxDataViewRenderer)
 
 // ---------------------------------------------------------
@@ -2512,6 +2801,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)
 
 // ---------------------------------------------------------
@@ -2546,6 +2844,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)
 
 // ---------------------------------------------------------
@@ -2586,6 +2893,11 @@ wxDataViewColumn::~wxDataViewColumn()
     delete m_NativeDataPtr;
 }
 
+int wxDataViewColumn::GetWidth() const
+{
+    return [m_NativeDataPtr->GetNativeColumnPtr() width];
+}
+
 bool wxDataViewColumn::IsSortKey() const
 {
     NSTableColumn *nsCol = GetNativeData()->GetNativeColumnPtr();
@@ -2602,7 +2914,8 @@ void wxDataViewColumn::SetAlignment(wxAlignment align)
 
 void wxDataViewColumn::SetBitmap(const wxBitmap& bitmap)
 {
-    // bitmaps and titles cannot exist at the same time - if the bitmap is set the title is removed:
+    // bitmaps and titles cannot exist at the same time - if the bitmap is set
+    // the title is removed:
     m_title = wxEmptyString;
     wxDataViewColumnBase::SetBitmap(bitmap);
     [[m_NativeDataPtr->GetNativeColumnPtr() headerCell] setImage:[[bitmap.GetNSImage() retain] autorelease]];
@@ -2662,7 +2975,8 @@ void wxDataViewColumn::SetSortOrder(bool ascending)
 
 void wxDataViewColumn::SetTitle(const wxString& title)
 {
-    // bitmaps and titles cannot exist at the same time - if the title is set the bitmap is removed:
+    // bitmaps and titles cannot exist at the same time - if the title is set
+    // the bitmap is removed:
     wxDataViewColumnBase::SetBitmap(wxBitmap());
     m_title = title;
     [[m_NativeDataPtr->GetNativeColumnPtr() headerCell] setStringValue:[[wxCFStringRef(title).AsNSString() retain] autorelease]];