Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
SWTDND zwischen zwei TreViewern in beide Richtungen
nachdem ich den eigentlichen DND-Support für meine beiden TreeViewer (2 FileBrowser, einer ist quasi lokal, einer symbolisiert ein Archiv) hinbekommen habe und auch unterscheiden kann, ob mein Target ein File oder ein Directory ist, stoße ich nun auf folgendes Problem.
Der User soll sowohl Dateien von LOKAL -> ARCHIV als auch von ARCHIV -> LOKAL per DND kopieren können. Heißt, ich hab in beiden TreeViewern eine DragSource und ein DropTarget für die gleiche Art von TransferTypes. Wenn ich nun eine Datei im gleichen TreeViewer kopieren will, klappt das wunderbar, weil der DropTarget nicht verlassen wird. Will ich aber in den anderen TreeViewer wechseln wird ja der DropTarget verlassen und somit die dragLeave()-Methode aufgerufen, was dazu führt, dass das DND Event abgebrochen wird.
Komme ich irgendwie an die DragSource bzw. den DropTarget ran, sodass ich beide auf Gleichheit prüfen kann und dann ggfs. die dragLeave()-Methode überschreiben kann oder wie löse ich dieses Problem?
Das DragEvent wird nur abgebrochen, wenn ich es über einen Scrollbalken des Viewers ziehe. Wenn ich keinen Scrollbalken hab, kann ich die Dateien ohne Probleme in beide Richtungen verschieben.
Das sind übrigens die beiden Zeilen, wo ich (hier einem) Viewer den Drag- und DropSupport zuweise. Bei dem zweiten sieht es genau so aus.
ops sind die erlaubten Operations, types die TansferTypes und dann halt die 2 Listener, die auch vollständig ohne CompilerFehler implementiert sind.
Mal gucken, vielleicht finde ich ja noch mehr heraus. Falls doch zwischendurch jemand ne Idee hat: nur her damit.
package com.vknie.combination_manager;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
public class SongDragSource implements DragSourceListener {
private final TreeViewer viewer;
public SongDragSource(TreeViewer viewer){
this.viewer=viewer;
DragSource source = new DragSource(viewer.getControl(), DND.DROP_COPY);
source.setTransfer(new Transfer[] {FileTransfer.getInstance()});
source.addDragListener(this);
}
public void dragFinished(DragSourceEvent event) {
}
public void dragSetData(DragSourceEvent event) {
// Provide the data of the selected type
Object[] objects = ((IStructuredSelection)viewer.getSelection()).toArray();
if (FileTransfer.getInstance().isSupportedType(event.dataType)){
Collection<File> files = new HashSet<File>(objects.length);
for(int i=0;i<objects.length;i++){
Object each = objects[i];
if(each instanceof File){
files.add((File)each);
}
}
event.data = files.toArray(new File[files.size()]);
}
}
public void dragStart(DragSourceEvent event) {
// only start when at least one File in the tree is selected
event.doit = !viewer.getSelection().isEmpty();
}
}
createPartControl(Composite parent) und hookDragAndDrop() aus dem LocalBrowserView.java
Java:
public void createPartControl(Composite parent) {
GridLayout gl = new GridLayout();
gl.numColumns=1;
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
parent.setLayout(gl);
File[] roots = File.listRoots();
String[] drives = new String[roots.length];
for(int i=0;i<roots.length;i++){
drives[i]=roots[i].getAbsolutePath();
}
final Combo cb_drives = new Combo(parent, SWT.SINGLE);
cb_drives.setItems(drives);
cb_drives.select(0);
cb_drives.setLayoutData(gd);
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new LocalBrowserContentProvider());
viewer.setLabelProvider(new LocalBrowserLabelProvider());
viewer.setInput(new File(cb_drives.getItem(cb_drives.getSelectionIndex())));
gd = new GridData(GridData.FILL_BOTH);
viewer.getControl().setLayoutData(gd);
cb_drives.addSelectionListener(new SelectionListener(){
public void widgetDefaultSelected(SelectionEvent e) {
// TODO Auto-generated method stub
}
public void widgetSelected(SelectionEvent e) {
viewer.setInput(new File(cb_drives.getItem(cb_drives.getSelectionIndex())));
}
});
hookDragAndDrop();
}
private void hookDragAndDrop(){
new SongDragSource(viewer);
new SongDropTarget(viewer);
}
Die Combobox listet mir die Drives auf und der FileBrowser wird dann in dem TreeViewer geladen. Das funktioniert auch wunderbar.
Content- und Labelprovider:
Java:
class LocalBrowserContentProvider implements ITreeContentProvider{
public Object[] getChildren(Object parentElement) {
return ((File)parentElement).listFiles();
}
public Object getParent(Object element) {
return ((File)element).getParentFile();
}
public boolean hasChildren(Object element) {
Object[] obj = getChildren(element);
return obj == null ? false : obj.length > 0;
}
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
public void dispose() {
// nothing to dispose
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// nothing changed
}
}
class LocalBrowserLabelProvider implements ILabelProvider{
private List listeners;
private Image file;
private Image dir;
public LocalBrowserLabelProvider(){
listeners = new ArrayList();
file = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE);
dir = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER);
}
public Image getImage(Object element) {
return ((File)element).isDirectory() ? dir : file;
}
public String getText(Object element) {
String text = ((File)element).getName();
if(text.length() == 0){
text = ((File)element).getPath();
}
return text;
}
public void addListener(ILabelProviderListener listener) {
listeners.add(listener);
}
public void dispose() {
// nothing to dispose
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {
listeners.remove(listener);
}
}
Der zweite FileBrowser (ArchiveBrowserView.java) ist identisch mit diesem.
Was funktioniert:
dragStart, dragEnter, dragOver, dragSetData, dropAccept
Dateien um den Scrollbalken herum (also z.B. oben über das Menü oder auch aus dem Fenster raus) auf die andere View ziehen.
Oder auch, wenn kein Scrollbalken vorhanden ist, dann kann ich auch quer rüberziehen.
Was nicht geht:
Dateien über den Scrollbalken der View ziehen.
Drop() Methode wird auch iwi nicht aufgerufen, egal ob in der gleichen View oder in der anderen.
Bischen ist gut, bin zu faul das jetzt alles durch zu schauen...
Hier mal ein kleines Beispiel für dich, welches den Zweck darstellen sollte
Java:
package dd;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
public class Snippet91 {
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(2, false));
final TreeViewer tv = new TreeViewer(shell);
final Tree tree1 = tv.getTree();
tv.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
tv.setContentProvider(new FileTreeContentProvider());
tv.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object arg0) {
String text = ((File) arg0).getName();
if (text.length() == 0) {
text = ((File) arg0).getPath();
}
return text;
}
});
tv.setInput("root");
final TreeViewer tv2 = new TreeViewer(shell);
final Tree tree2 = tv2.getTree();
tv2.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
tv2.setContentProvider(new FileTreeContentProvider());
tv2.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object arg0) {
String text = ((File) arg0).getName();
if (text.length() == 0) {
text = ((File) arg0).getPath();
}
return text;
}
});
tv2.setInput("root");
Transfer[] types = new Transfer[] { FileTransfer.getInstance() };
final Transfer type = FileTransfer.getInstance();
int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_LINK;
//Drag Tree 1
DragSource source = new DragSource(tree1, operations);
source.setTransfer(types);
source.addDragListener(new DragSourceListener() {
public void dragStart(DragSourceEvent event) {
if(tv.getSelection() == null){
event.doit = false;
}
}
public void dragSetData(DragSourceEvent event) {
if (type.isSupportedType(event.dataType)) {
IStructuredSelection selection = (IStructuredSelection) tv.getSelection();
List<File> files = selection.toList();
List<String> list = new ArrayList<String>();
for(File file : files){
list.add(file.getAbsolutePath());
}
event.data = list.toArray(new String [1]);
}
}
public void dragFinished(DragSourceEvent event) {
}
});
//Drag Tree 2
source = new DragSource(tree2, operations);
source.setTransfer(types);
source.addDragListener(new DragSourceListener() {
public void dragStart(DragSourceEvent event) {
if(tv2.getSelection() == null){
event.doit = false;
}
}
public void dragSetData(DragSourceEvent event) {
if (type.isSupportedType(event.dataType)) {
event.data = tv2.getSelection();
}
}
public void dragFinished(DragSourceEvent event) {
}
});
DropTarget target = new DropTarget(tree2, operations);
target.setTransfer(types);
target.addDropListener(new DropTargetListener() {
@Override
public void dropAccept(DropTargetEvent event) {
// TODO Auto-generated method stub
}
@Override
public void drop(DropTargetEvent event) {
if (type.isSupportedType(event.currentDataType)) {
System.out.println("drop" + event.data);
for (String file: (String [])event.data) {
System.out.println(file);
}
}
}
@Override
public void dragOver(DropTargetEvent event) {
}
@Override
public void dragOperationChanged(DropTargetEvent event) {
if (event.detail == DND.DROP_DEFAULT) {
if ((event.operations & DND.DROP_COPY) != 0) {
event.detail = DND.DROP_COPY;
} else {
event.detail = DND.DROP_NONE;
}
}
}
@Override
public void dragLeave(DropTargetEvent event) {
// TODO Auto-generated method stub
}
@Override
public void dragEnter(DropTargetEvent event) {
if (event.detail == DND.DROP_DEFAULT) {
if ((event.operations & DND.DROP_COPY) != 0) {
event.detail = DND.DROP_COPY;
} else {
event.detail = DND.DROP_NONE;
}
}
}
});
shell.setSize(400, 400);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
/**
* This class provides the content for the tree in FileTree
*/
public static class FileTreeContentProvider implements ITreeContentProvider {
/**
* Gets the children of the specified object
*
* @param arg0
* the parent object
* @return Object[]
*/
public Object[] getChildren(Object arg0) {
// Return the files and subdirectories in this directory
return ((File) arg0).listFiles();
}
/**
* Gets the parent of the specified object
*
* @param arg0
* the object
* @return Object
*/
public Object getParent(Object arg0) {
// Return this file's parent file
return ((File) arg0).getParentFile();
}
/**
* Returns whether the passed object has children
*
* @param arg0
* the parent object
* @return boolean
*/
public boolean hasChildren(Object arg0) {
// Get the children
Object[] obj = getChildren(arg0);
// Return whether the parent has children
return obj == null ? false : obj.length > 0;
}
/**
* Gets the root element(s) of the tree
*
* @param arg0
* the input data
* @return Object[]
*/
public Object[] getElements(Object arg0) {
// These are the root elements of the tree
// We don't care what arg0 is, because we just want all
// the root nodes in the file system
return File.listRoots();
}
@Override
public void dispose() {
// TODO Auto-generated method stub
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// TODO Auto-generated method stub
}
}
}
Du siehst 2 Viewer die deinen root anzeigen... du kannst von dem linken viewer auf den rechten ziehen und loslassen dann wird dir das file in der console angezeigt... das einfügen in den tree hab ich mal weggelassen, da du anscheinend ja nur mit dem drag and drop probleme hast...
Du bekommst doch bestimmt eine Exception?? Dein dragSetData sieht nicht korrekt aus, da soviel ich weiß FileTextTransfer nur String[] entgegen nimmt... Und in drag over kommt eventuell noch eine NPE
hatte im Grunde nichts anderes als du in meinen Methoden stehen, nur an manchen Stellen etwas mehr.
Eine Exception hab ich ja keine bekommen, das hätte mir weitergeholfen.
Hab das Problem aber gerade lokalisiert. Hab mal alle nicht unbedingt notwendigen dragMethoden auskommentiert. Es lag an der dragOver, wo ich das event.item IMMER in ein TreeItem gecastet hab. Das hat er natürlich beim Überfahren des Scrollbalkens dann nicht gewollt (aber auch keine Exception geschmissen seltsamerweise, sonst wär es mir ja aufgefallen).
hab das jetzt mit nem if instanceof umklammert und schon funktioniert alles einwandfrei.
Ja, sollte man vllt sowieso IMMER machen, aber hey ^^
um die DropMethode muss ich mich jetzt nur noch kümmern...
du meinst dragSetData sei nicht richtig?
werd mir die FileTransfer Klasse nochmal angucken
danke für den Hinweis
[edit]
hab mal deine dragSetData-Methode kopiert... jetzt wird die drop()-Methode auch aufgerufen, hattest Recht mit dem String[], wusste ich nicht. Kopier mir hier aus mehreren Büchern was zusammen da kann schonmal was daneben gehen
ich schau mir den Code an und versuche das, was ich brauche auf meine Zwecke umzuschreiben, aber die grundsätzliche Idee, wie es geht "kopier" ich halt
Den Artikel kannte ich bereits, auch den entsprechenden für JFace mit den Viewern. Hätte danach auch alles funktionieren sollen, aber halt blöd, wenn man falsch castet.
Aber ich kann nicht verstehen, dass KEINE Exception ausgegeben wird, also bei mir wurde ein ausgegeben. Hast du eine normale SWT/JFace Anwendung oder eine Eclipse RCP Anwendung?
ich fands auch komisch, dass ich keine Exception bekommen hab. Sonst ist JAVA ja nicht so knausrig damit. Gerade Class-Cast-Exceptions krieg ich meist genug *hust*
ich fands auch komisch, dass ich keine Exception bekommen hab. Sonst ist JAVA ja nicht so knausrig damit. Gerade Class-Cast-Exceptions krieg ich meist genug *hust*
Bekommt du andere consolen Ausgaben angezeigt???
Wenn nicht musst du beim starten -consoleLog deiner RCP Anwendung mitgeben dann siehst du auch deine RuntimeException auf der Konsole...