]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/cocoa/dataview.mm
Fix wrong tab order in wxAuiNotebook after dragging.
[wxWidgets.git] / src / osx / cocoa / dataview.mm
index 3a244c6829c2dcb894759228d5ad9b52ac52ca30..632af4b04b95fc05e9ed79da3f023c60d2326310 100644 (file)
     #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"
+#include "wx/stopwatch.h"
+#include "wx/dcgraph.h"
 
 // ============================================================================
 // Constants used locally
@@ -154,11 +156,46 @@ inline wxDataViewItem wxDataViewItemFromMaybeNilItem(id item)
 {
 }
 
+    // Get the identifier we use for the specified column. This should be used
+    // for finding columns from identifier only, to initialize the identifier
+    // of a new column use initWithColumnPointer below instead.
+    +(NSString*) identifierForColumnPointer:(const wxDataViewColumn*)column;
+
+    // Initialize the column with the given pointer to the associated
+    // wxDataViewColumn. This pointer can later be retrieved using
+    // getColumnPointer.
+    -(id) initWithColumnPointer:(const wxDataViewColumn*)column;
+
+    // Retrieve the associated column.
+    -(wxDataViewColumn*) getColumnPointer;
+
     -(id) dataCellForRow:(NSInteger)row;
 @end
 
 @implementation wxDVCNSTableColumn
 
