X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/80ce465c64d6f250e26cd69e62671a189302e897..be0d0fedf936869e554b1335ac423a71c9750fe9:/src/osx/cocoa/dataview.mm?ds=sidebyside diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index 87d16daae7..2aeac7950d 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -24,6 +24,7 @@ #include "wx/osx/private.h" #include "wx/osx/cocoa/dataview.h" #include "wx/renderer.h" +#include "wx/stopwatch.h" // ============================================================================ // Constants used locally @@ -321,7 +322,6 @@ NSTableColumn* CreateNativeColumn(const wxDataViewColumn *column) ); // setting the size related parameters: - const int width = column->GetWidthVariable(); int resizingMask; if (column->IsResizeable()) { @@ -329,7 +329,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 +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: @@ -495,6 +494,9 @@ outlineView:(NSOutlineView*)outlineView acceptDrop:(id)info item:(id)item childIndex:(NSInteger)index { + wxUnusedVar(outlineView); + wxUnusedVar(index); + NSArray* supportedTypes( [NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil] ); @@ -610,6 +612,8 @@ outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(id)item { + wxUnusedVar(outlineView); + if ((item == currentParentItem) && (index < ((NSInteger) [self getChildCount]))) return [self getChild:index]; @@ -626,12 +630,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; @@ -651,6 +659,8 @@ 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([[tableColumn identifier] pointer])); @@ -674,6 +684,8 @@ outlineView:(NSOutlineView*)outlineView forTableColumn:(NSTableColumn*)tableColumn byItem:(id)item { + wxUnusedVar(outlineView); + wxDataViewColumn* col(static_cast([[tableColumn identifier] pointer])); col->GetRenderer()-> @@ -682,6 +694,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. @@ -731,6 +745,9 @@ outlineView:(NSOutlineView*)outlineView -(NSDragOperation) outlineView:(NSOutlineView*)outlineView validateDrop:(id)info proposedItem:(id)item proposedChildIndex:(NSInteger)index { + wxUnusedVar(outlineView); + wxUnusedVar(index); + NSArray* supportedTypes([NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]); NSPasteboard* pasteboard([info draggingPasteboard]); @@ -828,6 +845,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 @@ -1535,6 +1554,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 @@ -1554,6 +1575,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 @@ -1625,6 +1648,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()); @@ -1641,6 +1666,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()); @@ -1657,6 +1684,9 @@ outlineView:(NSOutlineView*)outlineView -(BOOL) outlineView:(NSOutlineView*)outlineView shouldSelectTableColumn:(NSTableColumn*)tableColumn { + wxUnusedVar(tableColumn); + wxUnusedVar(outlineView); + return NO; } @@ -1665,6 +1695,8 @@ outlineView:(NSOutlineView*)outlineView forTableColumn:(NSTableColumn*)tableColumn item:(id)item { + wxUnusedVar(outlineView); + wxDataViewCtrl * const dvc = implementation->GetDataViewCtrl(); wxDataViewModel * const model = dvc->GetModel(); @@ -1695,6 +1727,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(); } @@ -1747,6 +1782,8 @@ outlineView:(NSOutlineView*)outlineView -(void) outlineViewSelectionDidChange:(NSNotification*)notification { + wxUnusedVar(notification); + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); wxDataViewEvent event(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED,dvc->GetId()); @@ -1942,10 +1979,132 @@ bool wxCocoaDataViewControl::InsertColumn(unsigned int pos, wxDataViewColumn* co [m_OutlineView addTableColumn:nativeColumn]; if (pos != static_cast([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 +2191,8 @@ bool wxCocoaDataViewControl::Remove(const wxDataViewItem& parent, const wxDataVi bool wxCocoaDataViewControl::Update(const wxDataViewColumn *columnPtr) { + wxUnusedVar(columnPtr); + return false; } @@ -2487,6 +2648,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) // --------------------------------------------------------- @@ -2837,6 +3003,8 @@ wxDataViewProgressRenderer::wxDataViewProgressRenderer(const wxString& label, int align) : wxDataViewRenderer(varianttype,mode,align) { + wxUnusedVar(label); + NSLevelIndicatorCell* cell; cell = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]; @@ -2886,7 +3054,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); } @@ -2900,7 +3069,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); } @@ -2924,7 +3094,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); } @@ -2951,6 +3122,7 @@ void wxDataViewColumn::SetMinWidth(int minWidth) void wxDataViewColumn::SetReorderable(bool reorderable) { + wxUnusedVar(reorderable); } void wxDataViewColumn::SetHidden(bool hidden) @@ -2965,10 +3137,10 @@ bool wxDataViewColumn::IsHidden() const return [m_NativeDataPtr->GetNativeColumnPtr() isHidden]; } -void wxDataViewColumn::SetResizeable(bool resizeable) +void wxDataViewColumn::SetResizeable(bool resizable) { - wxDataViewColumnBase::SetResizeable(resizeable); - if (resizeable) + wxDataViewColumnBase::SetResizeable(resizable); + if (resizable) [m_NativeDataPtr->GetNativeColumnPtr() setResizingMask:NSTableColumnUserResizingMask]; else [m_NativeDataPtr->GetNativeColumnPtr() setResizingMask:NSTableColumnNoResizing]; @@ -2976,7 +3148,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) @@ -3012,8 +3189,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(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))