Accept multiple data formats via drag-and-drop in wxDataViewCtrl

Allow specifying multiple formats to be accepted when dragging data to
wxDataViewCtrl in the generic and Cocoa implementations.

Add wxDataViewCtrlBase::EnableDropTarget() overload taking an array of
wxDataFormats to support this at the API level.

Add new DoEnableDropTarget() used by both EnableDropTarget() overloads
and implement it in the generic and Cocoa ports. GTK implementation
still uses only a single format, as before.

Also refactor the Cocoa implementation: all operations using dragged
data are now handled by wxDropTarget and unnecessary DataViewPboardType
as removed.

Update the dataview sample to show the new functionality.
This commit is contained in:
valid-ptr
2021-08-22 10:25:32 +03:00
committed by Vadim Zeitlin
parent d30986be78
commit 7129d2b11c
16 changed files with 260 additions and 378 deletions

View File

@@ -535,6 +535,10 @@ private:
// wxDataViewCtrlBase
// ---------------------------------------------------------
#if wxUSE_DRAG_AND_DROP
WX_DEFINE_ARRAY(wxDataFormat,wxDataFormatArray);
#endif
#define wxDV_SINGLE 0x0000 // for convenience
#define wxDV_MULTIPLE 0x0001 // can select multiple items
@@ -760,8 +764,21 @@ public:
#if wxUSE_DRAG_AND_DROP
virtual bool EnableDragSource(const wxDataFormat& WXUNUSED(format))
{ return false; }
virtual bool EnableDropTarget(const wxDataFormat& WXUNUSED(format))
{ return false; }
bool EnableDropTarget(const wxDataFormatArray& formats)
{ return DoEnableDropTarget(formats); }
bool EnableDropTarget(const wxDataFormat& format)
{
wxDataFormatArray formats;
if (format.GetType() != wxDF_INVALID)
{
formats.Add(format);
}
return EnableDropTarget(formats);
}
#endif // wxUSE_DRAG_AND_DROP
// define control visual attributes
@@ -792,6 +809,14 @@ protected:
virtual void DoSetExpanderColumn() = 0 ;
virtual void DoSetIndent() = 0;
#if wxUSE_DRAG_AND_DROP
virtual wxDataObject* CreateDataObject(const wxDataFormatArray& formats);
virtual bool DoEnableDropTarget(const wxDataFormatArray& WXUNUSED(formats))
{ return false; }
#endif // wxUSE_DRAG_AND_DROP
// Just expand this item assuming it is already shown, i.e. its parent has
// been already expanded using ExpandAncestors().
//

View File

@@ -284,7 +284,7 @@ public:
#if wxUSE_DRAG_AND_DROP
virtual bool EnableDragSource( const wxDataFormat &format ) wxOVERRIDE;
virtual bool EnableDropTarget( const wxDataFormat &format ) wxOVERRIDE;
virtual bool DoEnableDropTarget(const wxDataFormatArray& formats) wxOVERRIDE;
#endif // wxUSE_DRAG_AND_DROP
virtual wxBorder GetDefaultBorder() const wxOVERRIDE;

View File

@@ -166,7 +166,7 @@ public:
virtual bool IsExpanded( const wxDataViewItem & item ) const wxOVERRIDE;
virtual bool EnableDragSource( const wxDataFormat &format ) wxOVERRIDE;
virtual bool EnableDropTarget( const wxDataFormat &format ) wxOVERRIDE;
virtual bool DoEnableDropTarget( const wxDataFormatArray& formats ) wxOVERRIDE;
virtual wxDataViewColumn *GetCurrentColumn() const wxOVERRIDE;

View File

@@ -541,10 +541,6 @@ public:
virtual void StartEditor( const wxDataViewItem & item, unsigned int column ) wxOVERRIDE;
// drag & drop helper methods
wxDataFormat GetDnDDataFormat(wxDataObjectComposite* dataObjects);
wxDataObjectComposite* GetDnDDataObjects(NSData* dataObject) const;
// Cocoa-specific helpers
id GetItemAtRow(int row) const;

View File

@@ -480,7 +480,8 @@ public:
// this enum declares which methods should not be overridden in the native view classes
enum wxOSXSkipOverrides {
wxOSXSKIP_NONE = 0x0,
wxOSXSKIP_DRAW = 0x1
wxOSXSKIP_DRAW = 0x1,
wxOSXSKIP_DND = 0x2
};
void WXDLLIMPEXP_CORE wxOSXCocoaClassAddWXMethods(Class c, wxOSXSkipOverrides skipFlags = wxOSXSKIP_NONE);

