Skip to content

Instantly share code, notes, and snippets.

@brokendish
Created May 13, 2012 15:01
Show Gist options
  • Save brokendish/2688834 to your computer and use it in GitHub Desktop.
Save brokendish/2688834 to your computer and use it in GitHub Desktop.
TreeControle
package brokendish;
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.datatransfer.UnsupportedFlavorException;
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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.Arrays;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.RowMapper;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import brokendish.TreeControle.DnDTreeCellRenderer;
import brokendish.TreeControle.RJLTransferable;
/**
* TreeControle
* JTreeのドラッグドロップを実装する
*
* インタフェースの実装
* DragSourceListener :ドラッグ&ドロップ操作に関するオリジネータのイベントインタフェースを定義して、
*  ユーザーのジェスチャーの状態を監視したり、ドラッグ&ドロップ操作全体の最適な
*  「ドラッグオーバー」フィードバックをユーザーに提供します。
* DropTargetListener :対象の DropTarget を含む DnD 操作の通知を DropTarget クラスが提供するのに使うコールバックインタフェースです。
*  このインタフェースのメソッドを実装すると、ドラッグ&ドロップ操作中に視覚的な「ドラッグアンダー」フィードバックをユーザーに提供できます。
* DragGestureListener :このインタフェースは DragGestureRecognizer をソースとし、その (サブ) クラスのオブジェクトがドラッグ開始ジェスチャーを検出したときに呼び出されます。
*
* @author hidekin
*
*/
//JTreeを継承した「TreeControle」を定義
public class TreeControle extends JTree implements TreeSelectionListener,DragSourceListener, DropTargetListener, DragGestureListener {
//DataFlavor、このフレーバを識別するのために使用される文字列を定義する
private static final String NAME = "TREE-Controle";
//DataFlavorインスタンスを設定 引数:mimeType(DataFlavor.javaJVMLocalObjectMimeType)、フレーバ識別名
private static final DataFlavor localObjectFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType, NAME);
//サポートフレバー配列を設定
private static final DataFlavor[] supportedFlavors = { localObjectFlavor };
//ツリーノードローカル変数を定義 ドロップターゲットノード
private TreeNode dropTargetNode = null;
//ツリーノードローカル変数を定義 ドラッグ後ノード 
private TreeNode draggedNode = null;
// private TreePath path;
//コンストラクタ定義
public TreeControle() {
//JTreeスーパークラスをコール
super();
//「DnDTreeCellRenderer」クラスを引数にしてレンダラを登録する
setCellRenderer(new DnDTreeCellRenderer());
//setModelメソットでJTreeのDefaultTreeModelを指定する
setModel(new DefaultTreeModel(new DefaultMutableTreeNode("default")));
//ドラッグ&ドロップオペレーションを実装するために「DragSource」インスタンスを生成する
new DragSource().createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this);
//ドラッグ&ドロップオペレーションを実装するために「DropTarget」インスタンスを生成する
new DropTarget(this, this);
//Jtree上で右クリックでポップアップを表示するためのリスナー
setComponentPopupMenu(new TreePopUpMenu());
//ツリークリック時のイベント@@
addTreeSelectionListener(this);
}
public void addNode(){
//選択されているパスをオブジェクト変数「selectObject」に格納する
Object selectObject = getSelectionPath().getLastPathComponent();
//オブジェクト変数「draggingObject」を「MutableTreeNode」に型変換する
MutableTreeNode selectNode = (MutableTreeNode) selectObject;
System.out.println("selectNode = " + selectNode);
/* DefaultTreeModel model = (DefaultTreeModel)getModel();
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) path.getLastPathComponent();
DefaultMutableTreeNode child = new DefaultMutableTreeNode("New node");
//model.insertNodeInto(child, parent, 0);
parent.add(child);
model.nodeStructureChanged(parent);
expandPath(path); */
}
// DragGestureListener 処理------------------------------------開始
//ドラッグ開始の検出
@Override public void dragGestureRecognized(DragGestureEvent dge) {
//ドラッグを開始した Component の座標の Point を保持する
Point pt = dge.getDragOrigin();
//getPathForLocationメソットでノードへのパスを座標の Pointから取得する
TreePath path = getPathForLocation(pt.x, pt.y);
//パスの判定、座標が入ってない場合、何もしないで処理を抜ける
if(path==null || path.getParentPath()==null) {
return;
}
//ツリーノードローカル変数の「ドラッグ後ノード」に対象ノードの末端ノードを保持する(ディレクトリの階層ごと取得するため)
draggedNode = (TreeNode) path.getLastPathComponent();
//「RJLTransferable」クラスで移動可能かを判定する
Transferable trans = new RJLTransferable(draggedNode);
//DragSourceインスタンスを生成してドラッグを開始する
new DragSource().startDrag(dge, Cursor.getDefaultCursor(), trans, this);
}
// DragGestureListener 処理------------------------------------終了
// DragDropEndListener 処理------------------------------------開始
//ドラック終了の処理
@Override public void dragDropEnd(DragSourceDropEvent dsde) {
//ツリーノードローカル変数の「ドラッグノード」をクリア
dropTargetNode = null;
//ツリーノードローカル変数の「ドラッグ後ノード」をクリア
draggedNode = null;
//JTreeを再描画
repaint();
//20120520 Add-----------------------------------------------------------S
//ハッシュマップを再構築:ドラック後のハッシュマップ再構築
TreeSet.treeHashSetReroad();
//20120520 Add-----------------------------------------------------------E
}
// DragDropEndListener 処理------------------------------------終了
// -----------------------------------------------------------------DragSourceDragEvent 開始
// DragDropEnterListener 処理------------------------------------開始
//ドラッグイベント(OK時)を検出
@Override public void dragEnter(DragSourceDragEvent dsde) {
//移動操作、ドロップが現在許可されていることを示すデフォルトの Cursorをセット
dsde.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
// DragDropEnterListener 処理------------------------------------終了
//
@Override public void dragOver(DragSourceDragEvent dsde) {}
//
@Override public void dropActionChanged(DragSourceDragEvent dsde) {}
// -----------------------------------------------------------------DragSourceDragEvent 終了
// -----------------------------------------------------------------DragSourceEvent 開始
// DragDropExitListener 処理------------------------------------開始
//ドラッグイベント(NG時)を検出
@Override public void dragExit(DragSourceEvent dse) {
//移動操作、ドロップが現在許可されていないことを示すデフォルトの Cursorをセット
dse.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
}
// DragDropExitListener 処理------------------------------------終了
// -----------------------------------------------------------------DragSourceEvent 終了
// -----------------------------------------------------------------DropTargetDragEvent 開始
//
@Override public void dropActionChanged(DropTargetDragEvent dtde) {}
//
@Override public void dragEnter(DropTargetDragEvent dtde) {}
//**ドラッグの検出&ドロップ先のチェック**
@Override public void dragOver(DropTargetDragEvent dtde) {
//イベントのgetCurrentDataFlavorsを取得し、DataFlavor配列に格納
DataFlavor[] f = dtde.getCurrentDataFlavors();
//getHumanPresentableNameメソットでサポートされているDataFlavorを取得する
boolean isDataFlavorSupported = f[0].getHumanPresentableName().equals(NAME);
//サポートされているDataFlavorかを判定
if(!isDataFlavorSupported) {
//サポートされていないDataFlavor(例えばデスクトップからファイルなど)
rejectDrag(dtde);
return;
}
//getLocationメソッドでドラッグ元の座標を取得
Point pt = dtde.getLocation();
//getPathForLocationメソットでノードへのパスを座標の Pointから取得する
TreePath path = getPathForLocation(pt.x, pt.y);
//移動先の判定
if(path==null) {
//ノード以外の場所(例えばJTreeの余白など)
rejectDrag(dtde);
return;
}
//選択されているパスをオブジェクト変数「draggingObject」に格納する
Object draggingObject = getSelectionPath().getLastPathComponent();
//オブジェクト変数「draggingObject」を「MutableTreeNode」に型変換する
MutableTreeNode draggingNode = (MutableTreeNode) draggingObject;
//DefaultMutableTreeNode型の変数「targetNode」に対象ノードの末端ノードを保持する(ディレクトリの階層ごと取得するため)
DefaultMutableTreeNode targetNode = (DefaultMutableTreeNode) path.getLastPathComponent();
//ドロップ先の親ノードを取得する
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) targetNode.getParent();
//親ノードの判定
while(parentNode!=null) {
//System.out.println("parentNode= "+parentNode);
//親ノードを子ノードにドロップしようとしている場合
if(draggingNode.equals(parentNode)) {
//ドラッグ不可
rejectDrag(dtde);
return;
}
//ドロップ先の親ノードを取得
parentNode = (DefaultMutableTreeNode)parentNode.getParent();
}
//ドロップ先ターゲットを設定
dropTargetNode = targetNode;
//System.out.println("dropTargetNode= "+dropTargetNode);
//acceptDragメソッドを使用して選択しているドラッグを受け入れる
dtde.acceptDrag(dtde.getDropAction());
//JTreeを再描画
repaint();
}
// -----------------------------------------------------------------DropTargetDragEvent 終了
// -----------------------------------------------------------------DropTargetEvent 開始
//
@Override public void dragExit(DropTargetEvent dte) {}
// -----------------------------------------------------------------DropTargetEvent 終了
// -----------------------------------------------------------------DropTargetEvent 開始
//**ドロップの検出&ドロップ先のチェック**
@Override public void drop(DropTargetDropEvent dtde) {
//ドラッグ先の位置を「getSelectionPath().getLastPathComponent()」で取得してオブジェクト変数「draggingObject」に設定する
Object draggingObject = getSelectionPath().getLastPathComponent();
//DefaultTreeModelを取得する
DefaultTreeModel model = (DefaultTreeModel) getModel();
//getLocationメソッドでドロップ先の座標を取得
Point p = dtde.getLocation();
//getPathForLocationメソットでノードへのパスを座標の Pointから取得する
TreePath path = getPathForLocation(p.x, p.y);
//ドロップ先の座標がNull(ノード以外にドロップ)、MutableTreeNode以外の場合はドロップを許可しない
if(path==null || !(draggingObject instanceof MutableTreeNode)) {
//ドロップを許可しない
dtde.dropComplete(false);
//
return;
}
//draggingObjectをMutableTreeNode型に型変換してMutableTreeNode変数に格納する
MutableTreeNode draggingNode = (MutableTreeNode) draggingObject;
//DefaultMutableTreeNode型の変数「targetNode」に対象ノードの末端ノードを保持する(ディレクトリの階層ごと取得するため)
DefaultMutableTreeNode targetNode = (DefaultMutableTreeNode) path.getLastPathComponent();
//ドラッグ元の親ノードを取得する
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) targetNode.getParent();
//ドラッグ元とドロップ先が同じな場合ドロップを許可しない
if(targetNode.equals(draggingNode)) {
//ドロップを許可しない
dtde.dropComplete(false);
//
return;
}
//ドロップアクション「DnDConstants.ACTION_MOVE」でドロップを受け入れる
dtde.acceptDrop(DnDConstants.ACTION_MOVE);
//DefaultTreeModel(model)からドラッグノード(draggingNode)をその親から削除する
/*removeNodeFromParent
* 引数は1つで、削除したいノードおよびリーフを指定します。中間ノードを指定した場合には、リーフも含めて全て削除されます。
*/
model.removeNodeFromParent(draggingNode);
/*insertNodeIntoを使用してノードをインサートする
* insertNodeInto」は
* 第1引数に追加するリーフ、
* 第2引数にどの親のノードのところに追加するか、
* 第3引数に何番目の子供として追加するか指定します。
* 第3引数は親ノードに既に複数の子供がいる場合に意味がありますが、いない場合には「0」
*/
if(parentNode!=null && targetNode.isLeaf()) {
//親ノードではない場合かつ、targetNodeがisLeaf(子)の場合、
model.insertNodeInto(draggingNode, parentNode, parentNode.getIndex(targetNode));
//
}else{
//上記外、
model.insertNodeInto(draggingNode, targetNode, targetNode.getChildCount());
}
//ドロップを完了する
dtde.dropComplete(true);
}
// -----------------------------------------------------------------DropTargetEvent 終了
// -----------------------------------------------------------------DropTargetDragEvent 終了
//
private void rejectDrag(DropTargetDragEvent dtde) {
//選択している値がドロップ不可を「rejectDrag」呼び出す
dtde.rejectDrag();
//dropTargetNodeをクリア
dropTargetNode = null; // dropTargetNode(flag)をnullにして
//JTreeを再描画
repaint(); // Rectangle2D、Lineを消すためJTreeを再描画
}
// -----------------------------------------------------------------DropTargetDragEvent 終了
//
static class RJLTransferable implements Transferable {
//オブジェクト変数を定義
Object object;
//RJLTransferableのコンストラクタ
public RJLTransferable(Object o) {
//オブジェクト変数に0を設定
object = o;
}
//TransferableのgetTransferDataをオーバーライド。UnsupportedFlavorException, IOExceptionをスローする
@Override public Object getTransferData(DataFlavor df) throws UnsupportedFlavorException, IOException {
//isDataFlavorSupportedの判定
if(isDataFlavorSupported(df)) {
//サポート対象のオブジェクトの場合
return object;
//
}else{
//UnsupportedFlavorExceptionをスローする
throw new UnsupportedFlavorException(df);
}
}
//TransferableのisDataFlavorSupportedをオーバーライド。
@Override public boolean isDataFlavorSupported(DataFlavor df) {
//getHumanPresentableName().equals(NAME)を返却する
return (df.getHumanPresentableName().equals(NAME));
//return (df.equals(localObjectFlavor));
}
//TransferableのgetTransferDataFlavorsをオーバライド。
@Override public DataFlavor[] getTransferDataFlavors() {
//supportedFlavorsを返却
return supportedFlavors;
}
}
// カスタムレンダラクラス:ドロップ選択にアンダーラインを引いて位置をわかるようにする
// DefaultTreeCellRenderer は不透明ではないため、これを継承したサブクラスでペイントする
class DnDTreeCellRenderer extends DefaultTreeCellRenderer {
//
private static final int BOTTOM_PAD = 30;
//
private boolean isTargetNode;
//
private boolean isTargetNodeLeaf;
//
// private boolean isLastItem;
//
// private Insets normalInsets;
//
// private Insets lastItemInsets;
//
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());
//
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);
}
}
}
}
@Override
public void valueChanged(TreeSelectionEvent arg0) {
// TODO 自動生成されたメソッド・スタブ
//ツリークリック時のイベント
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment