Merge branch 'dvc-multi-format-dnd'
Accept multiple data formats via drag-and-drop in wxDataViewCtrl. See #2478, #2616.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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() );
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
@@ -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;
|
||||
@@ -2394,13 +2385,13 @@ wxDragResult wxDataViewMainWindow::OnData( wxDataFormat format, wxCoord x, wxCoo
|
||||
{
|
||||
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
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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,17 +709,41 @@ 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 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));
|
||||
if (!dt->GetData())
|
||||
return NSDragOperationNone;
|
||||
|
||||
wxDataObjectComposite *obj = static_cast<wxDataObjectComposite*>(dt->GetDataObject());
|
||||
event.InitData(obj, format);
|
||||
}
|
||||
else // Otherwise set just the data format
|
||||
{
|
||||
event.SetDataFormat(format);
|
||||
}
|
||||
|
||||
// Setup other event properties
|
||||
event.SetProposedDropIndex(index);
|
||||
if (index == -1)
|
||||
{
|
||||
@@ -733,19 +758,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 +788,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 +796,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 +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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user