X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/8f2a8de6e754cbbd6d0d7c216c5b44518fae872e..cb6b81bc94108bcb0a702ac5fdaf4944fa7706a0:/src/osx/cocoa/dataview.mm diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index fe913b7039..d2d219d18e 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -4,7 +4,6 @@ // Author: // Modified by: // Created: 2009-01-31 -// RCS-ID: $Id: dataview.mm$ // Copyright: // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// @@ -21,274 +20,437 @@ #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 // ============================================================================ + #define DataViewPboardType @"OutlineViewItem" // ============================================================================ // Classes used locally in dataview.mm // ============================================================================ -@interface wxCustomRendererObject : NSObject -{ -@public - NSTableColumn* tableColumn; // not owned by the class - wxDataViewCustomRenderer* customRenderer; // not owned by the class +// ============================================================================ +// wxPointerObject +// ============================================================================ + +@implementation wxPointerObject - wxPointerObject* item; // not owned by the class +-(id) init +{ + self = [super init]; + if (self != nil) + self->pointer = NULL; + return self; } - // - // initialization - // - -(id) init; - -(id) initWithRenderer:(wxDataViewCustomRenderer*)initRenderer item:(wxPointerObject*)initItem column:(NSTableColumn*)initTableColumn; - -@end +-(id) initWithPointer:(void*) initPointer +{ + self = [super init]; + if (self != nil) + self->pointer = initPointer; + return self; +} -@implementation wxCustomRendererObject // -// initialization +// inherited methods from NSObject // --(id) init +-(BOOL) isEqual:(id)object { - self = [super init]; - if (self != nil) - { - customRenderer = NULL; - item = NULL; - tableColumn = NULL; - } - return self; + return (object != nil) && + ([object isKindOfClass:[wxPointerObject class]]) && + (pointer == [((wxPointerObject*) object) pointer]); } --(id) initWithRenderer:(wxDataViewCustomRenderer*)initRenderer item:(wxPointerObject*)initItem column:(NSTableColumn*)initTableColumn +-(NSUInteger) hash { - self = [super init]; - if (self != nil) - { - customRenderer = initRenderer; - item = initItem; - tableColumn = initTableColumn; - } - return self; + return (NSUInteger) pointer; } --(id) copyWithZone:(NSZone*)zone +-(void*) pointer { - wxCustomRendererObject* copy; - - - copy = [[[self class] allocWithZone:zone] init]; - copy->customRenderer = customRenderer; - copy->item = item; - copy->tableColumn = tableColumn; + return pointer; +} - return copy; +-(void) setPointer:(void*) newPointer +{ + pointer = newPointer; } @end -// ============================================================================ -// Functions used locally in dataview.mm -// ============================================================================ -static NSInteger CompareItems(id item1, id item2, void* context) +namespace +{ + +inline wxDataViewItem wxDataViewItemFromItem(id item) { - NSArray* const sortDescriptors = (NSArray*) context; + return wxDataViewItem([static_cast(item) pointer]); +} + +inline wxDataViewItem wxDataViewItemFromMaybeNilItem(id item) +{ + return item == nil ? wxDataViewItem() : wxDataViewItemFromItem(item); +} - NSUInteger const noOfDescriptors = [sortDescriptors count]; +} // anonymous namespace - NSInteger result(NSOrderedAscending); +// ---------------------------------------------------------------------------- +// wxCustomRendererObject +// ---------------------------------------------------------------------------- +@interface wxCustomRendererObject : NSObject +{ +@public + wxDataViewCustomRenderer* customRenderer; // not owned by the class +} - for (NSUInteger i=0; iCompare(wxDataViewItem([((wxPointerObject*) item1) pointer]), - wxDataViewItem([((wxPointerObject*) item2) pointer]), - [sortDescriptor columnPtr]->GetModelColumn(), - [sortDescriptor ascending] == YES); - if (wxComparisonResult < 0) +-(id) init +{ + self = [super init]; + if (self != nil) { - result = NSOrderedAscending; - break; + customRenderer = NULL; } - else if (wxComparisonResult > 0) + return self; +} + +-(id) initWithRenderer:(wxDataViewCustomRenderer*)renderer +{ + self = [super init]; + if (self != nil) { - result = NSOrderedDescending; - break; + customRenderer = renderer; } - else - result = NSOrderedSame; - } - return result; + return self; } -static NSTextAlignment ConvertToNativeHorizontalTextAlignment(int alignment) +-(id) copyWithZone:(NSZone*)zone { - if (alignment & wxALIGN_CENTER_HORIZONTAL) // center alignment is chosen also if alignment is equal to -1 - return NSCenterTextAlignment; - else if (alignment & wxALIGN_RIGHT) - return NSRightTextAlignment; - else - return NSLeftTextAlignment; + wxCustomRendererObject* copy; + + copy = [[[self class] allocWithZone:zone] init]; + copy->customRenderer = customRenderer; + + return copy; } +@end -static NSTableColumn* CreateNativeColumn(wxDataViewColumn const* columnPtr) +// ---------------------------------------------------------------------------- +// wxDVCNSTableColumn: exists only to override NSTableColumn:dataCellForRow: +// ---------------------------------------------------------------------------- + +@interface wxDVCNSTableColumn : NSTableColumn { - NSTableColumn* nativeColumn([[NSTableColumn alloc] initWithIdentifier:[[[wxPointerObject alloc] initWithPointer:const_cast(columnPtr)] autorelease]]); +} + // 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 native column: - if ((nativeColumn != NULL) && (columnPtr->GetRenderer() != NULL)) - { - // setting the size related parameters: - if (columnPtr->IsResizeable()) - { - [nativeColumn setResizingMask:NSTableColumnUserResizingMask]; - [nativeColumn setMinWidth:columnPtr->GetMinWidth()]; - [nativeColumn setMaxWidth:columnPtr->GetMaxWidth()]; - } - else + // 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(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( + [static_cast([self identifier]) integerValue]); +} + +-(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 + + const wxDataViewColumn * const dvCol = [self getColumnPointer]; + + const wxDataViewCtrl * const dvc = dvCol->GetOwner(); + const wxCocoaDataViewControl * const + peer = static_cast(dvc->GetPeer()); + + + // once we do have everything, simply ask NSOutlineView for the item... + const id item = peer->GetItemAtRow(row); + if ( item ) { - [nativeColumn setResizingMask:NSTableColumnNoResizing]; - [nativeColumn setMinWidth:columnPtr->GetWidth()]; - [nativeColumn setMaxWidth:columnPtr->GetWidth()]; + // ... 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; } - [nativeColumn setWidth:columnPtr->GetWidth()]; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - // setting the visibility: - [nativeColumn setHidden:static_cast(columnPtr->IsHidden())]; -#endif - // setting the header: - [[nativeColumn headerCell] setAlignment:ConvertToNativeHorizontalTextAlignment(columnPtr->GetAlignment())]; - [[nativeColumn headerCell] setStringValue:[[wxCFStringRef(columnPtr->GetTitle()).AsNSString() retain] autorelease]]; - // setting data cell's properties: - [[nativeColumn dataCell] setWraps:NO]; - // setting the default data cell: - [nativeColumn setDataCell:columnPtr->GetRenderer()->GetNativeData()->GetColumnCell()]; - // setting the editablility: - bool const dataCellIsEditable = (columnPtr->GetRenderer()->GetMode() == wxDATAVIEW_CELL_EDITABLE); - [nativeColumn setEditable:dataCellIsEditable]; - [[nativeColumn dataCell] setEditable:dataCellIsEditable]; - } - // done: - return nativeColumn; + return [super dataCellForRow:row]; } +@end + // ============================================================================ -// Public helper functions for dataview implementation on OSX +// local helpers // ============================================================================ -wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent), wxWindowID WXUNUSED(id), wxPoint const& pos, wxSize const& size, - long style, long WXUNUSED(extraStyle)) + +namespace { - return new wxCocoaDataViewControl(wxpeer,pos,size,style); + +// 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(); } -// ============================================================================ -// wxPointerObject -// ============================================================================ -// -// This is a helper class to store a pointer in an object. -// -@implementation wxPointerObject -// -// object initialization -// --(id) init +bool ObjectToBool(NSObject *object) { - self = [super init]; - if (self != nil) - self->pointer = NULL; - return self; + // 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]; } --(id) initWithPointer:(void*) initPointer +long ObjectToLong(NSObject *object) { - self = [super init]; - if (self != nil) - self->pointer = initPointer; - return self; + wxCHECK_MSG( [object isKindOfClass:[NSNumber class]], -1, + wxString::Format + ( + "number expected but got %s", + wxCFStringRef::AsString([object className]) + )); + + return [(NSNumber *)object longValue]; } -// -// inherited methods from NSObject -// --(BOOL) isEqual:(id)object +wxDateTime ObjectToDate(NSObject *object) { - return (object != nil) && ([object isKindOfClass:[wxPointerObject class]]) && (pointer == [((wxPointerObject*) object) pointer]); + 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; } --(NSUInteger) hash +NSInteger CompareItems(id item1, id item2, void* context) { - return (NSUInteger) pointer; + NSArray* const sortDescriptors = (NSArray*) context; + + NSUInteger const count = [sortDescriptors count]; + + NSInteger result = NSOrderedSame; + for ( NSUInteger i = 0; i < count && result == NSOrderedSame; ++i ) + { + wxSortDescriptorObject* const + sortDescriptor = (wxSortDescriptorObject*) + [sortDescriptors objectAtIndex:i]; + + int rc = [sortDescriptor modelPtr]->Compare + ( + wxDataViewItemFromItem(item1), + wxDataViewItemFromItem(item2), + [sortDescriptor columnPtr]->GetModelColumn(), + [sortDescriptor ascending] == YES + ); + + if ( rc < 0 ) + result = NSOrderedAscending; + else if ( rc > 0 ) + result = NSOrderedDescending; + } + + return result; } -// -// access to pointer -// --(void*) pointer +NSTextAlignment ConvertToNativeHorizontalTextAlignment(int alignment) { - return pointer; + if (alignment & wxALIGN_CENTER_HORIZONTAL) + return NSCenterTextAlignment; + else if (alignment & wxALIGN_RIGHT) + return NSRightTextAlignment; + else + return NSLeftTextAlignment; } --(void) setPointer:(void*) newPointer +NSTableColumn* CreateNativeColumn(const wxDataViewColumn *column) { - pointer = newPointer; + wxDataViewRenderer * const renderer = column->GetRenderer(); + + wxCHECK_MSG( renderer, NULL, "column should have a renderer" ); + + wxDVCNSTableColumn * const nativeColumn( + [[wxDVCNSTableColumn alloc] initWithColumnPointer: column] + ); + + // setting the size related parameters: + int resizingMask; + if (column->IsResizeable()) + { + resizingMask = NSTableColumnUserResizingMask; + [nativeColumn setMinWidth:column->GetMinWidth()]; + [nativeColumn setMaxWidth:column->GetMaxWidth()]; + } + 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 + // 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 setResizingMask:resizingMask]; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + // setting the visibility: + [nativeColumn setHidden:static_cast(column->IsHidden())]; +#endif + + wxDataViewRendererNativeData * const renderData = renderer->GetNativeData(); + + // setting the header: + [[nativeColumn headerCell] setAlignment: + ConvertToNativeHorizontalTextAlignment(column->GetAlignment())]; + [[nativeColumn headerCell] setStringValue: + [[wxCFStringRef(column->GetTitle()).AsNSString() retain] autorelease]]; + renderData->ApplyLineBreakMode([nativeColumn headerCell]); + + // setting data cell's properties: + [[nativeColumn dataCell] setWraps:NO]; + // setting the default data cell: + [nativeColumn setDataCell:renderData->GetColumnCell()]; + // setting the editablility: + const bool isEditable = renderer->GetMode() == wxDATAVIEW_CELL_EDITABLE; + + [nativeColumn setEditable:isEditable]; + [[nativeColumn dataCell] setEditable:isEditable]; + + return nativeColumn; } -@end +} // anonymous namespace + +// ============================================================================ +// Public helper functions for dataview implementation on OSX +// ============================================================================ + +wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, + wxWindowMac* WXUNUSED(parent), + wxWindowID WXUNUSED(id), + const wxPoint& pos, + const wxSize& size, + long style, + long WXUNUSED(extraStyle)) +{ + return new wxCocoaDataViewControl(wxpeer,pos,size,style); +} // ============================================================================ // wxSortDescriptorObject // ============================================================================ + @implementation wxSortDescriptorObject -// -// initialization -// -(id) init { - self = [super init]; - if (self != nil) - { - columnPtr = NULL; - modelPtr = NULL; - } - return self; + self = [super init]; + if (self != nil) + { + columnPtr = NULL; + modelPtr = NULL; + } + return self; } --(id) initWithModelPtr:(wxDataViewModel*)initModelPtr sortingColumnPtr:(wxDataViewColumn*)initColumnPtr ascending:(BOOL)sortAscending +-(id) +initWithModelPtr:(wxDataViewModel*)initModelPtr + sortingColumnPtr:(wxDataViewColumn*)initColumnPtr + ascending:(BOOL)sortAscending { - self = [super initWithKey:@"dummy" ascending:sortAscending]; - if (self != nil) - { - columnPtr = initColumnPtr; - modelPtr = initModelPtr; - } - return self; + self = [super initWithKey:@"dummy" ascending:sortAscending]; + if (self != nil) + { + columnPtr = initColumnPtr; + modelPtr = initModelPtr; + } + return self; } -(id) copyWithZone:(NSZone*)zone { - wxSortDescriptorObject* copy; + wxSortDescriptorObject* copy; - copy = [super copyWithZone:zone]; - copy->columnPtr = columnPtr; - copy->modelPtr = modelPtr; + copy = [super copyWithZone:zone]; + copy->columnPtr = columnPtr; + copy->modelPtr = modelPtr; - return copy; + return copy; } // @@ -296,22 +458,22 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(wxDataViewColumn*) columnPtr { - return columnPtr; + return columnPtr; } -(wxDataViewModel*) modelPtr { - return modelPtr; + return modelPtr; } -(void) setColumnPtr:(wxDataViewColumn*)newColumnPtr { - columnPtr = newColumnPtr; + columnPtr = newColumnPtr; } -(void) setModelPtr:(wxDataViewModel*)newModelPtr { - modelPtr = newModelPtr; + modelPtr = newModelPtr; } @end @@ -326,500 +488,516 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(id) init { - self = [super init]; - if (self != nil) - { - implementation = NULL; - model = NULL; + self = [super init]; + if (self != nil) + { + implementation = NULL; + model = NULL; - currentParentItem = nil; + currentParentItem = nil; - children = [[NSMutableArray alloc] init]; - items = [[NSMutableSet alloc] init]; - } - return self; + children = [[NSMutableArray alloc] init]; + items = [[NSMutableSet alloc] init]; + } + return self; } -(void) dealloc { - [currentParentItem release]; + [currentParentItem release]; - [children release]; - [items release]; + [children release]; + [items release]; - [super dealloc]; + [super dealloc]; } // // methods of informal protocol: // --(BOOL) outlineView:(NSOutlineView*)outlineView acceptDrop:(id)info item:(id)item childIndex:(NSInteger)index +-(BOOL) +outlineView:(NSOutlineView*)outlineView + acceptDrop:(id)info + item:(id)item childIndex:(NSInteger)index { - bool dragSuccessful; + wxUnusedVar(outlineView); + wxUnusedVar(index); + + NSArray* supportedTypes( + [NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil] + ); - NSArray* supportedTypes([NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]); + NSPasteboard* pasteboard([info draggingPasteboard]); - NSPasteboard* pasteboard([info draggingPasteboard]); + NSString* bestType([pasteboard availableTypeFromArray:supportedTypes]); - NSString* bestType([pasteboard availableTypeFromArray:supportedTypes]); + if ( bestType == nil ) + return FALSE; + wxDataViewCtrl * const dvc(implementation->GetDataViewCtrl()); - if (bestType != nil) - { - wxDataViewCtrl* const dataViewCtrlPtr(implementation->GetDataViewCtrl()); + wxCHECK_MSG( dvc, false, + "Pointer to data view control not set correctly." ); + wxCHECK_MSG( dvc->GetModel(), false, + "Pointer to model not set correctly." ); - wxCHECK_MSG(dataViewCtrlPtr != NULL, false,_("Pointer to data view control not set correctly.")); - wxCHECK_MSG(dataViewCtrlPtr->GetModel() != NULL,false,_("Pointer to model not set correctly.")); - // create wxWidget's event: - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_DROP,dataViewCtrlPtr->GetId()); + wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_DROP, dvc->GetId()); + event.SetEventObject(dvc); + event.SetItem(wxDataViewItemFromItem(item)); + event.SetModel(dvc->GetModel()); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetItem(wxDataViewItem([((wxPointerObject*) item) pointer])); - dataViewEvent.SetModel(dataViewCtrlPtr->GetModel()); - if ([bestType compare:DataViewPboardType] == NSOrderedSame) + BOOL dragSuccessful = false; + if ( [bestType compare:DataViewPboardType] == NSOrderedSame ) { - NSArray* dataArray((NSArray*)[pasteboard propertyListForType:DataViewPboardType]); - NSUInteger indexDraggedItem, noOfDraggedItems([dataArray count]); - - indexDraggedItem = 0; - while (indexDraggedItem < noOfDraggedItems) - { - wxDataObjectComposite* dataObjects(implementation->GetDnDDataObjects((NSData*)[dataArray objectAtIndex:indexDraggedItem])); + NSArray* dataArray((NSArray*) + [pasteboard propertyListForType:DataViewPboardType]); + NSUInteger indexDraggedItem, noOfDraggedItems([dataArray count]); - if ((dataObjects != NULL) && (dataObjects->GetFormatCount() > 0)) - { - wxMemoryBuffer buffer; - - // copy data into data object: - dataViewEvent.SetDataObject(dataObjects); - dataViewEvent.SetDataFormat(implementation->GetDnDDataFormat(dataObjects)); - // copy data into buffer: - dataObjects->GetDataHere(dataViewEvent.GetDataFormat().GetType(),buffer.GetWriteBuf(dataViewEvent.GetDataSize())); - buffer.UngetWriteBuf(dataViewEvent.GetDataSize()); - dataViewEvent.SetDataBuffer(buffer.GetData()); - // finally, send event: - if (dataViewCtrlPtr->HandleWindowEvent(dataViewEvent) && dataViewEvent.IsAllowed()) - { - dragSuccessful = true; - ++indexDraggedItem; - } - else - { - dragSuccessful = true; - indexDraggedItem = noOfDraggedItems; // stop loop - } - } - else + indexDraggedItem = 0; + while (indexDraggedItem < noOfDraggedItems) { - dragSuccessful = false; - indexDraggedItem = noOfDraggedItems; // stop loop + wxDataObjectComposite* dataObjects( + implementation->GetDnDDataObjects((NSData*) + [dataArray objectAtIndex:indexDraggedItem])); + + if (dataObjects && (dataObjects->GetFormatCount() > 0)) + { + wxMemoryBuffer buffer; + + // copy data into data object: + event.SetDataObject(dataObjects); + event.SetDataFormat( + implementation->GetDnDDataFormat(dataObjects)); + // copy data into buffer: + dataObjects->GetDataHere( + event.GetDataFormat().GetType(), + buffer.GetWriteBuf(event.GetDataSize())); + buffer.UngetWriteBuf(event.GetDataSize()); + event.SetDataBuffer(buffer.GetData()); + // finally, send event: + if (dvc->HandleWindowEvent(event) && event.IsAllowed()) + { + dragSuccessful = true; + ++indexDraggedItem; + } + else + { + dragSuccessful = true; + indexDraggedItem = noOfDraggedItems; // stop loop + } + } + else + { + dragSuccessful = false; + indexDraggedItem = noOfDraggedItems; // stop loop + } + // clean-up: + delete dataObjects; } - // clean-up: - delete dataObjects; - } } else { - CFDataRef osxData; // needed to convert internally used UTF-16 representation to a UTF-8 representation - wxDataObjectComposite* dataObjects (new wxDataObjectComposite()); - wxTextDataObject* textDataObject(new wxTextDataObject()); - - osxData = ::CFStringCreateExternalRepresentation(kCFAllocatorDefault,(CFStringRef)[pasteboard stringForType:NSStringPboardType],kCFStringEncodingUTF8,32); - if (textDataObject->SetData(::CFDataGetLength(osxData),::CFDataGetBytePtr(osxData))) - dataObjects->Add(textDataObject); - else - delete textDataObject; - // send event if data could be copied: - if (dataObjects->GetFormatCount() > 0) - { - dataViewEvent.SetDataObject(dataObjects); - dataViewEvent.SetDataFormat(implementation->GetDnDDataFormat(dataObjects)); - if (dataViewCtrlPtr->HandleWindowEvent(dataViewEvent) && dataViewEvent.IsAllowed()) - dragSuccessful = true; + // 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))) + dataObjects->Add(textDataObject); + else + delete textDataObject; + // send event if data could be copied: + if (dataObjects->GetFormatCount() > 0) + { + event.SetDataObject(dataObjects); + event.SetDataFormat(implementation->GetDnDDataFormat(dataObjects)); + if (dvc->HandleWindowEvent(event) && event.IsAllowed()) + dragSuccessful = true; + else + dragSuccessful = false; + } else - dragSuccessful = false; - } - else - dragSuccessful = false; - // clean up: - ::CFRelease(osxData); - delete dataObjects; + dragSuccessful = false; + // clean up: + ::CFRelease(osxData); + delete dataObjects; } - } - else - dragSuccessful = false; - return dragSuccessful; + 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]))) - return [self getChild:index]; - else - { + wxUnusedVar(outlineView); + + if ((item == currentParentItem) && + (index < ((NSInteger) [self getChildCount]))) + return [self getChild:index]; + wxDataViewItemArray dataViewChildren; - wxCHECK_MSG(model != NULL,0,_("Valid model in data source does not exist.")); - (void) model->GetChildren((item == nil) ? wxDataViewItem() : wxDataViewItem([((wxPointerObject*) item) pointer]),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]; + [children sortUsingFunction:CompareItems context:sortDescriptors]; return [self getChild:index]; - } } -(BOOL) outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item { - wxCHECK_MSG(model != NULL,0,_("Valid model in data source does not exist.")); - return model->IsContainer(wxDataViewItem([((wxPointerObject*) item) pointer])); + 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 { - NSInteger noOfChildren; + wxUnusedVar(outlineView); + + NSInteger noOfChildren; - wxDataViewItemArray dataViewChildren; + wxDataViewItemArray dataViewChildren; - wxCHECK_MSG(model != NULL,0,_("Valid model in data source does not exist.")); - noOfChildren = 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 noOfChildren; + wxCHECK_MSG( model, 0, "Valid model in data source does not exist." ); + noOfChildren = model->GetChildren(wxDataViewItemFromMaybeNilItem(item), + dataViewChildren); + [self bufferItem:item withChildren:&dataViewChildren]; + if ([sortDescriptors count] > 0) + [children sortUsingFunction:CompareItems context:sortDescriptors]; + return noOfChildren; } --(id) outlineView:(NSOutlineView*)outlineView objectValueForTableColumn:(NSTableColumn*)tableColumn byItem:(id)item +-(id) +outlineView:(NSOutlineView*)outlineView + objectValueForTableColumn:(NSTableColumn*)tableColumn + byItem:(id)item { - wxDataViewColumn* dataViewColumnPtr(reinterpret_cast([[tableColumn identifier] pointer])); + wxUnusedVar(outlineView); + + wxCHECK_MSG( model, nil, "Valid model in data source does not exist." ); - wxDataViewItem dataViewItem([((wxPointerObject*) item) pointer]); + wxDataViewColumn* const + col([static_cast(tableColumn) getColumnPointer]); + 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 != NULL,0,_("Valid model in data source does not exist.")); - model->GetValue(value,dataViewItem,dataViewColumnPtr->GetModelColumn()); - dataViewColumnPtr->GetRenderer()->SetValue(value); - return nil; + return nil; } --(void) outlineView:(NSOutlineView*)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn*)tableColumn byItem:(id)item +-(void) +outlineView:(NSOutlineView*)outlineView + setObjectValue:(id)object + forTableColumn:(NSTableColumn*)tableColumn + byItem:(id)item { - wxDataViewColumn* dataViewColumnPtr(reinterpret_cast([[tableColumn identifier] pointer])); + wxUnusedVar(outlineView); - wxDataViewItem dataViewItem([((wxPointerObject*) item) pointer]); + wxDataViewColumn* const + col([static_cast(tableColumn) getColumnPointer]); - - if (((dynamic_cast(dataViewColumnPtr->GetRenderer()) != NULL) || (dynamic_cast(dataViewColumnPtr->GetRenderer()) != NULL)) && - ([object isKindOfClass:[NSString class]] == YES)) - { - model->SetValue(wxVariant(wxCFStringRef([((NSString*) object) retain]).AsString()),dataViewItem,dataViewColumnPtr->GetModelColumn()); // the string has to be retained before being passed to wxCFStringRef - model->ValueChanged(dataViewItem,dataViewColumnPtr->GetModelColumn()); - } - else if (dynamic_cast(dataViewColumnPtr->GetRenderer()) != NULL) - { - if ([object isKindOfClass:[NSNumber class]] == YES) - { - model->SetValue(wxVariant(dynamic_cast(dataViewColumnPtr->GetRenderer())->GetChoice([((NSNumber*) object) intValue])), - dataViewItem,dataViewColumnPtr->GetModelColumn()); - model->ValueChanged(dataViewItem,dataViewColumnPtr->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,dataViewColumnPtr->GetModelColumn()); - model->ValueChanged(dataViewItem,dataViewColumnPtr->GetModelColumn()); - } - } - else if ((dynamic_cast(dataViewColumnPtr->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,dataViewColumnPtr->GetModelColumn()); - model->ValueChanged(dataViewItem,dataViewColumnPtr->GetModelColumn()); - } - else if ((dynamic_cast(dataViewColumnPtr->GetRenderer()) != NULL) && ([object isKindOfClass:[NSNumber class]] == YES)) - { - model->SetValue(wxVariant((bool) [((NSNumber*) object) boolValue]),dataViewItem,dataViewColumnPtr->GetModelColumn()); - model->ValueChanged(dataViewItem,dataViewColumnPtr->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. { - NSArray* newDescriptors; + 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. + NSArray* newDescriptors; - NSMutableArray* wxSortDescriptors; + NSMutableArray* wxSortDescriptors; - NSUInteger noOfDescriptors; + NSUInteger noOfDescriptors; - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); - // convert NSSortDescriptors to wxSortDescriptorObjects: - newDescriptors = [outlineView sortDescriptors]; - noOfDescriptors = [newDescriptors count]; - wxSortDescriptors = [NSMutableArray arrayWithCapacity:noOfDescriptors]; - for (NSUInteger i=0; iGetColumn([[newDescriptor key] intValue]) - ascending:[newDescriptor ascending]] autorelease]]; - } - [[outlineView dataSource] setSortDescriptors:wxSortDescriptors]; + [wxSortDescriptors addObject:[[[wxSortDescriptorObject alloc] initWithModelPtr:model + sortingColumnPtr:dvc->GetColumn([[newDescriptor key] intValue]) + ascending:[newDescriptor ascending]] autorelease]]; + } + [(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 dataViewEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED,dataViewCtrlPtr->GetId()); // variable defintion + // 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_DATAVIEW_COLUMN_SORTED,dvc->GetId()); // variable definition - dataViewEvent.SetEventObject(dataViewCtrlPtr); - if (noOfDescriptors > 0) - { - // constant definition for abbreviational purposes: - wxDataViewColumn* const dataViewColumnPtr = [[wxSortDescriptors objectAtIndex:0] columnPtr]; + event.SetEventObject(dvc); + if (noOfDescriptors > 0) + { + wxDataViewColumn* const col = [[wxSortDescriptors objectAtIndex:0] columnPtr]; - dataViewEvent.SetColumn(dataViewCtrlPtr->GetColumnPosition(dataViewColumnPtr)); - dataViewEvent.SetDataViewColumn(dataViewColumnPtr); - } - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); + event.SetColumn(dvc->GetColumnPosition(col)); + event.SetDataViewColumn(col); + } + dvc->GetEventHandler()->ProcessEvent(event); - // start re-ordering the data; - // children's buffer must be cleared first because it contains the old order: - [self clearChildren]; - // sorting is done while reloading the data: - [outlineView reloadData]; + // start re-ordering the data; + // children's buffer must be cleared first because it contains the old order: + [self clearChildren]; + // sorting is done while reloading the data: + [outlineView reloadData]; } -(NSDragOperation) outlineView:(NSOutlineView*)outlineView validateDrop:(id)info proposedItem:(id)item proposedChildIndex:(NSInteger)index { - NSArray* supportedTypes([NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]); + wxUnusedVar(outlineView); + wxUnusedVar(index); - NSDragOperation dragOperation; + NSArray* supportedTypes([NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]); - NSPasteboard* pasteboard([info draggingPasteboard]); + NSPasteboard* pasteboard([info draggingPasteboard]); - NSString* bestType([pasteboard availableTypeFromArray:supportedTypes]); + NSString* bestType([pasteboard availableTypeFromArray:supportedTypes]); + if (bestType == nil) + return NSDragOperationNone; + NSDragOperation dragOperation = NSDragOperationNone; + wxDataViewCtrl* const dvc(implementation->GetDataViewCtrl()); - if (bestType != nil) - { - wxDataViewCtrl* const dataViewCtrlPtr(implementation->GetDataViewCtrl()); + wxCHECK_MSG(dvc, false, "Pointer to data view control not set correctly."); + wxCHECK_MSG(dvc->GetModel(), false, "Pointer to model not set correctly."); - wxCHECK_MSG(dataViewCtrlPtr != NULL, false,_("Pointer to data view control not set correctly.")); - wxCHECK_MSG(dataViewCtrlPtr->GetModel() != NULL,false,_("Pointer to model not set correctly.")); - // create wxWidget's event: - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_DROP_POSSIBLE,dataViewCtrlPtr->GetId()); + wxDataViewEvent + event(wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE,dvc->GetId()); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetItem(wxDataViewItem([((wxPointerObject*) item) pointer])); - dataViewEvent.SetModel(dataViewCtrlPtr->GetModel()); + event.SetEventObject(dvc); + event.SetItem(wxDataViewItemFromItem(item)); + event.SetModel(dvc->GetModel()); if ([bestType compare:DataViewPboardType] == NSOrderedSame) { - NSArray* dataArray((NSArray*)[pasteboard propertyListForType:DataViewPboardType]); - NSUInteger indexDraggedItem, noOfDraggedItems([dataArray count]); - - indexDraggedItem = 0; - while (indexDraggedItem < noOfDraggedItems) - { - wxDataObjectComposite* dataObjects(implementation->GetDnDDataObjects((NSData*)[dataArray objectAtIndex:indexDraggedItem])); + NSArray* dataArray((NSArray*)[pasteboard propertyListForType:DataViewPboardType]); + NSUInteger indexDraggedItem, noOfDraggedItems([dataArray count]); - if ((dataObjects != NULL) && (dataObjects->GetFormatCount() > 0)) + indexDraggedItem = 0; + while (indexDraggedItem < noOfDraggedItems) { - wxMemoryBuffer buffer; - - // copy data into data object: - dataViewEvent.SetDataObject(dataObjects); - dataViewEvent.SetDataFormat(implementation->GetDnDDataFormat(dataObjects)); - // copy data into buffer: - dataObjects->GetDataHere(dataViewEvent.GetDataFormat().GetType(),buffer.GetWriteBuf(dataViewEvent.GetDataSize())); - buffer.UngetWriteBuf(dataViewEvent.GetDataSize()); - dataViewEvent.SetDataBuffer(buffer.GetData()); - // finally, send event: - if (dataViewCtrlPtr->HandleWindowEvent(dataViewEvent) && dataViewEvent.IsAllowed()) - { - dragOperation = NSDragOperationEvery; - ++indexDraggedItem; - } - else - { - dragOperation = NSDragOperationNone; - indexDraggedItem = noOfDraggedItems; // stop loop - } - } - else - { - dragOperation = NSDragOperationNone; - indexDraggedItem = noOfDraggedItems; // stop loop + wxDataObjectComposite* dataObjects(implementation->GetDnDDataObjects((NSData*)[dataArray objectAtIndex:indexDraggedItem])); + + if (dataObjects && (dataObjects->GetFormatCount() > 0)) + { + wxMemoryBuffer buffer; + + // copy data into data object: + event.SetDataObject(dataObjects); + event.SetDataFormat(implementation->GetDnDDataFormat(dataObjects)); + // copy data into buffer: + dataObjects->GetDataHere(event.GetDataFormat().GetType(),buffer.GetWriteBuf(event.GetDataSize())); + buffer.UngetWriteBuf(event.GetDataSize()); + event.SetDataBuffer(buffer.GetData()); + // finally, send event: + if (dvc->HandleWindowEvent(event) && event.IsAllowed()) + { + dragOperation = NSDragOperationEvery; + ++indexDraggedItem; + } + else + { + dragOperation = NSDragOperationNone; + indexDraggedItem = noOfDraggedItems; // stop loop + } + } + else + { + dragOperation = NSDragOperationNone; + indexDraggedItem = noOfDraggedItems; // stop loop + } + // clean-up: + delete dataObjects; } - // clean-up: - delete dataObjects; - } } else { - CFDataRef osxData; // needed to convert internally used UTF-16 representation to a UTF-8 representation - wxDataObjectComposite* dataObjects (new wxDataObjectComposite()); - wxTextDataObject* textDataObject(new wxTextDataObject()); - - osxData = ::CFStringCreateExternalRepresentation(kCFAllocatorDefault,(CFStringRef)[pasteboard stringForType:NSStringPboardType],kCFStringEncodingUTF8,32); - if (textDataObject->SetData(::CFDataGetLength(osxData),::CFDataGetBytePtr(osxData))) - dataObjects->Add(textDataObject); - else - delete textDataObject; - // send event if data could be copied: - if (dataObjects->GetFormatCount() > 0) - { - dataViewEvent.SetDataObject(dataObjects); - dataViewEvent.SetDataFormat(implementation->GetDnDDataFormat(dataObjects)); - if (dataViewCtrlPtr->HandleWindowEvent(dataViewEvent) && dataViewEvent.IsAllowed()) - dragOperation = NSDragOperationEvery; + // 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))) + dataObjects->Add(textDataObject); + else + delete textDataObject; + // send event if data could be copied: + if (dataObjects->GetFormatCount() > 0) + { + event.SetDataObject(dataObjects); + event.SetDataFormat(implementation->GetDnDDataFormat(dataObjects)); + if (dvc->HandleWindowEvent(event) && event.IsAllowed()) + dragOperation = NSDragOperationEvery; + else + dragOperation = NSDragOperationNone; + } else - dragOperation = NSDragOperationNone; - } - else - dragOperation = NSDragOperationNone; - // clean up: - ::CFRelease(osxData); - delete dataObjects; + dragOperation = NSDragOperationNone; + // clean up: + ::CFRelease(osxData); + delete dataObjects; } - } - else - dragOperation = NSDragOperationNone; - return dragOperation; + + return dragOperation; } -(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 { - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + wxUnusedVar(outlineView); - wxDataViewItemArray dataViewItems; + // 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; - wxCHECK_MSG(dataViewCtrlPtr != NULL, false,_("Pointer to data view control not set correctly.")); - wxCHECK_MSG(dataViewCtrlPtr->GetModel() != NULL,false,_("Pointer to model not set correctly.")); - 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 - wxString dataString; // contains the string data of all items + wxCHECK_MSG(dvc, false,"Pointer to data view control not set correctly."); + wxCHECK_MSG(dvc->GetModel(),false,"Pointer to model not set correctly."); - // send a begin drag event for all selected items and proceed with dragging unless the event is vetoed: - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_BEGIN_DRAG,dataViewCtrlPtr->GetId()); - - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetModel(dataViewCtrlPtr->GetModel()); - for (size_t itemCounter=0; itemCounter<[writeItems count]; ++itemCounter) + if ([writeItems count] > 0) { - bool itemStringAvailable(false); // a flag indicating if for the current item a string is available - wxDataObjectComposite* itemObject(new wxDataObjectComposite()); // data object for current item - wxString itemString; // contains the TAB concatenated data of an item - - dataViewEvent.SetItem(wxDataViewItem([((wxPointerObject*) [writeItems objectAtIndex:itemCounter]) pointer])); - itemString = ::ConcatenateDataViewItemValues(dataViewCtrlPtr,dataViewEvent.GetItem()); - itemObject->Add(new wxTextDataObject(itemString)); - dataViewEvent.SetDataObject(itemObject); - // check if event has not been vetoed: - if (dataViewCtrlPtr->HandleWindowEvent(dataViewEvent) && dataViewEvent.IsAllowed() && (dataViewEvent.GetDataObject()->GetFormatCount() > 0)) - { - // constant definition for abbreviational purposes: - size_t const noOfFormats = dataViewEvent.GetDataObject()->GetFormatCount(); - // variable definition and initialization: - wxDataFormat* dataFormats(new wxDataFormat[noOfFormats]); - - dataViewEvent.GetDataObject()->GetAllFormats(dataFormats,wxDataObject::Get); - for (size_t formatCounter=0; formatCounterGetId()); + + event.SetEventObject(dvc); + event.SetModel(dvc->GetModel()); + for (size_t itemCounter=0; itemCounter<[writeItems count]; ++itemCounter) { - // constant definitions for abbreviational purposes: - wxDataFormatId const idDataFormat = dataFormats[formatCounter].GetType(); - size_t const dataSize = dataViewEvent.GetDataObject()->GetDataSize(idDataFormat); - size_t const dataBufferSize = sizeof(wxDataFormatId)+dataSize; - // variable definitions (used in all case statements): - wxMemoryBuffer dataBuffer(dataBufferSize); - - dataBuffer.AppendData(&idDataFormat,sizeof(wxDataFormatId)); - switch (idDataFormat) - { - case wxDF_TEXT: - if (!itemStringAvailable) // otherwise wxDF_UNICODETEXT already filled up the string; and the UNICODE representation has priority - { - dataViewEvent.GetDataObject()->GetDataHere(wxDF_TEXT,dataBuffer.GetAppendBuf(dataSize)); - dataBuffer.UngetAppendBuf(dataSize); - [dataArray addObject:[NSData dataWithBytes:dataBuffer.GetData() length:dataBufferSize]]; - itemString = wxString(reinterpret_cast(dataBuffer.GetData())+sizeof(wxDataFormatId),wxConvLocal); - itemStringAvailable = true; - } - break; - case wxDF_UNICODETEXT: - { - dataViewEvent.GetDataObject()->GetDataHere(wxDF_UNICODETEXT,dataBuffer.GetAppendBuf(dataSize)); - dataBuffer.UngetAppendBuf(dataSize); - if (itemStringAvailable) // does an object already exist as an ASCII text (see wxDF_TEXT case statement)? - [dataArray replaceObjectAtIndex:itemCounter withObject:[NSData dataWithBytes:dataBuffer.GetData() length:dataBufferSize]]; - else - [dataArray addObject:[NSData dataWithBytes:dataBuffer.GetData() length:dataBufferSize]]; - itemString = wxString::FromUTF8(reinterpret_cast(dataBuffer.GetData())+sizeof(wxDataFormatId),dataSize); - itemStringAvailable = true; - } /* block */ - break; - default: - wxFAIL_MSG(_("Data object has invalid or unsupported data format")); - [dataArray release]; - return NO; - } + bool itemStringAvailable(false); // a flag indicating if for the current item a string is available + wxDataObjectComposite* itemObject(new wxDataObjectComposite()); // data object for current item + wxString itemString; // contains the TAB concatenated data of an item + + 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)) + { + size_t const noOfFormats = event.GetDataObject()->GetFormatCount(); + wxDataFormat* dataFormats(new wxDataFormat[noOfFormats]); + + event.GetDataObject()->GetAllFormats(dataFormats,wxDataObject::Get); + for (size_t formatCounter=0; formatCounterGetDataSize(idDataFormat); + size_t const dataBufferSize = sizeof(wxDataFormatId)+dataSize; + // variable definitions (used in all case statements): + // give additional headroom for trailing NULL + wxMemoryBuffer dataBuffer(dataBufferSize+4); + + dataBuffer.AppendData(&idDataFormat,sizeof(wxDataFormatId)); + switch (idDataFormat) + { + case wxDF_TEXT: + // 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); + [dataArray addObject:[NSData dataWithBytes:dataBuffer.GetData() length:dataBufferSize]]; + itemString = wxString(static_cast(dataBuffer.GetData())+sizeof(wxDataFormatId),wxConvLocal); + itemStringAvailable = true; + } + break; + case wxDF_UNICODETEXT: + { + event.GetDataObject()->GetDataHere(wxDF_UNICODETEXT,dataBuffer.GetAppendBuf(dataSize)); + dataBuffer.UngetAppendBuf(dataSize); + if (itemStringAvailable) // does an object already exist as an ASCII text (see wxDF_TEXT case statement)? + [dataArray replaceObjectAtIndex:itemCounter withObject:[NSData dataWithBytes:dataBuffer.GetData() length:dataBufferSize]]; + else + [dataArray addObject:[NSData dataWithBytes:dataBuffer.GetData() length:dataBufferSize]]; + itemString = wxString::FromUTF8(static_cast(dataBuffer.GetData())+sizeof(wxDataFormatId),dataSize); + itemStringAvailable = true; + } /* block */ + break; + default: + wxFAIL_MSG("Data object has invalid or unsupported data format"); + return NO; + } + } + delete[] dataFormats; + delete itemObject; + if (dataStringAvailable) + { + if (itemStringAvailable) + { + if (itemCounter > 0) + dataString << wxT('\n'); + dataString << itemString; + } + else + dataStringAvailable = false; + } + } + else + { + delete itemObject; + return NO; // dragging was vetoed or no data available + } } - delete[] dataFormats; - delete itemObject; if (dataStringAvailable) - if (itemStringAvailable) - { - if (itemCounter > 0) - dataString << wxT('\n'); - dataString << itemString; - } - else - dataStringAvailable = false; - } - else - { - [dataArray release]; - delete itemObject; - return NO; // dragging was vetoed or no data available - } - } - if (dataStringAvailable) - { - wxCFStringRef osxString(dataString); + { + wxCFStringRef osxString(dataString); - [pasteboard declareTypes:[NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil] owner:nil]; - [pasteboard setPropertyList:dataArray forType:DataViewPboardType]; - [pasteboard setString:osxString.AsNSString() forType:NSStringPboardType]; + [pasteboard declareTypes:[NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil] owner:nil]; + [pasteboard setPropertyList:dataArray forType:DataViewPboardType]; + [pasteboard setString:osxString.AsNSString() forType:NSStringPboardType]; + } + else + { + [pasteboard declareTypes:[NSArray arrayWithObject:DataViewPboardType] owner:nil]; + [pasteboard setPropertyList:dataArray forType:DataViewPboardType]; + } + return YES; } else - { - [pasteboard declareTypes:[NSArray arrayWithObject:DataViewPboardType] owner:nil]; - [pasteboard setPropertyList:dataArray forType:DataViewPboardType]; - } - return YES; - } - else - return NO; // no items to drag (should never occur) + return NO; // no items to drag (should never occur) } // @@ -827,32 +1005,32 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(void) addToBuffer:(wxPointerObject*)item { - [items addObject:item]; + [items addObject:item]; } -(void) clearBuffer { - [items removeAllObjects]; + [items removeAllObjects]; } --(wxPointerObject*) getDataViewItemFromBuffer:(wxDataViewItem const&)item +-(wxPointerObject*) getDataViewItemFromBuffer:(const wxDataViewItem&)item { - return [items member:[[[wxPointerObject alloc] initWithPointer:item.GetID()] autorelease]]; + return [items member:[[[wxPointerObject alloc] initWithPointer:item.GetID()] autorelease]]; } -(wxPointerObject*) getItemFromBuffer:(wxPointerObject*)item { - return [items member:item]; + return [items member:item]; } -(BOOL) isInBuffer:(wxPointerObject*)item { - return [items containsObject:item]; + return [items containsObject:item]; } -(void) removeFromBuffer:(wxPointerObject*)item { - [items removeObject:item]; + [items removeObject:item]; } // @@ -860,27 +1038,27 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(void) appendChild:(wxPointerObject*)item { - [children addObject:item]; + [children addObject:item]; } -(void) clearChildren { - [children removeAllObjects]; + [children removeAllObjects]; } -(wxPointerObject*) getChild:(NSUInteger)index { - return [children objectAtIndex:index]; + return [children objectAtIndex:index]; } -(NSUInteger) getChildCount { - return [children count]; + return [children count]; } -(void) removeChild:(NSUInteger)index { - [children removeObjectAtIndex:index]; + [children removeObjectAtIndex:index]; } // @@ -888,9 +1066,9 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(void) clearBuffers { - [self clearBuffer]; - [self clearChildren]; - [self setCurrentParentItem:nil]; + [self clearBuffer]; + [self clearChildren]; + [self setCurrentParentItem:nil]; } // @@ -898,14 +1076,14 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(NSArray*) sortDescriptors { - return sortDescriptors; + return sortDescriptors; } -(void) setSortDescriptors:(NSArray*)newSortDescriptors { - [newSortDescriptors retain]; - [sortDescriptors release]; - sortDescriptors = newSortDescriptors; + [newSortDescriptors retain]; + [sortDescriptors release]; + sortDescriptors = newSortDescriptors; } // @@ -913,34 +1091,34 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(wxPointerObject*) currentParentItem { - return currentParentItem; + return currentParentItem; } -(wxCocoaDataViewControl*) implementation { - return implementation; + return implementation; } -(wxDataViewModel*) model { - return model; + return model; } -(void) setCurrentParentItem:(wxPointerObject*)newCurrentParentItem { - [newCurrentParentItem retain]; - [currentParentItem release]; - currentParentItem = newCurrentParentItem; + [newCurrentParentItem retain]; + [currentParentItem release]; + currentParentItem = newCurrentParentItem; } -(void) setImplementation:(wxCocoaDataViewControl*) newImplementation { - implementation = newImplementation; + implementation = newImplementation; } -(void) setModel:(wxDataViewModel*) newModel { - model = newModel; + model = newModel; } // @@ -948,32 +1126,37 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(void) bufferItem:(wxPointerObject*)parentItem withChildren:(wxDataViewItemArray*)dataViewChildrenPtr { - NSInteger const noOfChildren = (*dataViewChildrenPtr).GetCount(); - - [self setCurrentParentItem:parentItem]; - [self clearChildren]; - for (NSInteger indexChild=0; indexChild([self objectValue]); - return NSMakeSize(customRendererObject->customRenderer->GetSize().GetWidth(),customRendererObject->customRenderer->GetSize().GetHeight()); + const wxSize size = obj->customRenderer->GetSize(); + return NSMakeSize(size.x, size.y); } // @@ -998,41 +1199,48 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(void) drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - wxCustomRendererObject* customRendererObject(((wxCustomRendererObject*)[self objectValue])); - - - // draw its own background: - [[self backgroundColor] set]; - NSRectFill(cellFrame); - - (void) (customRendererObject->customRenderer->Render(wxFromNSRect(controlView,cellFrame),customRendererObject->customRenderer->GetDC(),0)); - customRendererObject->customRenderer->SetDC(NULL); -} + wxCustomRendererObject * const + obj = static_cast([self objectValue]); + if ( !obj ) + { + // this may happen for the custom cells in container rows: they don't + // have any values + return; + } -#if 0 //TODO FIXME: MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 --(NSUInteger) hitTestForEvent:(NSEvent*)event inRect:(NSRect)cellFrame ofView:(NSView*)controlView -{ - NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil]; + wxDataViewCustomRenderer * const renderer = obj->customRenderer; - wxCustomRendererObject* customRendererObject((wxCustomRendererObject*)[self objectValue]); + // 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); - customRendererObject->customRenderer->LeftClick(wxFromNSPoint(controlView,point),wxFromNSRect(controlView,cellFrame), - customRendererObject->GetOwner()->GetOwner(),wxDataViewItem([customRendererObject->item pointer]), - [this->m_OutlineView columnWithIdentifier:[customRendererObject->GetColumnPtr() identifier]]); - return NSCellHitContentArea; + CGContextRestoreGState( context ); } -#endif -(NSRect) imageRectForBounds:(NSRect)cellFrame { - return cellFrame; + return cellFrame; } -(NSRect) titleRectForBounds:(NSRect)cellFrame { - return cellFrame; + return cellFrame; } @end @@ -1046,40 +1254,39 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(id) init { - self = [super init]; - if (self != nil) - { - // initializing the text part: - [self setLineBreakMode:NSLineBreakByTruncatingMiddle]; - [self setSelectable:YES]; - // initializing the image part: - image = nil; - imageSize = NSMakeSize(16,16); - spaceImageText = 5.0; - xImageShift = 5.0; - } - return self; + self = [super init]; + if (self != nil) + { + // initializing the text part: + [self setSelectable:YES]; + // initializing the image part: + image = nil; + imageSize = NSMakeSize(16,16); + spaceImageText = 5.0; + xImageShift = 5.0; + } + return self; } -(id) copyWithZone:(NSZone*)zone { - wxImageTextCell* cell; + wxImageTextCell* cell; - cell = (wxImageTextCell*) [super copyWithZone:zone]; - cell->image = [image retain]; - cell->imageSize = imageSize; - cell->spaceImageText = spaceImageText; - cell->xImageShift = xImageShift; + cell = (wxImageTextCell*) [super copyWithZone:zone]; + cell->image = [image retain]; + cell->imageSize = imageSize; + cell->spaceImageText = spaceImageText; + cell->xImageShift = xImageShift; - return cell; + return cell; } -(void) dealloc { - [image release]; + [image release]; - [super dealloc]; + [super dealloc]; } // @@ -1087,26 +1294,26 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(NSTextAlignment) alignment { - return cellAlignment; + return cellAlignment; } -(void) setAlignment:(NSTextAlignment)newAlignment { - cellAlignment = newAlignment; - switch (newAlignment) - { - case NSCenterTextAlignment: - case NSLeftTextAlignment: - case NSJustifiedTextAlignment: - case NSNaturalTextAlignment: - [super setAlignment:NSLeftTextAlignment]; - break; - case NSRightTextAlignment: - [super setAlignment:NSRightTextAlignment]; - break; - default: - wxFAIL_MSG(_("Unknown alignment type.")); - } + cellAlignment = newAlignment; + switch (newAlignment) + { + case NSCenterTextAlignment: + case NSLeftTextAlignment: + case NSJustifiedTextAlignment: + case NSNaturalTextAlignment: + [super setAlignment:NSLeftTextAlignment]; + break; + case NSRightTextAlignment: + [super setAlignment:NSRightTextAlignment]; + break; + default: + wxFAIL_MSG("Unknown alignment type."); + } } // @@ -1114,24 +1321,24 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(NSImage*) image { - return image; + return image; } -(void) setImage:(NSImage*)newImage { - [newImage retain]; - [image release]; - image = newImage; + [newImage retain]; + [image release]; + image = newImage; } -(NSSize) imageSize { - return imageSize; + return imageSize; } -(void) setImageSize:(NSSize) newImageSize { - imageSize = newImageSize; + imageSize = newImageSize; } // @@ -1139,24 +1346,24 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(NSSize) cellImageSize { - return NSMakeSize(imageSize.width+xImageShift+spaceImageText,imageSize.height); + return NSMakeSize(imageSize.width+xImageShift+spaceImageText,imageSize.height); } -(NSSize) cellSize { - NSSize cellSize([super cellSize]); + NSSize cellSize([super cellSize]); - if (imageSize.height > cellSize.height) - cellSize.height = imageSize.height; - cellSize.width += imageSize.width+xImageShift+spaceImageText; + if (imageSize.height > cellSize.height) + cellSize.height = imageSize.height; + cellSize.width += imageSize.width+xImageShift+spaceImageText; - return cellSize; + return cellSize; } -(NSSize) cellTextSize { - return [super cellSize]; + return [super cellSize]; } // @@ -1164,182 +1371,205 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(void) determineCellParts:(NSRect)cellFrame imagePart:(NSRect*)imageFrame textPart:(NSRect*)textFrame { - switch (cellAlignment) - { - case NSCenterTextAlignment: - { - 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: - 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); - } - break; - case NSJustifiedTextAlignment: - case NSLeftTextAlignment: - case NSNaturalTextAlignment: // how to determine the natural writing direction? TODO - NSDivideRect(cellFrame,imageFrame,textFrame,xImageShift+imageSize.width+spaceImageText,NSMinXEdge); - break; - case NSRightTextAlignment: - { - 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: - 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); - } - break; - default: - *imageFrame = NSZeroRect; - *textFrame = NSZeroRect; - wxFAIL_MSG(_("Unhandled alignment type.")); - } + switch (cellAlignment) + { + case NSCenterTextAlignment: + { + CGFloat const cellSpace = cellFrame.size.width-[self cellSize].width; + + // 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); + } + break; + case NSJustifiedTextAlignment: + case NSLeftTextAlignment: + case NSNaturalTextAlignment: // how to determine the natural writing direction? TODO + NSDivideRect(cellFrame,imageFrame,textFrame,xImageShift+imageSize.width+spaceImageText,NSMinXEdge); + break; + case NSRightTextAlignment: + { + CGFloat const cellSpace = cellFrame.size.width-[self cellSize].width; + + // 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); + } + break; + default: + *imageFrame = NSZeroRect; + *textFrame = NSZeroRect; + wxFAIL_MSG("Unhandled alignment type."); + } } -(void) drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView { - NSRect textFrame, imageFrame; - - - [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): - if ([self drawsBackground]) - { - [[self backgroundColor] set]; - NSRectFill(imageFrame); - } - 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: - if (imageFrame.size.width >= xImageShift+imageSize.width+spaceImageText) + NSRect textFrame, imageFrame; + + + [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): + if ([self drawsBackground]) { - imageFrame.origin.x += imageFrame.size.width-imageSize.width-spaceImageText; - imageFrame.size.width = imageSize.width; + [[self backgroundColor] set]; + NSRectFill(imageFrame); } - else + if (image != nil) { - imageFrame.origin.x += xImageShift; - imageFrame.size.width -= xImageShift+spaceImageText; + // 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; + imageFrame.size.width = imageSize.width; + } + else + { + imageFrame.origin.x += xImageShift; + imageFrame.size.width -= xImageShift+spaceImageText; + } + // ...and the image has to be centered in the y-direction: + if (imageFrame.size.height > imageSize.height) + 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 + // content is flipped: + NSAffineTransform* coordinateTransform([NSAffineTransform transform]); + + if ([controlView isFlipped]) + { + [coordinateTransform scaleXBy: 1.0 yBy:-1.0]; // first the coordinate system is brought back to bottom-top orientation + [coordinateTransform translateXBy:0.0 yBy:(-2.0)*imageFrame.origin.y-imageFrame.size.height]; // the coordinate system has to be moved to compensate for the + [coordinateTransform concat]; // other orientation and the position of the image's frame + } + [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): + [coordinateTransform invert]; + [coordinateTransform concat]; } - // ...and the image has to be centered in the y-direction: - if (imageFrame.size.height > imageSize.height) - 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 - // content is flipped: - NSAffineTransform* coordinateTransform([NSAffineTransform transform]); - - if ([controlView isFlipped]) + // let the textfield cell draw the text part: + if (textFrame.size.width > [self cellTextSize].width) { - [coordinateTransform scaleXBy: 1.0 yBy:-1.0]; // first the coordinate system is brought back to bottom-top orientation - [coordinateTransform translateXBy:0.0 yBy:(-2.0)*imageFrame.origin.y-imageFrame.size.height]; // the coordinate system has to be moved to compensate for the - [coordinateTransform concat]; // other orientation and the position of the image's frame + // 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; } - [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): - [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 - [super drawWithFrame:textFrame inView:controlView]; + [super drawWithFrame:textFrame inView:controlView]; } -(void) editWithFrame:(NSRect)aRect inView:(NSView*)controlView editor:(NSText*)textObj delegate:(id)anObject event:(NSEvent*)theEvent { - NSRect textFrame, imageFrame; + NSRect textFrame, imageFrame; - [self determineCellParts:aRect imagePart:&imageFrame textPart:&textFrame]; - [super editWithFrame:textFrame inView:controlView editor:textObj delegate:anObject event:theEvent]; + [self determineCellParts:aRect imagePart:&imageFrame textPart:&textFrame]; + [super editWithFrame:textFrame inView:controlView editor:textObj delegate:anObject event:theEvent]; } #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 -(NSUInteger) hitTestForEvent:(NSEvent*)event inRect:(NSRect)cellFrame ofView:(NSView*)controlView { - NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil]; + NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil]; - NSRect imageFrame, textFrame; + NSRect imageFrame, textFrame; - [self determineCellParts:cellFrame imagePart:&imageFrame textPart:&textFrame]; - if (image != nil) - { - // the image is shifted... - if (imageFrame.size.width >= xImageShift+imageSize.width+spaceImageText) + [self determineCellParts:cellFrame imagePart:&imageFrame textPart:&textFrame]; + if (image != nil) { - imageFrame.origin.x += imageFrame.size.width-imageSize.width-spaceImageText; - imageFrame.size.width = imageSize.width; + // the image is shifted... + if (imageFrame.size.width >= xImageShift+imageSize.width+spaceImageText) + { + imageFrame.origin.x += imageFrame.size.width-imageSize.width-spaceImageText; + imageFrame.size.width = imageSize.width; + } + else + { + imageFrame.origin.x += xImageShift; + imageFrame.size.width -= xImageShift+spaceImageText; + } + // ...and centered: + 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 (NSMouseInRect(point, imageFrame, [controlView isFlipped])) + return NSCellHitContentArea; } - else + // if the image was not hit let's try the text part: + if (textFrame.size.width > [self cellTextSize].width) { - imageFrame.origin.x += xImageShift; - imageFrame.size.width -= xImageShift+spaceImageText; + // 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; } - // ...and centered: - 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 (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 - return [super hitTestForEvent:event inRect:textFrame ofView:controlView]; + + return [super hitTestForEvent:event inRect:textFrame ofView:controlView]; } #endif -(NSRect) imageRectForBounds:(NSRect)cellFrame { - NSRect textFrame, imageFrame; + NSRect textFrame, imageFrame; - [self determineCellParts:cellFrame imagePart:&imageFrame textPart:&textFrame]; - if (imageFrame.size.width >= xImageShift+imageSize.width+spaceImageText) - { - imageFrame.origin.x += imageFrame.size.width-imageSize.width-spaceImageText; - imageFrame.size.width = imageSize.width; - } - else - { - imageFrame.origin.x += xImageShift; - imageFrame.size.width -= xImageShift+spaceImageText; - } - // ...and centered: - if (imageFrame.size.height > imageSize.height) - imageFrame.size.height = imageSize.height; - imageFrame.origin.y += ceil(0.5*(cellFrame.size.height-imageFrame.size.height)); + [self determineCellParts:cellFrame imagePart:&imageFrame textPart:&textFrame]; + if (imageFrame.size.width >= xImageShift+imageSize.width+spaceImageText) + { + imageFrame.origin.x += imageFrame.size.width-imageSize.width-spaceImageText; + imageFrame.size.width = imageSize.width; + } + else + { + imageFrame.origin.x += xImageShift; + imageFrame.size.width -= xImageShift+spaceImageText; + } + // ...and centered: + if (imageFrame.size.height > imageSize.height) + imageFrame.size.height = imageSize.height; + imageFrame.origin.y += ceil(0.5*(cellFrame.size.height-imageFrame.size.height)); - return imageFrame; + return imageFrame; } -(void) selectWithFrame:(NSRect)aRect inView:(NSView*)controlView editor:(NSText*)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength { - NSRect textFrame, imageFrame; + NSRect textFrame, imageFrame; - [self determineCellParts:aRect imagePart:&imageFrame textPart:&textFrame]; - [super selectWithFrame:textFrame inView:controlView editor:textObj delegate:anObject start:selStart length:selLength]; + [self determineCellParts:aRect imagePart:&imageFrame textPart:&textFrame]; + [super selectWithFrame:textFrame inView:controlView editor:textObj delegate:anObject start:selStart length:selLength]; } -(NSRect) titleRectForBounds:(NSRect)cellFrame { - NSRect textFrame, imageFrame; + NSRect textFrame, imageFrame; - [self determineCellParts:cellFrame imagePart:&imageFrame textPart:&textFrame]; - return textFrame; + [self determineCellParts:cellFrame imagePart:&imageFrame textPart:&textFrame]; + return textFrame; } @end @@ -1354,18 +1584,20 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(id) init { - self = [super init]; - if (self != nil) - { - isEditingCell = NO; - [self registerForDraggedTypes:[NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]]; - [self setDelegate:self]; - [self setDoubleAction:@selector(actionDoubleClick:)]; - [self setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO]; - [self setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES]; - [self setTarget:self]; - } - return self; + self = [super init]; + if (self != nil) + { + currentlyEditedColumn = + currentlyEditedRow = -1; + + [self registerForDraggedTypes:[NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]]; + [self setDelegate:self]; + [self setDoubleAction:@selector(actionDoubleClick:)]; + [self setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO]; + [self setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES]; + [self setTarget:self]; + } + return self; } // @@ -1373,29 +1605,32 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(wxCocoaDataViewControl*) implementation { - return implementation; + return implementation; } -(void) setImplementation:(wxCocoaDataViewControl*) newImplementation { - implementation = newImplementation; + implementation = newImplementation; } // // 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 { - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + 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 + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED,dataViewCtrlPtr->GetId()); // variable definition + wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_ACTIVATED,dvc->GetId()); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetItem(wxDataViewItem([((wxPointerObject*) [self itemAtRow:[self clickedRow]]) pointer])); - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); + event.SetEventObject(dvc); + event.SetItem(wxDataViewItemFromItem([self itemAtRow:[self clickedRow]])); + dvc->GetEventHandler()->ProcessEvent(event); } @@ -1403,117 +1638,162 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // 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 { - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + wxUnusedVar(theEvent); - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU,dataViewCtrlPtr->GetId()); + // 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(); - wxDataViewItemArray selectedItems; + wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_CONTEXT_MENU,dvc->GetId()); + wxDataViewItemArray selectedItems; - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetModel(dataViewCtrlPtr->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: - if (dataViewCtrlPtr->GetSelections(selectedItems) > 0) - dataViewEvent.SetItem(selectedItems[0]); - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); - // nothing is done: - return nil; + + 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: + if (dvc->GetSelections(selectedItems) > 0) + event.SetItem(selectedItems[0]); + dvc->GetEventHandler()->ProcessEvent(event); + // nothing is done: + return nil; } // // delegate methods // --(void) outlineView:(NSOutlineView*)outlineView mouseDownInHeaderOfTableColumn:(NSTableColumn*)tableColumn +-(void) outlineView:(NSOutlineView*)outlineView didClickTableColumn:(NSTableColumn*)tableColumn { - wxDataViewColumn* const dataViewColumnPtr(reinterpret_cast([[tableColumn identifier] pointer])); - - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + wxDataViewColumn* const + col([static_cast(tableColumn) getColumnPointer]); - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK,dataViewCtrlPtr->GetId()); + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); + wxDataViewEvent + event(wxEVT_DATAVIEW_COLUMN_HEADER_CLICK,dvc->GetId()); - // first, send an event that the user clicked into a column's header: - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetColumn(dataViewCtrlPtr->GetColumnPosition(dataViewColumnPtr)); - dataViewEvent.SetDataViewColumn(dataViewColumnPtr); - dataViewCtrlPtr->HandleWindowEvent(dataViewEvent); - // 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: - if (dataViewColumnPtr->IsSortable() && ([tableColumn sortDescriptorPrototype] == nil)) - { - // 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]; + // first, send an event that the user clicked into a column's header: + event.SetEventObject(dvc); + event.SetColumn(dvc->GetColumnPosition(col)); + event.SetDataViewColumn(col); + dvc->HandleWindowEvent(event); - for (UInt32 i=0; iIsSortable() && ([tableColumn sortDescriptorPrototype] == nil)) + { + // 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; iGetDataViewCtrl(); + wxUnusedVar(outlineView); - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING,dataViewCtrlPtr->GetId()); // variable definition + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); + wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_COLLAPSING,dvc->GetId()); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetItem (wxDataViewItem([((wxPointerObject*) item) pointer])); - dataViewEvent.SetModel (dataViewCtrlPtr->GetModel()); - // finally send the equivalent wxWidget event: - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); - // opening the container is allowed if not vetoed: - return dataViewEvent.IsAllowed(); + + event.SetEventObject(dvc); + event.SetItem (wxDataViewItemFromItem(item)); + event.SetModel (dvc->GetModel()); + // finally send the equivalent wxWidget event: + dvc->GetEventHandler()->ProcessEvent(event); + // opening the container is allowed if not vetoed: + return event.IsAllowed(); } -(BOOL) outlineView:(NSOutlineView*)outlineView shouldExpandItem:(id)item { - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + wxUnusedVar(outlineView); + + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING,dataViewCtrlPtr->GetId()); // variable definition + wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_EXPANDING,dvc->GetId()); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetItem (wxDataViewItem([((wxPointerObject*) item) pointer])); - dataViewEvent.SetModel (dataViewCtrlPtr->GetModel()); - // finally send the equivalent wxWidget event: - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); - // opening the container is allowed if not vetoed: - return dataViewEvent.IsAllowed(); + event.SetEventObject(dvc); + event.SetItem (wxDataViewItemFromItem(item)); + event.SetModel (dvc->GetModel()); + // finally send the equivalent wxWidget event: + dvc->GetEventHandler()->ProcessEvent(event); + // opening the container is allowed if not vetoed: + return event.IsAllowed(); } -(BOOL) outlineView:(NSOutlineView*)outlineView shouldSelectTableColumn:(NSTableColumn*)tableColumn { - return NO; + wxUnusedVar(tableColumn); + wxUnusedVar(outlineView); + + return NO; } --(void) outlineView:(NSOutlineView*)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*) tableColumn item:(id)item +-(void) outlineView:(wxCocoaOutlineView*)outlineView + willDisplayCell:(id)cell + forTableColumn:(NSTableColumn*)tableColumn + item:(id)item { - wxDataViewColumn* dataViewColumnPtr(reinterpret_cast([[tableColumn identifier] pointer])); + wxUnusedVar(outlineView); + + wxDataViewCtrl * const dvc = implementation->GetDataViewCtrl(); + wxDataViewModel * const model = dvc->GetModel(); + + wxDataViewColumn* const + dvCol([static_cast(tableColumn) getColumnPointer]); + const unsigned colIdx = dvCol->GetModelColumn(); + + wxDataViewItem dvItem(wxDataViewItemFromItem(item)); + + 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); + // set the state (enabled/disabled) of the item + renderer->OSXApplyEnabled(model->IsEnabled(dvItem, colIdx)); - dataViewColumnPtr->GetRenderer()->GetNativeData()->SetColumnPtr(tableColumn); - dataViewColumnPtr->GetRenderer()->GetNativeData()->SetItem(item); - dataViewColumnPtr->GetRenderer()->GetNativeData()->SetItemCell(cell); - (void) dataViewColumnPtr->GetRenderer()->MacRender(); + // and finally do draw it + renderer->MacRender(); } // @@ -1521,325 +1801,483 @@ wxWidgetImplType* CreateDataView(wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(pare // -(void) outlineViewColumnDidMove:(NSNotification*)notification { - int const newColumnPosition = [[[notification userInfo] objectForKey:@"NSNewColumn"] intValue]; + int const newColumnPosition = [[[notification userInfo] objectForKey:@"NSNewColumn"] intValue]; - wxDataViewColumn* const dataViewColumnPtr(reinterpret_cast([[[[self tableColumns] objectAtIndex:newColumnPosition] identifier] pointer])); + NSTableColumn* + tableColumn = [[self tableColumns] objectAtIndex:newColumnPosition]; + wxDataViewColumn* const + col([static_cast(tableColumn) getColumnPointer]); - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_REORDERED,dataViewCtrlPtr->GetId()); + wxDataViewEvent event(wxEVT_DATAVIEW_COLUMN_REORDERED,dvc->GetId()); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetColumn(dataViewCtrlPtr->GetColumnPosition(dataViewColumnPtr)); - dataViewEvent.SetDataViewColumn(dataViewColumnPtr); - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); + event.SetEventObject(dvc); + event.SetColumn(dvc->GetColumnPosition(col)); + event.SetDataViewColumn(col); + dvc->GetEventHandler()->ProcessEvent(event); } -(void) outlineViewItemDidCollapse:(NSNotification*)notification { - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED,dataViewCtrlPtr->GetId()); + wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_COLLAPSED,dvc->GetId()); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetItem(wxDataViewItem([((wxPointerObject*) [[notification userInfo] objectForKey:@"NSObject"]) pointer])); - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); + event.SetEventObject(dvc); + event.SetItem(wxDataViewItemFromItem( + [[notification userInfo] objectForKey:@"NSObject"])); + dvc->GetEventHandler()->ProcessEvent(event); } -(void) outlineViewItemDidExpand:(NSNotification*)notification { - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED,dataViewCtrlPtr->GetId()); + wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_EXPANDED,dvc->GetId()); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetItem(wxDataViewItem([((wxPointerObject*) [[notification userInfo] objectForKey:@"NSObject"]) pointer])); - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); + event.SetEventObject(dvc); + event.SetItem(wxDataViewItemFromItem( + [[notification userInfo] objectForKey:@"NSObject"])); + dvc->GetEventHandler()->ProcessEvent(event); } -(void) outlineViewSelectionDidChange:(NSNotification*)notification { - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + wxUnusedVar(notification); - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED,dataViewCtrlPtr->GetId()); // variable definition + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); + wxDataViewEvent event(wxEVT_DATAVIEW_SELECTION_CHANGED,dvc->GetId()); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetModel (dataViewCtrlPtr->GetModel()); - // finally send the equivalent wxWidget event: - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); + event.SetEventObject(dvc); + 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): - [super textDidBeginEditing: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!) - wxDataViewColumn* const dataViewColumnPtr = reinterpret_cast([[[[self tableColumns] objectAtIndex:[self editedColumn]] identifier] pointer]); + // 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]; - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + // remember the column being edited, it will be used in textDidEndEditing: + currentlyEditedColumn = [self editedColumn]; + currentlyEditedRow = [self editedRow]; + NSTableColumn* + tableColumn = [[self tableColumns] objectAtIndex:currentlyEditedColumn]; + wxDataViewColumn* const + col([static_cast(tableColumn) getColumnPointer]); - // stop editing of a custom item first (if necessary) - dataViewCtrlPtr->FinishCustomItemEditing(); - // set the flag that currently a cell is being edited (see also textDidEndEditing:): - isEditingCell = YES; + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); - // now, send the event: - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED,dataViewCtrlPtr->GetId()); // variable definition - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetItem(wxDataViewItem([((wxPointerObject*) [self itemAtRow:[self editedRow]]) pointer])); - dataViewEvent.SetColumn(dataViewCtrlPtr->GetColumnPosition(dataViewColumnPtr)); - dataViewEvent.SetDataViewColumn(dataViewColumnPtr); - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); + // stop editing of a custom item first (if necessary) + dvc->FinishCustomItemEditing(); + + // now, send the event: + wxDataViewEvent + event(wxEVT_DATAVIEW_ITEM_EDITING_STARTED,dvc->GetId()); + + event.SetEventObject(dvc); + event.SetItem( + wxDataViewItemFromItem([self itemAtRow:currentlyEditedRow])); + event.SetColumn(dvc->GetColumnPosition(col)); + event.SetDataViewColumn(col); + dvc->GetEventHandler()->ProcessEvent(event); } -(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): - [super textDidEndEditing:notification]; + // 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_DATAVIEW_ITEM_EDITING_DONE event is only sent if a + // corresponding wxEVT_DATAVIEW_ITEM_EDITING_STARTED has been sent + // before; to check if a wxEVT_DATAVIEW_ITEM_EDITING_STARTED has + // been sent the last edited column/row are valid: + if ( currentlyEditedColumn != -1 && currentlyEditedRow != -1 ) + { + NSTableColumn* + tableColumn = [[self tableColumns] objectAtIndex:currentlyEditedColumn]; + wxDataViewColumn* const + col([static_cast(tableColumn) getColumnPointer]); - // 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 flag isEditingCell is used: - if (isEditingCell == YES) - { - wxDataViewColumn* const dataViewColumnPtr = reinterpret_cast([[[[self tableColumns] objectAtIndex:[self editedColumn]] identifier] pointer]); + wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl(); - wxDataViewCtrl* const dataViewCtrlPtr = implementation->GetDataViewCtrl(); + // send event to wxWidgets: + wxDataViewEvent + event(wxEVT_DATAVIEW_ITEM_EDITING_DONE,dvc->GetId()); - // send event to wxWidgets: - wxDataViewEvent dataViewEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE,dataViewCtrlPtr->GetId()); // variable definition + event.SetEventObject(dvc); + event.SetItem( + wxDataViewItemFromItem([self itemAtRow:currentlyEditedRow])); + event.SetColumn(dvc->GetColumnPosition(col)); + event.SetDataViewColumn(col); + dvc->GetEventHandler()->ProcessEvent(event); - dataViewEvent.SetEventObject(dataViewCtrlPtr); - dataViewEvent.SetItem(wxDataViewItem([((wxPointerObject*) [self itemAtRow:[self editedRow]]) pointer])); - dataViewEvent.SetColumn(dataViewCtrlPtr->GetColumnPosition(dataViewColumnPtr)); - dataViewEvent.SetDataViewColumn(dataViewColumnPtr); - dataViewCtrlPtr->GetEventHandler()->ProcessEvent(dataViewEvent); - // set flag to the inactive state: - isEditingCell = NO; - } + + // we're not editing any more + currentlyEditedColumn = + currentlyEditedRow = -1; + } } @end + // ============================================================================ // wxCocoaDataViewControl // ============================================================================ -// -// constructors / destructor -// -wxCocoaDataViewControl::wxCocoaDataViewControl(wxWindow* peer, wxPoint const& pos, wxSize const& 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*) this->GetWXWidget(); // definition for abbreviational purposes + // initialize scrollview (the outline view is part of a scrollview): + NSScrollView* scrollview = (NSScrollView*) GetWXWidget(); + [scrollview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [scrollview setBorderType:NSNoBorder]; + [scrollview setHasVerticalScroller:YES]; + [scrollview setHasHorizontalScroller:YES]; + [scrollview setAutohidesScrollers:YES]; + [scrollview setDocumentView:m_OutlineView]; - [scrollview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [scrollview setBorderType:NSNoBorder]; - [scrollview setHasVerticalScroller:YES]; - [scrollview setHasHorizontalScroller:YES]; - [scrollview setAutohidesScrollers:YES]; - [scrollview setDocumentView:this->m_OutlineView]; + // we cannot call InstallHandler(m_OutlineView) here, because we are handling + // our action:s ourselves, only associate the view with this impl + Associate(m_OutlineView,this); + // initialize the native control itself too + InitOutlineView(style); +} - // setting up the native control itself - NSUInteger maskGridStyle(NSTableViewGridNone); +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) + maskGridStyle |= NSTableViewSolidVerticalGridLineMask; + [m_OutlineView setGridStyleMask:maskGridStyle]; + [m_OutlineView setAllowsMultipleSelection: (style & wxDV_MULTIPLE) != 0]; + [m_OutlineView setUsesAlternatingRowBackgroundColors:(style & wxDV_ROW_LINES) != 0]; - [this->m_OutlineView setImplementation:this]; - [this->m_OutlineView setColumnAutoresizingStyle:NSTableViewSequentialColumnAutoresizingStyle]; - [this->m_OutlineView setIndentationPerLevel:this->GetDataViewCtrl()->GetIndent()]; - if (style & wxDV_HORIZ_RULES) - maskGridStyle |= NSTableViewSolidHorizontalGridLineMask; - if (style & wxDV_VERT_RULES) - maskGridStyle |= NSTableViewSolidVerticalGridLineMask; - [this->m_OutlineView setGridStyleMask:maskGridStyle]; - [this->m_OutlineView setAllowsMultipleSelection: (style & wxDV_MULTIPLE) != 0]; - [this->m_OutlineView setUsesAlternatingRowBackgroundColors:(style & wxDV_ROW_LINES) != 0]; + if ( style & wxDV_NO_HEADER ) + [m_OutlineView setHeaderView:nil]; } -wxCocoaDataViewControl::~wxCocoaDataViewControl(void) +wxCocoaDataViewControl::~wxCocoaDataViewControl() { - [this->m_DataSource release]; - [this->m_OutlineView release]; + [m_DataSource release]; + [m_OutlineView release]; } // // column related methods (inherited from wxDataViewWidgetImpl) // -bool wxCocoaDataViewControl::ClearColumns(void) +bool wxCocoaDataViewControl::ClearColumns() { - bool const bufAllowsMultipleSelection = [this->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; + // therefore, the whole view is deleted and newly constructed: + [m_OutlineView release]; + m_OutlineView = [[wxCocoaOutlineView alloc] init]; + [((NSScrollView*) GetWXWidget()) setDocumentView:m_OutlineView]; + [m_OutlineView setDataSource:m_DataSource]; + InitOutlineView(GetDataViewCtrl()->GetWindowStyle()); - // 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: - [this->m_OutlineView release]; - this->m_OutlineView = [[wxCocoaOutlineView alloc] init]; - [((NSScrollView*) this->GetWXWidget()) setDocumentView:this->m_OutlineView]; - - // setting up the native control itself - [this->m_OutlineView setImplementation:this]; - [this->m_OutlineView setColumnAutoresizingStyle:NSTableViewSequentialColumnAutoresizingStyle]; - [this->m_OutlineView setIndentationPerLevel:this->GetDataViewCtrl()->GetIndent()]; - if (bufAllowsMultipleSelection) - [this->m_OutlineView setAllowsMultipleSelection:YES]; - [this->m_OutlineView setDataSource:this->m_DataSource]; - // done: - return true; + return true; } bool wxCocoaDataViewControl::DeleteColumn(wxDataViewColumn* columnPtr) { - if ([this->m_OutlineView outlineTableColumn] == columnPtr->GetNativeData()->GetNativeColumnPtr()) - [this->m_OutlineView setOutlineTableColumn:nil]; // due to a bug this does not work - [this->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 (([this->m_OutlineView columnWithIdentifier:[[[wxPointerObject alloc] initWithPointer:columnPtr] autorelease]]) == -1); + if ([m_OutlineView outlineTableColumn] == columnPtr->GetNativeData()->GetNativeColumnPtr()) + [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:[wxDVCNSTableColumn identifierForColumnPointer:columnPtr]]) == -1); } -void wxCocoaDataViewControl::DoSetExpanderColumn(wxDataViewColumn const* columnPtr) +void wxCocoaDataViewControl::DoSetExpanderColumn(const wxDataViewColumn *columnPtr) { - [this->m_OutlineView setOutlineTableColumn:columnPtr->GetNativeData()->GetNativeColumnPtr()]; + [m_OutlineView setOutlineTableColumn:columnPtr->GetNativeData()->GetNativeColumnPtr()]; } wxDataViewColumn* wxCocoaDataViewControl::GetColumn(unsigned int pos) const { - return reinterpret_cast([[[[this->m_OutlineView tableColumns] objectAtIndex:pos] identifier] pointer]); + NSTableColumn* tableColumn = [[m_OutlineView tableColumns] objectAtIndex:pos]; + return [static_cast(tableColumn) getColumnPointer]; } -int wxCocoaDataViewControl::GetColumnPosition(wxDataViewColumn const* columnPtr) const +int wxCocoaDataViewControl::GetColumnPosition(const wxDataViewColumn *columnPtr) const { - return [this->m_OutlineView columnWithIdentifier:[[[wxPointerObject alloc] initWithPointer:const_cast(columnPtr)] autorelease]]; + return [m_OutlineView columnWithIdentifier:[wxDVCNSTableColumn identifierForColumnPointer:columnPtr]]; } bool wxCocoaDataViewControl::InsertColumn(unsigned int pos, wxDataViewColumn* columnPtr) { - NSTableColumn* nativeColumn; + // 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: + [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); + } - // create column and set the native data of the dataview column: - 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: - [this->m_OutlineView addTableColumn:nativeColumn]; - if (pos != static_cast([this->m_OutlineView numberOfColumns]-1)) - [this->m_OutlineView moveColumn:[this->m_OutlineView numberOfColumns]-1 toColumn:pos]; - // done: - return true; + [column setWidth:calculator.GetMaxWidth()]; +#endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 } // // item related methods (inherited from wxDataViewWidgetImpl) // -bool wxCocoaDataViewControl::Add(wxDataViewItem const& parent, wxDataViewItem const& WXUNUSED(item)) +bool wxCocoaDataViewControl::Add(const wxDataViewItem& parent, const wxDataViewItem& WXUNUSED(item)) { - if (parent.IsOk()) - [this->m_OutlineView reloadItem:[this->m_DataSource getDataViewItemFromBuffer:parent] reloadChildren:YES]; - else - [this->m_OutlineView reloadData]; - return true; + if (parent.IsOk()) + [m_OutlineView reloadItem:[m_DataSource getDataViewItemFromBuffer:parent] reloadChildren:YES]; + else + [m_OutlineView reloadData]; + return true; } -bool wxCocoaDataViewControl::Add(wxDataViewItem const& parent, wxDataViewItemArray const& WXUNUSED(items)) +bool wxCocoaDataViewControl::Add(const wxDataViewItem& parent, const wxDataViewItemArray& WXUNUSED(items)) { - if (parent.IsOk()) - [this->m_OutlineView reloadItem:[this->m_DataSource getDataViewItemFromBuffer:parent] reloadChildren:YES]; - else - [this->m_OutlineView reloadData]; - return true; + if (parent.IsOk()) + [m_OutlineView reloadItem:[m_DataSource getDataViewItemFromBuffer:parent] reloadChildren:YES]; + else + [m_OutlineView reloadData]; + return true; } -void wxCocoaDataViewControl::Collapse(wxDataViewItem const& item) +void wxCocoaDataViewControl::Collapse(const wxDataViewItem& item) { - [this->m_OutlineView collapseItem:[this->m_DataSource getDataViewItemFromBuffer:item]]; + [m_OutlineView collapseItem:[m_DataSource getDataViewItemFromBuffer:item]]; } -void wxCocoaDataViewControl::EnsureVisible(wxDataViewItem const& item, wxDataViewColumn const* columnPtr) +void wxCocoaDataViewControl::EnsureVisible(const wxDataViewItem& item, const wxDataViewColumn *columnPtr) { - if (item.IsOk()) - { - [this->m_OutlineView scrollRowToVisible:[this->m_OutlineView rowForItem:[this->m_DataSource getDataViewItemFromBuffer:item]]]; - if (columnPtr != NULL) - [this->m_OutlineView scrollColumnToVisible:this->GetColumnPosition(columnPtr)]; - } + if (item.IsOk()) + { + [m_OutlineView scrollRowToVisible:[m_OutlineView rowForItem:[m_DataSource getDataViewItemFromBuffer:item]]]; + if (columnPtr) + [m_OutlineView scrollColumnToVisible:GetColumnPosition(columnPtr)]; + } } -void wxCocoaDataViewControl::Expand(wxDataViewItem const& item) +void wxCocoaDataViewControl::Expand(const wxDataViewItem& item) { - [this->m_OutlineView expandItem:[this->m_DataSource getDataViewItemFromBuffer:item]]; + [m_OutlineView expandItem:[m_DataSource getDataViewItemFromBuffer:item]]; } -unsigned int wxCocoaDataViewControl::GetCount(void) const +unsigned int wxCocoaDataViewControl::GetCount() const { - return [this->m_OutlineView numberOfRows]; + return [m_OutlineView numberOfRows]; } -wxRect wxCocoaDataViewControl::GetRectangle(wxDataViewItem const& item, wxDataViewColumn const* columnPtr) +wxRect wxCocoaDataViewControl::GetRectangle(const wxDataViewItem& item, const wxDataViewColumn *columnPtr) { - return wxFromNSRect([m_osxView superview],[this->m_OutlineView frameOfCellAtColumn:this->GetColumnPosition(columnPtr) - row:[this->m_OutlineView rowForItem:[this->m_DataSource getDataViewItemFromBuffer:item]]]); + return wxFromNSRect([m_osxView superview],[m_OutlineView frameOfCellAtColumn:GetColumnPosition(columnPtr) + row:[m_OutlineView rowForItem:[m_DataSource getDataViewItemFromBuffer:item]]]); } -bool wxCocoaDataViewControl::IsExpanded(wxDataViewItem const& item) const +bool wxCocoaDataViewControl::IsExpanded(const wxDataViewItem& item) const { - return [this->m_OutlineView isItemExpanded:[this->m_DataSource getDataViewItemFromBuffer:item]]; + return [m_OutlineView isItemExpanded:[m_DataSource getDataViewItemFromBuffer:item]]; } -bool wxCocoaDataViewControl::Reload(void) +bool wxCocoaDataViewControl::Reload() { - [this->m_DataSource clearBuffers]; - [this->m_OutlineView scrollColumnToVisible:0]; - [this->m_OutlineView scrollRowToVisible:0]; - [this->m_OutlineView reloadData]; - return true; + [m_DataSource clearBuffers]; + [m_OutlineView reloadData]; + [m_OutlineView scrollColumnToVisible:0]; + [m_OutlineView scrollRowToVisible:0]; + return true; } -bool wxCocoaDataViewControl::Remove(wxDataViewItem const& parent, wxDataViewItem const& WXUNUSED(item)) +bool wxCocoaDataViewControl::Remove(const wxDataViewItem& parent, const wxDataViewItem& WXUNUSED(item)) { - if (parent.IsOk()) - [this->m_OutlineView reloadItem:[this->m_DataSource getDataViewItemFromBuffer:parent] reloadChildren:YES]; - else - [this->m_OutlineView reloadData]; - return true; + if (parent.IsOk()) + [m_OutlineView reloadItem:[m_DataSource getDataViewItemFromBuffer:parent] reloadChildren:YES]; + else + [m_OutlineView reloadData]; + return true; } -bool wxCocoaDataViewControl::Remove(wxDataViewItem const& parent, wxDataViewItemArray const& WXUNUSED(item)) +bool wxCocoaDataViewControl::Remove(const wxDataViewItem& parent, const wxDataViewItemArray& WXUNUSED(item)) { - if (parent.IsOk()) - [this->m_OutlineView reloadItem:[this->m_DataSource getDataViewItemFromBuffer:parent] reloadChildren:YES]; - else - [this->m_OutlineView reloadData]; - return true; + if (parent.IsOk()) + [m_OutlineView reloadItem:[m_DataSource getDataViewItemFromBuffer:parent] reloadChildren:YES]; + else + [m_OutlineView reloadData]; + return true; } -bool wxCocoaDataViewControl::Update(wxDataViewColumn const* columnPtr) +bool wxCocoaDataViewControl::Update(const wxDataViewColumn *columnPtr) { - return false; + wxUnusedVar(columnPtr); + + return false; } -bool wxCocoaDataViewControl::Update(wxDataViewItem const& WXUNUSED(parent), wxDataViewItem const& item) +bool wxCocoaDataViewControl::Update(const wxDataViewItem& WXUNUSED(parent), const wxDataViewItem& item) { - [this->m_OutlineView reloadItem:[this->m_DataSource getDataViewItemFromBuffer:item]]; - return true; + [m_OutlineView reloadItem:[m_DataSource getDataViewItemFromBuffer:item]]; + return true; } -bool wxCocoaDataViewControl::Update(wxDataViewItem const& WXUNUSED(parent), wxDataViewItemArray const& items) +bool wxCocoaDataViewControl::Update(const wxDataViewItem& WXUNUSED(parent), const wxDataViewItemArray& items) { - for (size_t i=0; im_OutlineView reloadItem:[this->m_DataSource getDataViewItemFromBuffer:items[i]]]; - return true; + for (size_t i=0; im_DataSource release]; - if (model != NULL) - { - this->m_DataSource = [[wxCocoaOutlineDataSource alloc] init]; - [this->m_DataSource setImplementation:this]; - [this->m_DataSource setModel:model]; - } - else - this->m_DataSource = NULL; - [this->m_OutlineView setDataSource:this->m_DataSource]; // if there is a data source the data is immediately going to be requested - return true; + [m_DataSource release]; + if (model) + { + m_DataSource = [[wxCocoaOutlineDataSource alloc] init]; + [m_DataSource setImplementation:this]; + [m_DataSource setModel:model]; + } + else + m_DataSource = NULL; + [m_OutlineView setDataSource:m_DataSource]; // if there is a data source the data is immediately going to be requested + return true; } // // 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([this->m_OutlineView selectedRowIndexes]); + NSIndexSet* selectedRowIndexes([m_OutlineView selectedRowIndexes]); - NSUInteger indexRow; + NSUInteger indexRow; - sel.Empty(); - sel.Alloc([selectedRowIndexes count]); - indexRow = [selectedRowIndexes firstIndex]; - while (indexRow != NSNotFound) - { - sel.Add(wxDataViewItem([[this->m_OutlineView itemAtRow:indexRow] pointer])); - indexRow = [selectedRowIndexes indexGreaterThanIndex:indexRow]; - } - return sel.GetCount(); + sel.Empty(); + sel.Alloc([selectedRowIndexes count]); + indexRow = [selectedRowIndexes firstIndex]; + while (indexRow != NSNotFound) + { + sel.Add(wxDataViewItem([[m_OutlineView itemAtRow:indexRow] pointer])); + indexRow = [selectedRowIndexes indexGreaterThanIndex:indexRow]; + } + return sel.GetCount(); } -bool wxCocoaDataViewControl::IsSelected(wxDataViewItem const& item) const +bool wxCocoaDataViewControl::IsSelected(const wxDataViewItem& item) const { - return [this->m_OutlineView isRowSelected:[this->m_OutlineView rowForItem:[this->m_DataSource getDataViewItemFromBuffer:item]]]; + return [m_OutlineView isRowSelected:[m_OutlineView rowForItem:[m_DataSource getDataViewItemFromBuffer:item]]]; } -void wxCocoaDataViewControl::Select(wxDataViewItem const& item) +void wxCocoaDataViewControl::Select(const wxDataViewItem& item) { - if (item.IsOk()) - [this->m_OutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:[this->m_OutlineView rowForItem:[this->m_DataSource getDataViewItemFromBuffer:item]]] - byExtendingSelection:NO]; + if (item.IsOk()) + [m_OutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:[m_OutlineView rowForItem:[m_DataSource getDataViewItemFromBuffer:item]]] + byExtendingSelection:GetDataViewCtrl()->HasFlag(wxDV_MULTIPLE) ? YES : NO]; } -void wxCocoaDataViewControl::SelectAll(void) +void wxCocoaDataViewControl::SelectAll() { - [this->m_OutlineView selectAll:this->m_OutlineView]; + [m_OutlineView selectAll:m_OutlineView]; } -void wxCocoaDataViewControl::Unselect(wxDataViewItem const& item) +void wxCocoaDataViewControl::Unselect(const wxDataViewItem& item) { - if (item.IsOk()) - [this->m_OutlineView deselectRow:[this->m_OutlineView rowForItem:[this->m_DataSource getDataViewItemFromBuffer:item]]]; + if (item.IsOk()) + [m_OutlineView deselectRow:[m_OutlineView rowForItem:[m_DataSource getDataViewItemFromBuffer:item]]]; } -void wxCocoaDataViewControl::UnselectAll(void) +void wxCocoaDataViewControl::UnselectAll() { - [this->m_OutlineView deselectAll:this->m_OutlineView]; + [m_OutlineView deselectAll:m_OutlineView]; } // // sorting related methods // -wxDataViewColumn* wxCocoaDataViewControl::GetSortingColumn(void) const +wxDataViewColumn* wxCocoaDataViewControl::GetSortingColumn() const { - NSArray* const columns = [this->m_OutlineView tableColumns]; + NSArray* const columns = [m_OutlineView tableColumns]; - UInt32 const noOfColumns = [columns count]; + UInt32 const noOfColumns = [columns count]; - for (UInt32 i=0; i([[[columns objectAtIndex:i] identifier] pointer]); - return NULL; + for (UInt32 i=0; im_DataSource clearChildren]; - [this->m_OutlineView reloadData]; + [m_DataSource clearChildren]; + [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]; } // @@ -1936,40 +2408,40 @@ void wxCocoaDataViewControl::Resort(void) // void wxCocoaDataViewControl::DoSetIndent(int indent) { - [this->m_OutlineView setIndentationPerLevel:static_cast(indent)]; + [m_OutlineView setIndentationPerLevel:static_cast(indent)]; } -void wxCocoaDataViewControl::HitTest(wxPoint const& point, wxDataViewItem& item, wxDataViewColumn*& columnPtr) const +void wxCocoaDataViewControl::HitTest(const wxPoint& point, wxDataViewItem& item, wxDataViewColumn*& columnPtr) const { - NSPoint const nativePoint = wxToNSPoint((NSScrollView*) this->GetWXWidget(),point); + NSPoint const nativePoint = wxToNSPoint((NSScrollView*) GetWXWidget(),point); - int indexColumn; - int indexRow; + int indexColumn; + int indexRow; - indexColumn = [this->m_OutlineView columnAtPoint:nativePoint]; - indexRow = [this->m_OutlineView rowAtPoint: nativePoint]; - if ((indexColumn >= 0) && (indexRow >= 0)) - { - columnPtr = reinterpret_cast([[[[this->m_OutlineView tableColumns] objectAtIndex:indexColumn] identifier] pointer]); - item = wxDataViewItem([[this->m_OutlineView itemAtRow:indexRow] pointer]); - } - else - { - columnPtr = NULL; - item = wxDataViewItem(); - } + indexColumn = [m_OutlineView columnAtPoint:nativePoint]; + indexRow = [m_OutlineView rowAtPoint: nativePoint]; + if ((indexColumn >= 0) && (indexRow >= 0)) + { + columnPtr = GetColumn(indexColumn); + item = wxDataViewItem([[m_OutlineView itemAtRow:indexRow] pointer]); + } + else + { + columnPtr = NULL; + item = wxDataViewItem(); + } } -void wxCocoaDataViewControl::SetRowHeight(wxDataViewItem const& WXUNUSED(item), unsigned int WXUNUSED(height)) - // Not supported by the native control +void wxCocoaDataViewControl::SetRowHeight(const wxDataViewItem& WXUNUSED(item), unsigned int WXUNUSED(height)) + // Not supported by the native control { } -void wxCocoaDataViewControl::OnSize(void) +void wxCocoaDataViewControl::OnSize() { - if ([this->m_OutlineView numberOfColumns] == 1) - [this->m_OutlineView sizeLastColumnToFit]; + if ([m_OutlineView numberOfColumns] == 1) + [m_OutlineView sizeLastColumnToFit]; } // @@ -1977,11 +2449,10 @@ void wxCocoaDataViewControl::OnSize(void) // wxDataFormat wxCocoaDataViewControl::GetDnDDataFormat(wxDataObjectComposite* dataObjects) { - wxDataFormat resultFormat; + wxDataFormat resultFormat; + if ( !dataObjects ) + return resultFormat; - - if (dataObjects != NULL) - { bool compatible(true); size_t const noOfFormats = dataObjects->GetFormatCount(); @@ -1989,110 +2460,285 @@ wxDataFormat wxCocoaDataViewControl::GetDnDDataFormat(wxDataObjectComposite* dat wxDataFormat* formats; - // get all formats and check afterwards if the formats are compatible; if they are compatible the preferred format is returned otherwise - // wxDF_INVALID is returned; - // currently compatible types (ordered by priority are): - // - wxDF_UNICODETEXT - wxDF_TEXT + // get all formats and check afterwards if the formats are compatible; if + // they are compatible the preferred format is returned otherwise + // wxDF_INVALID is returned; + // currently compatible types (ordered by priority are): + // - wxDF_UNICODETEXT - wxDF_TEXT formats = new wxDataFormat[noOfFormats]; dataObjects->GetAllFormats(formats); indexFormat = 0; while ((indexFormat < noOfFormats) && compatible) { - switch (resultFormat.GetType()) - { - case wxDF_INVALID: - resultFormat.SetType(formats[indexFormat].GetType()); // first format (should only be reached if indexFormat == 0) - break; + switch (resultFormat.GetType()) + { + case wxDF_INVALID: + resultFormat.SetType(formats[indexFormat].GetType()); // first format (should only be reached if indexFormat == 0) + break; + case wxDF_TEXT: + if (formats[indexFormat].GetType() == wxDF_UNICODETEXT) + resultFormat.SetType(wxDF_UNICODETEXT); + else // incompatible + { + resultFormat.SetType(wxDF_INVALID); + compatible = false; + } + break; + case wxDF_UNICODETEXT: + if (formats[indexFormat].GetType() != wxDF_TEXT) + { + resultFormat.SetType(wxDF_INVALID); + compatible = false; + } + break; + default: + resultFormat.SetType(wxDF_INVALID); // not (yet) supported format + compatible = false; + } + ++indexFormat; + } + + delete[] formats; + + return resultFormat; +} + +wxDataObjectComposite* wxCocoaDataViewControl::GetDnDDataObjects(NSData* dataObject) const +{ + wxDataFormatId dataFormatID; + + + [dataObject getBytes:&dataFormatID length:sizeof(wxDataFormatId)]; + switch (dataFormatID) + { case wxDF_TEXT: - if (formats[indexFormat].GetType() == wxDF_UNICODETEXT) - resultFormat.SetType(wxDF_UNICODETEXT); - else // incompatible - { - resultFormat.SetType(wxDF_INVALID); - compatible = false; - } - break; case wxDF_UNICODETEXT: - if (formats[indexFormat].GetType() != wxDF_TEXT) - { - resultFormat.SetType(wxDF_INVALID); - compatible = false; - } - break; + { + wxTextDataObject* textDataObject(new wxTextDataObject()); + + if (textDataObject->SetData(wxDataFormat(dataFormatID),[dataObject length]-sizeof(wxDataFormatId),static_cast([dataObject bytes])+sizeof(wxDataFormatId))) + { + wxDataObjectComposite* dataObjectComposite(new wxDataObjectComposite()); + + dataObjectComposite->Add(textDataObject); + return dataObjectComposite; + } + else + { + delete textDataObject; + return NULL; + } + } + break; default: - resultFormat.SetType(wxDF_INVALID); // not (yet) supported format - compatible = false; - } - ++indexFormat; - } /* while */ - // clean up: - delete[] formats; - } - return resultFormat; + return NULL; + } } -wxDataObjectComposite* wxCocoaDataViewControl::GetDnDDataObjects(NSData* dataObject) const +id wxCocoaDataViewControl::GetItemAtRow(int row) const { - wxDataFormatId dataFormatID; + return [m_OutlineView itemAtRow:row]; +} +// ---------------------------------------------------------------------------- +// wxDataViewRendererNativeData +// ---------------------------------------------------------------------------- - [dataObject getBytes:&dataFormatID length:sizeof(wxDataFormatId)]; - switch (dataFormatID) - { - case wxDF_TEXT: - case wxDF_UNICODETEXT: - { - wxTextDataObject* textDataObject(new wxTextDataObject()); +void wxDataViewRendererNativeData::Init() +{ + m_origFont = NULL; + m_origTextColour = NULL; + m_ellipsizeMode = wxELLIPSIZE_MIDDLE; - if (textDataObject->SetData(wxDataFormat(dataFormatID),[dataObject length]-sizeof(wxDataFormatId),reinterpret_cast([dataObject bytes])+sizeof(wxDataFormatId))) - { - wxDataObjectComposite* dataObjectComposite(new wxDataObjectComposite()); + if ( m_ColumnCell ) + ApplyLineBreakMode(m_ColumnCell); +} - dataObjectComposite->Add(textDataObject); - return dataObjectComposite; - } - else - { - delete textDataObject; - return NULL; - } - } - break; - default: - return NULL; - } +void wxDataViewRendererNativeData::ApplyLineBreakMode(NSCell *cell) +{ + NSLineBreakMode nsMode = NSLineBreakByWordWrapping; + switch ( m_ellipsizeMode ) + { + case wxELLIPSIZE_NONE: + nsMode = NSLineBreakByClipping; + break; + + case wxELLIPSIZE_START: + nsMode = NSLineBreakByTruncatingHead; + break; + + case wxELLIPSIZE_MIDDLE: + nsMode = NSLineBreakByTruncatingMiddle; + break; + + case wxELLIPSIZE_END: + nsMode = NSLineBreakByTruncatingTail; + break; + } + + wxASSERT_MSG( nsMode != NSLineBreakByWordWrapping, "unknown wxEllipsizeMode" ); + + [cell setLineBreakMode: nsMode]; } // --------------------------------------------------------- // wxDataViewRenderer // --------------------------------------------------------- -wxDataViewRenderer::wxDataViewRenderer(wxString const& 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) { } -wxDataViewRenderer::~wxDataViewRenderer(void) +wxDataViewRenderer::~wxDataViewRenderer() { - delete this->m_NativeDataPtr; + delete m_NativeDataPtr; } void wxDataViewRenderer::SetAlignment(int align) { - this->m_alignment = align; - [this->GetNativeData()->GetColumnCell() setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; + m_alignment = align; + [GetNativeData()->GetColumnCell() setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; } void wxDataViewRenderer::SetMode(wxDataViewCellMode mode) { - this->m_mode = mode; - if (this->GetOwner() != NULL) - [this->GetOwner()->GetNativeData()->GetNativeColumnPtr() setEditable:(mode == wxDATAVIEW_CELL_EDITABLE)]; + m_mode = mode; + if ( GetOwner() ) + [GetOwner()->GetNativeData()->GetNativeColumnPtr() setEditable:(mode == wxDATAVIEW_CELL_EDITABLE)]; } void wxDataViewRenderer::SetNativeData(wxDataViewRendererNativeData* newNativeDataPtr) { - delete this->m_NativeDataPtr; - this->m_NativeDataPtr = newNativeDataPtr; + delete m_NativeDataPtr; + m_NativeDataPtr = newNativeDataPtr; +} + +void wxDataViewRenderer::EnableEllipsize(wxEllipsizeMode mode) +{ + // we need to store this value to apply it to the columns headerCell in + // CreateNativeColumn() + GetNativeData()->SetEllipsizeMode(mode); + + // but we may already apply it to the column cell which will be used for + // this column + GetNativeData()->ApplyLineBreakMode(GetNativeData()->GetColumnCell()); +} + +wxEllipsizeMode wxDataViewRenderer::GetEllipsizeMode() const +{ + return GetNativeData()->GetEllipsizeMode(); +} + +void +wxDataViewRenderer::OSXOnCellChanged(NSObject *object, + const wxDataViewItem& item, + unsigned col) +{ + // 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]] ) + 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 colorWithCalibratedRed: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]; +} + +void wxDataViewRenderer::OSXApplyEnabled(bool enabled) +{ + [GetNativeData()->GetItemCell() setEnabled:enabled]; } IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer,wxDataViewRendererBase) @@ -2100,18 +2746,32 @@ IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer,wxDataViewRendererBase) // --------------------------------------------------------- // wxDataViewCustomRenderer // --------------------------------------------------------- -wxDataViewCustomRenderer::wxDataViewCustomRenderer(wxString const& varianttype, wxDataViewCellMode mode, int align) - :wxDataViewRenderer(varianttype,mode,align), m_editorCtrlPtr(NULL), m_DCPtr(NULL) +wxDataViewCustomRenderer::wxDataViewCustomRenderer(const wxString& varianttype, + wxDataViewCellMode mode, + int align) + : wxDataViewCustomRendererBase(varianttype, mode, align), + m_editorCtrlPtr(NULL), + m_DCPtr(NULL) { - this->SetNativeData(new wxDataViewRendererNativeData([[wxCustomCell alloc] init])); + SetNativeData(new wxDataViewRendererNativeData([[wxCustomCell alloc] init])); } bool wxDataViewCustomRenderer::MacRender() { - [this->GetNativeData()->GetItemCell() setObjectValue:[[[wxCustomRendererObject alloc] initWithRenderer:this - item:this->GetNativeData()->GetItem() - column:this->GetNativeData()->GetColumnPtr()] autorelease]]; - return true; + [GetNativeData()->GetItemCell() setObjectValue:[[[wxCustomRendererObject alloc] initWithRenderer:this] autorelease]]; + 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) @@ -2119,31 +2779,41 @@ IMPLEMENT_ABSTRACT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer) // --------------------------------------------------------- // wxDataViewTextRenderer // --------------------------------------------------------- -wxDataViewTextRenderer::wxDataViewTextRenderer(wxString const& varianttype, wxDataViewCellMode mode, int align) - :wxDataViewRenderer(varianttype,mode,align) +wxDataViewTextRenderer::wxDataViewTextRenderer(const wxString& varianttype, + wxDataViewCellMode mode, + int align) + : wxDataViewRenderer(varianttype,mode,align) { - NSTextFieldCell* cell; + NSTextFieldCell* cell; - cell = [[NSTextFieldCell alloc] init]; - [cell setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; - [cell setLineBreakMode:NSLineBreakByTruncatingMiddle]; - this->SetNativeData(new wxDataViewRendererNativeData(cell)); - [cell release]; + cell = [[NSTextFieldCell alloc] init]; + [cell setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; + SetNativeData(new wxDataViewRendererNativeData(cell)); + [cell release]; } bool wxDataViewTextRenderer::MacRender() { - if (this->GetValue().GetType() == this->GetVariantType()) - { - [this->GetNativeData()->GetItemCell() setObjectValue:wxCFStringRef(this->GetValue().GetString()).AsNSString()]; - return true; - } - else - { - wxFAIL_MSG(wxString(_("Text renderer cannot render value because of wrong value type; value type: ")) << this->GetValue().GetType()); - return false; - } + if (GetValue().GetType() == GetVariantType()) + { + [GetNativeData()->GetItemCell() setObjectValue:wxCFStringRef(GetValue().GetString()).AsNSString()]; + return true; + } + else + { + wxFAIL_MSG(wxString("Text renderer cannot render value because of wrong value type; value type: ") << GetValue().GetType()); + return false; + } +} + +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) @@ -2151,31 +2821,35 @@ IMPLEMENT_CLASS(wxDataViewTextRenderer,wxDataViewRenderer) // --------------------------------------------------------- // wxDataViewBitmapRenderer // --------------------------------------------------------- -wxDataViewBitmapRenderer::wxDataViewBitmapRenderer(wxString const& varianttype, wxDataViewCellMode mode, int align) - :wxDataViewRenderer(varianttype,mode,align) +wxDataViewBitmapRenderer::wxDataViewBitmapRenderer(const wxString& varianttype, + wxDataViewCellMode mode, + int align) + : wxDataViewRenderer(varianttype,mode,align) { - NSImageCell* cell; + NSImageCell* cell; - cell = [[NSImageCell alloc] init]; - this->SetNativeData(new wxDataViewRendererNativeData(cell)); - [cell release]; + cell = [[NSImageCell alloc] init]; + SetNativeData(new wxDataViewRendererNativeData(cell)); + [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(this->GetValue().GetType() == this->GetVariantType(),false,wxString(_("Bitmap renderer cannot render value; value type: ")) << this->GetValue().GetType()); + wxCHECK_MSG(GetValue().GetType() == GetVariantType(),false,wxString("Bitmap renderer cannot render value; value type: ") << GetValue().GetType()); - wxBitmap bitmap; + wxBitmap bitmap; - bitmap << this->GetValue(); - if (bitmap.IsOk()) - [this->GetNativeData()->GetItemCell() setObjectValue:[[bitmap.GetNSImage() retain] autorelease]]; - return true; + bitmap << GetValue(); + if (bitmap.IsOk()) + [GetNativeData()->GetItemCell() setObjectValue:[[bitmap.GetNSImage() retain] autorelease]]; + return true; } IMPLEMENT_CLASS(wxDataViewBitmapRenderer,wxDataViewRenderer) @@ -2183,33 +2857,47 @@ IMPLEMENT_CLASS(wxDataViewBitmapRenderer,wxDataViewRenderer) // ------------------------------------- // wxDataViewChoiceRenderer // ------------------------------------- -wxDataViewChoiceRenderer::wxDataViewChoiceRenderer(wxArrayString const& choices, wxDataViewCellMode mode, int alignment) - :wxDataViewRenderer(wxT("string"),mode,alignment), m_Choices(choices) +wxDataViewChoiceRenderer::wxDataViewChoiceRenderer(const wxArrayString& choices, + wxDataViewCellMode mode, + int alignment) + : wxDataViewRenderer(wxT("string"), mode, alignment), + m_choices(choices) { - NSPopUpButtonCell* cell; + NSPopUpButtonCell* cell; - cell = [[NSPopUpButtonCell alloc] init]; - [cell setControlSize:NSMiniControlSize]; - [cell setFont:[[NSFont fontWithName:[[cell font] fontName] size:[NSFont systemFontSizeForControlSize:NSMiniControlSize]] autorelease]]; - for (size_t i=0; iSetNativeData(new wxDataViewRendererNativeData(cell)); - [cell release]; + cell = [[NSPopUpButtonCell alloc] init]; + [cell setControlSize:NSMiniControlSize]; + [cell setFont:[NSFont fontWithName:[[cell font] fontName] size:[NSFont systemFontSizeForControlSize:NSMiniControlSize]]]; + for (size_t i=0; iGetOwner()->GetModel(); + model->ChangeValue(GetChoice(ObjectToLong(value)), item, col); } bool wxDataViewChoiceRenderer::MacRender() { - if (this->GetValue().GetType() == this->GetVariantType()) - { - [((NSPopUpButtonCell*) this->GetNativeData()->GetItemCell()) selectItemWithTitle:[[wxCFStringRef(this->GetValue().GetString()).AsNSString() retain] autorelease]]; - return true; - } - else - { - wxFAIL_MSG(wxString(_("Choice renderer cannot render value because of wrong value type; value type: ")) << this->GetValue().GetType()); - return false; - } + if (GetValue().GetType() == GetVariantType()) + { + [((NSPopUpButtonCell*) GetNativeData()->GetItemCell()) selectItemWithTitle:[[wxCFStringRef(GetValue().GetString()).AsNSString() retain] autorelease]]; + return true; + } + else + { + wxFAIL_MSG(wxString("Choice renderer cannot render value because of wrong value type; value type: ") << GetValue().GetType()); + return false; + } } IMPLEMENT_CLASS(wxDataViewChoiceRenderer,wxDataViewRenderer) @@ -2217,68 +2905,93 @@ IMPLEMENT_CLASS(wxDataViewChoiceRenderer,wxDataViewRenderer) // --------------------------------------------------------- // wxDataViewDateRenderer // --------------------------------------------------------- -wxDataViewDateRenderer::wxDataViewDateRenderer(wxString const& varianttype, wxDataViewCellMode mode, int align) - :wxDataViewRenderer(varianttype,mode,align) + +wxDataViewDateRenderer::wxDataViewDateRenderer(const wxString& varianttype, + wxDataViewCellMode mode, + int align) + : wxDataViewRenderer(varianttype,mode,align) { - NSTextFieldCell* cell; + NSTextFieldCell* cell; - NSDateFormatter* dateFormatter; + NSDateFormatter* dateFormatter; - dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; - [dateFormatter setDateStyle:NSDateFormatterShortStyle]; - cell = [[NSTextFieldCell alloc] init]; - [cell setFormatter:dateFormatter]; - [cell setLineBreakMode:NSLineBreakByTruncatingMiddle]; - this->SetNativeData(new wxDataViewRendererNativeData(cell,[NSDate dateWithString:@"2000-12-30 20:00:00 +0000"])); - [cell release]; - [dateFormatter release]; + dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; + [dateFormatter setDateStyle:NSDateFormatterShortStyle]; + cell = [[NSTextFieldCell alloc] init]; + [cell setFormatter:dateFormatter]; + SetNativeData(new wxDataViewRendererNativeData(cell,[NSDate dateWithString:@"2000-12-30 20:00:00 +0000"])); + [cell release]; + [dateFormatter release]; } bool wxDataViewDateRenderer::MacRender() { - if (this->GetValue().GetType() == this->GetVariantType()) - { - if (this->GetValue().GetDateTime().IsValid()) + if (GetValue().GetType() == GetVariantType()) { - // -- 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 - [this->GetNativeData()->GetItemCell() setObjectValue:this->GetNativeData()->GetObject()]; // GetObject() returns a date for testing the size of a date object - [[this->GetNativeData()->GetItemCell() formatter] setTimeStyle:NSDateFormatterShortStyle]; - for (int dateFormatterStyle=4; dateFormatterStyle>0; --dateFormatterStyle) - { - [[this->GetNativeData()->GetItemCell() formatter] setDateStyle:(NSDateFormatterStyle)dateFormatterStyle]; - if (dateFormatterStyle == 1) + if (GetValue().GetDateTime().IsValid()) { - // 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 ([this->GetNativeData()->GetItemCell() cellSize].width > [this->GetNativeData()->GetColumnPtr() width]) - [[this->GetNativeData()->GetItemCell() formatter] setTimeStyle:NSDateFormatterNoStyle]; - break; // basically not necessary as the loop would end anyway but let's save the last comparison + // -- 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 + + // 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 ([GetNativeData()->GetItemCell() cellSize].width > [GetNativeData()->GetColumnPtr() width]) + [[GetNativeData()->GetItemCell() formatter] setTimeStyle:NSDateFormatterNoStyle]; + { + // 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: + [GetNativeData()->GetItemCell() setObjectValue:[NSDate dateWithTimeIntervalSince1970:GetValue().GetDateTime().ToUTC().Subtract(wxDateTime(1,wxDateTime::Jan,1970)).GetSeconds().ToDouble()]]; } - else if ([this->GetNativeData()->GetItemCell() cellSize].width <= [this->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: - [this->GetNativeData()->GetItemCell() setObjectValue:[NSDate dateWithTimeIntervalSince1970:this->GetValue().GetDateTime().ToUTC().Subtract(wxDateTime(1,wxDateTime::Jan,1970)).GetSeconds().ToDouble()]]; + return true; + } + else + { + wxFAIL_MSG(wxString("Date renderer cannot render value because of wrong value type; value type: ") << GetValue().GetType()); + return false; } - return true; - } - else - { - wxFAIL_MSG(wxString(_("Date renderer cannot render value because of wrong value type; value type: ")) << this->GetValue().GetType()); - return false; - } +} + +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) @@ -2286,38 +2999,54 @@ IMPLEMENT_ABSTRACT_CLASS(wxDataViewDateRenderer,wxDataViewRenderer) // --------------------------------------------------------- // wxDataViewIconTextRenderer // --------------------------------------------------------- -wxDataViewIconTextRenderer::wxDataViewIconTextRenderer(wxString const& varianttype, wxDataViewCellMode mode, int align) - :wxDataViewRenderer(varianttype,mode) +wxDataViewIconTextRenderer::wxDataViewIconTextRenderer(const wxString& varianttype, + wxDataViewCellMode mode, + int align) + : wxDataViewRenderer(varianttype,mode) { - wxImageTextCell* cell; + wxImageTextCell* cell; - cell = [[wxImageTextCell alloc] init]; - [cell setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; - this->SetNativeData(new wxDataViewRendererNativeData(cell)); - [cell release]; + cell = [[wxImageTextCell alloc] init]; + [cell setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; + SetNativeData(new wxDataViewRendererNativeData(cell)); + [cell release]; } bool wxDataViewIconTextRenderer::MacRender() { - if (this->GetValue().GetType() == this->GetVariantType()) - { - wxDataViewIconText iconText; + if (GetValue().GetType() == GetVariantType()) + { + wxDataViewIconText iconText; - wxImageTextCell* cell; + wxImageTextCell* cell; - cell = (wxImageTextCell*) this->GetNativeData()->GetItemCell(); - iconText << this->GetValue(); - if (iconText.GetIcon().IsOk()) - [cell setImage:[[wxBitmap(iconText.GetIcon()).GetNSImage() retain] autorelease]]; - [cell setStringValue:[[wxCFStringRef(iconText.GetText()).AsNSString() retain] autorelease]]; - return true; - } - else - { - wxFAIL_MSG(wxString(_("Icon & text renderer cannot render value because of wrong value type; value type: ")) << this->GetValue().GetType()); - return false; - } + cell = (wxImageTextCell*) GetNativeData()->GetItemCell(); + 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; + } + else + { + wxFAIL_MSG(wxString("Icon & text renderer cannot render value because of wrong value type; value type: ") << GetValue().GetType()); + return false; + } +} + +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) @@ -2325,32 +3054,43 @@ IMPLEMENT_ABSTRACT_CLASS(wxDataViewIconTextRenderer,wxDataViewRenderer) // --------------------------------------------------------- // wxDataViewToggleRenderer // --------------------------------------------------------- -wxDataViewToggleRenderer::wxDataViewToggleRenderer(wxString const& varianttype, wxDataViewCellMode mode, int align) - :wxDataViewRenderer(varianttype,mode) +wxDataViewToggleRenderer::wxDataViewToggleRenderer(const wxString& varianttype, + wxDataViewCellMode mode, + int align) + : wxDataViewRenderer(varianttype,mode) { - NSButtonCell* cell; + NSButtonCell* cell; - cell = [[NSButtonCell alloc] init]; - [cell setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; - [cell setButtonType:NSSwitchButton]; - [cell setImagePosition:NSImageOnly]; - this->SetNativeData(new wxDataViewRendererNativeData(cell)); - [cell release]; + cell = [[NSButtonCell alloc] init]; + [cell setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; + [cell setButtonType:NSSwitchButton]; + [cell setImagePosition:NSImageOnly]; + SetNativeData(new wxDataViewRendererNativeData(cell)); + [cell release]; } bool wxDataViewToggleRenderer::MacRender() { - if (this->GetValue().GetType() == this->GetVariantType()) - { - [this->GetNativeData()->GetItemCell() setIntValue:this->GetValue().GetLong()]; - return true; - } - else - { - wxFAIL_MSG(wxString(_("Toggle renderer cannot render value because of wrong value type; value type: ")) << this->GetValue().GetType()); - return false; - } + if (GetValue().GetType() == GetVariantType()) + { + [GetNativeData()->GetItemCell() setIntValue:GetValue().GetLong()]; + return true; + } + else + { + wxFAIL_MSG(wxString("Toggle renderer cannot render value because of wrong value type; value type: ") << GetValue().GetType()); + return false; + } +} + +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) @@ -2358,31 +3098,44 @@ IMPLEMENT_ABSTRACT_CLASS(wxDataViewToggleRenderer,wxDataViewRenderer) // --------------------------------------------------------- // wxDataViewProgressRenderer // --------------------------------------------------------- -wxDataViewProgressRenderer::wxDataViewProgressRenderer(wxString const& label, wxString const& varianttype, wxDataViewCellMode mode, int align) - :wxDataViewRenderer(varianttype,mode,align) +wxDataViewProgressRenderer::wxDataViewProgressRenderer(const wxString& label, + const wxString& varianttype, + wxDataViewCellMode mode, + int align) + : wxDataViewRenderer(varianttype,mode,align) { - NSLevelIndicatorCell* cell; + wxUnusedVar(label); + + NSLevelIndicatorCell* cell; - - cell = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]; - [cell setMinValue:0]; - [cell setMaxValue:100]; - this->SetNativeData(new wxDataViewRendererNativeData(cell)); - [cell release]; + cell = [[NSLevelIndicatorCell alloc] initWithLevelIndicatorStyle:NSContinuousCapacityLevelIndicatorStyle]; + [cell setMinValue:0]; + [cell setMaxValue:100]; + SetNativeData(new wxDataViewRendererNativeData(cell)); + [cell release]; } bool wxDataViewProgressRenderer::MacRender() { - if (this->GetValue().GetType() == this->GetVariantType()) - { - [this->GetNativeData()->GetItemCell() setIntValue:this->GetValue().GetLong()]; - return true; - } - else - { - wxFAIL_MSG(wxString(_("Progress renderer cannot render value because of wrong value type; value type: ")) << this->GetValue().GetType()); - return false; - } + if (GetValue().GetType() == GetVariantType()) + { + [GetNativeData()->GetItemCell() setIntValue:GetValue().GetLong()]; + return true; + } + else + { + wxFAIL_MSG(wxString("Progress renderer cannot render value because of wrong value type; value type: ") << GetValue().GetType()); + return false; + } +} + +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) @@ -2390,123 +3143,182 @@ IMPLEMENT_ABSTRACT_CLASS(wxDataViewProgressRenderer,wxDataViewRenderer) // --------------------------------------------------------- // wxDataViewColumn // --------------------------------------------------------- -wxDataViewColumn::wxDataViewColumn(const wxString& title, wxDataViewRenderer* renderer, unsigned int model_column, int width, wxAlignment align, int flags) - :wxDataViewColumnBase(renderer, model_column), m_NativeDataPtr(new wxDataViewColumnNativeData()), m_title(title) + +wxDataViewColumn::wxDataViewColumn(const wxString& title, + wxDataViewRenderer* renderer, + unsigned int model_column, + int width, + wxAlignment align, + int flags) + : wxDataViewColumnBase(renderer, model_column), + m_NativeDataPtr(new wxDataViewColumnNativeData()), + m_title(title) { - this->InitCommon(width, align, flags); - if ((renderer != NULL) && (renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT)) - renderer->SetAlignment(align); + InitCommon(width, align, flags); + if (renderer && !renderer->IsCustomRenderer() && + (renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT)) + renderer->SetAlignment(align); } -wxDataViewColumn::wxDataViewColumn(const wxBitmap& bitmap, wxDataViewRenderer* renderer, unsigned int model_column, int width, wxAlignment align, int flags) - :wxDataViewColumnBase(bitmap, renderer, model_column), m_NativeDataPtr(new wxDataViewColumnNativeData()) +wxDataViewColumn::wxDataViewColumn(const wxBitmap& bitmap, + wxDataViewRenderer* renderer, + unsigned int model_column, + int width, + wxAlignment align, + int flags) + : wxDataViewColumnBase(bitmap, renderer, model_column), + m_NativeDataPtr(new wxDataViewColumnNativeData()) { - this->InitCommon(width, align, flags); - if ((renderer != NULL) && (renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT)) - renderer->SetAlignment(align); + InitCommon(width, align, flags); + if (renderer && !renderer->IsCustomRenderer() && + (renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT)) + renderer->SetAlignment(align); } -wxDataViewColumn::~wxDataViewColumn(void) +wxDataViewColumn::~wxDataViewColumn() { - delete this->m_NativeDataPtr; + delete m_NativeDataPtr; +} + +int wxDataViewColumn::GetWidth() const +{ + return [m_NativeDataPtr->GetNativeColumnPtr() width]; } bool wxDataViewColumn::IsSortKey() const { - return ((this->GetNativeData()->GetNativeColumnPtr() != NULL) && ([this->GetNativeData()->GetNativeColumnPtr() sortDescriptorPrototype] != nil)); + NSTableColumn *nsCol = GetNativeData()->GetNativeColumnPtr(); + return nsCol && ([nsCol sortDescriptorPrototype] != nil); } void wxDataViewColumn::SetAlignment(wxAlignment align) { - this->m_alignment = align; - [[this->m_NativeDataPtr->GetNativeColumnPtr() headerCell] setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; - if ((this->m_renderer != NULL) && (this->m_renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT)) - this->m_renderer->SetAlignment(align); + m_alignment = align; + [[m_NativeDataPtr->GetNativeColumnPtr() headerCell] setAlignment:ConvertToNativeHorizontalTextAlignment(align)]; + if (m_renderer && !m_renderer->IsCustomRenderer() && + (m_renderer->GetAlignment() == wxDVR_DEFAULT_ALIGNMENT)) + m_renderer->SetAlignment(align); } -void wxDataViewColumn::SetBitmap(wxBitmap const& bitmap) +void wxDataViewColumn::SetBitmap(const wxBitmap& bitmap) { - // bitmaps and titles cannot exist at the same time - if the bitmap is set the title is removed: - this->m_title = wxEmptyString; - this->wxDataViewColumnBase::SetBitmap(bitmap); - [[this->m_NativeDataPtr->GetNativeColumnPtr() headerCell] setImage:[[bitmap.GetNSImage() retain] autorelease]]; + // 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]]; } void wxDataViewColumn::SetMaxWidth(int maxWidth) { - this->m_maxWidth = maxWidth; - [this->m_NativeDataPtr->GetNativeColumnPtr() setMaxWidth:maxWidth]; + m_maxWidth = maxWidth; + [m_NativeDataPtr->GetNativeColumnPtr() setMaxWidth:maxWidth]; } void wxDataViewColumn::SetMinWidth(int minWidth) { - this->m_minWidth = minWidth; - [this->m_NativeDataPtr->GetNativeColumnPtr() setMinWidth:minWidth]; + m_minWidth = minWidth; + [m_NativeDataPtr->GetNativeColumnPtr() setMinWidth:minWidth]; } void wxDataViewColumn::SetReorderable(bool reorderable) { + wxUnusedVar(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) +void wxDataViewColumn::SetResizeable(bool resizable) { - this->wxDataViewColumnBase::SetResizeable(resizeable); - if (resizeable) - [this->m_NativeDataPtr->GetNativeColumnPtr() setResizingMask:NSTableColumnUserResizingMask]; - else - [this->m_NativeDataPtr->GetNativeColumnPtr() setResizingMask:NSTableColumnNoResizing]; + wxDataViewColumnBase::SetResizeable(resizable); + if (resizable) + [m_NativeDataPtr->GetNativeColumnPtr() setResizingMask:NSTableColumnUserResizingMask]; + else + [m_NativeDataPtr->GetNativeColumnPtr() setResizingMask:NSTableColumnNoResizing]; } void wxDataViewColumn::SetSortable(bool sortable) { - this->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) { - if (m_ascending != ascending) - { - m_ascending = ascending; - if (this->IsSortKey()) + if (m_ascending != ascending) { - // change sorting order: - NSArray* sortDescriptors; - NSSortDescriptor* sortDescriptor; - NSTableColumn* tableColumn; - - tableColumn = this->m_NativeDataPtr->GetNativeColumnPtr(); - sortDescriptor = [[NSSortDescriptor alloc] initWithKey:[[tableColumn sortDescriptorPrototype] key] ascending:m_ascending]; - sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; - [tableColumn setSortDescriptorPrototype:sortDescriptor]; - [[tableColumn tableView] setSortDescriptors:sortDescriptors]; - [sortDescriptor release]; + m_ascending = ascending; + if (IsSortKey()) + { + // change sorting order: + NSArray* sortDescriptors; + NSSortDescriptor* sortDescriptor; + NSTableColumn* tableColumn; + + tableColumn = m_NativeDataPtr->GetNativeColumnPtr(); + sortDescriptor = [[NSSortDescriptor alloc] initWithKey:[[tableColumn sortDescriptorPrototype] key] ascending:m_ascending]; + sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; + [tableColumn setSortDescriptorPrototype:sortDescriptor]; + [[tableColumn tableView] setSortDescriptors:sortDescriptors]; + [sortDescriptor release]; + } } - } } -void wxDataViewColumn::SetTitle(wxString const& title) +void wxDataViewColumn::SetTitle(const wxString& title) { - // bitmaps and titles cannot exist at the same time - if the title is set the bitmap is removed: - this->wxDataViewColumnBase::SetBitmap(wxBitmap()); - this->m_title = title; - [[this->m_NativeDataPtr->GetNativeColumnPtr() headerCell] setStringValue:[[wxCFStringRef(title).AsNSString() retain] autorelease]]; + // 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]]; } void wxDataViewColumn::SetWidth(int width) { - [this->m_NativeDataPtr->GetNativeColumnPtr() setWidth:width]; - this->m_width = 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(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) { - delete this->m_NativeDataPtr; - this->m_NativeDataPtr = newNativeDataPtr; + delete m_NativeDataPtr; + m_NativeDataPtr = newNativeDataPtr; } + #endif // (wxUSE_DATAVIEWCTRL == 1) && !defined(wxUSE_GENERICDATAVIEWCTRL)