Merge branch 'dvc-multi-format-dnd'

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

See #2478, #2616.
This commit is contained in:
Vadim Zeitlin
2022-01-15 23:39:03 +01:00
16 changed files with 290 additions and 373 deletions

View File

@@ -760,8 +760,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 EnableDropTargets(const wxVector<wxDataFormat>& formats)
{ return DoEnableDropTarget(formats); }
bool EnableDropTarget(const wxDataFormat& format)
{
wxVector<wxDataFormat> formats;
if (format.GetType() != wxDF_INVALID)
{
formats.push_back(format);
}
return DoEnableDropTarget(formats);
}
#endif // wxUSE_DRAG_AND_DROP
// define control visual attributes
@@ -792,6 +805,17 @@ protected:
virtual void DoSetExpanderColumn() = 0 ;
virtual void DoSetIndent() = 0;
#if wxUSE_DRAG_AND_DROP
// Helper function which can be used by DoEnableDropTarget() implementations
// in the derived classes: return a composite data object supporting the
// given formats or null if the vector is empty.
static wxDataObjectComposite*
CreateDataObject(const wxVector<wxDataFormat>& formats);
virtual bool DoEnableDropTarget(const wxVector<wxDataFormat>& 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().
//
@@ -912,6 +936,9 @@ public:
// insertion of items, this is the proposed child index for the insertion.
void SetProposedDropIndex(int index) { m_proposedDropIndex = index; }
int GetProposedDropIndex() const { return m_proposedDropIndex;}
// Internal, only used by wxWidgets itself.
void InitData(wxDataObjectComposite* obj, wxDataFormat format);
#endif // wxUSE_DRAG_AND_DROP
virtual wxEvent *Clone() const wxOVERRIDE { return new wxDataViewEvent(*this); }
@@ -945,6 +972,7 @@ protected:
#if wxUSE_DRAG_AND_DROP
wxDataObject *m_dataObject;
wxMemoryBuffer m_dataBuf;
wxDataFormat m_dataFormat;
void* m_dataBuffer;
size_t m_dataSize;

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 wxVector<wxDataFormat>& 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 wxVector<wxDataFormat>& 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 wxVector<wxDataFormat>& 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 wxVector<wxDataFormat>& formats );
static wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);

View File

