664 lines
21 KiB
Java
664 lines
21 KiB
Java
/*
|
|
|
|
Copyright 2006 Eric Hakenholz
|
|
|
|
This file is part of C.a.R. software.
|
|
|
|
C.a.R. is a free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, version 3 of the License.
|
|
|
|
C.a.R. is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
package eric.macros;
|
|
|
|
import java.awt.AlphaComposite;
|
|
import java.awt.Color;
|
|
import java.awt.GradientPaint;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.Insets;
|
|
import java.awt.Point;
|
|
import java.awt.Rectangle;
|
|
import java.awt.SystemColor;
|
|
import java.awt.datatransfer.DataFlavor;
|
|
import java.awt.datatransfer.Transferable;
|
|
import java.awt.datatransfer.UnsupportedFlavorException;
|
|
import java.awt.dnd.Autoscroll;
|
|
import java.awt.dnd.DnDConstants;
|
|
import java.awt.dnd.DragGestureEvent;
|
|
import java.awt.dnd.DragGestureListener;
|
|
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 java.awt.dnd.InvalidDnDOperationException;
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionListener;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.event.MouseListener;
|
|
import java.awt.geom.AffineTransform;
|
|
import java.awt.geom.Rectangle2D;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.IOException;
|
|
|
|
import javax.swing.Icon;
|
|
import javax.swing.JLabel;
|
|
import javax.swing.JTree;
|
|
import javax.swing.Timer;
|
|
import javax.swing.event.TreeSelectionEvent;
|
|
import javax.swing.event.TreeSelectionListener;
|
|
import javax.swing.tree.DefaultMutableTreeNode;
|
|
import javax.swing.tree.DefaultTreeModel;
|
|
import javax.swing.tree.MutableTreeNode;
|
|
import javax.swing.tree.TreePath;
|
|
|
|
public class CTree extends JTree implements DragSourceListener,
|
|
DragGestureListener, Autoscroll, TreeSelectionListener, MouseListener {
|
|
// Constants...
|
|
|
|
/**
|
|
*
|
|
*/
|
|
private static final long serialVersionUID = 1L;
|
|
// Fields...
|
|
private TreePath _pathSource; // The path being dragged
|
|
private BufferedImage _imgGhost; // The 'drag image'
|
|
private final Point _ptOffset = new Point(); // Where, in the drag image,
|
|
// the mouse was clicked
|
|
private boolean dropped = false;
|
|
public MacrosList JML;
|
|
public NodePopupMenu nodepopup;
|
|
|
|
// Constructors...
|
|
public CTree(final MacrosList jml) // Use the default JTree constructor so
|
|
// that we get a sample TreeModel built
|
|
// for us
|
|
{
|
|
JML = jml;
|
|
putClientProperty("JTree.lineStyle", "none");
|
|
|
|
// this.addTreeSelectionListener(this);
|
|
// this.getModel().addTreeModelListener(this);
|
|
|
|
this.addMouseListener(this);
|
|
// Make this JTree a drag source
|
|
final DragSource dragSource = DragSource.getDefaultDragSource();
|
|
dragSource.createDefaultDragGestureRecognizer(this,
|
|
DnDConstants.ACTION_COPY_OR_MOVE, this);
|
|
|
|
// Also, make this JTree a drag target
|
|
final DropTarget dropTarget = new DropTarget(this,
|
|
new CDropTargetListener());
|
|
dropTarget.setDefaultActions(DnDConstants.ACTION_COPY_OR_MOVE);
|
|
|
|
nodepopup = new NodePopupMenu(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
private DefaultMutableTreeNode cloneAll(final DefaultMutableTreeNode Ndfrom) {
|
|
final DefaultMutableTreeNode Ndto = (DefaultMutableTreeNode) Ndfrom
|
|
.clone();
|
|
if (!(Ndfrom.isLeaf())) {
|
|
for (int i = 0; i < Ndfrom.getChildCount(); i++) {
|
|
final DefaultMutableTreeNode mynode = cloneAll((DefaultMutableTreeNode) Ndfrom
|
|
.getChildAt(i));
|
|
Ndto.add(mynode);
|
|
}
|
|
}
|
|
return Ndto;
|
|
}
|
|
|
|
// Interface: DragGestureListener
|
|
public void dragGestureRecognized(final DragGestureEvent e) {
|
|
|
|
final Point ptDragOrigin = e.getDragOrigin();
|
|
final TreePath path = getPathForLocation(ptDragOrigin.x, ptDragOrigin.y);
|
|
if (path == null)
|
|
return;
|
|
if (isRootPath(path))
|
|
return; // Ignore user trying to drag the root node
|
|
|
|
// Work out the offset of the drag point from the TreePath bounding
|
|
// rectangle origin
|
|
final Rectangle raPath = getPathBounds(path);
|
|
_ptOffset.setLocation(ptDragOrigin.x - raPath.x, ptDragOrigin.y
|
|
- raPath.y);
|
|
|
|
// Get the cell renderer (which is a JLabel) for the path being dragged
|
|
final JLabel lbl = (JLabel) getCellRenderer()
|
|
.getTreeCellRendererComponent(this, // tree
|
|
path.getLastPathComponent(), // value
|
|
false, // isSelected (dont want a colored background)
|
|
isExpanded(path), // isExpanded
|
|
getModel().isLeaf(path.getLastPathComponent()), // isLeaf
|
|
0, // row (not important for rendering)
|
|
false // hasFocus (dont want a focus rectangle)
|
|
);
|
|
lbl.setSize((int) raPath.getWidth(), (int) raPath.getHeight()); // <--
|
|
// The
|
|
// layout
|
|
// manager
|
|
// would
|
|
// normally
|
|
// do
|
|
// this
|
|
|
|
// Get a buffered image of the selection for dragging a ghost image
|
|
_imgGhost = new BufferedImage((int) raPath.getWidth(), (int) raPath
|
|
.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
|
|
final Graphics2D g2 = _imgGhost.createGraphics();
|
|
|
|
// Ask the cell renderer to paint itself into the BufferedImage
|
|
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 0.5f)); // Make
|
|
// the
|
|
// image
|
|
// ghostlike
|
|
lbl.paint(g2);
|
|
|
|
// Now paint a gradient UNDER the ghosted JLabel text (but not under the
|
|
// icon if any)
|
|
// Note: this will need tweaking if your icon is not positioned to the
|
|
// left of the text
|
|
final Icon icon = lbl.getIcon();
|
|
final int nStartOfText = (icon == null) ? 0 : icon.getIconWidth()
|
|
+ lbl.getIconTextGap();
|
|
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER,
|
|
0.5f)); // Make the gradient ghostlike
|
|
g2.setPaint(new GradientPaint(nStartOfText, 0,
|
|
SystemColor.controlShadow, getWidth(), 0, new Color(255, 255,
|
|
255, 0)));
|
|
g2.fillRect(nStartOfText, 0, getWidth(), _imgGhost.getHeight());
|
|
|
|
g2.dispose();
|
|
|
|
setSelectionPath(path); // Select this path in the tree
|
|
|
|
// System.out.println("DRAGGING: "+path.getLastPathComponent());
|
|
|
|
// DefaultMutableTreeNode
|
|
// mynode=(DefaultMutableTreeNode)path.getLastPathComponent();
|
|
// Transferable transferable = (Transferable) mynode.getUserObject();
|
|
// Wrap the path being transferred into a Transferable object
|
|
final Transferable transferable = new CTransferableTreePath(path);
|
|
|
|
// Remember the path being dragged (because if it is being moved, we
|
|
// will have to delete it later)
|
|
_pathSource = path;
|
|
|
|
// We pass our drag image just in case it IS supported by the platform
|
|
|
|
try {
|
|
this.setEditable(false);
|
|
// e.startDrag(new Cursor(Cursor.HAND_CURSOR),transferable,this);
|
|
e.startDrag(null, _imgGhost, new Point(5, 5), transferable, this);
|
|
|
|
} catch (final InvalidDnDOperationException dnde) {
|
|
// JOptionPane.showMessageDialog(null, "coucou2");
|
|
}
|
|
|
|
// e.startDrag(null, _imgGhost, new Point(5,5), transferable, this);
|
|
|
|
}
|
|
|
|
// Interface: DragSourceListener
|
|
public void dragEnter(final DragSourceDragEvent e) {
|
|
}
|
|
|
|
public void dragOver(final DragSourceDragEvent e) {
|
|
}
|
|
|
|
public void dragExit(final DragSourceEvent e) {
|
|
}
|
|
|
|
public void dropActionChanged(final DragSourceDragEvent e) {
|
|
}
|
|
|
|
public void dragDropEnd(final DragSourceDropEvent e) {
|
|
if (e.getDropSuccess()) {
|
|
final int nAction = e.getDropAction();
|
|
if (nAction == DnDConstants.ACTION_MOVE) { // The dragged item
|
|
// (_pathSource) has
|
|
// been inserted at the
|
|
// target selected by
|
|
// the user.
|
|
// Now it is time to delete it from its original location.
|
|
// System.out.println("REMOVING: " +
|
|
// _pathSource.getLastPathComponent());
|
|
|
|
if (dropped) {
|
|
final DefaultTreeModel model = (DefaultTreeModel) getModel();
|
|
final MutableTreeNode node = (MutableTreeNode) _pathSource
|
|
.getLastPathComponent();
|
|
MutableTreeNode parent = (MutableTreeNode) node.getParent();
|
|
model.removeNodeFromParent(node);
|
|
while (parent.isLeaf()) {
|
|
final MutableTreeNode grandparent = (MutableTreeNode) parent
|
|
.getParent();
|
|
model.removeNodeFromParent(parent);
|
|
parent = grandparent;
|
|
}
|
|
|
|
dropped = false;
|
|
}
|
|
|
|
_pathSource = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DropTargetListener interface object...
|
|
class CDropTargetListener implements DropTargetListener {
|
|
// Fields...
|
|
private TreePath _pathLast = null;
|
|
private final Rectangle2D _raCueLine = new Rectangle2D.Float();
|
|
private Rectangle2D _raGhost = new Rectangle2D.Float();
|
|
private final Color _colorCueLine;
|
|
private Point _ptLast = new Point();
|
|
private final Timer _timerHover;
|
|
private int _nLeftRight = 0; // Cumulative left/right mouse movement
|
|
// Constructor...
|
|
|
|
public CDropTargetListener() {
|
|
_colorCueLine = new Color(SystemColor.controlShadow.getRed(),
|
|
SystemColor.controlShadow.getGreen(),
|
|
SystemColor.controlShadow.getBlue(), 64);
|
|
|
|
// Set up a hover timer, so that a node will be automatically
|
|
// expanded or collapsed
|
|
// if the user lingers on it for more than a short time
|
|
_timerHover = new Timer(1000, new ActionListener() {
|
|
public void actionPerformed(final ActionEvent e) {
|
|
_nLeftRight = 0; // Reset left/right movement trend
|
|
if (isRootPath(_pathLast))
|
|
return; // Do nothing if we are hovering over the root
|
|
// node
|
|
if (isExpanded(_pathLast))
|
|
collapsePath(_pathLast);
|
|
else
|
|
expandPath(_pathLast);
|
|
}
|
|
});
|
|
_timerHover.setRepeats(false); // Set timer to one-shot mode
|
|
}
|
|
|
|
// DropTargetListener interface
|
|
public void dragEnter(final DropTargetDragEvent e) {
|
|
if (!isDragAcceptable(e))
|
|
e.rejectDrag();
|
|
else
|
|
e.acceptDrag(e.getDropAction());
|
|
}
|
|
|
|
public void dragExit(final DropTargetEvent e) {
|
|
if (!DragSource.isDragImageSupported()) {
|
|
repaint(_raGhost.getBounds());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is where the ghost image is drawn
|
|
*/
|
|
public void dragOver(final DropTargetDragEvent e) {
|
|
// Even if the mouse is not moving, this method is still invoked 10
|
|
// times per second
|
|
final Point pt = e.getLocation();
|
|
if (pt.equals(_ptLast))
|
|
return;
|
|
|
|
// Try to determine whether the user is flicking the cursor right or
|
|
// left
|
|
final int nDeltaLeftRight = pt.x - _ptLast.x;
|
|
if ((_nLeftRight > 0 && nDeltaLeftRight < 0)
|
|
|| (_nLeftRight < 0 && nDeltaLeftRight > 0))
|
|
_nLeftRight = 0;
|
|
_nLeftRight += nDeltaLeftRight;
|
|
|
|
_ptLast = pt;
|
|
|
|
final Graphics2D g2 = (Graphics2D) getGraphics();
|
|
|
|
// If a drag image is not supported by the platform, then draw my
|
|
// own drag image
|
|
if (!DragSource.isDragImageSupported()) {
|
|
paintImmediately(_raGhost.getBounds()); // Rub out the last
|
|
// ghost image and cue
|
|
// line
|
|
// And remember where we are about to draw the new ghost image
|
|
_raGhost.setRect(pt.x - _ptOffset.x, pt.y - _ptOffset.y,
|
|
_imgGhost.getWidth(), _imgGhost.getHeight());
|
|
g2.drawImage(_imgGhost, AffineTransform.getTranslateInstance(
|
|
_raGhost.getX(), _raGhost.getY()), null);
|
|
} else
|
|
// Just rub out the last cue line
|
|
paintImmediately(_raCueLine.getBounds());
|
|
|
|
final TreePath path = getClosestPathForLocation(pt.x, pt.y);
|
|
if (!(path == _pathLast)) {
|
|
_nLeftRight = 0; // We've moved up or down, so reset left/right
|
|
// movement trend
|
|
_pathLast = path;
|
|
_timerHover.restart();
|
|
}
|
|
|
|
// In any case draw (over the ghost image if necessary) a cue line
|
|
// indicating where a drop will occur
|
|
final Rectangle raPath = getPathBounds(path);
|
|
_raCueLine.setRect(0, raPath.y + (int) raPath.getHeight(),
|
|
getWidth(), 2);
|
|
|
|
g2.setColor(_colorCueLine);
|
|
g2.fill(_raCueLine);
|
|
|
|
// Now superimpose the left/right movement indicator if necessary
|
|
if (_nLeftRight > 20) {
|
|
} else if (_nLeftRight < -20) {
|
|
} else {
|
|
}
|
|
|
|
// And include the cue line in the area to be rubbed out next time
|
|
_raGhost = _raGhost.createUnion(_raCueLine);
|
|
|
|
/*
|
|
* // Do this if you want to prohibit dropping onto the drag source
|
|
* if (path.equals(_pathSource)) e.rejectDrag(); else
|
|
* e.acceptDrag(e.getDropAction());
|
|
*/
|
|
}
|
|
|
|
public void dropActionChanged(final DropTargetDragEvent e) {
|
|
if (!isDragAcceptable(e))
|
|
e.rejectDrag();
|
|
else
|
|
e.acceptDrag(e.getDropAction());
|
|
}
|
|
|
|
public void drop(final DropTargetDropEvent e) {
|
|
_timerHover.stop(); // Prevent hover timer from doing an unwanted
|
|
// expandPath or collapsePath
|
|
|
|
if (!isDropAcceptable(e)) {
|
|
e.rejectDrop();
|
|
return;
|
|
}
|
|
|
|
e.acceptDrop(e.getDropAction());
|
|
|
|
final Transferable transferable = e.getTransferable();
|
|
|
|
final DataFlavor[] flavors = transferable.getTransferDataFlavors();
|
|
for (final DataFlavor flavor : flavors) {
|
|
if (flavor
|
|
.isMimeTypeEqual(DataFlavor.javaJVMLocalObjectMimeType)) {
|
|
try {
|
|
final Point pt = e.getLocation();
|
|
final TreePath pathTarget = getClosestPathForLocation(
|
|
pt.x, pt.y);
|
|
final TreePath pathSource = (TreePath) transferable
|
|
.getTransferData(flavor);
|
|
|
|
// System.out.println("DROPPING: "+pathSource.getLastPathComponent());
|
|
// TreeModel model = getModel();
|
|
|
|
final DefaultTreeModel model = (DefaultTreeModel) getModel();
|
|
final TreePath pathNewChild = null;
|
|
|
|
final DefaultMutableTreeNode nodeorg = (DefaultMutableTreeNode) pathSource
|
|
.getLastPathComponent();
|
|
DefaultMutableTreeNode nodeto = (DefaultMutableTreeNode) pathTarget
|
|
.getLastPathComponent();
|
|
|
|
// avoid a folder to be drag inside its own hierarchy
|
|
dropped = true;
|
|
if (!(nodeorg.isLeaf())) {
|
|
DefaultMutableTreeNode parent = nodeto;
|
|
while (parent != null) {
|
|
if (parent.equals(nodeorg)) {
|
|
dropped = false;
|
|
JML.repaint();
|
|
return;
|
|
}
|
|
parent = (DefaultMutableTreeNode) parent
|
|
.getParent();
|
|
}
|
|
}
|
|
|
|
if (dropped) {
|
|
DefaultMutableTreeNode nodeparentto = (nodeto
|
|
.isLeaf()) ? (DefaultMutableTreeNode) pathTarget
|
|
.getParentPath().getLastPathComponent()
|
|
: nodeto;
|
|
final TreePath tp = new TreePath(nodeparentto
|
|
.getPath());
|
|
if (!(isExpanded(tp))) {
|
|
nodeto = nodeparentto;
|
|
nodeparentto = (DefaultMutableTreeNode) nodeto
|
|
.getParent();
|
|
}
|
|
int h = 0;
|
|
for (h = 0; h < nodeparentto.getChildCount(); h++) {
|
|
if (nodeparentto.getChildAt(h).equals(nodeto))
|
|
break;
|
|
}
|
|
if (h == nodeparentto.getChildCount())
|
|
h = -1;
|
|
model.insertNodeInto(cloneAll(nodeorg),
|
|
nodeparentto, h + 1);
|
|
}
|
|
|
|
// model.insertNodeInto()
|
|
// .
|
|
// .. Add your code here to ask your TreeModel to copy
|
|
// the node and act on the mouse gestures...
|
|
// .
|
|
|
|
// For example:
|
|
|
|
// If pathTarget is an expanded BRANCH,
|
|
// then insert source UNDER it (before the first child
|
|
// if any)
|
|
// If pathTarget is a collapsed BRANCH (or a LEAF),
|
|
// then insert source AFTER it
|
|
// Note: a leaf node is always marked as collapsed
|
|
// You ask the model to do the copying...
|
|
// ...and you supply the copyNode method in the model as
|
|
// well of course.
|
|
// if (_nShift == 0)
|
|
// pathNewChild = model.copyNode(pathSource, pathTarget,
|
|
// isExpanded(pathTarget));
|
|
// else if (_nShift > 0) // The mouse is being flicked
|
|
// to the right (so move the node right)
|
|
// pathNewChild = model.copyNodeRight(pathSource,
|
|
// pathTarget);
|
|
// else // The mouse is being flicked to the left (so
|
|
// move the node left)
|
|
// pathNewChild = model.copyNodeLeft(pathSource);
|
|
|
|
if (pathNewChild != null)
|
|
setSelectionPath(pathNewChild); // Mark this as the
|
|
// selected path in
|
|
// the tree
|
|
break; // No need to check remaining flavors
|
|
} catch (final UnsupportedFlavorException ufe) {
|
|
// System.out.println(ufe);
|
|
e.dropComplete(false);
|
|
return;
|
|
} catch (final IOException ioe) {
|
|
// System.out.println(ioe);
|
|
e.dropComplete(false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
e.dropComplete(true);
|
|
}
|
|
|
|
// Helpers...
|
|
public boolean isDragAcceptable(final DropTargetDragEvent e) {
|
|
// Only accept COPY or MOVE gestures (ie LINK is not supported)
|
|
if ((e.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) == 0)
|
|
return false;
|
|
|
|
// Only accept this particular flavor
|
|
if (!e.isDataFlavorSupported(CTransferableTreePath.TREEPATH_FLAVOR))
|
|
return false;
|
|
|
|
/*
|
|
* // Do this if you want to prohibit dropping onto the drag
|
|
* source... Point pt = e.getLocation(); TreePath path =
|
|
* getClosestPathForLocation(pt.x, pt.y); if
|
|
* (path.equals(_pathSource)) return false;
|
|
*/
|
|
|
|
/*
|
|
* // Do this if you want to select the best flavor on offer...
|
|
* DataFlavor[] flavors = e.getCurrentDataFlavors(); for (int i = 0;
|
|
* i < flavors.length; i++ ) { DataFlavor flavor = flavors[i]; if
|
|
* (flavor.isMimeTypeEqual(DataFlavor.javaJVMLocalObjectMimeType))
|
|
* return true; }
|
|
*/
|
|
return true;
|
|
}
|
|
|
|
public boolean isDropAcceptable(final DropTargetDropEvent e) {
|
|
// Only accept COPY or MOVE gestures (ie LINK is not supported)
|
|
if ((e.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) == 0)
|
|
return false;
|
|
|
|
// Only accept this particular flavor
|
|
if (!e.isDataFlavorSupported(CTransferableTreePath.TREEPATH_FLAVOR))
|
|
return false;
|
|
|
|
/*
|
|
* // Do this if you want to prohibit dropping onto the drag
|
|
* source... Point pt = e.getLocation(); TreePath path =
|
|
* getClosestPathForLocation(pt.x, pt.y); if
|
|
* (path.equals(_pathSource)) return false;
|
|
*/
|
|
|
|
/*
|
|
* // Do this if you want to select the best flavor on offer...
|
|
* DataFlavor[] flavors = e.getCurrentDataFlavors(); for (int i = 0;
|
|
* i < flavors.length; i++ ) { DataFlavor flavor = flavors[i]; if
|
|
* (flavor.isMimeTypeEqual(DataFlavor.javaJVMLocalObjectMimeType))
|
|
* return true; }
|
|
*/
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
// Autoscroll Interface...
|
|
// The following code was borrowed from the book:
|
|
// Java Swing
|
|
// By Robert Eckstein, Marc Loy & Dave Wood
|
|
// Paperback - 1221 pages 1 Ed edition (September 1998)
|
|
// O'Reilly & Associates; ISBN: 156592455X
|
|
//
|
|
// The relevant chapter of which can be found at:
|
|
// http://www.oreilly.com/catalog/jswing/chapter/dnd.beta.pdf
|
|
|
|
private static final int AUTOSCROLL_MARGIN = 12;
|
|
|
|
// Ok, weíve been told to scroll because the mouse cursor is in our
|
|
// scroll zone.
|
|
public void autoscroll(final Point pt) {
|
|
// Figure out which row weíre on.
|
|
int nRow = getRowForLocation(pt.x, pt.y);
|
|
|
|
// If we are not on a row then ignore this autoscroll request
|
|
if (nRow < 0)
|
|
return;
|
|
|
|
final Rectangle raOuter = getBounds();
|
|
// Now decide if the row is at the top of the screen or at the
|
|
// bottom. We do this to make the previous row (or the next
|
|
// row) visible as appropriate. If weíre at the absolute top or
|
|
// bottom, just return the first or last row respectively.
|
|
|
|
nRow = (pt.y + raOuter.y <= AUTOSCROLL_MARGIN) // Is row at top of
|
|
// screen?
|
|
? (nRow <= 0 ? 0 : nRow - 1) // Yes, scroll up one row
|
|
: (nRow < getRowCount() - 1 ? nRow + 1 : nRow); // No, scroll
|
|
// down one row
|
|
|
|
scrollRowToVisible(nRow);
|
|
}
|
|
|
|
// Calculate the insets for the *JTREE*, not the viewport
|
|
// the tree is in. This makes it a bit messy.
|
|
public Insets getAutoscrollInsets() {
|
|
final Rectangle raOuter = getBounds();
|
|
final Rectangle raInner = getParent().getBounds();
|
|
return new Insets(raInner.y - raOuter.y + AUTOSCROLL_MARGIN, raInner.x
|
|
- raOuter.x + AUTOSCROLL_MARGIN, raOuter.height
|
|
- raInner.height - raInner.y + raOuter.y + AUTOSCROLL_MARGIN,
|
|
raOuter.width - raInner.width - raInner.x + raOuter.x
|
|
+ AUTOSCROLL_MARGIN);
|
|
}
|
|
|
|
/*
|
|
* // Use this method if you want to see the boundaries of the // autoscroll
|
|
* active region. Toss it out, otherwise. public void
|
|
* paintComponent(Graphics g) { super.paintComponent(g); Rectangle raOuter =
|
|
* getBounds(); Rectangle raInner = getParent().getBounds();
|
|
* g.setColor(Color.red); g.drawRect(-raOuter.x + 12, -raOuter.y + 12,
|
|
* raInner.width - 24, raInner.height - 24); }
|
|
*/
|
|
|
|
private boolean isRootPath(final TreePath path) {
|
|
return isRootVisible() && getRowForPath(path) == 0;
|
|
}
|
|
|
|
// Ready to go : execute macro on click
|
|
public void valueChanged(final TreeSelectionEvent e) {
|
|
// JDefaultMutableTreeNode node =
|
|
// (JDefaultMutableTreeNode)this.getLastSelectedPathComponent();
|
|
// if (node.isLeaf()) {
|
|
// node.runZmacro();
|
|
// };
|
|
|
|
}
|
|
|
|
// MouseListener interface
|
|
public void mouseClicked(final MouseEvent e) {
|
|
nodepopup.handleMouseClick(e);
|
|
}
|
|
|
|
public void mousePressed(final MouseEvent e) {
|
|
nodepopup.actualiseproperties();
|
|
nodepopup.handlePopup(e);
|
|
}
|
|
|
|
public void mouseReleased(final MouseEvent e) {
|
|
nodepopup.handlePopup(e);
|
|
}
|
|
|
|
public void mouseEntered(final MouseEvent e) {
|
|
// ShowToolTip(e);
|
|
}
|
|
|
|
public void mouseExited(final MouseEvent e) {
|
|
// HideToolTip();
|
|
}
|
|
|
|
|
|
}
|