001: /*
002: * $Id: JGraphpadTransferHandler.java,v 1.1.1.1 2005/08/04 11:21:58 gaudenz Exp $
003: * Copyright (c) 2001-2005, Gaudenz Alder
004: *
005: * All rights reserved.
006: *
007: * See LICENSE file for license details. If you are unable to locate
008: * this file please contact info (at) jgraph (dot) com.
009: */
010: package com.jgraph.pad.graph;
011:
012: import java.awt.Dimension;
013: import java.awt.Point;
014: import java.awt.datatransfer.DataFlavor;
015: import java.awt.datatransfer.Transferable;
016: import java.awt.geom.Point2D;
017: import java.awt.geom.Rectangle2D;
018: import java.io.IOException;
019: import java.io.Reader;
020: import java.util.List;
021: import java.util.Map;
022:
023: import javax.swing.ImageIcon;
024: import javax.swing.JComponent;
025:
026: import org.jgraph.JGraph;
027: import org.jgraph.graph.DefaultGraphModel;
028: import org.jgraph.graph.GraphConstants;
029: import org.jgraph.graph.GraphModel;
030: import org.jgraph.graph.GraphTransferHandler;
031: import org.jgraph.plaf.basic.BasicGraphUI;
032:
033: import com.jgraph.JGraphEditor;
034: import com.jgraph.JGraphpad;
035: import com.jgraph.pad.util.JGraphpadImageIcon;
036:
037: /**
038: * Transfer handler for graphs that accepts external files and text.
039: */
040: public class JGraphpadTransferHandler extends GraphTransferHandler {
041:
042: /**
043: * Holds the prototype which is used to create new vertices.
044: */
045: protected transient Object prototype;
046:
047: /**
048: * Constructs a new transfer handler for the specified prototype.
049: *
050: * @param prototype
051: * The prototype to be used to create new cells.
052: */
053: public JGraphpadTransferHandler(Object prototype) {
054: this .prototype = prototype;
055: }
056:
057: /**
058: * Constructs a new cell from {@link #prototype} using the specified model
059: * and assigns it the new user object.
060: *
061: * @param model
062: * The model to use for cloning the prototype.
063: * @param userObject
064: * The user object to be assigned to the clone.
065: * @return Returns a prototype clone with the specified user object.
066: */
067: protected Object createCell(GraphModel model, Object userObject) {
068: Object cell = DefaultGraphModel.cloneCell(model, prototype);
069: model.valueForCellChanged(cell, userObject);
070: return cell;
071: }
072:
073: /**
074: * Extends the parent implementation to accept text and
075: * {@link DataFlavor#javaFileListFlavor} flavors.
076: *
077: * @param comp
078: * The component to drop the transferable to.
079: * @param flavors
080: * The supported data flavors of the transferable.
081: * @return Returns true if the flavor is accepted.
082: */
083: public boolean canImport(JComponent comp, DataFlavor[] flavors) {
084: if (flavors != null) {
085: if (DataFlavor.selectBestTextFlavor(flavors) != null)
086: return true;
087: for (int i = 0; i < flavors.length; i++)
088: if (flavors[i].equals(DataFlavor.javaFileListFlavor))
089: return true;
090: }
091: return super .canImport(comp, flavors);
092: }
093:
094: /**
095: * Overrides the parent implementation to import transferable data. Note: It
096: * is a special rule in JGraph not to override the
097: * {@link GraphTransferHandler#importData(JComponent, Transferable)} method
098: * because the return value has a different semantic. This implementation
099: * silently ignores all exceptions.
100: *
101: * @param comp
102: * The component to drop the transferable to.
103: * @param t
104: * The transferable data to be inserted into the component.
105: * @return Returns true if the transferable data was inserted.
106: */
107: public boolean importDataImpl(JComponent comp, Transferable t) {
108: if (super .importDataImpl(comp, t))
109: return true; // exit
110: else if (comp instanceof JGraph
111: && ((JGraph) comp).isDropEnabled()) {
112: try {
113: JGraph graph = (JGraph) comp;
114: Point2D p = getInsertionLocation(graph);
115:
116: // Drops the java file list as a sequence of cells
117: if (t
118: .isDataFlavorSupported(DataFlavor.javaFileListFlavor))
119: insertValues(
120: graph,
121: p,
122: ((List) t
123: .getTransferData(DataFlavor.javaFileListFlavor))
124: .toArray());
125:
126: // Drops as single text cell
127: else {
128: DataFlavor bestFlavor = DataFlavor
129: .selectBestTextFlavor(t
130: .getTransferDataFlavors());
131: if (bestFlavor != null) {
132:
133: // Constructs a string using the reader and passes
134: // the text to the insertText method.
135: Reader reader = bestFlavor.getReaderForText(t);
136: insertValues(graph, p,
137: new Object[] { getString(reader) });
138: }
139: }
140: } catch (Exception exception) {
141: // ignore
142: }
143: }
144: return false;
145: }
146:
147: /**
148: * Helper method to return the insertion location for a drop operation in
149: * the specified graph. This implementation returns a scaled clone of
150: * {@link BasicGraphUI#getInsertionLocation()} or a dummy point if the
151: * insertion location is not available in the graph ui.
152: *
153: * @param graph
154: * The graph to determine the insertion location for.
155: * @return Returns the insertion location for the specified graph.
156: */
157: protected Point2D getInsertionLocation(JGraph graph) {
158: Point2D p = graph.getUI().getInsertionLocation();
159: if (p != null)
160: p = graph.fromScreen(graph.snap((Point2D) p.clone()));
161:
162: // Returns a dummy point at (gridSize, gridSize) in case
163: // the insertion location is not available from the ui.
164: if (p == null) {
165: double gs = graph.getGridSize();
166: p = new Point((int) gs, (int) gs);
167: }
168: return p;
169: }
170:
171: /**
172: * Helper method to read the specified reader into a string.
173: *
174: * @param reader
175: * The reader to read into the string.
176: * @return Returns the string stored in the reader.
177: */
178: protected String getString(Reader reader) throws IOException {
179: StringBuffer s = new StringBuffer();
180: char[] c = new char[1];
181: while (reader.read(c) != -1)
182: s.append(c);
183: return s.toString();
184: }
185:
186: /**
187: * Inserts the specified list of values into the specified graph. If a known
188: * image extension is seen then the icon attribute is setup accordingly.
189: *
190: * @param graph
191: * The graph to insert the cells into.
192: * @param p
193: * The point at which to insert the cells.
194: * @param values
195: * The list of values to be inserted.
196: */
197: protected void insertValues(JGraph graph, Point2D p, Object[] values) {
198: double gs = graph.getGridSize();
199: Dimension d = new Dimension((int) gs, (int) (2 * gs));
200: Object[] cells = new Object[values.length];
201:
202: // Loops through the files in the list and creates
203: // a cell for each one, using the file as an icon
204: // if it has a n known extension.
205: for (int i = 0; i < values.length; i++) {
206: cells[i] = createCell(graph.getModel(), values[i]);
207: Map attrs = graph.getModel().getAttributes(cells[i]);
208:
209: // Uses the file as an icon if it has a known extension
210: String url = String.valueOf(cells[i]).toLowerCase();
211: if (JGraphpad.isImage(url)) {
212: ImageIcon icon = (JGraphEditor.isURL(url)) ? new JGraphpadImageIcon(
213: JGraphEditor.toURL(url))
214: : new JGraphpadImageIcon(url);
215: if (icon != null)
216: GraphConstants.setIcon(attrs, icon);
217: }
218:
219: // Sets the default bounds of the cell forcing a resize
220: GraphConstants.setResize(attrs, true);
221: GraphConstants.setBounds(attrs, new Rectangle2D.Double(p
222: .getX(), p.getY(), d.getWidth(), d.getHeight()));
223:
224: // Shifts the point for the next cell to be inserted
225: p
226: .setLocation(p.getX(), p.getY() + d.getHeight()
227: + 1.5 * gs);
228: graph.snap(p);
229: }
230:
231: // Inserts the cells into the graph
232: graph.getGraphLayoutCache().insert(cells);
233: }
234:
235: }
|