]> git.saurik.com Git - wxWidgets.git/blobdiff - src/osx/cocoa/dataview.mm
always skip OnSize
[wxWidgets.git] / src / osx / cocoa / dataview.mm
index 8f14fbec25a2896dafd95f6882c20629a12d8452..7243ab2e030027ade28b80b157989dd709cde150 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"
 
 // ============================================================================
 // Constants used locally
@@ -276,7 +277,6 @@ 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];
@@ -322,7 +322,6 @@ NSTableColumn* CreateNativeColumn(const wxDataViewColumn *column)
     );
 
     // setting the size related parameters:
-    const int width = column->GetWidthVariable();
     int resizingMask;
     if (column->IsResizeable())
     {
@@ -341,7 +340,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:
@@ -604,6 +602,7 @@ outlineView:(NSOutlineView*)outlineView
         ::CFRelease(osxData);
         delete dataObjects;
     }
+    return dragSuccessful;
 }
 
 -(id) outlineView:(NSOutlineView*)outlineView
@@ -681,9 +680,10 @@ outlineView:(NSOutlineView*)outlineView
 }
 
 -(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;
@@ -699,23 +699,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));
@@ -796,7 +794,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());
 
@@ -826,10 +826,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;
@@ -844,7 +845,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());
 
@@ -864,9 +866,7 @@ outlineView:(NSOutlineView*)outlineView
             // 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);
@@ -883,7 +883,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);
@@ -1290,7 +1293,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);
@@ -1305,7 +1310,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);
@@ -1325,7 +1332,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];
@@ -1333,8 +1341,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;
@@ -1350,8 +1360,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]);
 
@@ -1363,14 +1375,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];
 }
 
@@ -1409,13 +1428,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
@@ -1507,12 +1533,13 @@ 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);
@@ -1525,9 +1552,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());
@@ -1538,8 +1566,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);
@@ -1567,13 +1596,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)
@@ -1595,7 +1626,7 @@ 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);
@@ -1611,7 +1642,7 @@ 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);
@@ -1663,6 +1694,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();
 }
@@ -1717,20 +1751,22 @@ outlineView:(NSOutlineView*)outlineView
 {
     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:
@@ -1749,7 +1785,7 @@ outlineView:(NSOutlineView*)outlineView
 
     // 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(
@@ -1761,15 +1797,18 @@ outlineView:(NSOutlineView*)outlineView
 
 -(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 =
@@ -1780,7 +1819,7 @@ outlineView:(NSOutlineView*)outlineView
 
         // 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(
@@ -1905,10 +1944,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)
 //
@@ -2032,6 +2193,22 @@ bool wxCocoaDataViewControl::AssociateModel(wxDataViewModel* model)
 //
 // selection related methods (inherited from wxDataViewWidgetImpl)
 //
+
+wxDataViewItem wxCocoaDataViewControl::GetCurrentItem() const
+{
+    return wxDataViewItem([[m_OutlineView itemAtRow:[m_OutlineView selectedRow]] pointer]);
+}
+
+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::GetSelections(wxDataViewItemArray& sel) const
 {
     NSIndexSet* selectedRowIndexes([m_OutlineView selectedRowIndexes]);
@@ -2059,7 +2236,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()
@@ -2434,6 +2611,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)
 
 // ---------------------------------------------------------
@@ -2527,11 +2709,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());
 
@@ -2613,33 +2797,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;
@@ -2817,7 +3015,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);
 }
 
@@ -2831,7 +3030,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);
 }
 
@@ -2855,13 +3055,15 @@ 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);
 }
 
 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]];
@@ -2883,6 +3085,18 @@ void wxDataViewColumn::SetReorderable(bool reorderable)
 {
 }
 
+void wxDataViewColumn::SetHidden(bool hidden)
+{
+    // How to set flag here?
+
+    [m_NativeDataPtr->GetNativeColumnPtr() setHidden:hidden];
+}
+
+bool wxDataViewColumn::IsHidden() const
+{
+    return [m_NativeDataPtr->GetNativeColumnPtr() isHidden];
+}
+
 void wxDataViewColumn::SetResizeable(bool resizeable)
 {
     wxDataViewColumnBase::SetResizeable(resizeable);
@@ -2894,7 +3108,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)
@@ -2921,7 +3140,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]];
@@ -2929,8 +3149,29 @@ void wxDataViewColumn::SetTitle(const wxString& title)
 
 void wxDataViewColumn::SetWidth(int width)
 {
-    [m_NativeDataPtr->GetNativeColumnPtr() setWidth:width];
     m_width = width;
+
+    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::SetAsSortKey(bool WXUNUSED(sort))