Generic drop target possible?

Hello all,

I am hoping to write a “generic” drop target meaning that it
accepts drops of “anything” and decides what to do with it
based upon the type received. Is that possible with
wxPython4 ?

I am trying like this:

class cGenericDropTarget(wx.DropTarget):
	def __init__(self, *args, **kwargs):
		super().__init__(*args, **kwargs)
		data_object = wx.DataObjectComposite()
		data_object.Add(wx.FileDataObject(), True)
		data_object.Add(wx.TextDataObject())
		# not accepted by Add():
		#data_object.Add(wx.URLDataObject())
		data_object.Add(wx.BitmapDataObject())
		self.SetDataObject(data_object)

	def OnDrop(self, x, y):
		print('received a drop request at', x, y, 'accepting')
		return True		# receive any drop

	def OnData(self, x, y, suggested_drag_result):
		print('receiving dropped data at', x, y)
		print('suggested drag result:', suggested_drag_result)
		# copy data from drop source to our data object
		copied = self.GetData()
		print('copied data from source into our data object:', copied)
		print('our composite object:', self.DataObject)
		received_format = self.DataObject.GetReceivedFormat()
		print('received format obj:', received_format)
		format_int = received_format.GetType()
		try:
			format_str = received_format.Id
		except Exception:
			_log.exception('wx.DataFormat.Id not supported')
			format_str = None
		print('format as int:', format_int)
		print('format as str:', format_str)
		filled_in_data_object = self.DataObject.GetObject(received_format)
		print('filled in object:', filled_in_data_object)
		print('data size:', filled_in_data_object.GetDataSize())
		if format_int == wx.DF_FILENAME:
			print('files:', filled_in_data_object.Filenames)
		elif format_int == wx.DF_UNICODETEXT:
			print('text:', filled_in_data_object.Text)
		else:
			print('unknown type')
		# this segfaults:
		#data = filled_in_data_object.GetDataHere(format_int)
		#print('data:', data)
		return suggested_drag_result

This is, of course, not generic, but restricted to file
names, text data, and bitmap data. At the very least I would
like to also accept URLs dragged in from a browser.

Should I add a wx.CustomDataObject() as sub object and that
will somehow magically receive any data not accepted by the
other data objects ?

Elsewhere I have read that one might attempt to add other
data objects to an URL data object because that already is
a composite. However, elsewhere

https://docs.wxpython.org/wx.URLDataObject.html

it says URL objects may or may not be …

Thanks,
Karsten

To be truly generic you would probably have to derive directly from wx.DataObject and deal with the raw bytes being transferred and the wx.DataFormat data format types or names. This would not have been possible before wxPython4, but it should be now because of the better ability to override the C++ virtual methods and using buffer objects like bytearray and memoryview.

There isn’t any examples of deriving directly from wx.DataObject in the demo, but there is some code in the unittests that may help point you in the right direction. See test_dataobj.py. You’ll need to override most of the methods in the wx.DataObject class and provide the functionality to indicate supported formats and moving bytes to or from the other end. Reviewing the C++ implementations of the other dataobject types may also help figure out what to do and how to do it.

Good luck.