1package com.mxgraph.examples.swing;
2
3import java.awt.Color;
4import java.awt.Point;
5import java.net.URL;
6import java.text.NumberFormat;
7import java.util.Iterator;
8import java.util.List;
9import java.util.ServiceLoader;
10
11import javax.swing.ImageIcon;
12import javax.swing.UIManager;
13
14import org.w3c.dom.Document;
15
16import com.mxgraph.examples.swing.editor.BasicGraphEditor;
17import com.mxgraph.examples.swing.editor.EditorMenuBar;
18import com.mxgraph.examples.swing.editor.EditorPalette;
19import com.mxgraph.examples.swing.editor.EditorPaletteFactory;
20import com.mxgraph.io.mxCodec;
21import com.mxgraph.model.mxCell;
22import com.mxgraph.model.mxGeometry;
23import com.mxgraph.model.mxICell;
24import com.mxgraph.model.mxIGraphModel;
25import com.mxgraph.swing.mxGraphComponent;
26import com.mxgraph.swing.util.mxGraphTransferable;
27import com.mxgraph.util.mxConstants;
28import com.mxgraph.util.mxEvent;
29import com.mxgraph.util.mxEventObject;
30import com.mxgraph.util.mxPoint;
31import com.mxgraph.util.mxResources;
32import com.mxgraph.util.mxUtils;
33import com.mxgraph.util.mxEventSource.mxIEventListener;
34import com.mxgraph.view.mxCellState;
35import com.mxgraph.view.mxGraph;
36
37public class GraphEditor extends BasicGraphEditor
38{
39
40	/**
41	 *
42	 */
43	private static final long serialVersionUID = -4601740824088314699L;
44
45	/**
46	 * Holds the shared number formatter.
47	 *
48	 * @see NumberFormat#getInstance()
49	 */
50	public static final NumberFormat numberFormat = NumberFormat.getInstance();
51
52	/**
53	 * Holds the URL for the icon to be used as a handle for creating new
54	 * connections. This is currently unused.
55	 */
56	public static URL url = null;
57
58	//GraphEditor.class.getResource("/com/mxgraph/examples/swing/images/connector.gif");
59
60	public GraphEditor()
61	{
62		this("mxGraph Editor", new CustomGraphComponent(new CustomGraph()));
63	}
64
65	/**
66	 *
67	 */
68	public GraphEditor(String appTitle, mxGraphComponent component)
69	{
70		super(appTitle, component);
71		final mxGraph graph = graphComponent.getGraph();
72
73		// Creates the shapes palette
74		EditorPalette shapesPalette = insertPalette(mxResources.get("shapes"));
75		EditorPalette imagesPalette = insertPalette(mxResources.get("images"));
76		EditorPalette symbolsPalette = insertPalette(mxResources.get("symbols"));
77
78		ServiceLoader<EditorPaletteFactory> sl = ServiceLoader.load(EditorPaletteFactory.class, this.getClass().getClassLoader());
79		Iterator<EditorPaletteFactory> epfit = sl.iterator();
80		while (epfit.hasNext()) {
81			EditorPaletteFactory epf = epfit.next();
82			EditorPalette customPalette = insertPalette(epf.getTitle());
83			epf.populate(customPalette);
84		}
85
86		// Sets the edge template to be used for creating new edges if an edge
87		// is clicked in the shape palette
88		shapesPalette.addListener(mxEvent.SELECT, new mxIEventListener()
89		{
90			public void invoke(Object sender, mxEventObject evt)
91			{
92				Object tmp = evt.getProperty("transferable");
93
94				if (tmp instanceof mxGraphTransferable)
95				{
96					mxGraphTransferable t = (mxGraphTransferable) tmp;
97					Object cell = t.getCells()[0];
98
99					if (graph.getModel().isEdge(cell))
100					{
101						((CustomGraph) graph).setEdgeTemplate(cell);
102					}
103				}
104			}
105
106		});
107
108		// Adds some template cells for dropping into the graph
109		shapesPalette
110				.addTemplate(
111						"Container",
112						new ImageIcon(
113								GraphEditor.class
114										.getResource("/com/mxgraph/examples/swing/images/swimlane.png")),
115						"swimlane", 280, 280, "Container");
116		shapesPalette
117				.addTemplate(
118						"Rectangle",
119						new ImageIcon(
120								GraphEditor.class
121										.getResource("/com/mxgraph/examples/swing/images/rectangle.png")),
122						null, 160, 120, "");
123		shapesPalette
124				.addTemplate(
125						"Rounded Rectangle",
126						new ImageIcon(
127								GraphEditor.class
128										.getResource("/com/mxgraph/examples/swing/images/rounded.png")),
129						"rounded=1", 160, 120, "");
130		shapesPalette
131				.addTemplate(
132						"Ellipse",
133						new ImageIcon(
134								GraphEditor.class
135										.getResource("/com/mxgraph/examples/swing/images/ellipse.png")),
136						"ellipse", 160, 160, "");
137		shapesPalette
138				.addTemplate(
139						"Double Ellipse",
140						new ImageIcon(
141								GraphEditor.class
142										.getResource("/com/mxgraph/examples/swing/images/doubleellipse.png")),
143						"ellipse;shape=doubleEllipse", 160, 160, "");
144		shapesPalette
145				.addTemplate(
146						"Triangle",
147						new ImageIcon(
148								GraphEditor.class
149										.getResource("/com/mxgraph/examples/swing/images/triangle.png")),
150						"triangle", 120, 160, "");
151		shapesPalette
152				.addTemplate(
153						"Rhombus",
154						new ImageIcon(
155								GraphEditor.class
156										.getResource("/com/mxgraph/examples/swing/images/rhombus.png")),
157						"rhombus", 160, 160, "");
158		shapesPalette
159				.addTemplate(
160						"Horizontal Line",
161						new ImageIcon(
162								GraphEditor.class
163										.getResource("/com/mxgraph/examples/swing/images/hline.png")),
164						"line", 160, 10, "");
165		shapesPalette
166				.addTemplate(
167						"Hexagon",
168						new ImageIcon(
169								GraphEditor.class
170										.getResource("/com/mxgraph/examples/swing/images/hexagon.png")),
171						"shape=hexagon", 160, 120, "");
172		shapesPalette
173				.addTemplate(
174						"Cylinder",
175						new ImageIcon(
176								GraphEditor.class
177										.getResource("/com/mxgraph/examples/swing/images/cylinder.png")),
178						"shape=cylinder", 120, 160, "");
179		shapesPalette.addTemplate("Actor", new ImageIcon(GraphEditor.class
180				.getResource("/com/mxgraph/examples/swing/images/actor.png")),
181				"shape=actor", 120, 160, "");
182		shapesPalette.addTemplate("Cloud", new ImageIcon(GraphEditor.class
183				.getResource("/com/mxgraph/examples/swing/images/cloud.png")),
184				"ellipse;shape=cloud", 160, 120, "");
185
186		shapesPalette
187				.addEdgeTemplate(
188						"Straight",
189						new ImageIcon(
190								GraphEditor.class
191										.getResource("/com/mxgraph/examples/swing/images/straight.png")),
192						"straight", 120, 120, "");
193		shapesPalette
194				.addEdgeTemplate(
195						"Horizontal Connector",
196						new ImageIcon(
197								GraphEditor.class
198										.getResource("/com/mxgraph/examples/swing/images/connect.png")),
199						null, 100, 100, "");
200		shapesPalette
201				.addEdgeTemplate(
202						"Vertical Connector",
203						new ImageIcon(
204								GraphEditor.class
205										.getResource("/com/mxgraph/examples/swing/images/vertical.png")),
206						"vertical", 100, 100, "");
207		shapesPalette
208				.addEdgeTemplate(
209						"Entity Relation",
210						new ImageIcon(
211								GraphEditor.class
212										.getResource("/com/mxgraph/examples/swing/images/entity.png")),
213						"entity", 100, 100, "");
214		shapesPalette.addEdgeTemplate("Arrow", new ImageIcon(GraphEditor.class
215				.getResource("/com/mxgraph/examples/swing/images/arrow.png")),
216				"arrow", 120, 120, "");
217
218		imagesPalette.addTemplate("Bell", new ImageIcon(GraphEditor.class
219				.getResource("/com/mxgraph/examples/swing/images/bell.png")),
220				"image;image=/com/mxgraph/examples/swing/images/bell.png", 50,
221				50, "Bell");
222		imagesPalette.addTemplate("Box", new ImageIcon(GraphEditor.class
223				.getResource("/com/mxgraph/examples/swing/images/box.png")),
224				"image;image=/com/mxgraph/examples/swing/images/box.png", 50,
225				50, "Box");
226		imagesPalette
227				.addTemplate(
228						"Cube",
229						new ImageIcon(
230								GraphEditor.class
231										.getResource("/com/mxgraph/examples/swing/images/cube_green.png")),
232						"image;image=/com/mxgraph/examples/swing/images/cube_green.png",
233						50, 50, "Cube");
234		imagesPalette
235				.addTemplate(
236						"User",
237						new ImageIcon(
238								GraphEditor.class
239										.getResource("/com/mxgraph/examples/swing/images/dude3.png")),
240						"roundImage;image=/com/mxgraph/examples/swing/images/dude3.png",
241						50, 50, "User");
242		imagesPalette
243				.addTemplate(
244						"Earth",
245						new ImageIcon(
246								GraphEditor.class
247										.getResource("/com/mxgraph/examples/swing/images/earth.png")),
248						"roundImage;image=/com/mxgraph/examples/swing/images/earth.png",
249						50, 50, "Earth");
250		imagesPalette.addTemplate("Gear", new ImageIcon(GraphEditor.class
251				.getResource("/com/mxgraph/examples/swing/images/gear.png")),
252				"roundImage;image=/com/mxgraph/examples/swing/images/gear.png",
253				50, 50, "Gear");
254		imagesPalette.addTemplate("Home", new ImageIcon(GraphEditor.class
255				.getResource("/com/mxgraph/examples/swing/images/house.png")),
256				"image;image=/com/mxgraph/examples/swing/images/house.png", 50,
257				50, "Home");
258		imagesPalette
259				.addTemplate(
260						"Package",
261						new ImageIcon(
262								GraphEditor.class
263										.getResource("/com/mxgraph/examples/swing/images/package.png")),
264						"image;image=/com/mxgraph/examples/swing/images/package.png",
265						50, 50, "Package");
266		imagesPalette
267				.addTemplate(
268						"Printer",
269						new ImageIcon(
270								GraphEditor.class
271										.getResource("/com/mxgraph/examples/swing/images/printer.png")),
272						"image;image=/com/mxgraph/examples/swing/images/printer.png",
273						50, 50, "Printer");
274		imagesPalette.addTemplate("Server", new ImageIcon(GraphEditor.class
275				.getResource("/com/mxgraph/examples/swing/images/server.png")),
276				"image;image=/com/mxgraph/examples/swing/images/server.png",
277				50, 50, "Server");
278		imagesPalette
279				.addTemplate(
280						"Workplace",
281						new ImageIcon(
282								GraphEditor.class
283										.getResource("/com/mxgraph/examples/swing/images/workplace.png")),
284						"image;image=/com/mxgraph/examples/swing/images/workplace.png",
285						50, 50, "Workplace");
286		imagesPalette
287				.addTemplate(
288						"Wrench",
289						new ImageIcon(
290								GraphEditor.class
291										.getResource("/com/mxgraph/examples/swing/images/wrench.png")),
292						"roundImage;image=/com/mxgraph/examples/swing/images/wrench.png",
293						50, 50, "Wrench");
294
295		symbolsPalette
296				.addTemplate(
297						"Cancel",
298						new ImageIcon(
299								GraphEditor.class
300										.getResource("/com/mxgraph/examples/swing/images/cancel_end.png")),
301						"roundImage;image=/com/mxgraph/examples/swing/images/cancel_end.png",
302						80, 80, "Cancel");
303		symbolsPalette
304				.addTemplate(
305						"Error",
306						new ImageIcon(
307								GraphEditor.class
308										.getResource("/com/mxgraph/examples/swing/images/error.png")),
309						"roundImage;image=/com/mxgraph/examples/swing/images/error.png",
310						80, 80, "Error");
311		symbolsPalette
312				.addTemplate(
313						"Event",
314						new ImageIcon(
315								GraphEditor.class
316										.getResource("/com/mxgraph/examples/swing/images/event.png")),
317						"roundImage;image=/com/mxgraph/examples/swing/images/event.png",
318						80, 80, "Event");
319		symbolsPalette
320				.addTemplate(
321						"Fork",
322						new ImageIcon(
323								GraphEditor.class
324										.getResource("/com/mxgraph/examples/swing/images/fork.png")),
325						"rhombusImage;image=/com/mxgraph/examples/swing/images/fork.png",
326						80, 80, "Fork");
327		symbolsPalette
328				.addTemplate(
329						"Inclusive",
330						new ImageIcon(
331								GraphEditor.class
332										.getResource("/com/mxgraph/examples/swing/images/inclusive.png")),
333						"rhombusImage;image=/com/mxgraph/examples/swing/images/inclusive.png",
334						80, 80, "Inclusive");
335		symbolsPalette.addTemplate("Link", new ImageIcon(GraphEditor.class
336				.getResource("/com/mxgraph/examples/swing/images/link.png")),
337				"roundImage;image=/com/mxgraph/examples/swing/images/link.png",
338				80, 80, "Link");
339		symbolsPalette
340				.addTemplate(
341						"Merge",
342						new ImageIcon(
343								GraphEditor.class
344										.getResource("/com/mxgraph/examples/swing/images/merge.png")),
345						"rhombusImage;image=/com/mxgraph/examples/swing/images/merge.png",
346						80, 80, "Merge");
347		symbolsPalette
348				.addTemplate(
349						"Message",
350						new ImageIcon(
351								GraphEditor.class
352										.getResource("/com/mxgraph/examples/swing/images/message.png")),
353						"roundImage;image=/com/mxgraph/examples/swing/images/message.png",
354						80, 80, "Message");
355		symbolsPalette
356				.addTemplate(
357						"Multiple",
358						new ImageIcon(
359								GraphEditor.class
360										.getResource("/com/mxgraph/examples/swing/images/multiple.png")),
361						"roundImage;image=/com/mxgraph/examples/swing/images/multiple.png",
362						80, 80, "Multiple");
363		symbolsPalette.addTemplate("Rule", new ImageIcon(GraphEditor.class
364				.getResource("/com/mxgraph/examples/swing/images/rule.png")),
365				"roundImage;image=/com/mxgraph/examples/swing/images/rule.png",
366				80, 80, "Rule");
367		symbolsPalette
368				.addTemplate(
369						"Terminate",
370						new ImageIcon(
371								GraphEditor.class
372										.getResource("/com/mxgraph/examples/swing/images/terminate.png")),
373						"roundImage;image=/com/mxgraph/examples/swing/images/terminate.png",
374						80, 80, "Terminate");
375		symbolsPalette
376				.addTemplate(
377						"Timer",
378						new ImageIcon(
379								GraphEditor.class
380										.getResource("/com/mxgraph/examples/swing/images/timer.png")),
381						"roundImage;image=/com/mxgraph/examples/swing/images/timer.png",
382						80, 80, "Timer");
383	}
384
385	/**
386	 *
387	 */
388	public static class CustomGraphComponent extends mxGraphComponent
389	{
390
391		/**
392		 *
393		 */
394		private static final long serialVersionUID = -6833603133512882012L;
395
396		/**
397		 *
398		 * @param graph
399		 */
400		public CustomGraphComponent(mxGraph graph)
401		{
402			super(graph);
403
404			// Sets switches typically used in an editor
405			setPageVisible(true);
406			setGridVisible(true);
407			setToolTips(true);
408			getConnectionHandler().setCreateTarget(true);
409
410			// Loads the defalt stylesheet from an external file
411			mxCodec codec = new mxCodec();
412			Document doc = mxUtils.loadDocument(GraphEditor.class.getResource(
413					"/com/mxgraph/examples/swing/resources/default-style.xml")
414					.toString());
415			codec.decode(doc.getDocumentElement(), graph.getStylesheet());
416
417			// Sets the background to white
418			getViewport().setOpaque(false);
419			setBackground(Color.WHITE);
420		}
421
422		/**
423		 * Overrides drop behaviour to set the cell style if the target
424		 * is not a valid drop target and the cells are of the same
425		 * type (eg. both vertices or both edges).
426		 */
427		public Object[] importCells(Object[] cells, double dx, double dy,
428				Object target, Point location)
429		{
430			if (target == null && cells.length == 1 && location != null)
431			{
432				target = getCellAt(location.x, location.y);
433
434				if (target instanceof mxICell && cells[0] instanceof mxICell)
435				{
436					mxICell targetCell = (mxICell) target;
437					mxICell dropCell = (mxICell) cells[0];
438
439					if (targetCell.isVertex() == dropCell.isVertex()
440							|| targetCell.isEdge() == dropCell.isEdge())
441					{
442						mxIGraphModel model = graph.getModel();
443						model.setStyle(target, model.getStyle(cells[0]));
444						graph.setSelectionCell(target);
445
446						return null;
447					}
448				}
449			}
450
451			return super.importCells(cells, dx, dy, target, location);
452		}
453
454	}
455
456	/**
457	 * A graph that creates new edges from a given template edge.
458	 */
459	public static class CustomGraph extends mxGraph
460	{
461		/**
462		 * Holds the edge to be used as a template for inserting new edges.
463		 */
464		protected Object edgeTemplate;
465
466		/**
467		 * Custom graph that defines the alternate edge style to be used when
468		 * the middle control point of edges is double clicked (flipped).
469		 */
470		public CustomGraph()
471		{
472			setAlternateEdgeStyle("edgeStyle=mxEdgeStyle.ElbowConnector;elbow=vertical");
473		}
474
475		/**
476		 * Sets the edge template to be used to inserting edges.
477		 */
478		public void setEdgeTemplate(Object template)
479		{
480			edgeTemplate = template;
481		}
482
483		/**
484		 * Prints out some useful information about the cell in the tooltip.
485		 */
486		public String getToolTipForCell(Object cell)
487		{
488			String tip = "<html>";
489			mxGeometry geo = getModel().getGeometry(cell);
490			mxCellState state = getView().getState(cell);
491
492			if (getModel().isEdge(cell))
493			{
494				tip += "points={";
495
496				if (geo != null)
497				{
498					List<mxPoint> points = geo.getPoints();
499
500					if (points != null)
501					{
502						Iterator<mxPoint> it = points.iterator();
503
504						while (it.hasNext())
505						{
506							mxPoint point = it.next();
507							tip += "[x=" + numberFormat.format(point.getX())
508									+ ",y=" + numberFormat.format(point.getY())
509									+ "],";
510						}
511
512						tip = tip.substring(0, tip.length() - 1);
513					}
514				}
515
516				tip += "}<br>";
517				tip += "absPoints={";
518
519				if (state != null)
520				{
521
522					for (int i = 0; i < state.getAbsolutePointCount(); i++)
523					{
524						mxPoint point = state.getAbsolutePoint(i);
525						tip += "[x=" + numberFormat.format(point.getX())
526								+ ",y=" + numberFormat.format(point.getY())
527								+ "],";
528					}
529
530					tip = tip.substring(0, tip.length() - 1);
531				}
532
533				tip += "}";
534			}
535			else
536			{
537				tip += "geo=[";
538
539				if (geo != null)
540				{
541					tip += "x=" + numberFormat.format(geo.getX()) + ",y="
542							+ numberFormat.format(geo.getY()) + ",width="
543							+ numberFormat.format(geo.getWidth()) + ",height="
544							+ numberFormat.format(geo.getHeight());
545				}
546
547				tip += "]<br>";
548				tip += "state=[";
549
550				if (state != null)
551				{
552					tip += "x=" + numberFormat.format(state.getX()) + ",y="
553							+ numberFormat.format(state.getY()) + ",width="
554							+ numberFormat.format(state.getWidth())
555							+ ",height="
556							+ numberFormat.format(state.getHeight());
557				}
558
559				tip += "]";
560			}
561
562			mxPoint trans = getView().getTranslate();
563
564			tip += "<br>scale=" + numberFormat.format(getView().getScale())
565					+ ", translate=[x=" + numberFormat.format(trans.getX())
566					+ ",y=" + numberFormat.format(trans.getY()) + "]";
567			tip += "</html>";
568
569			return tip;
570		}
571
572		/**
573		 * Overrides the method to use the currently selected edge template for
574		 * new edges.
575		 *
576		 * @param graph
577		 * @param parent
578		 * @param id
579		 * @param value
580		 * @param source
581		 * @param target
582		 * @param style
583		 * @return
584		 */
585		public Object createEdge(Object parent, String id, Object value,
586				Object source, Object target, String style)
587		{
588			if (edgeTemplate != null)
589			{
590				mxCell edge = (mxCell) cloneCells(new Object[] { edgeTemplate })[0];
591				edge.setId(id);
592
593				return edge;
594			}
595
596			return super.createEdge(parent, id, value, source, target, style);
597		}
598
599	}
600
601	/**
602	 *
603	 * @param args
604	 */
605	public static void main(String[] args)
606	{
607		try
608		{
609			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
610		}
611		catch (Exception e1)
612		{
613			e1.printStackTrace();
614		}
615
616		mxConstants.SHADOW_COLOR = Color.LIGHT_GRAY;
617		GraphEditor editor = new GraphEditor();
618		editor.createFrame(new EditorMenuBar(editor)).setVisible(true);
619	}
620}
621