Created
May 13, 2012 15:01
-
-
Save brokendish/2688834 to your computer and use it in GitHub Desktop.
TreeControle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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