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)