Drag and drop from Tree View to List

Okay a little bit of work and understanding, and taking @PGriffith's tip, and I was able to accomplish this.

This will do multi or single selection, and will handle dragging folders. The drop listener also filters out duplicate paths.

You'll want to add this code to a custom function on your Tree View component that you call from the InternalFrameActivated event on the window.

def addDragSource(self):
	from java.awt.dnd import DragSourceAdapter, DragGestureListener, DragSource, DnDConstants
	from java.awt.datatransfer import DataFlavor, Transferable
	
	#A custom transferable which allows a List to be transfered
	#via Drag and Drop.
	class customTransferable(Transferable):
		_transferData = None
		def __init__(self,data):
			self._transferData = data
		
		def getTransferData(self,flavor):
			return self._transferData
		
		def getTransferDataFlavors(self):
			return [DataFlavor(list,'List')]
		
		def isDataFlavorSupported(self,flavor):
			if not DataFlavor(list,'List'):
				return False
			return True
	
	#Custom listener to build the transferable when a drag gesture is recognized.
	#Takes in a component (assumes PMITreeView)		
	class customDragGestureListener(DragGestureListener):
		_comp = None
		_selectedPaths = []
		def __init__(self,comp):
			self._comp = comp
			
		def dragGestureRecognized(self,e):
			dataFlavor = DataFlavor(list,'List')
			
			self.addPaths(self._comp.selectedPaths)
			
			transferable = customTransferable(self._selectedPaths)
			e.startDrag(DragSource.DefaultCopyDrop,transferable)
	
		def addPaths(self,paths):
			for path in paths:
				if not self._comp.separationCharacter in path:
					#this is a root folder, add all sub paths of this folder
					subPaths = [subPath for subPath in self._comp.data.getColumnAsList(0) if path in subPath]
					self.addPaths(subPaths) 
				#if path is found in first columnn then it is a folder.
				#only add paths that aren't in 
				elif path in self._comp.data.getColumnAsList(0):
					#build subPaths list
					subPaths = [row['path'] + '/{}'.format(row['text'])	for row in system.dataset.toPyDataSet(self._comp.data) if row['path'] == path]
					self.addPaths(subPaths)
				elif not path in self._selectedPaths:
					self._selectedPaths.append(path)
				
	
	ds = DragSource.getDefaultDragSource()
	ds.createDefaultDragGestureRecognizer(self, DnDConstants.ACTION_COPY, customDragGestureListener(self))

Then add this to the List component. You will also need to call this from InternalFrameActivated

def addDropTarget(self):
	from java.awt.dnd import DropTargetAdapter, DropTarget
	from java.awt.datatransfer import DataFlavor
	class customDropListener(DropTargetAdapter):
		_comp = None
		def __init__(self,comp):
			self._comp = comp
		def drop(self,e):
			e.acceptDrop(e.getDropAction())
			self._comp.addData(e.getTransferable().getTransferData(DataFlavor(list,'List')))
			e.dropComplete(True)
			
	DropTarget(self,customDropListener(self))

I also used a custom addData function on the List here for the filtering.

def addData(self,data):
	paths = self.data.getColumnAsList(0)
	
	if not paths and not self.data.columnCount:
		#this takes care of an empty dataset
		self.data = system.dataset.addColumn(self.data,[],'Paths',str)
	newRows = [[path] for path in data if not path in paths]
	self.data = system.dataset.addRows(self.data,newRows)
5 Likes