View File

@@ -208,6 +208,10 @@ public:
virtual void EditItem(const wxDataViewItem& item, const wxDataViewColumn *column) wxOVERRIDE;
#if wxUSE_DRAG_AND_DROP
virtual bool DoEnableDropTarget( const wxDataFormatArray& formats ) wxOVERRIDE;
#endif // wxUSE_DRAG_AND_DROP
// returns the n-th pointer to a column;
// this method is different from GetColumn(unsigned int pos) because here 'n' is not a position in the control but the n-th
// position in the internal list/array of column pointers

View File

@@ -119,7 +119,7 @@ public:
virtual bool IsExpanded( const wxDataViewItem & item ) const;
virtual bool EnableDragSource( const wxDataFormat &format );
virtual bool EnableDropTarget( const wxDataFormat &format );
virtual bool DoEnableDropTarget( const wxDataFormatArray& formats ) wxOVERRIDE;
static wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);

View File

@@ -1390,9 +1390,23 @@ public:
virtual bool EnableDragSource( const wxDataFormat &format );
/**
Enable drop operations using the given @a format.
Enable drop operations for each @a format from passed array.
Currently this is fully implemented in the generic and native macOS versions.
On GTK the only first element of array will be used.
@note Passing empty array disables drop operations at all.
@since 3.1.5
*/
virtual bool EnableDropTarget( const wxDataFormat &format );
bool EnableDropTarget(const wxDataFormatArray& formats);
/**
Enable drop operations using the given @a format.
Under the hood just calls overloaded EnableDropTarget() with an array holds single passed format.
@note Since 3.1.5 wxDF_INVALID can be passed to disable drop operations at all.
*/
bool EnableDropTarget( const wxDataFormat &format );
/**
Call this to ensure that the given item is visible.

View File

@@ -1430,21 +1430,20 @@ void MyFrame::OnDrop( wxDataViewEvent &event )
return;
}
wxTextDataObject obj;
obj.SetData( wxDF_UNICODETEXT, event.GetDataSize(), event.GetDataBuffer() );
const wxTextDataObject* const obj = static_cast<wxTextDataObject*>(event.GetDataObject());
if ( item.IsOk() )
{
if (m_music_model->IsContainer(item))
{
wxLogMessage("Text '%s' dropped in container '%s' (proposed index = %i)",
obj.GetText(), m_music_model->GetTitle(item), event.GetProposedDropIndex());
obj->GetText(), m_music_model->GetTitle(item), event.GetProposedDropIndex());
}
else
wxLogMessage("Text '%s' dropped on item '%s'", obj.GetText(), m_music_model->GetTitle(item));
wxLogMessage("Text '%s' dropped on item '%s'", obj->GetText(), m_music_model->GetTitle(item));
}
else
wxLogMessage("Text '%s' dropped on background (proposed index = %i)", obj.GetText(), event.GetProposedDropIndex());
wxLogMessage("Text '%s' dropped on background (proposed index = %i)", obj->GetText(), event.GetProposedDropIndex());
}
#endif // wxUSE_DRAG_AND_DROP

View File

@@ -1688,6 +1688,64 @@ void wxDataViewCtrlBase::StartEditor(const wxDataViewItem& item, unsigned int co
EditItem(item, GetColumn(column));
}
#if wxUSE_DRAG_AND_DROP
wxDataObject* wxDataViewCtrlBase::CreateDataObject(const wxDataFormatArray& formats)
{
if (formats.GetCount() == 0)
{
return NULL;
}
wxDataObjectComposite *dataObject(new wxDataObjectComposite);
for (size_t i = 0; i < formats.GetCount(); ++i)
{
switch (formats.Item(i).GetType())
{
case wxDF_TEXT:
case wxDF_OEMTEXT:
case wxDF_UNICODETEXT:
dataObject->Add(new wxTextDataObject);
break;
case wxDF_BITMAP:
dataObject->Add(new wxBitmapDataObject);
break;
case wxDF_FILENAME:
dataObject->Add(new wxFileDataObject);
break;
case wxDF_HTML:
dataObject->Add(new wxHTMLDataObject);
break;
case wxDF_METAFILE:
case wxDF_SYLK:
case wxDF_DIF:
case wxDF_TIFF:
case wxDF_DIB:
case wxDF_PALETTE:
case wxDF_PENDATA:
case wxDF_RIFF:
case wxDF_WAVE:
case wxDF_ENHMETAFILE:
case wxDF_LOCALE:
case wxDF_PRIVATE:
dataObject->Add(new wxCustomDataObject(formats.Item(i)));
break;
case wxDF_INVALID:
case wxDF_MAX:
break;
}
}
return dataObject;
}
#endif // wxUSE_DRAG_AND_DROP
// ---------------------------------------------------------
// wxDataViewEvent
// ---------------------------------------------------------

View File

@@ -922,7 +922,6 @@ public:
};
bool EnableDragSource( const wxDataFormat &format );
bool EnableDropTarget( const wxDataFormat &format );
void RefreshDropHint();
void RemoveDropHint();
@@ -1032,8 +1031,6 @@ private:
bool m_dragEnabled;
wxDataFormat m_dragFormat;
bool m_dropEnabled;
wxDataFormat m_dropFormat;
DropItemInfo m_dropItemInfo;
#endif // wxUSE_DRAG_AND_DROP
@@ -2076,7 +2073,6 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i
m_dragStart = wxPoint(0,0);
m_dragEnabled = false;
m_dropEnabled = false;
m_dropItemInfo = DropItemInfo();
#endif // wxUSE_DRAG_AND_DROP
@@ -2132,17 +2128,6 @@ bool wxDataViewMainWindow::EnableDragSource( const wxDataFormat &format )
return true;
}
bool wxDataViewMainWindow::EnableDropTarget( const wxDataFormat &format )
{
m_dropFormat = format;
m_dropEnabled = format != wxDF_INVALID;
if (m_dropEnabled)
SetDropTarget( new wxDataViewDropTarget( new wxCustomDataObject( format ), this ) );
return true;
}
void wxDataViewMainWindow::RefreshDropHint()
{
const unsigned row = m_dropItemInfo.m_row;
@@ -2389,18 +2374,18 @@ bool wxDataViewMainWindow::OnDrop( wxDataFormat format, wxCoord x, wxCoord y )
return true;
}
wxDragResult wxDataViewMainWindow::OnData( wxDataFormat format, wxCoord x, wxCoord y,
wxDragResult def )
wxDragResult wxDataViewMainWindow::OnData(wxDataFormat format, wxCoord x, wxCoord y,
wxDragResult def)
{
DropItemInfo dropItemInfo = GetDropItemInfo(x, y);
wxCustomDataObject *obj = (wxCustomDataObject *) GetDropTarget()->GetDataObject();
wxDataObjectComposite *obj = static_cast<wxDataObjectComposite*>(GetDropTarget()->GetDataObject());
wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_DROP, m_owner, dropItemInfo.m_item);
event.SetProposedDropIndex(dropItemInfo.m_proposedDropIndex);
event.SetDataFormat( format );
event.SetDataSize( obj->GetSize() );
event.SetDataBuffer( obj->GetData() );
event.SetDataSize(obj->GetDataSize(format));
event.SetDataObject(obj->GetObject(format));
event.SetDropEffect( def );
if ( !m_owner->HandleWindowEvent( event ) || !event.IsAllowed() )
return wxDragNone;
@@ -5816,9 +5801,17 @@ bool wxDataViewCtrl::EnableDragSource( const wxDataFormat &format )
return m_clientArea->EnableDragSource( format );
}
bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat &format )
bool wxDataViewCtrl::DoEnableDropTarget( const wxDataFormatArray &formats )
{
return m_clientArea->EnableDropTarget( format );
wxDataViewDropTarget* dt = NULL;
if (wxDataObject* dataObject = CreateDataObject(formats))
{
dt = new wxDataViewDropTarget(dataObject, m_clientArea);
}
m_clientArea->SetDropTarget(dt);
return true;
}
#endif // wxUSE_DRAG_AND_DROP

View File

@@ -211,7 +211,7 @@ public:
// dnd iface
bool EnableDragSource( const wxDataFormat &format );
bool EnableDropTarget( const wxDataFormat &format );
bool EnableDropTarget( const wxDataFormatArray &formats );
gboolean row_draggable( GtkTreeDragSource *drag_source, GtkTreePath *path );
gboolean drag_data_delete( GtkTreeDragSource *drag_source, GtkTreePath* path );
@@ -3794,9 +3794,16 @@ bool wxDataViewCtrlInternal::EnableDragSource( const wxDataFormat &format )
return true;
}
bool wxDataViewCtrlInternal::EnableDropTarget( const wxDataFormat &format )
bool wxDataViewCtrlInternal::EnableDropTarget( const wxDataFormatArray& formats )
{
wxGtkString atom_str( gdk_atom_name( format ) );
if (formats.GetCount() == 0)
{
gtk_tree_view_unset_rows_drag_dest(GTK_TREE_VIEW(m_owner->GtkGetTreeView()));
return true;
}
wxGtkString atom_str( gdk_atom_name( formats.Item(0) ) );
m_dropTargetTargetEntryTarget = wxCharBuffer( atom_str );
m_dropTargetTargetEntry.target = m_dropTargetTargetEntryTarget.data();
@@ -4922,10 +4929,10 @@ bool wxDataViewCtrl::EnableDragSource( const wxDataFormat &format )
return m_internal->EnableDragSource( format );
}
bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat &format )
bool wxDataViewCtrl::DoEnableDropTarget( const wxDataFormatArray& formats )
{
wxCHECK_MSG( m_internal, false, "model must be associated before calling EnableDragTarget" );
return m_internal->EnableDropTarget( format );
return m_internal->EnableDropTarget( formats );
}
bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col )

View File

@@ -26,6 +26,7 @@
#include "wx/osx/private.h"
#include "wx/osx/private/available.h"
#include "wx/osx/private/datatransfer.h"
#include "wx/osx/cocoa/dataview.h"
#include "wx/renderer.h"
#include "wx/stopwatch.h"
@@ -708,18 +709,40 @@ outlineView:(NSOutlineView*)outlineView
return [self setupAndCallDataViewEvents:wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE dropInfo:info item:item proposedChildIndex:index];
}
-(NSDragOperation) callDataViewEvents:(wxEventType)eventType dataObjects:(wxDataObjectComposite*)dataObjects item:(id)item
-(NSDragOperation) setupAndCallDataViewEvents:(wxEventType)eventType dropInfo:(id<NSDraggingInfo>)info item:(id)item
proposedChildIndex:(NSInteger)index
{
NSDragOperation dragOperation = NSDragOperationNone;
wxDataViewCtrl* const dvc(implementation->GetDataViewCtrl());
wxDropTarget* dt = dvc->GetDropTarget();
if (!dt)
return NSDragOperationNone;
NSPasteboard* pasteboard([info draggingPasteboard]);
wxOSXPasteboard wxPastboard(pasteboard);
dt->SetCurrentDragSource(&wxPastboard);
wxDataFormat format = dt->GetMatchingPair();
if (format == wxDF_INVALID)
return NSDragOperationNone;
// Create event
wxDataViewEvent event(eventType, dvc, wxDataViewItemFromItem(item));
if (dataObjects && (dataObjects->GetFormatCount() > 0))
// Retrieve data info if user released mouse buttton (drop occured)
if (eventType == wxEVT_DATAVIEW_ITEM_DROP)
{
// copy data into data object:
event.SetDataObject(dataObjects);
event.SetDataFormat(implementation->GetDnDDataFormat(dataObjects));
if (!dt->GetData())
return NSDragOperationNone;
wxDataObjectComposite *obj = static_cast<wxDataObjectComposite*>(dt->GetDataObject());
event.SetDataSize(obj->GetDataSize(format));
event.SetDataObject(obj->GetObject(format));
}
// Setup other event properties
event.SetProposedDropIndex(index);
event.SetDataFormat(format);
if (index == -1)
{
event.SetDropEffect(wxDragCopy);
@@ -733,19 +756,8 @@ outlineView:(NSOutlineView*)outlineView
//copy/move or similar to support it.
event.SetDropEffect(wxDragNone);
}
wxDataFormatId formatId = event.GetDataFormat().GetType();
wxMemoryBuffer buffer;
// copy data into buffer:
if ( formatId != wxDF_INVALID)
{
size_t size = dataObjects->GetDataSize(formatId);
event.SetDataSize(size);
dataObjects->GetDataHere(formatId,buffer.GetWriteBuf(size));
buffer.UngetWriteBuf(size);
event.SetDataBuffer(buffer.GetData());
}
NSDragOperation dragOperation = NSDragOperationNone;
// finally, send event:
if (dvc->HandleWindowEvent(event) && event.IsAllowed())
@@ -774,84 +786,6 @@ outlineView:(NSOutlineView*)outlineView
{
dragOperation = NSDragOperationNone;
}
}
else
{
dragOperation = NSDragOperationNone;
}
return dragOperation;
}
-(NSDragOperation) setupAndCallDataViewEvents:(wxEventType)eventType dropInfo:(id<NSDraggingInfo>)info item:(id)item
proposedChildIndex:(NSInteger)index
{
NSArray* supportedTypes(
[NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]
);
NSPasteboard* pasteboard([info draggingPasteboard]);
NSString* bestType([pasteboard availableTypeFromArray:supportedTypes]);
if ( bestType == nil )
return NSDragOperationNone;
NSDragOperation dragOperation = NSDragOperationNone;
wxDataViewCtrl* const dvc(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.");
// wxDataViewEvent event(eventType, dvc, wxDataViewItemFromItem(item));
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]));
dragOperation = [self callDataViewEvents:eventType dataObjects:dataObjects item:item proposedChildIndex:index];
if ( dragOperation != NSDragOperationNone )
++indexDraggedItem;
else
indexDraggedItem = noOfDraggedItems;
// clean-up:
delete dataObjects;
}
}
else
{
// 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],
#if defined(wxNEEDS_UTF16_FOR_TEXT_DATAOBJ)
kCFStringEncodingUTF16,
#else
kCFStringEncodingUTF8,
#endif
32);
if (textDataObject->SetData(::CFDataGetLength(osxData),::CFDataGetBytePtr(osxData)))
dataObjects->Add(textDataObject);
else
delete textDataObject;
// send event if data could be copied:
dragOperation = [self callDataViewEvents:eventType dataObjects:dataObjects item:item proposedChildIndex:index];
// clean up:
::CFRelease(osxData);
delete dataObjects;
}
return dragOperation;
}
@@ -860,124 +794,36 @@ outlineView:(NSOutlineView*)outlineView
{
wxUnusedVar(outlineView);
// the pasteboard will be filled up with an array containing the data as
// returned by the events (including the data type) and a concatenation of
// text (string) data; the text data will only be put onto the pasteboard
// if for all items a string representation exists
wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
wxDataViewItemArray dataViewItems;
wxCHECK_MSG(dvc, false,"Pointer to data view control not set correctly.");
wxCHECK_MSG(dvc->GetModel(),false,"Pointer to model not set correctly.");
BOOL result = NO;
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]]; // data of all items
wxString dataString; // contains the string data of all items
// send a begin drag event for all selected items and proceed with
// dragging unless the event is vetoed:
for (size_t itemCounter=0; itemCounter<[writeItems count]; ++itemCounter)
{
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
const wxDataViewItem item = wxDataViewItemFromItem([writeItems objectAtIndex:itemCounter]);
// Send a begin drag event for the first selected item and send wxEVT_DATAVIEW_ITEM_BEGIN_DRAG.
// If there are several items selected, user can process each in event handler and
// fill up the corresponding wxDataObject the way he wants.
const wxDataViewItem item = wxDataViewItemFromItem([writeItems objectAtIndex:0]);
wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_BEGIN_DRAG, dvc, item);
itemString = ::ConcatenateDataViewItemValues(dvc, item);
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))
if (dvc->HandleWindowEvent(event) && event.IsAllowed() && event.GetDataObject())
{
size_t const noOfFormats = event.GetDataObject()->GetFormatCount();
wxDataFormat* dataFormats(new wxDataFormat[noOfFormats]);
wxDataObject *dataObject = event.GetDataObject();
event.GetDataObject()->GetAllFormats(dataFormats,wxDataObject::Get);
for (size_t formatCounter=0; formatCounter<noOfFormats; ++formatCounter)
{
// constant definitions for abbreviational purposes:
wxDataFormatId const idDataFormat = dataFormats[formatCounter].GetType();
size_t const dataSize = event.GetDataObject()->GetDataSize(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);
wxOSXPasteboard wxPastboard(pasteboard);
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<char const*>(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<char const*>(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
}
}
if (dataStringAvailable)
{
wxCFStringRef osxString(dataString);
wxPastboard.Clear();
dataObject->WriteToSink(&wxPastboard);
wxPastboard.Flush();
[pasteboard declareTypes:[NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil] owner:nil];
[pasteboard setPropertyList:dataArray forType:DataViewPboardType];
[pasteboard setString:osxString.AsNSString() forType:NSStringPboardType];
result = 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 result;
}
//
@@ -1639,7 +1485,7 @@ outlineView:(NSOutlineView*)outlineView
if (!initialized)
{
initialized = YES;
wxOSXCocoaClassAddWXMethods( self );
wxOSXCocoaClassAddWXMethods(self, wxOSXSKIP_DND);
}
}
@@ -1654,8 +1500,6 @@ outlineView:(NSOutlineView*)outlineView
currentlyEditedColumn =
currentlyEditedRow = -1;
[self setAutoresizesOutlineColumn:NO];
[self registerForDraggedTypes:[NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]];
[self setDelegate:self];
[self setDoubleAction:@selector(actionDoubleClick:)];
[self setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO];
@@ -2501,9 +2345,20 @@ bool wxCocoaDataViewControl::Update(const wxDataViewColumn *columnPtr)
return false;
}
bool wxCocoaDataViewControl::Update(const wxDataViewItem& WXUNUSED(parent), const wxDataViewItem& item)
bool wxCocoaDataViewControl::Update(const wxDataViewItem& parent, const wxDataViewItem& item)
{
if (GetSortingColumn())
{
if (parent.IsOk())
[m_OutlineView reloadItem:[m_DataSource getDataViewItemFromBuffer:parent] reloadChildren:YES];
else
[m_OutlineView reloadData];
}
else
{
[m_OutlineView reloadItem:[m_DataSource getDataViewItemFromBuffer:item]];
}
return true;
}
@@ -2718,96 +2573,6 @@ void wxCocoaDataViewControl::OnSize()
[m_OutlineView sizeLastColumnToFit];
}
//
// drag & drop helper methods
//
wxDataFormat wxCocoaDataViewControl::GetDnDDataFormat(wxDataObjectComposite* dataObjects)
{
wxDataFormat resultFormat;
if ( !dataObjects )
return resultFormat;
bool compatible(true);
size_t const noOfFormats = dataObjects->GetFormatCount();
size_t indexFormat;
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
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;
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:
case wxDF_UNICODETEXT:
{
wxTextDataObject* textDataObject(new wxTextDataObject());
if (textDataObject->SetData(wxDataFormat(dataFormatID),[dataObject length]-sizeof(wxDataFormatId),static_cast<char const*>([dataObject bytes])+sizeof(wxDataFormatId)))
{
wxDataObjectComposite* dataObjectComposite(new wxDataObjectComposite());
dataObjectComposite->Add(textDataObject);
return dataObjectComposite;
}
else
{
delete textDataObject;
return NULL;
}
}
default:
return NULL;
}
}
id wxCocoaDataViewControl::GetItemAtRow(int row) const
{
return [m_OutlineView itemAtRow:row];

View File

@@ -2484,10 +2484,13 @@ void wxOSXCocoaClassAddWXMethods(Class c, wxOSXSkipOverrides skipFlags)
wxOSX_CLASS_ADD_METHOD(c, @selector(controlDoubleAction:), (IMP) wxOSX_controlDoubleAction, "v@:@" )
#if wxUSE_DRAG_AND_DROP
if ( !(skipFlags & wxOSXSKIP_DND) )
{
wxOSX_CLASS_ADD_METHOD(c, @selector(draggingEntered:), (IMP) wxOSX_draggingEntered, "I@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(draggingUpdated:), (IMP) wxOSX_draggingUpdated, "I@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(draggingExited:), (IMP) wxOSX_draggingExited, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(performDragOperation:), (IMP) wxOSX_performDragOperation, "c@:@" )
}
#endif
#if OBJC_API_VERSION < 2

View File

@@ -687,6 +687,23 @@ void wxDataViewCtrl::EditItem(const wxDataViewItem& item, const wxDataViewColumn
GetDataViewPeer()->StartEditor(item, GetColumnPosition(column));
}
#if wxUSE_DRAG_AND_DROP
bool wxDataViewCtrl::DoEnableDropTarget(const wxDataFormatArray &formats)
{
wxDropTarget* dt = NULL;
if (wxDataObject* dataObject = CreateDataObject(formats))
{
dt = new wxDropTarget(dataObject);
}
SetDropTarget(dt);
return true;
}
#endif // wxUSE_DRAG_AND_DROP
void wxDataViewCtrl::FinishCustomItemEditing()
{
if (GetCustomRendererItem().IsOk())

View File

@@ -285,7 +285,7 @@ bool wxDataViewCtrl::EnableDragSource( const wxDataFormat &format )
return false;
}
bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat &format )
bool wxDataViewCtrl::DoEnableDropTarget( const wxDataFormatArray &formats )
{
return false;
}