001: /* SwingML
002: * Copyright (C) 2002 SwingML Team
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the
016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017: * Boston, MA 02111-1307, USA.
018: *
019: * Authors:
020: * Ezequiel Cuellar <ecuellar@crosslogic.com>
021: *
022: */
023: package org.swingml.component;
024:
025: import java.awt.*;
026: import java.awt.datatransfer.*;
027: import java.awt.dnd.*;
028: import java.awt.event.*;
029: import java.io.*;
030: import java.util.*;
031:
032: import javax.swing.*;
033: import javax.swing.event.*;
034: import javax.swing.tree.*;
035:
036: import org.swingml.*;
037: import org.swingml.event.*;
038: import org.swingml.model.*;
039: import org.swingml.system.*;
040:
041: public class JTreeComponent extends JTree implements XMLTranslatable,
042: DropTargetListener, DragSourceListener, TreeSelectionListener,
043: DragGestureListener, MouseListener, TreeExpansionListener,
044: TreeWillExpandListener {
045:
046: private DragSource dragSource = null;
047: private EventHandler eventHandler = EventHandler.getInstance();
048: private TreePath eventPath = null;
049: private JTreeModel model = null;
050: private DefaultMutableTreeNode sourceNode = null;
051: private DefaultMutableTreeNode targetNode = null;
052: private StringBuffer xmlValue = null;
053:
054: public JTreeComponent(TreeNodeComponent aNode, JTreeModel aModel) {
055: super (aNode);
056: this .model = aModel;
057: super .setName(model.getName());
058: super .addTreeSelectionListener(this );
059: super .addMouseListener(this );
060: if (model.isDndEnabled()) {
061: // DropTarget theDropTarget = new DropTarget(this, DnDConstants.ACTION_MOVE, this, true);
062: new DropTarget(this , DnDConstants.ACTION_MOVE, this , true);
063: this .dragSource = DragSource.getDefaultDragSource();
064: this .dragSource.createDefaultDragGestureRecognizer(this ,
065: DnDConstants.ACTION_MOVE, this );
066: }
067: super .addTreeExpansionListener(this );
068: super .addTreeWillExpandListener(this );
069: DefaultTreeCellRenderer r = new DefaultTreeCellRenderer();
070: r.setOpenIcon(model.getOpenFolderIcon() != null ? model
071: .getOpenFolderIcon() : r.getDefaultOpenIcon());
072: r.setClosedIcon(model.getClosedFolderIcon() != null ? model
073: .getClosedFolderIcon() : r.getDefaultClosedIcon());
074: r.setLeafIcon(model.getLeafIcon() != null ? model.getLeafIcon()
075: : r.getDefaultLeafIcon());
076: setCellRenderer(r);
077: }
078:
079: public void dragDropEnd(DragSourceDropEvent aEvt) {
080: super .updateUI();
081: }
082:
083: //-- DragSourceListener realization.
084: public void dragEnter(DragSourceDragEvent aEvt) {
085: setCursor(aEvt);
086: }
087:
088: public void dragEnter(DropTargetDragEvent aEvt) {
089: if (this .isDropValid(aEvt)) {
090: aEvt.acceptDrag(DnDConstants.ACTION_MOVE);
091: } else {
092: aEvt.rejectDrag();
093: }
094: }
095:
096: public void dragExit(DragSourceEvent aEvt) {
097: setCursor(aEvt);
098: }
099:
100: public void dragExit(DropTargetEvent aEvt) {
101: }
102:
103: //-- DragGestureListener realization.
104: public void dragGestureRecognized(DragGestureEvent aEvt) {
105: if (this .sourceNode != super .getModel().getRoot()) {
106: this .dragSource.startDrag(aEvt,
107: DragSource.DefaultMoveNoDrop,
108: (Transferable) this .sourceNode, this );
109: }
110: }
111:
112: public void dragOver(DragSourceDragEvent aEvt) {
113: setCursor(aEvt);
114: }
115:
116: public void dragOver(DropTargetDragEvent aEvt) {
117: if (isDropValid(aEvt)) {
118: aEvt.acceptDrag(DnDConstants.ACTION_MOVE);
119: } else {
120: aEvt.rejectDrag();
121: }
122: }
123:
124: //-- DropTargetListener realization.
125: public void drop(DropTargetDropEvent aEvt) {
126: try {
127: if (this .isDropValid(aEvt)) {
128: this .sourceNode = (DefaultMutableTreeNode) aEvt
129: .getTransferable().getTransferData(
130: TreeNodeComponent.dataFlavor);
131: if (this .sourceNode.isLeaf()) {
132: /*
133: * If the node being dragged is leaf then it will be added after the
134: * last leaf node of the current parent.
135: * */
136: //-- targetNode is set in isValid() method.
137: Enumeration theChildren = this .targetNode
138: .children();
139: DefaultMutableTreeNode theIterationNode = null;
140: int theIndex = 0;
141: while (theChildren.hasMoreElements()) {
142: theIterationNode = (DefaultMutableTreeNode) theChildren
143: .nextElement();
144: if (theIterationNode.isLeaf()) {
145: theIndex = targetNode
146: .getIndex(theIterationNode);
147: }
148: }
149: if (this .sourceNode.getParent() != this .targetNode
150: && theIndex > 0) {
151: theIndex++;
152: }
153: targetNode.insert(this .sourceNode, theIndex);
154: } else {
155: /*
156: * If the node being dragged is not leaf the it will be added at the end of
157: * the current parent.
158: * */
159: this .targetNode.add(this .sourceNode);
160: }
161: aEvt.acceptDrop(TransferHandler.MOVE);
162: aEvt.dropComplete(true);
163: super .updateUI();
164: } else {
165: aEvt.rejectDrop();
166: }
167: } catch (IllegalArgumentException e) {
168: SwingUtilities.invokeLater(new Runnable() {
169:
170: public void run() {
171: JOptionPane
172: .showMessageDialog(JTreeComponent.this ,
173: "Can't drag a folder onto itself or one of its children.");
174: }
175: });
176: } catch (UnsupportedFlavorException e) {
177: SwingMLLogger.getInstance().log(e);
178: } catch (IOException e) {
179: SwingMLLogger.getInstance().log(e);
180: }
181: }
182:
183: public void dropActionChanged(DragSourceDragEvent aEvt) {
184: setCursor(aEvt);
185: }
186:
187: public void dropActionChanged(DropTargetDragEvent aEvt) {
188: if (this .isDropValid(aEvt)) {
189: aEvt.acceptDrag(DnDConstants.ACTION_MOVE);
190: } else {
191: aEvt.rejectDrag();
192: }
193: }
194:
195: public TreePath getEventPath() {
196: return this .eventPath;
197: }
198:
199: //-- XMLTranslatable realization.
200: public String getXMLValue() {
201: this .xmlValue = new StringBuffer();
202: this .processTreeNode((TreeNodeComponent) super .getModel()
203: .getRoot());
204: return this .xmlValue.toString();
205: }
206:
207: //-- Utility methods.
208: private boolean isDropValid(DropTargetEvent aEvt) {
209: Point thePoint = null;
210: if (aEvt instanceof DropTargetDropEvent) {
211: thePoint = ((DropTargetDropEvent) aEvt).getLocation()
212: .getLocation();
213: } else if (aEvt instanceof DropTargetDragEvent) {
214: thePoint = ((DropTargetDragEvent) aEvt).getLocation()
215: .getLocation();
216: }
217: TreePath thePath = getPathForLocation(thePoint.x, thePoint.y);
218: if (thePath != null) {
219: //-- Sets the targetNode;
220: this .targetNode = (DefaultMutableTreeNode) thePath
221: .getLastPathComponent();
222: if (this .targetNode.isLeaf()) {
223: return false;
224: } else {
225: return true;
226: }
227: }
228: return false;
229: }
230:
231: // MouseListener Realization
232: /**
233: * @see java.awt.event.MouseListener#mouseClicked(MouseEvent)
234: */
235: public void mouseClicked(MouseEvent aEvt) {
236: final int DOUBLE_CLICK_COUNT = 2;
237: final int SINGLE_CLICK_COUNT = 1;
238: String theEventType = null;
239: switch (aEvt.getClickCount()) {
240: case DOUBLE_CLICK_COUNT:
241: theEventType = Constants.MOUSE_DOUBLE_CLICKED;
242: break;
243: case SINGLE_CLICK_COUNT:
244: theEventType = Constants.MOUSE_SINGLE_CLICKED;
245: break;
246: default:
247: theEventType = null;
248: break;
249: }
250: if (theEventType != null && theEventType.length() > 0) {
251: this .eventHandler.handleEvent(this .model, theEventType,
252: this );
253: }
254: }
255:
256: /**
257: * @see java.awt.event.MouseListener#mouseEntered(MouseEvent)
258: */
259: public void mouseEntered(MouseEvent aEvt) {
260: }
261:
262: /**
263: * @see java.awt.event.MouseListener#mouseExited(MouseEvent)
264: */
265: public void mouseExited(MouseEvent aEvt) {
266: }
267:
268: /**
269: * @see java.awt.event.MouseListener#mousePressed(MouseEvent)
270: */
271: public void mousePressed(MouseEvent aEvt) {
272: }
273:
274: /**
275: * @see java.awt.event.MouseListener#mouseReleased(MouseEvent)
276: */
277: public void mouseReleased(MouseEvent aEvt) {
278: }
279:
280: public void processTreeNode(TreeNodeComponent aNode) {
281: this .xmlValue.append("<TREE NAME=\"" + aNode.getName()
282: + " \" TEXT=\"" + aNode.getUserObject() + "\">\n");
283: TreeNodeComponent theChild = null;
284: int theCount = aNode.getChildCount();
285: for (int i = 0; i < theCount; i++) {
286: theChild = (TreeNodeComponent) aNode.getChildAt(i);
287: if (!theChild.isLeaf()) {
288: this .processTreeNode(theChild);
289: } else {
290: this .xmlValue.append("<NODE TEXT=\""
291: + theChild.getUserObject() + "\"/>\n");
292: }
293: }
294: this .xmlValue.append("</TREE>\n");
295: }
296:
297: public void setCursor(DragSourceEvent aEvt) {
298: if (aEvt instanceof DragSourceDragEvent) {
299: Cursor theResult = null;
300: int theDropAction = ((DragSourceDragEvent) aEvt)
301: .getDropAction();
302: int theTargetActions = ((DragSourceDragEvent) aEvt)
303: .getUserAction();
304: if ((theDropAction & theTargetActions) != 0) { //-- Able to drop
305: if (theDropAction == DnDConstants.ACTION_MOVE) {
306: theResult = DragSource.DefaultMoveDrop;
307: }
308: } else { //-- Unable to drop
309: if (theDropAction == DnDConstants.ACTION_MOVE) {
310: theResult = DragSource.DefaultMoveNoDrop;
311: }
312: }
313: aEvt.getDragSourceContext().setCursor(theResult);
314: } else {
315: aEvt.getDragSourceContext().setCursor(
316: DragSource.DefaultMoveNoDrop);
317: }
318: }
319:
320: // TreeExpansionListener Realization
321: public void treeCollapsed(TreeExpansionEvent aEvt) {
322: this .eventPath = aEvt.getPath();
323: this .eventHandler.handleEvent(this .model,
324: Constants.TREE_COLLAPSED, this );
325: }
326:
327: public void treeExpanded(TreeExpansionEvent aEvt) {
328: this .eventPath = aEvt.getPath();
329: this .eventHandler.handleEvent(this .model,
330: Constants.TREE_EXPANDED, this );
331: }
332:
333: // TreeWillExpandListener Realization
334: public void treeWillCollapse(TreeExpansionEvent aEvt)
335: throws ExpandVetoException {
336: this .eventPath = aEvt.getPath();
337: this .eventHandler.handleEvent(this .model,
338: Constants.TREE_WILL_COLLAPSE, this );
339: }
340:
341: public void treeWillExpand(TreeExpansionEvent e)
342: throws ExpandVetoException {
343: this .eventPath = e.getPath();
344: eventHandler.handleEvent(this .model,
345: Constants.TREE_WILL_EXPAND, this );
346: }
347:
348: //
349: // class JTreeComponentCellRenderer extends DefaultTreeCellRenderer {
350: // public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
351: // return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
352: // }
353: // }
354:
355: //-- TreeSelectionListener realization.
356: public void valueChanged(TreeSelectionEvent aEvt) {
357: if (aEvt.getNewLeadSelectionPath() != null) {
358: this .sourceNode = (DefaultMutableTreeNode) aEvt
359: .getNewLeadSelectionPath().getLastPathComponent();
360: }
361: this.eventHandler.handleEvent(this.model,
362: Constants.TREE_VALUE_CHANGED, this);
363: }
364: }
|