++(NSString*) identifierForColumnPointer:(const wxDataViewColumn*)column
+{
+    // Starting from OS X 10.7 the column identifier must be an NSString and
+    // not just some arbitrary object, so we serialize the pointer into the
+    // string. Notice the use of NSInteger which is big enough to store a
+    // pointer in both 32 and 64 bit builds.
+    return [NSString stringWithFormat:@"%lu", reinterpret_cast<NSUInteger>(column)];
+}
+
+-(id) initWithColumnPointer:(const wxDataViewColumn*)column
+{
+    [self initWithIdentifier: [wxDVCNSTableColumn identifierForColumnPointer:column]];
+    return self;
+}
+
+-(wxDataViewColumn*) getColumnPointer
+{
+    // The case to NSString is needed for OS X < 10.7.
+    return reinterpret_cast<wxDataViewColumn*>(
+            [static_cast<NSString*>([self identifier]) integerValue]);
+}
+
 -(id) dataCellForRow:(NSInteger)row
 {
     // what we want to do here is to simply return nil for the cells which
@@ -166,13 +203,7 @@ inline wxDataViewItem wxDataViewItemFromMaybeNilItem(id item)
     // 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 wxDataViewColumn * const dvCol = [self getColumnPointer];
 
     const wxDataViewCtrl * const dvc = dvCol->GetOwner();
     const wxCocoaDataViewControl * const
@@ -314,14 +345,10 @@ NSTableColumn* CreateNativeColumn(const wxDataViewColumn *column)
     wxCHECK_MSG( renderer, NULL, "column should have a renderer" );
 
     wxDVCNSTableColumn * const nativeColumn(
-        [[wxDVCNSTableColumn alloc] initWithIdentifier:
-            [[[wxPointerObject alloc] initWithPointer:
-                const_cast<wxDataViewColumn*>(column)]
-             autorelease]]
+        [[wxDVCNSTableColumn alloc] initWithColumnPointer: column]
     );
 
     // setting the size related parameters:
-    const int width = column->GetWidthVariable();
     int resizingMask;
     if (column->IsResizeable())
     {
@@ -329,7 +356,7 @@ NSTableColumn* CreateNativeColumn(const wxDataViewColumn *column)
         [nativeColumn setMinWidth:column->GetMinWidth()];
         [nativeColumn setMaxWidth:column->GetMaxWidth()];
     }
-    else // column is not resizeable [by user]
+    else // column is not resizable [by user]
     {
         // if the control doesn't show a header, make the columns resize
         // automatically, this is particularly important for the single column
@@ -340,7 +367,6 @@ NSTableColumn* CreateNativeColumn(const wxDataViewColumn *column)
                             : NSTableColumnNoResizing;
     }
     [nativeColumn setResizingMask:resizingMask];
-    [nativeColumn setWidth:width];
 
 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
     // setting the visibility:
@@ -495,6 +521,9 @@ outlineView:(NSOutlineView*)outlineView
     acceptDrop:(id<NSDraggingInfo>)info
     item:(id)item childIndex:(NSInteger)index
 {
+    wxUnusedVar(outlineView);
+    wxUnusedVar(index);
+    
     NSArray* supportedTypes(
         [NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]
     );
@@ -518,7 +547,7 @@ outlineView:(NSOutlineView*)outlineView
     event.SetItem(wxDataViewItemFromItem(item));
     event.SetModel(dvc->GetModel());
 
-    BOOL dragSuccessful;
+    BOOL dragSuccessful = false;
     if ( [bestType compare:DataViewPboardType] == NSOrderedSame )
     {
         NSArray* dataArray((NSArray*)
@@ -603,12 +632,15 @@ outlineView:(NSOutlineView*)outlineView
         ::CFRelease(osxData);
         delete dataObjects;
     }
+    return dragSuccessful;
 }
 
 -(id) outlineView:(NSOutlineView*)outlineView
     child:(NSInteger)index
     ofItem:(id)item
 {
+    wxUnusedVar(outlineView);
+
     if ((item == currentParentItem) &&
             (index < ((NSInteger) [self getChildCount])))
         return [self getChild:index];
@@ -625,12 +657,16 @@ outlineView:(NSOutlineView*)outlineView
 
 -(BOOL) outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item
 {
+    wxUnusedVar(outlineView);
+
     wxCHECK_MSG( model, 0, "Valid model in data source does not exist." );
     return model->IsContainer(wxDataViewItemFromItem(item));
 }
 
 -(NSInteger) outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(id)item
 {
+    wxUnusedVar(outlineView);
+
     NSInteger noOfChildren;
 
     wxDataViewItemArray dataViewChildren;
@@ -650,9 +686,12 @@ outlineView:(NSOutlineView*)outlineView
     objectValueForTableColumn:(NSTableColumn*)tableColumn
     byItem:(id)item
 {
+    wxUnusedVar(outlineView);
+
     wxCHECK_MSG( model, nil, "Valid model in data source does not exist." );
 
-    wxDataViewColumn* col(static_cast<wxDataViewColumn*>([[tableColumn identifier] pointer]));
+    wxDataViewColumn* const
+        col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
     const unsigned colIdx = col->GetModelColumn();
 
     wxDataViewItem dataViewItem(wxDataViewItemFromItem(item));
@@ -673,7 +712,10 @@ outlineView:(NSOutlineView*)outlineView
     forTableColumn:(NSTableColumn*)tableColumn
     byItem:(id)item
 {
-    wxDataViewColumn* col(static_cast<wxDataViewColumn*>([[tableColumn identifier] pointer]));
+    wxUnusedVar(outlineView);
+
+    wxDataViewColumn* const
+        col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
 
     col->GetRenderer()->
         OSXOnCellChanged(object, wxDataViewItemFromItem(item), col->GetModelColumn());
@@ -681,6 +723,8 @@ outlineView:(NSOutlineView*)outlineView
 
 -(void) outlineView:(NSOutlineView*)outlineView sortDescriptorsDidChange:(NSArray*)oldDescriptors
 {
+    wxUnusedVar(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.
@@ -705,11 +749,11 @@ outlineView:(NSOutlineView*)outlineView
             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:
-    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED,dvc->GetId()); // variable defintion
+    wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED,dvc->GetId()); // variable definition
 
     event.SetEventObject(dvc);
     if (noOfDescriptors > 0)
@@ -730,6 +774,9 @@ outlineView:(NSOutlineView*)outlineView
 
 -(NSDragOperation) outlineView:(NSOutlineView*)outlineView validateDrop:(id<NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
 {
+    wxUnusedVar(outlineView);
+    wxUnusedVar(index);
+
     NSArray* supportedTypes([NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]);
 
     NSPasteboard* pasteboard([info draggingPasteboard]);
@@ -738,7 +785,7 @@ outlineView:(NSOutlineView*)outlineView
     if (bestType == nil)
         return NSDragOperationNone;
 
-    NSDragOperation dragOperation;
+    NSDragOperation dragOperation = NSDragOperationNone;
     wxDataViewCtrl* const dvc(implementation->GetDataViewCtrl());
 
     wxCHECK_MSG(dvc, false, "Pointer to data view control not set correctly.");
@@ -827,6 +874,8 @@ outlineView:(NSOutlineView*)outlineView
 
 -(BOOL) outlineView:(NSOutlineView*)outlineView writeItems:(NSArray*)writeItems toPasteboard:(NSPasteboard*)pasteboard
 {
+    wxUnusedVar(outlineView);
+
     // 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
@@ -842,7 +891,7 @@ outlineView:(NSOutlineView*)outlineView
     if ([writeItems count] > 0)
     {
         bool            dataStringAvailable(true); // a flag indicating if for all items a data string is available
-        NSMutableArray* dataArray = [[NSMutableArray arrayWithCapacity:[writeItems count]] retain]; // data of all items
+        NSMutableArray* dataArray = [NSMutableArray arrayWithCapacity:[writeItems count]]; // 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
@@ -877,7 +926,8 @@ outlineView:(NSOutlineView*)outlineView
                     size_t const dataSize       = event.GetDataObject()->GetDataSize(idDataFormat);
                     size_t const dataBufferSize = sizeof(wxDataFormatId)+dataSize;
                     // variable definitions (used in all case statements):
-                    wxMemoryBuffer dataBuffer(dataBufferSize);
+                    // give additional headroom for trailing NULL
+                    wxMemoryBuffer dataBuffer(dataBufferSize+4);
 
                     dataBuffer.AppendData(&idDataFormat,sizeof(wxDataFormatId));
                     switch (idDataFormat)
@@ -909,7 +959,6 @@ outlineView:(NSOutlineView*)outlineView
                             break;
                         default:
                             wxFAIL_MSG("Data object has invalid or unsupported data format");
-                            [dataArray release];
                             return NO;
                     }
                 }
@@ -927,7 +976,6 @@ outlineView:(NSOutlineView*)outlineView
             }
             else
             {
-                [dataArray release];
                 delete itemObject;
                 return NO; // dragging was vetoed or no data available
             }
@@ -1118,6 +1166,23 @@ outlineView:(NSOutlineView*)outlineView
 
 @implementation wxCustomCell
 
+#if 0 // starting implementation for custom cell clicks
+
+- (id)init
+{
+    self = [super init];
+    [self setAction:@selector(clickedAction)];
+    [self setTarget:self];
+    return self;
+}
+
+- (void) clickedAction: (id) sender
+{
+    wxUnusedVar(sender);
+}
+
+#endif
+
 -(NSSize) cellSize
 {
     wxCustomRendererObject * const
@@ -1144,9 +1209,27 @@ outlineView:(NSOutlineView*)outlineView
 
     wxDataViewCustomRenderer * const renderer = obj->customRenderer;
 
-    wxDC * const dc = renderer->GetDC();
-    renderer->WXCallRender(wxFromNSRect(controlView, cellFrame), dc, 0);
-    renderer->SetDC(NULL);
+    // if this method is called everything is already setup correctly, 
+    CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
+    CGContextSaveGState( context );
+    
+    if ( ![controlView isFlipped] )
+    {
+        CGContextTranslateCTM( context, 0,  [controlView bounds].size.height );
+        CGContextScaleCTM( context, 1, -1 );
+    }
+        
+    wxGCDC dc;
+    wxGraphicsContext* gc = wxGraphicsContext::CreateFromNative(context);
+    dc.SetGraphicsContext(gc);
+
+    int state = 0;
+    if ( [self isHighlighted] )
+        state |= wxDATAVIEW_CELL_SELECTED;
+
+    renderer->WXCallRender(wxFromNSRect(controlView, cellFrame), &dc, state);
+
+    CGContextRestoreGState( context );
 }
 
 -(NSRect) imageRectForBounds:(NSRect)cellFrame
@@ -1534,6 +1617,8 @@ outlineView:(NSOutlineView*)outlineView
 //
 -(void) actionDoubleClick:(id)sender
 {
+    wxUnusedVar(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
@@ -1553,6 +1638,8 @@ outlineView:(NSOutlineView*)outlineView
 //
 -(NSMenu*) menuForEvent:(NSEvent*)theEvent
 {
+    wxUnusedVar(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
@@ -1581,7 +1668,8 @@ outlineView:(NSOutlineView*)outlineView
 //
 -(void) outlineView:(NSOutlineView*)outlineView mouseDownInHeaderOfTableColumn:(NSTableColumn*)tableColumn
 {
-    wxDataViewColumn* const col(static_cast<wxDataViewColumn*>([[tableColumn identifier] pointer]));
+    wxDataViewColumn* const
+        col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
 
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
@@ -1624,6 +1712,8 @@ outlineView:(NSOutlineView*)outlineView
 
 -(BOOL) outlineView:(NSOutlineView*)outlineView shouldCollapseItem:(id)item
 {
+    wxUnusedVar(outlineView);
+
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
     wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING,dvc->GetId());
@@ -1640,6 +1730,8 @@ outlineView:(NSOutlineView*)outlineView
 
 -(BOOL) outlineView:(NSOutlineView*)outlineView shouldExpandItem:(id)item
 {
+    wxUnusedVar(outlineView);
+
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
     wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING,dvc->GetId());
@@ -1656,6 +1748,9 @@ outlineView:(NSOutlineView*)outlineView
 
 -(BOOL) outlineView:(NSOutlineView*)outlineView shouldSelectTableColumn:(NSTableColumn*)tableColumn
 {
+    wxUnusedVar(tableColumn);
+    wxUnusedVar(outlineView);
+
     return NO;
 }
 
@@ -1664,14 +1759,13 @@ outlineView:(NSOutlineView*)outlineView
     forTableColumn:(NSTableColumn*)tableColumn
     item:(id)item
 {
+    wxUnusedVar(outlineView);
+
     wxDataViewCtrl * const dvc = implementation->GetDataViewCtrl();
     wxDataViewModel * const model = dvc->GetModel();
 
-    wxDataViewColumn * const
-        dvCol(static_cast<wxDataViewColumn*>(
-                    [[tableColumn identifier] pointer]
-                    )
-             );
+    wxDataViewColumn* const
+        dvCol([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
     const unsigned colIdx = dvCol->GetModelColumn();
 
     wxDataViewItem dvItem(wxDataViewItemFromItem(item));
@@ -1694,6 +1788,9 @@ outlineView:(NSOutlineView*)outlineView
     model->GetAttr(dvItem, colIdx, attr);
     renderer->OSXApplyAttr(attr);
 
+    // set the state (enabled/disabled) of the item
+    renderer->OSXApplyEnabled(model->IsEnabled(dvItem, colIdx));
+
     // and finally do draw it
     renderer->MacRender();
 }
@@ -1705,7 +1802,10 @@ outlineView:(NSOutlineView*)outlineView
 {
     int const newColumnPosition = [[[notification userInfo] objectForKey:@"NSNewColumn"] intValue];
 
-    wxDataViewColumn* const col(static_cast<wxDataViewColumn*>([[[[self tableColumns] objectAtIndex:newColumnPosition] identifier] pointer]));
+    NSTableColumn*
+        tableColumn = [[self tableColumns] objectAtIndex:newColumnPosition];
+    wxDataViewColumn* const
+        col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
 
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
@@ -1746,6 +1846,8 @@ outlineView:(NSOutlineView*)outlineView
 
 -(void) outlineViewSelectionDidChange:(NSNotification*)notification
 {
+    wxUnusedVar(notification);
+
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
     wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED,dvc->GetId());
@@ -1770,9 +1872,10 @@ outlineView:(NSOutlineView*)outlineView
     currentlyEditedColumn = [self editedColumn];
     currentlyEditedRow = [self editedRow];
 
-    wxDataViewColumn* const col =
-        static_cast<wxDataViewColumn*>(
-                [[[[self tableColumns] objectAtIndex:currentlyEditedColumn] identifier] pointer]);
+    NSTableColumn*
+        tableColumn = [[self tableColumns] objectAtIndex:currentlyEditedColumn];
+    wxDataViewColumn* const
+        col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
 
     wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
@@ -1808,9 +1911,10 @@ outlineView:(NSOutlineView*)outlineView
     // been sent the last edited column/row are valid:
     if ( currentlyEditedColumn != -1 && currentlyEditedRow != -1 )
     {
-        wxDataViewColumn* const col =
-            static_cast<wxDataViewColumn*>(
-                    [[[[self tableColumns] objectAtIndex:currentlyEditedColumn] identifier] pointer]);
+        NSTableColumn*
+            tableColumn = [[self tableColumns] objectAtIndex:currentlyEditedColumn];
+        wxDataViewColumn* const
+            col([static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer]);
 
         wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
 
@@ -1912,7 +2016,7 @@ bool wxCocoaDataViewControl::DeleteColumn(wxDataViewColumn* columnPtr)
         [m_OutlineView setOutlineTableColumn:nil]; // due to a bug this does not work
     [m_OutlineView removeTableColumn:columnPtr->GetNativeData()->GetNativeColumnPtr()]; // due to a confirmed bug #6555162 the deletion does not work for
     // outline table columns (... and there is no workaround)
-    return (([m_OutlineView columnWithIdentifier:[[[wxPointerObject alloc] initWithPointer:columnPtr] autorelease]]) == -1);
+    return (([m_OutlineView columnWithIdentifier:[wxDVCNSTableColumn identifierForColumnPointer:columnPtr]]) == -1);
 }
 
 void wxCocoaDataViewControl::DoSetExpanderColumn(const wxDataViewColumn *columnPtr)
@@ -1922,12 +2026,13 @@ void wxCocoaDataViewControl::DoSetExpanderColumn(const wxDataViewColumn *columnP
 
 wxDataViewColumn* wxCocoaDataViewControl::GetColumn(unsigned int pos) const
 {
-    return static_cast<wxDataViewColumn*>([[[[m_OutlineView tableColumns] objectAtIndex:pos] identifier] pointer]);
+    NSTableColumn* tableColumn = [[m_OutlineView tableColumns] objectAtIndex:pos];
+    return [static_cast<wxDVCNSTableColumn*>(tableColumn) getColumnPointer];
 }
 
 int wxCocoaDataViewControl::GetColumnPosition(const wxDataViewColumn *columnPtr) const
 {
-    return [m_OutlineView columnWithIdentifier:[[[wxPointerObject alloc] initWithPointer:const_cast<wxDataViewColumn*>(columnPtr)] autorelease]];
+    return [m_OutlineView columnWithIdentifier:[wxDVCNSTableColumn identifierForColumnPointer:columnPtr]];
 }
 
 bool wxCocoaDataViewControl::InsertColumn(unsigned int pos, wxDataViewColumn* columnPtr)
@@ -1941,10 +2046,132 @@ bool wxCocoaDataViewControl::InsertColumn(unsigned int pos, wxDataViewColumn* co
     [m_OutlineView addTableColumn:nativeColumn];
     if (pos != static_cast<unsigned int>([m_OutlineView numberOfColumns]-1))
         [m_OutlineView moveColumn:[m_OutlineView numberOfColumns]-1 toColumn:pos];
+
+    // set columns width now that it can be computed even for autosized columns:
+    columnPtr->SetWidth(columnPtr->GetWidthVariable());
+
     // done:
     return true;
 }
 
+void wxCocoaDataViewControl::FitColumnWidthToContent(unsigned int pos)
+{
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+    const int count = GetCount();
+    NSTableColumn *column = GetColumn(pos)->GetNativeData()->GetNativeColumnPtr();
+
+    class MaxWidthCalculator
+    {
+    public:
+        MaxWidthCalculator(wxCocoaOutlineView *view,
+                           NSTableColumn *column, unsigned columnIndex)
+            : m_width(0),
+              m_view(view),
+              m_column(columnIndex),
+              m_indent(0)
+        {
+            // account for indentation in the column with expander
+            if ( column == [m_view outlineTableColumn] )
+                m_indent = [m_view indentationPerLevel];
+        }
+
+        void UpdateWithWidth(int width)
+        {
+            m_width = wxMax(m_width, width);
+        }
+
+        void UpdateWithRow(int row)
+        {
+            NSCell *cell = [m_view preparedCellAtColumn:m_column row:row];
+            unsigned cellWidth = [cell cellSize].width + 1/*round the float up*/;
+
+            if ( m_indent )
+                cellWidth += m_indent * ([m_view levelForRow:row] + 1);
+
+            m_width = wxMax(m_width, cellWidth);
+        }
+
+        int GetMaxWidth() const { return m_width; }
+
+    private:
+        int m_width;
+        wxCocoaOutlineView *m_view;
+        unsigned m_column;
+        int m_indent;
+    };
+
+    MaxWidthCalculator calculator(m_OutlineView, column, pos);
+
+    if ( [column headerCell] )
+    {
+        calculator.UpdateWithWidth([[column headerCell] cellSize].width + 1/*round the float up*/);
+    }
+
+    // The code below deserves some explanation. For very large controls, we
+    // simply can't afford to calculate sizes for all items, it takes too
+    // long. So the best we can do is to check the first and the last N/2
+    // items in the control for some sufficiently large N and calculate best
+    // sizes from that. That can result in the calculated best width being too
+    // small for some outliers, but it's better to get slightly imperfect
+    // result than to wait several seconds after every update. To avoid highly
+    // visible miscalculations, we also include all currently visible items
+    // no matter what.  Finally, the value of N is determined dynamically by
+    // measuring how much time we spent on the determining item widths so far.
+
+#if wxUSE_STOPWATCH
+    int top_part_end = count;
+    static const long CALC_TIMEOUT = 20/*ms*/;
+    // don't call wxStopWatch::Time() too often
+    static const unsigned CALC_CHECK_FREQ = 100;
+    wxStopWatch timer;
+#else
+    // use some hard-coded limit, that's the best we can do without timer
+    int top_part_end = wxMin(500, count);
+#endif // wxUSE_STOPWATCH/!wxUSE_STOPWATCH
+
+    int row = 0;
+
+    for ( row = 0; row < top_part_end; row++ )
+    {
+#if wxUSE_STOPWATCH
+        if ( row % CALC_CHECK_FREQ == CALC_CHECK_FREQ-1 &&
+             timer.Time() > CALC_TIMEOUT )
+            break;
+#endif // wxUSE_STOPWATCH
+        calculator.UpdateWithRow(row);
+    }
+
+    // row is the first unmeasured item now; that's our value of N/2
+
+    if ( row < count )
+    {
+        top_part_end = row;
+
+        // add bottom N/2 items now:
+        const int bottom_part_start = wxMax(row, count - row);
+        for ( row = bottom_part_start; row < count; row++ )
+            calculator.UpdateWithRow(row);
+
+        // finally, include currently visible items in the calculation:
+        const NSRange visible = [m_OutlineView rowsInRect:[m_OutlineView visibleRect]];
+        const int first_visible = wxMax(visible.location, top_part_end);
+        const int last_visible = wxMin(first_visible + visible.length, bottom_part_start);
+
+        for ( row = first_visible; row < last_visible; row++ )
+            calculator.UpdateWithRow(row);
+
+        wxLogTrace("dataview",
+                   "determined best size from %d top, %d bottom plus %d more visible items out of %d total",
+                   top_part_end,
+                   count - bottom_part_start,
+                   wxMax(0, last_visible - first_visible),
+                   count);
+    }
+
+    [column setWidth:calculator.GetMaxWidth()];
+#endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+}
+
 //
 // item related methods (inherited from wxDataViewWidgetImpl)
 //
@@ -2005,9 +2232,9 @@ bool wxCocoaDataViewControl::IsExpanded(const wxDataViewItem& item) const
 bool wxCocoaDataViewControl::Reload()
 {
     [m_DataSource clearBuffers];
+    [m_OutlineView reloadData];
     [m_OutlineView scrollColumnToVisible:0];
     [m_OutlineView scrollRowToVisible:0];
-    [m_OutlineView reloadData];
     return true;
 }
 
@@ -2031,6 +2258,8 @@ bool wxCocoaDataViewControl::Remove(const wxDataViewItem& parent, const wxDataVi
 
 bool wxCocoaDataViewControl::Update(const wxDataViewColumn *columnPtr)
 {
+    wxUnusedVar(columnPtr);
+    
     return false;
 }
 
@@ -2068,6 +2297,35 @@ bool wxCocoaDataViewControl::AssociateModel(wxDataViewModel* model)
 //
 // selection related methods (inherited from wxDataViewWidgetImpl)
 //
+
+wxDataViewItem wxCocoaDataViewControl::GetCurrentItem() const
+{
+    return wxDataViewItem([[m_OutlineView itemAtRow:[m_OutlineView selectedRow]] pointer]);
+}
+
+wxDataViewColumn *wxCocoaDataViewControl::GetCurrentColumn() const
+{
+    int col = [m_OutlineView selectedColumn];
+    if ( col == -1 )
+        return NULL;
+    return GetColumn(col);
+}
+
+void wxCocoaDataViewControl::SetCurrentItem(const wxDataViewItem& item)
+{
+    // We can't have unselected current item in a NSTableView, as the
+    // documentation of its deselectRow method explains, the control will
+    // automatically change the current item to the closest still selected item
+    // if the current item is deselected. So we have no choice but to select
+    // the item in the same time as making it current.
+    Select(item);
+}
+
+int wxCocoaDataViewControl::GetSelectedItemsCount() const
+{
+    return [m_OutlineView numberOfSelectedRows];
+}
+
 int wxCocoaDataViewControl::GetSelections(wxDataViewItemArray& sel) const
 {
     NSIndexSet* selectedRowIndexes([m_OutlineView selectedRowIndexes]);
@@ -2095,7 +2353,7 @@ void wxCocoaDataViewControl::Select(const wxDataViewItem& item)
 {
     if (item.IsOk())
         [m_OutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:[m_OutlineView rowForItem:[m_DataSource getDataViewItemFromBuffer:item]]]
-            byExtendingSelection:NO];
+            byExtendingSelection:GetDataViewCtrl()->HasFlag(wxDV_MULTIPLE) ? YES : NO];
 }
 
 void wxCocoaDataViewControl::SelectAll()
@@ -2126,7 +2384,7 @@ wxDataViewColumn* wxCocoaDataViewControl::GetSortingColumn() const
 
     for (UInt32 i=0; i<noOfColumns; ++i)
         if ([[columns objectAtIndex:i] sortDescriptorPrototype] != nil)
-            return static_cast<wxDataViewColumn*>([[[columns objectAtIndex:i] identifier] pointer]);
+            return GetColumn(i);
     return NULL;
 }
 
@@ -2136,6 +2394,11 @@ void wxCocoaDataViewControl::Resort()
     [m_OutlineView reloadData];
 }
 
+void wxCocoaDataViewControl::StartEditor( const wxDataViewItem & item, unsigned int column )
+{
+    [m_OutlineView editColumn:column row:[m_OutlineView rowForItem:[m_DataSource getDataViewItemFromBuffer:item]] withEvent:nil select:YES];
+}
+
 //
 // other methods (inherited from wxDataViewWidgetImpl)
 //
@@ -2156,7 +2419,7 @@ void wxCocoaDataViewControl::HitTest(const wxPoint& point, wxDataViewItem& item,
     indexRow    = [m_OutlineView rowAtPoint:   nativePoint];
     if ((indexColumn >= 0) && (indexRow >= 0))
     {
-        columnPtr = static_cast<wxDataViewColumn*>([[[[m_OutlineView tableColumns] objectAtIndex:indexColumn] identifier] pointer]);
+        columnPtr = GetColumn(indexColumn);
         item      = wxDataViewItem([[m_OutlineView itemAtRow:indexRow] pointer]);
     }
     else
@@ -2373,12 +2636,11 @@ 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
+    // TODO: This code should really be removed and this function be made pure
+    //       virtual. We just need to decide what to do with custom renderers
+    //       (i.e. wxDataViewCustomRenderer), currently OS X "in place" editing
+    //       which doesn't really create an editor control is not compatible
+    //       with the in place editing under other platforms.
 
     wxVariant value;
     if ( [object isKindOfClass:[NSString class]] )
@@ -2451,7 +2713,7 @@ void wxDataViewRenderer::OSXApplyAttr(const wxDataViewItemAttr& attr)
             }
 
             const wxColour& c = attr.GetColour();
-            colText = [NSColor colorWithDeviceRed:c.Red() / 255.
+            colText = [NSColor colorWithCalibratedRed:c.Red() / 255.
                 green:c.Green() / 255.
                 blue:c.Blue() / 255.
                 alpha:c.Alpha() / 255.];
@@ -2470,6 +2732,11 @@ void wxDataViewRenderer::OSXApplyAttr(const wxDataViewItemAttr& attr)
         [(id)cell setTextColor:colText];
 }
 
+void wxDataViewRenderer::OSXApplyEnabled(bool enabled)
+{
+    [GetNativeData()->GetItemCell() setEnabled:enabled];
+}
+
 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer,wxDataViewRendererBase)
 
 // ---------------------------------------------------------
@@ -2597,13 +2864,24 @@ wxDataViewChoiceRenderer::wxDataViewChoiceRenderer(const wxArrayString& choices,
 
     cell = [[NSPopUpButtonCell alloc] init];
     [cell setControlSize:NSMiniControlSize];
-    [cell setFont:[[NSFont fontWithName:[[cell font] fontName] size:[NSFont systemFontSizeForControlSize:NSMiniControlSize]] autorelease]];
+    [cell setFont:[NSFont fontWithName:[[cell font] fontName] size:[NSFont systemFontSizeForControlSize:NSMiniControlSize]]];
     for (size_t i=0; i<choices.GetCount(); ++i)
-        [cell addItemWithTitle:[[wxCFStringRef(choices[i]).AsNSString() retain] autorelease]];
+        [cell addItemWithTitle:wxCFStringRef(choices[i]).AsNSString()];
     SetNativeData(new wxDataViewRendererNativeData(cell));
     [cell release];
 }
 
+void
+wxDataViewChoiceRenderer::OSXOnCellChanged(NSObject *value,
+                                           const wxDataViewItem& item,
+                                           unsigned col)
+{
+    // At least under OS X 10.7 we get the index of the item selected and not
+    // its string.
+    wxDataViewModel *model = GetOwner()->GetOwner()->GetModel();
+    model->ChangeValue(GetChoice(ObjectToLong(value)), item, col);
+}
+
 bool wxDataViewChoiceRenderer::MacRender()
 {
     if (GetValue().GetType() == GetVariantType())
@@ -2743,6 +3021,8 @@ bool wxDataViewIconTextRenderer::MacRender()
         iconText << GetValue();
         if (iconText.GetIcon().IsOk())
             [cell setImage:[[wxBitmap(iconText.GetIcon()).GetNSImage() retain] autorelease]];
+        else
+            [cell setImage:nil];
         [cell setStringValue:[[wxCFStringRef(iconText.GetText()).AsNSString() retain] autorelease]];
         return true;
     }
@@ -2820,6 +3100,8 @@ wxDataViewProgressRenderer::wxDataViewProgressRenderer(const wxString& label,
                                                        int align)
     : wxDataViewRenderer(varianttype,mode,align)
 {
+    wxUnusedVar(label);
+    
     NSLevelIndicatorCell* cell;
 
     cell = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle];
@@ -2869,7 +3151,8 @@ wxDataViewColumn::wxDataViewColumn(const wxString& title,
        m_title(title)
 {
     InitCommon(width, align, flags);
-    if (renderer && (renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT))
+    if (renderer && !renderer->IsCustomRenderer() &&
+        (renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT))
         renderer->SetAlignment(align);
 }
 
@@ -2883,7 +3166,8 @@ wxDataViewColumn::wxDataViewColumn(const wxBitmap& bitmap,
       m_NativeDataPtr(new wxDataViewColumnNativeData())
 {
     InitCommon(width, align, flags);
-    if (renderer && (renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT))
+    if (renderer && !renderer->IsCustomRenderer() &&
+        (renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT))
         renderer->SetAlignment(align);
 }
 
@@ -2907,7 +3191,8 @@ void wxDataViewColumn::SetAlignment(wxAlignment align)
 {
     m_alignment = align;
     [[m_NativeDataPtr->GetNativeColumnPtr() headerCell] setAlignment:ConvertToNativeHorizontalTextAlignment(align)];
-    if (m_renderer && (m_renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT))
+    if (m_renderer && !m_renderer->IsCustomRenderer() &&
+        (m_renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT))
         m_renderer->SetAlignment(align);
 }
 
@@ -2934,12 +3219,25 @@ void wxDataViewColumn::SetMinWidth(int minWidth)
 
 void wxDataViewColumn::SetReorderable(bool reorderable)
 {
+    wxUnusedVar(reorderable);
+}
+
+void wxDataViewColumn::SetHidden(bool hidden)
+{
+    // How to set flag here?
+
+    [m_NativeDataPtr->GetNativeColumnPtr() setHidden:hidden];
 }
 
-void wxDataViewColumn::SetResizeable(bool resizeable)
+bool wxDataViewColumn::IsHidden() const
 {
-    wxDataViewColumnBase::SetResizeable(resizeable);
-    if (resizeable)
+    return [m_NativeDataPtr->GetNativeColumnPtr() isHidden];
+}
+
+void wxDataViewColumn::SetResizeable(bool resizable)
+{
+    wxDataViewColumnBase::SetResizeable(resizable);
+    if (resizable)
         [m_NativeDataPtr->GetNativeColumnPtr() setResizingMask:NSTableColumnUserResizingMask];
     else
         [m_NativeDataPtr->GetNativeColumnPtr() setResizingMask:NSTableColumnNoResizing];
@@ -2947,7 +3245,12 @@ void wxDataViewColumn::SetResizeable(bool resizeable)
 
 void wxDataViewColumn::SetSortable(bool sortable)
 {
-    wxDataViewColumnBase::SetSortable(sortable);
+    // wxDataViewColumnBase::SetSortable(sortable);
+    // Avoid endless recursion and just set the flag here
+    if (sortable)
+        m_flags |= wxDATAVIEW_COL_SORTABLE;
+    else
+        m_flags &= ~wxDATAVIEW_COL_SORTABLE;
 }
 
 void wxDataViewColumn::SetSortOrder(bool ascending)
@@ -2983,14 +3286,29 @@ void wxDataViewColumn::SetTitle(const wxString& title)
 
 void wxDataViewColumn::SetWidth(int width)
 {
-    [m_NativeDataPtr->GetNativeColumnPtr() setWidth:width];
     m_width = width;
-}
 
-void wxDataViewColumn::SetAsSortKey(bool WXUNUSED(sort))
-{
-    // see wxGTK native wxDataViewColumn implementation
-    wxFAIL_MSG("not implemented");
+    switch ( width )
+    {
+        case wxCOL_WIDTH_AUTOSIZE:
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
+            if ( GetOwner() )
+            {
+                wxCocoaDataViewControl *peer = static_cast<wxCocoaDataViewControl*>(GetOwner()->GetPeer());
+                peer->FitColumnWidthToContent(GetOwner()->GetColumnPosition(this));
+                break;
+            }
+#endif
+            // fall through if unsupported (OSX < 10.5) or not yet settable
+
+        case wxCOL_WIDTH_DEFAULT:
+            width = wxDVC_DEFAULT_WIDTH;
+            // fall through
+
+        default:
+            [m_NativeDataPtr->GetNativeColumnPtr() setWidth:width];
+            break;
+    }
 }
 
 void wxDataViewColumn::SetNativeData(wxDataViewColumnNativeData* newNativeDataPtr)