From 7129d2b11c77da50cc7c9721ee168c02ca7a8c03 Mon Sep 17 00:00:00 2001 From: valid-ptr Date: Sun, 22 Aug 2021 10:25:32 +0300 Subject: [PATCH] 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. --- include/wx/dataview.h | 29 ++- include/wx/generic/dataview.h | 2 +- include/wx/gtk/dataview.h | 2 +- include/wx/osx/cocoa/dataview.h | 4 - include/wx/osx/cocoa/private.h | 3 +- include/wx/osx/dataview.h | 4 + include/wx/qt/dataview.h | 2 +- interface/wx/dataview.h | 18 +- samples/dataview/dataview.cpp | 9 +- src/common/datavcmn.cpp | 58 +++++ src/generic/datavgen.cpp | 37 ++- src/gtk/dataview.cpp | 17 +- src/osx/cocoa/dataview.mm | 423 +++++++------------------------- src/osx/cocoa/window.mm | 11 +- src/osx/dataview_osx.cpp | 17 ++ src/qt/dataview.cpp | 2 +- 16 files changed, 260 insertions(+), 378 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index 0d7f46cd8f..624fbc3526 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -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(). // diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index 262d318696..f8636336d8 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -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; diff --git a/include/wx/gtk/dataview.h b/include/wx/gtk/dataview.h index b5933cd33a..718ae843c4 100644 --- a/include/wx/gtk/dataview.h +++ b/include/wx/gtk/dataview.h @@ -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; diff --git a/include/wx/osx/cocoa/dataview.h b/include/wx/osx/cocoa/dataview.h index 90be1a8ae0..7d63ed0208 100644 --- a/include/wx/osx/cocoa/dataview.h +++ b/include/wx/osx/cocoa/dataview.h @@ -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; diff --git a/include/wx/osx/cocoa/private.h b/include/wx/osx/cocoa/private.h index 48d4675acb..d35a452254 100644 --- a/include/wx/osx/cocoa/private.h +++ b/include/wx/osx/cocoa/private.h @@ -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); diff --git a/include/wx/osx/dataview.h b/include/wx/osx/dataview.h index 457eddbebd..6a3e2197ec 100644 --- a/include/wx/osx/dataview.h +++ b/include/wx/osx/dataview.h @@ -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 diff --git a/include/wx/qt/dataview.h b/include/wx/qt/dataview.h index 778bda4d67..a8b51ab7d2 100644 --- a/include/wx/qt/dataview.h +++ b/include/wx/qt/dataview.h @@ -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); diff --git a/interface/wx/dataview.h b/interface/wx/dataview.h index c1c4327c20..de76145267 100644 --- a/interface/wx/dataview.h +++ b/interface/wx/dataview.h @@ -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. diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index 6eb1cb388b..b679cf91c0 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -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(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 diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index cd070d2870..1eaa975bc6 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -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 // --------------------------------------------------------- diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 2712368c6f..2568a72fba 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -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(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 diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 7d8140d153..48b871272d 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -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 ) diff --git a/src/osx/cocoa/dataview.mm b/src/osx/cocoa/dataview.mm index 06bbddf9cc..09e1286e25 100644 --- a/src/osx/cocoa/dataview.mm +++ b/src/osx/cocoa/dataview.mm @@ -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,77 @@ 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)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)); - 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(dt->GetDataObject()); + event.SetDataSize(obj->GetDataSize(format)); + event.SetDataObject(obj->GetObject(format)); + } - event.SetDataSize(size); - dataObjects->GetDataHere(formatId,buffer.GetWriteBuf(size)); - buffer.UngetWriteBuf(size); - event.SetDataBuffer(buffer.GetData()); - } + // Setup other event properties + event.SetProposedDropIndex(index); + event.SetDataFormat(format); + 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 +790,40 @@ outlineView:(NSOutlineView*)outlineView return dragOperation; } --(NSDragOperation) setupAndCallDataViewEvents:(wxEventType)eventType dropInfo:(id)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; 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); + 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(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 - } + 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 +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) { - [m_OutlineView reloadItem:[m_DataSource getDataViewItemFromBuffer: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([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]; diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 537d091595..82efa9ae54 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -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 diff --git a/src/osx/dataview_osx.cpp b/src/osx/dataview_osx.cpp index def9d099d4..8f885de027 100644 --- a/src/osx/dataview_osx.cpp +++ b/src/osx/dataview_osx.cpp @@ -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()) diff --git a/src/qt/dataview.cpp b/src/qt/dataview.cpp index 61cf681ca0..fd1b4b280e 100644 --- a/src/qt/dataview.cpp +++ b/src/qt/dataview.cpp @@ -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; }