/******************************************************************************* * Copyright (c) 2010 Stefan A. Tzeggai. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * Stefan A. Tzeggai - initial API and implementation ******************************************************************************/ package org.geopublishing.geopublisher.gui.group; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Insets; import java.awt.Point; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragGestureRecognizer; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import javax.swing.DropMode; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import org.apache.log4j.Logger; import org.geopublishing.atlasViewer.GpCoreUtil; import org.geopublishing.atlasViewer.dp.DpEntry; import org.geopublishing.atlasViewer.dp.DpRef; import org.geopublishing.atlasViewer.map.MapRef; import org.geopublishing.atlasViewer.swing.RJLTransferable; import org.geopublishing.atlasViewer.swing.internal.DnDAtlasObject; import org.geopublishing.atlasViewer.swing.internal.DnDAtlasObject.AtlasDragSources; /** * A {@link JTree} that is reorderable by D'n'D * * @author <a href="mailto:skpublic@wikisquare.de">Stefan Alfons Tzeggai</a> */ public class CopyOfDnDJTree extends JTree implements DragSourceListener, DropTargetListener, DragGestureListener { private static final Logger LOGGER = Logger.getLogger(CopyOfDnDJTree.class); // **************************************************************************** // D'n'D stuff // **************************************************************************** static DataFlavor localObjectFlavor; static { try { localObjectFlavor = new DataFlavor( DataFlavor.javaJVMLocalObjectMimeType); } catch (ClassNotFoundException cnfe) { LOGGER.error(cnfe); } } static DataFlavor[] supportedFlavors = { localObjectFlavor }; DragSource dragSource; DropTarget dropTarget; TreeNode dropTargetNode, draggedNode; private Logger log = Logger.getLogger(CopyOfDnDJTree.class); /* * */ public CopyOfDnDJTree() { // setCellRenderer (new DnDTreeCellRenderer()); // **************************************************************************** // D'n'D Stuff // **************************************************************************** dragSource = new DragSource(); @SuppressWarnings("unused") DragGestureRecognizer dgr = dragSource .createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this); dropTarget = new DropTarget(this, this); setDropMode(DropMode.INSERT_ROWS); } /* * (non-Javadoc) * * @seejava.awt.dnd.DragGestureListener#dragGestureRecognized(java.awt.dnd. * DragGestureEvent) */ public void dragGestureRecognized(DragGestureEvent dge) { // log.debug ("dragGestureRecognized"); Point clickPoint = dge.getDragOrigin(); TreePath path = getPathForLocation(clickPoint.x, clickPoint.y); if (path == null) { log.debug("not on a node"); return; } draggedNode = (TreeNode) path.getLastPathComponent(); Transferable trans = new RJLTransferable(draggedNode, AtlasDragSources.DNDTREE, TreeNode.class); dragSource.startDrag(dge, Cursor .getPredefinedCursor(Cursor.MOVE_CURSOR), trans, this); } // DragSourceListener events public void dragDropEnd(DragSourceDropEvent dsde) { // log.debug ("dragDropEnd()"); dropTargetNode = null; draggedNode = null; repaint(); } /* * (non-Javadoc) * * @see * java.awt.dnd.DragSourceListener#dragEnter(java.awt.dnd.DragSourceDragEvent * ) */ public void dragEnter(DragSourceDragEvent dsde) { } /* * (non-Javadoc) * * @see * java.awt.dnd.DragSourceListener#dragExit(java.awt.dnd.DragSourceEvent) */ public void dragExit(DragSourceEvent dse) { } /* * (non-Javadoc) * * @see * java.awt.dnd.DragSourceListener#dragOver(java.awt.dnd.DragSourceDragEvent * ) */ public void dragOver(DragSourceDragEvent dsde) { } /* * (non-Javadoc) * * @seejava.awt.dnd.DragSourceListener#dropActionChanged(java.awt.dnd. * DragSourceDragEvent) */ public void dropActionChanged(DragSourceDragEvent dsde) { } /* * (non-Javadoc) * * @see * java.awt.dnd.DropTargetListener#dragEnter(java.awt.dnd.DropTargetDragEvent * ) */ public void dragEnter(DropTargetDragEvent dtde) { dtde.acceptDrag(DnDConstants.ACTION_MOVE); } /* * (non-Javadoc) * * @see * java.awt.dnd.DropTargetListener#dragExit(java.awt.dnd.DropTargetEvent) */ public void dragExit(DropTargetEvent dte) { } /* * (non-Javadoc) * * @see * java.awt.dnd.DropTargetListener#dragOver(java.awt.dnd.DropTargetDragEvent * ) */ public void dragOver(DropTargetDragEvent dtde) { // figure out which cell it's over, no drag to self Point dragPoint = dtde.getLocation(); TreePath path = getPathForLocation(dragPoint.x, dragPoint.y); if (path == null) dropTargetNode = null; else dropTargetNode = (TreeNode) path.getLastPathComponent(); repaint(); } /* * (non-Javadoc) * * @see * java.awt.dnd.DropTargetListener#drop(java.awt.dnd.DropTargetDropEvent) */ public void drop(DropTargetDropEvent dtde) { Point dropPoint = dtde.getLocation(); TreePath path = getPathForLocation(dropPoint.x, dropPoint.y); // log.debug("drop path is " + path); // Is evaluated in the finally block boolean dropped = false; try { if (path == null) return; dtde.acceptDrop(DnDConstants.ACTION_MOVE); // log.debug("Drop accepted. Transfering..."); Object droppedObject = dtde.getTransferable().getTransferData( localObjectFlavor); DefaultMutableTreeNode dropTargetNode = (DefaultMutableTreeNode) path .getLastPathComponent(); MutableTreeNode droppedNode = null; if (droppedObject instanceof DnDAtlasObject) { // remove from old location DnDAtlasObject transObj = (DnDAtlasObject) droppedObject; if ((transObj.getSource() == AtlasDragSources.DNDTREE)) { droppedNode = (MutableTreeNode) transObj.getObject(); // SK: if (droppedNode == dropTargetNode) return; if (droppedNode.getParent() != null) // Remove the source item, if it has a parent?! D'n'D // inside the GroupPane // if (dtde.getDropAction() == DnDConstants.ACTION_MOVE) // // Only remove if it is a move action ((DefaultTreeModel) getModel()) .removeNodeFromParent(droppedNode); } else if ((transObj.getSource() == AtlasDragSources.DATAPOOLLIST)) { // **************************************************************************** // This is a drop from the Datapool list // **************************************************************************** DpEntry dpe = (DpEntry) transObj.getObject(); droppedNode = new DpRef(dpe); } else if ((transObj.getSource() == AtlasDragSources.MAPPOOLLIST)) { // **************************************************************************** // This is a drop from the Mappool list // **************************************************************************** droppedNode = (MapRef) transObj.getObject(); } } else { droppedNode = new DefaultMutableTreeNode(droppedObject); } // insert into spec'd path. if dropped into a parent // make it last child of that parent // hochgeschoben, if (dropTargetNode.isLeaf()) { DefaultMutableTreeNode parent = (DefaultMutableTreeNode) dropTargetNode .getParent(); // SK: When dropping onto itself, parent == null if (parent == null) { dtde.dropComplete(false); return; } int index = parent.getIndex(dropTargetNode); ((DefaultTreeModel) getModel()).insertNodeInto(droppedNode, parent, index); } else { ((DefaultTreeModel) getModel()).insertNodeInto(droppedNode, dropTargetNode, dropTargetNode.getChildCount()); GpCoreUtil.expandToNode(this, droppedNode); } dropped = true; } catch (Exception e) { LOGGER.error(e); } finally { dtde.dropComplete(dropped); } } public void dropActionChanged(DropTargetDragEvent dtde) { } // custom renderer class DnDTreeCellRenderer extends DefaultTreeCellRenderer { boolean isTargetNode; boolean isTargetNodeLeaf; boolean isLastItem; Insets normalInsets, lastItemInsets; int BOTTOM_PAD = 30; public DnDTreeCellRenderer() { super(); normalInsets = super.getInsets(); lastItemInsets = new Insets(normalInsets.top, normalInsets.left, normalInsets.bottom + BOTTOM_PAD, normalInsets.right); } @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean isSelected, boolean isExpanded, boolean isLeaf, int row, boolean hasFocus) { isTargetNode = (value == dropTargetNode); isTargetNodeLeaf = (isTargetNode && ((TreeNode) value).isLeaf()); // isLastItem = (index == list.getModel().getSize()-1); // by SK auskommentiert weil keine funktion // boolean showSelected = isSelected & // (dropTargetNode == null); return super.getTreeCellRendererComponent(tree, value, isSelected, isExpanded, isLeaf, row, hasFocus); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); if (isTargetNode) { g.setColor(Color.black); if (isTargetNodeLeaf) { g.drawLine(0, 0, getSize().width, 0); } else { g.drawRect(0, 0, getSize().width - 1, getSize().height - 1); } } } } }