@@ -1390,9 +1390,25 @@ public:
virtual bool EnableDragSource( const wxDataFormat &format );
/**
Enable drop operations using the given @a format.
Enable drop operations using any of the specified @a formats.
Currently this is fully implemented in the generic and native macOS
versions. In wxGTK only the first element of the array is used.
@note Passing empty array disables drag and drop operations completely.
@since 3.1.6
*/
virtual bool EnableDropTarget( const wxDataFormat &format );
bool EnableDropTargets(const wxVector<wxDataFormat>& formats);
/**
Enable drop operations using the given @a format.
See EnableDropTargets() for providing more than one supported format.
@note Since 3.1.6 wxDF_INVALID can be passed to disable drag and drop support.
*/
bool EnableDropTarget( const wxDataFormat &format );
/**
Call this to ensure that the given item is visible.

View File

@@ -1430,6 +1430,11 @@ void MyFrame::OnDrop( wxDataViewEvent &event )
return;
}
// Note that instead of recreating a new data object here we could also
// retrieve the data object from the event, using its GetDataObject()
// method. This would be more efficient as it would avoid copying the text
// one more time, but would require a cast in the code and we don't really
// care about efficiency here.
wxTextDataObject obj;
obj.SetData( wxDF_UNICODETEXT, event.GetDataSize(), event.GetDataBuffer() );

View File

@@ -1688,6 +1688,67 @@ void wxDataViewCtrlBase::StartEditor(const wxDataViewItem& item, unsigned int co
EditItem(item, GetColumn(column));
}
#if wxUSE_DRAG_AND_DROP
/* static */
wxDataObjectComposite*
wxDataViewCtrlBase::CreateDataObject(const wxVector<wxDataFormat>& formats)
{
if (formats.empty())
{
return NULL;
}
wxDataObjectComposite *dataObject(new wxDataObjectComposite);
for (size_t i = 0; i < formats.size(); ++i)
{
switch (formats[i].GetType())
{
case wxDF_TEXT:
case wxDF_OEMTEXT:
case wxDF_UNICODETEXT:
dataObject->Add(new wxTextDataObject);
break;
case wxDF_BITMAP:
case wxDF_PNG:
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[i]));
break;
case wxDF_INVALID:
case wxDF_MAX:
break;
}
}
return dataObject;
}
#endif // wxUSE_DRAG_AND_DROP
// ---------------------------------------------------------
// wxDataViewEvent
// ---------------------------------------------------------
@@ -1744,6 +1805,28 @@ void wxDataViewEvent::Init(wxDataViewCtrlBase* dvc,
SetEventObject(dvc);
}
#if wxUSE_DRAG_AND_DROP
void wxDataViewEvent::InitData(wxDataObjectComposite* obj, wxDataFormat format)
{
SetDataFormat(format);
SetDataObject(obj->GetObject(format));
const size_t size = obj->GetDataSize(format);
SetDataSize(size);
if ( size )
{
obj->GetDataHere(format, m_dataBuf.GetWriteBuf(size));
m_dataBuf.UngetWriteBuf(size);
SetDataBuffer(m_dataBuf.GetData());
}
}
#endif // wxUSE_DRAG_AND_DROP
#if wxUSE_SPINCTRL
// -------------------------------------

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
@@ -1704,12 +1701,15 @@ public:
class wxDataViewDropTarget: public wxDropTarget
{
public:
wxDataViewDropTarget( wxDataObject *obj, wxDataViewMainWindow *win ) :
wxDropTarget( obj )
wxDataViewDropTarget( wxDataObjectComposite *obj, wxDataViewMainWindow *win ) :
wxDropTarget( obj ),
m_obj(obj)
{
m_win = win;
}
wxDataObjectComposite* GetCompositeDataObject() const { return m_obj; }
virtual wxDragResult OnDragOver( wxCoord x, wxCoord y, wxDragResult def ) wxOVERRIDE
{
wxDataFormat format = GetMatchingPair();
@@ -1739,6 +1739,9 @@ public:
virtual void OnLeave() wxOVERRIDE
{ m_win->OnLeave(); }
private:
wxDataObjectComposite* const m_obj;
wxDataViewMainWindow *m_win;
};
@@ -2076,7 +2079,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 +2134,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 +2380,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();
wxDataViewDropTarget* const
target = static_cast<wxDataViewDropTarget*>(GetDropTarget());
wxDataObjectComposite* const obj = target->GetCompositeDataObject();
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.InitData(obj, format);
event.SetDropEffect( def );
if ( !m_owner->HandleWindowEvent( event ) || !event.IsAllowed() )
return wxDragNone;
@@ -5823,9 +5814,17 @@ bool wxDataViewCtrl::EnableDragSource( const wxDataFormat &format )
return m_clientArea->EnableDragSource( format );
}
bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat &format )
bool wxDataViewCtrl::DoEnableDropTarget( const wxVector<wxDataFormat> &formats )
{
return m_clientArea->EnableDropTarget( format );
wxDataViewDropTarget* dt = NULL;
if (wxDataObjectComposite* 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 wxVector<wxDataFormat> &formats );
gboolean row_draggable( GtkTreeDragSource *drag_source, GtkTreePath *path );
gboolean drag_data_delete( GtkTreeDragSource *drag_source, GtkTreePath* path );
@@ -3794,9 +3794,17 @@ bool wxDataViewCtrlInternal::EnableDragSource( const wxDataFormat &format )
return true;
}
bool wxDataViewCtrlInternal::EnableDropTarget( const wxDataFormat &format )
bool wxDataViewCtrlInternal::EnableDropTarget( const wxVector<wxDataFormat>& formats )
{
wxGtkString atom_str( gdk_atom_name( format ) );
if (formats.empty())
{
gtk_tree_view_unset_rows_drag_dest(GTK_TREE_VIEW(m_owner->GtkGetTreeView()));
return true;
}
// TODO: Use all formats, not just the first one.
wxGtkString atom_str( gdk_atom_name( formats[0] ) );
m_dropTargetTargetEntryTarget = wxCharBuffer( atom_str );
m_dropTargetTargetEntry.target = m_dropTargetTargetEntryTarget.data();
@@ -4931,10 +4939,10 @@ bool wxDataViewCtrl::EnableDragSource( const wxDataFormat &format )
return m_internal->EnableDragSource( format );
}
bool wxDataViewCtrl::EnableDropTarget( const wxDataFormat &format )
bool wxDataViewCtrl::DoEnableDropTarget( const wxVector<wxDataFormat>& 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,71 +709,79 @@ 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
proposedChildIndex:(NSInteger)index
-(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 the data itself if user released mouse button (drop occurred)
if (eventType == wxEVT_DATAVIEW_ITEM_DROP)
{
// copy data into data object:
event.SetDataObject(dataObjects);
event.SetDataFormat(implementation->GetDnDDataFormat(dataObjects));
event.SetProposedDropIndex(index);
if (index == -1)
{
event.SetDropEffect(wxDragCopy);
}
else
{
//if index is not -1, we're going to set the default
//for the drop effect to None to be compatible with
//the other wxPlatforms that don't support it. In the
//user code for for the event, they can set this to
//copy/move or similar to support it.
event.SetDropEffect(wxDragNone);
}
wxDataFormatId formatId = event.GetDataFormat().GetType();
wxMemoryBuffer buffer;
if (!dt->GetData())
return NSDragOperationNone;
// copy data into buffer:
if ( formatId != wxDF_INVALID)
{
size_t size = dataObjects->GetDataSize(formatId);
wxDataObjectComposite *obj = static_cast<wxDataObjectComposite*>(dt->GetDataObject());
event.InitData(obj, format);
}
else // Otherwise set just the data format
{
event.SetDataFormat(format);
}
event.SetDataSize(size);
dataObjects->GetDataHere(formatId,buffer.GetWriteBuf(size));
buffer.UngetWriteBuf(size);
event.SetDataBuffer(buffer.GetData());
}
// Setup other event properties
event.SetProposedDropIndex(index);
if (index == -1)
{
event.SetDropEffect(wxDragCopy);
}
else
{
//if index is not -1, we're going to set the default
//for the drop effect to None to be compatible with
//the other wxPlatforms that don't support it. In the
//user code for for the event, they can set this to
//copy/move or similar to support it.
event.SetDropEffect(wxDragNone);
}
// finally, send event:
if (dvc->HandleWindowEvent(event) && event.IsAllowed())
NSDragOperation dragOperation = NSDragOperationNone;
// finally, send event:
if (dvc->HandleWindowEvent(event) && event.IsAllowed())
{
switch (event.GetDropEffect())
{
switch (event.GetDropEffect())
{
case wxDragCopy:
dragOperation = NSDragOperationCopy;
break;
case wxDragMove:
dragOperation = NSDragOperationMove;
break;
case wxDragLink:
dragOperation = NSDragOperationLink;
break;
case wxDragNone:
case wxDragCancel:
case wxDragError:
dragOperation = NSDragOperationNone;
break;
default:
dragOperation = NSDragOperationEvery;
}
}
else
{
dragOperation = NSDragOperationNone;
case wxDragCopy:
dragOperation = NSDragOperationCopy;
break;
case wxDragMove:
dragOperation = NSDragOperationMove;
break;
case wxDragLink:
dragOperation = NSDragOperationLink;
break;
case wxDragNone:
case wxDragCancel:
case wxDragError:
dragOperation = NSDragOperationNone;
break;
default:
dragOperation = NSDragOperationEvery;
}
}
else
@@ -783,201 +792,40 @@ outlineView:(NSOutlineView*)outlineView
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;
}
-(BOOL) outlineView:(NSOutlineView*)outlineView writeItems:(NSArray*)writeItems toPasteboard:(NSPasteboard*)pasteboard
{
wxUnusedVar(outlineView);
// the pasteboard will be filled up with an array containing the data as
// returned by the events (including the data type) and a concatenation of
// text (string) data; the text data will only be put onto the pasteboard
// 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 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);
// 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)
// check if event has not been vetoed:
if (dvc->HandleWindowEvent(event) && event.IsAllowed() && event.GetDataObject())
{
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
wxDataObject *dataObject = event.GetDataObject();
const wxDataViewItem item = wxDataViewItemFromItem([writeItems objectAtIndex:itemCounter]);
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))
{
size_t const noOfFormats = event.GetDataObject()->GetFormatCount();
wxDataFormat* dataFormats(new wxDataFormat[noOfFormats]);
wxOSXPasteboard wxPastboard(pasteboard);
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);
wxPastboard.Clear();
dataObject->WriteToSink(&wxPastboard);
wxPastboard.Flush();
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
}
result = YES;
}
if (dataStringAvailable)
{
wxCFStringRef osxString(dataString);
[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
return NO; // no items to drag (should never occur)
return result;
}
//
@@ -1639,7 +1487,7 @@ outlineView:(NSOutlineView*)outlineView
if (!initialized)
{
initialized = YES;
wxOSXCocoaClassAddWXMethods( self );
wxOSXCocoaClassAddWXMethods(self, wxOSXSKIP_DND);
}
}
@@ -1655,7 +1503,6 @@ outlineView:(NSOutlineView*)outlineView
currentlyEditedRow = -1;
[self setAutoresizesOutlineColumn:NO];
[self registerForDraggedTypes:[NSArray arrayWithObjects:DataViewPboardType,NSStringPboardType,nil]];
[self setDelegate:self];
[self setDoubleAction:@selector(actionDoubleClick:)];
[self setDraggingSourceOperationMask:NSDragOperationEvery forLocal:NO];
@@ -2718,96 +2565,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
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@:@" )
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

@@ -715,6 +715,23 @@ void wxDataViewCtrl::EditItem(const wxDataViewItem& item, const wxDataViewColumn
GetDataViewPeer()->StartEditor(item, GetColumnPosition(column));
}
#if wxUSE_DRAG_AND_DROP
bool wxDataViewCtrl::DoEnableDropTarget(const wxVector<wxDataFormat> &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 wxVector<wxDataFormat> &formats )
{
return false;
}