1 package com.mxgraph.examples.swing.editor;
2 
3 import java.awt.BorderLayout;
4 import java.awt.Point;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.awt.event.ComponentAdapter;
8 import java.awt.event.ComponentEvent;
9 import java.awt.event.MouseAdapter;
10 import java.awt.event.MouseEvent;
11 import java.awt.event.MouseMotionListener;
12 import java.awt.event.MouseWheelEvent;
13 import java.awt.event.MouseWheelListener;
14 import java.io.File;
15 import java.net.ProxySelector;
16 import java.net.URL;
17 import java.util.List;
18 import java.util.StringTokenizer;
19 
20 import javax.swing.AbstractAction;
21 import javax.swing.Action;
22 import javax.swing.BorderFactory;
23 import javax.swing.ImageIcon;
24 import javax.swing.JApplet;
25 import javax.swing.JCheckBoxMenuItem;
26 import javax.swing.JFrame;
27 import javax.swing.JLabel;
28 import javax.swing.JMenuBar;
29 import javax.swing.JOptionPane;
30 import javax.swing.JPanel;
31 import javax.swing.JPopupMenu;
32 import javax.swing.JScrollPane;
33 import javax.swing.JSplitPane;
34 import javax.swing.JTabbedPane;
35 import javax.swing.JToolBar;
36 import javax.swing.SwingUtilities;
37 import javax.swing.UIManager;
38 
39 import org.apache.commons.codec.DecoderException;
40 import org.apache.commons.codec.binary.Hex;
41 import org.apache.commons.codec.net.URLCodec;
42 
43 import com.mxgraph.layout.mxCircleLayout;
44 import com.mxgraph.layout.mxCompactTreeLayout;
45 import com.mxgraph.layout.mxEdgeLabelLayout;
46 import com.mxgraph.layout.mxIGraphLayout;
47 import com.mxgraph.layout.mxOrganicLayout;
48 import com.mxgraph.layout.mxParallelEdgeLayout;
49 import com.mxgraph.layout.mxPartitionLayout;
50 import com.mxgraph.layout.mxStackLayout;
51 import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
52 import com.mxgraph.swing.mxGraphComponent;
53 import com.mxgraph.swing.mxGraphOutline;
54 import com.mxgraph.swing.handler.mxKeyboardHandler;
55 import com.mxgraph.swing.handler.mxRubberband;
56 import com.mxgraph.swing.util.mxMorphing;
57 import com.mxgraph.util.mxEvent;
58 import com.mxgraph.util.mxEventObject;
59 import com.mxgraph.util.mxEventSource.mxIEventListener;
60 import com.mxgraph.util.mxRectangle;
61 import com.mxgraph.util.mxResources;
62 import com.mxgraph.util.mxUndoManager;
63 import com.mxgraph.util.mxUndoableEdit;
64 import com.mxgraph.util.mxUndoableEdit.mxUndoableChange;
65 import com.mxgraph.view.mxGraph;
66 
67 public class BasicGraphEditor extends JPanel
68 {
69 
70 	/**
71 	 *
72 	 */
73 	private static final long serialVersionUID = -6561623072112577140L;
74 
75 	/**
76 	 * Adds required resources for i18n
77 	 */
78 	static
79 	{
80 		mxResources.add("com/mxgraph/examples/swing/resources/editor");
81 	}
82 
83 	/**
84 	 *
85 	 */
86 	protected mxGraphComponent graphComponent;
87 
88 	/**
89 	 *
90 	 */
91 	protected mxGraphOutline graphOutline;
92 
93 	/**
94 	 *
95 	 */
96 	protected JTabbedPane libraryPane;
97 
98 	/**
99 	 *
100 	 */
101 	protected mxUndoManager undoManager;
102 
103 	/**
104 	 *
105 	 */
106 	protected String appTitle;
107 
108 	/**
109 	 *
110 	 */
111 	protected JLabel statusBar;
112 
113 	/**
114 	 *
115 	 */
116 	protected File currentFile;
117 
118 	/**
119 	 *
120 	 */
121 	protected boolean modified = false;
122 
123 	/**
124 	 *
125 	 */
126 	protected mxRubberband rubberband;
127 
128 	/**
129 	 *
130 	 */
131 	protected mxKeyboardHandler keyboardHandler;
132 
133 	/**
134 	 *
135 	 */
136 	protected mxIEventListener undoHandler = new mxIEventListener()
137 	{
138 		public void invoke(Object source, mxEventObject evt)
139 		{
140 			undoManager.undoableEditHappened((mxUndoableEdit) evt
141 					.getProperty("edit"));
142 		}
143 	};
144 
145 	/**
146 	 *
147 	 */
148 	protected mxIEventListener changeTracker = new mxIEventListener()
149 	{
150 		public void invoke(Object source, mxEventObject evt)
151 		{
152 			setModified(true);
153 		}
154 	};
155 
156 	/**
157 	 *
158 	 */
BasicGraphEditor(String appTitle, mxGraphComponent component, Config config)159 	public BasicGraphEditor(String appTitle, mxGraphComponent component, Config config)
160 	{
161 		this.config = config;
162 
163 		// Stores and updates the frame title
164 		this.appTitle = appTitle;
165 
166 		// Stores a reference to the graph and creates the command history
167 		graphComponent = component;
168 		final mxGraph graph = graphComponent.getGraph();
169 		undoManager = createUndoManager();
170 
171 		// Do not change the scale and translation after files have been loaded
172 		graph.setResetViewOnRootChange(false);
173 
174 		// Updates the modified flag if the graph model changes
175 		graph.getModel().addListener(mxEvent.CHANGE, changeTracker);
176 
177 		// Adds the command history to the model and view
178 		graph.getModel().addListener(mxEvent.UNDO, undoHandler);
179 		graph.getView().addListener(mxEvent.UNDO, undoHandler);
180 
181 		// Keeps the selection in sync with the command history
182 		mxIEventListener undoHandler = new mxIEventListener()
183 		{
184 			public void invoke(Object source, mxEventObject evt)
185 			{
186 				List<mxUndoableChange> changes = ((mxUndoableEdit) evt
187 						.getProperty("edit")).getChanges();
188 				graph.setSelectionCells(graph
189 						.getSelectionCellsForChanges(changes));
190 			}
191 		};
192 
193 		undoManager.addListener(mxEvent.UNDO, undoHandler);
194 		undoManager.addListener(mxEvent.REDO, undoHandler);
195 
196 		// Creates the graph outline component
197 		graphOutline = new mxGraphOutline(graphComponent);
198 
199 		// Creates the library pane that contains the tabs with the palettes
200 		libraryPane = new JTabbedPane();
201 
202 		// Creates the inner split pane that contains the library with the
203 		// palettes and the graph outline on the left side of the window
204 		JSplitPane inner = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
205 				libraryPane, graphOutline);
206 		inner.setDividerLocation(320);
207 		inner.setResizeWeight(1);
208 		inner.setDividerSize(6);
209 		inner.setBorder(null);
210 
211 		// Creates the outer split pane that contains the inner split pane and
212 		// the graph component on the right side of the window
213 		JSplitPane outer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, inner, graphComponent);
214 		outer.setOneTouchExpandable(true);
215 		outer.setDividerLocation(200);
216 		outer.setDividerSize(6);
217 		outer.setBorder(null);
218 
219 		// Creates the status bar
220 		statusBar = createStatusBar();
221 
222 		// Display some useful information about repaint events
223 		installRepaintListener();
224 
225 		// Puts everything together
226 		setLayout(new BorderLayout());
227 		add(outer, BorderLayout.CENTER);
228 		add(statusBar, BorderLayout.SOUTH);
229 		installToolBar();
230 
231 		// Installs rubberband selection and handling for some special
232 		// keystrokes such as F2, Control-C, -V, X, A etc.
233 		installHandlers();
234 		installListeners();
235 //		updateTitle();
236 	}
237 
238 	/**
239 	 *
240 	 */
createUndoManager()241 	protected mxUndoManager createUndoManager()
242 	{
243 		return new mxUndoManager();
244 	}
245 
246 	/**
247 	 *
248 	 */
installHandlers()249 	protected void installHandlers()
250 	{
251 		rubberband = new mxRubberband(graphComponent);
252 		keyboardHandler = new EditorKeyboardHandler(graphComponent);
253 	}
254 
255 	/**
256 	 *
257 	 */
installToolBar()258 	protected void installToolBar()
259 	{
260 		add(new EditorToolBar(this, JToolBar.HORIZONTAL), BorderLayout.NORTH);
261 	}
262 
263 	/**
264 	 *
265 	 */
createStatusBar()266 	protected JLabel createStatusBar()
267 	{
268 		JLabel statusBar = new JLabel(mxResources.get("ready"));
269 		statusBar.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4));
270 
271 		return statusBar;
272 	}
273 
274 	/**
275 	 *
276 	 */
installRepaintListener()277 	protected void installRepaintListener()
278 	{
279 		graphComponent.getGraph().addListener(mxEvent.REPAINT,
280 				new mxIEventListener()
281 				{
282 					public void invoke(Object source, mxEventObject evt)
283 					{
284 						String buffer = (graphComponent.getTripleBuffer() != null) ? ""
285 								: " (unbuffered)";
286 						mxRectangle dirty = (mxRectangle) evt
287 								.getProperty("region");
288 
289 						if (dirty == null)
290 						{
291 							status("Repaint all" + buffer);
292 						}
293 						else
294 						{
295 							status("Repaint: x=" + (int) (dirty.getX()) + " y="
296 									+ (int) (dirty.getY()) + " w="
297 									+ (int) (dirty.getWidth()) + " h="
298 									+ (int) (dirty.getHeight()) + buffer);
299 						}
300 					}
301 				});
302 	}
303 
304 	/**
305 	 *
306 	 */
insertPalette(String title)307 	public EditorPalette insertPalette(String title)
308 	{
309 		final EditorPalette palette = new EditorPalette();
310 		final JScrollPane scrollPane = new JScrollPane(palette);
311 		scrollPane
312 				.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
313 		scrollPane
314 				.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
315 		libraryPane.add(title, scrollPane);
316 
317 		// Updates the widths of the palettes if the container size changes
318 		libraryPane.addComponentListener(new ComponentAdapter()
319 		{
320 			/**
321 			 *
322 			 */
323 			public void componentResized(ComponentEvent e)
324 			{
325 				int w = scrollPane.getWidth()
326 						- scrollPane.getVerticalScrollBar().getWidth();
327 				palette.setPreferredWidth(w);
328 			}
329 
330 		});
331 
332 		return palette;
333 	}
334 
335 	/**
336 	 *
337 	 */
mouseWheelMoved(MouseWheelEvent e)338 	protected void mouseWheelMoved(MouseWheelEvent e)
339 	{
340 		if (e.getWheelRotation() < 0)
341 		{
342 			graphComponent.zoomIn();
343 		}
344 		else
345 		{
346 			graphComponent.zoomOut();
347 		}
348 
349 		status(mxResources.get("scale") + ": "
350 				+ (int) (100 * graphComponent.getGraph().getView().getScale())
351 				+ "%");
352 	}
353 
354 	/**
355 	 *
356 	 */
showOutlinePopupMenu(MouseEvent e)357 	protected void showOutlinePopupMenu(MouseEvent e)
358 	{
359 		Point pt = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(),
360 				graphComponent);
361 		JCheckBoxMenuItem item = new JCheckBoxMenuItem(mxResources
362 				.get("magnifyPage"));
363 		item.setSelected(graphOutline.isFitPage());
364 
365 		item.addActionListener(new ActionListener()
366 		{
367 			/**
368 			 *
369 			 */
370 			public void actionPerformed(ActionEvent e)
371 			{
372 				graphOutline.setFitPage(!graphOutline.isFitPage());
373 				graphOutline.repaint();
374 			}
375 		});
376 
377 		JCheckBoxMenuItem item2 = new JCheckBoxMenuItem(mxResources
378 				.get("showLabels"));
379 		item2.setSelected(graphOutline.isDrawLabels());
380 
381 		item2.addActionListener(new ActionListener()
382 		{
383 			/**
384 			 *
385 			 */
386 			public void actionPerformed(ActionEvent e)
387 			{
388 				graphOutline.setDrawLabels(!graphOutline.isDrawLabels());
389 				graphOutline.repaint();
390 			}
391 		});
392 
393 		JCheckBoxMenuItem item3 = new JCheckBoxMenuItem(mxResources
394 				.get("buffering"));
395 		item3.setSelected(graphOutline.isTripleBuffered());
396 
397 		item3.addActionListener(new ActionListener()
398 		{
399 			/**
400 			 *
401 			 */
402 			public void actionPerformed(ActionEvent e)
403 			{
404 				graphOutline
405 						.setTripleBuffered(!graphOutline.isTripleBuffered());
406 				graphOutline.repaint();
407 			}
408 		});
409 
410 		JPopupMenu menu = new JPopupMenu();
411 		menu.add(item);
412 		menu.add(item2);
413 		menu.add(item3);
414 		menu.show(graphComponent, pt.x, pt.y);
415 
416 		e.consume();
417 	}
418 
419 	/**
420 	 *
421 	 */
showGraphPopupMenu(MouseEvent e)422 	protected void showGraphPopupMenu(MouseEvent e)
423 	{
424 		Point pt = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(),
425 				graphComponent);
426 		EditorPopupMenu menu = new EditorPopupMenu(BasicGraphEditor.this);
427 		menu.show(graphComponent, pt.x, pt.y);
428 
429 		e.consume();
430 	}
431 
432 	/**
433 	 *
434 	 */
mouseLocationChanged(MouseEvent e)435 	protected void mouseLocationChanged(MouseEvent e)
436 	{
437 		status(e.getX() + ", " + e.getY());
438 	}
439 
440 	/**
441 	 *
442 	 */
installListeners()443 	protected void installListeners()
444 	{
445 		// Installs mouse wheel listener for zooming
446 		MouseWheelListener wheelTracker = new MouseWheelListener()
447 		{
448 			/**
449 			 *
450 			 */
451 			public void mouseWheelMoved(MouseWheelEvent e)
452 			{
453 				if (e.getSource() instanceof mxGraphOutline
454 						|| e.isControlDown())
455 				{
456 					BasicGraphEditor.this.mouseWheelMoved(e);
457 				}
458 			}
459 
460 		};
461 
462 		// Handles mouse wheel events in the outline and graph component
463 		graphOutline.addMouseWheelListener(wheelTracker);
464 		graphComponent.addMouseWheelListener(wheelTracker);
465 
466 		// Installs the popup menu in the outline
467 		graphOutline.addMouseListener(new MouseAdapter()
468 		{
469 
470 			/**
471 			 *
472 			 */
473 			public void mousePressed(MouseEvent e)
474 			{
475 				// Handles context menu on the Mac where the trigger is on mousepressed
476 				mouseReleased(e);
477 			}
478 
479 			/**
480 			 *
481 			 */
482 			public void mouseReleased(MouseEvent e)
483 			{
484 				if (e.isPopupTrigger())
485 				{
486 					showOutlinePopupMenu(e);
487 				}
488 			}
489 
490 		});
491 
492 		// Installs the popup menu in the graph component
493 		graphComponent.getGraphControl().addMouseListener(new MouseAdapter()
494 		{
495 
496 			/**
497 			 *
498 			 */
499 			public void mousePressed(MouseEvent e)
500 			{
501 				// Handles context menu on the Mac where the trigger is on mousepressed
502 				mouseReleased(e);
503 			}
504 
505 			/**
506 			 *
507 			 */
508 			public void mouseReleased(MouseEvent e)
509 			{
510 				if (e.isPopupTrigger())
511 				{
512 					showGraphPopupMenu(e);
513 				}
514 			}
515 
516 		});
517 
518 		// Installs a mouse motion listener to display the mouse location
519 		graphComponent.getGraphControl().addMouseMotionListener(
520 				new MouseMotionListener()
521 				{
522 
523 					/*
524 					 * (non-Javadoc)
525 					 * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
526 					 */
527 					public void mouseDragged(MouseEvent e)
528 					{
529 						mouseLocationChanged(e);
530 					}
531 
532 					/*
533 					 * (non-Javadoc)
534 					 * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
535 					 */
536 					public void mouseMoved(MouseEvent e)
537 					{
538 						mouseDragged(e);
539 					}
540 
541 				});
542 	}
543 
544 //	/**
545 //	 *
546 //	 */
547 //	public void setCurrentFile(File file)
548 //	{
549 //		File oldValue = currentFile;
550 //		currentFile = file;
551 //
552 //		firePropertyChange("currentFile", oldValue, file);
553 //
554 //		if (oldValue != file)
555 //		{
556 //			updateTitle();
557 //		}
558 //	}
559 
560 	/**
561 	 *
562 	 */
getCurrentFile()563 	public File getCurrentFile()
564 	{
565 		return currentFile;
566 	}
567 
568 	/**
569 	 *
570 	 * @param modified
571 	 */
setModified(boolean modified)572 	public void setModified(boolean modified)
573 	{
574 		boolean oldValue = this.modified;
575 		this.modified = modified;
576 
577 		firePropertyChange("modified", oldValue, modified);
578 
579 //		if (oldValue != modified)
580 //		{
581 //			updateTitle();
582 //		}
583 	}
584 
585 	/**
586 	 *
587 	 * @return
588 	 */
isModified()589 	public boolean isModified()
590 	{
591 		return modified;
592 	}
593 
594 	/**
595 	 *
596 	 */
getGraphComponent()597 	public mxGraphComponent getGraphComponent()
598 	{
599 		return graphComponent;
600 	}
601 
602 	/**
603 	 *
604 	 */
getGraphOutline()605 	public mxGraphOutline getGraphOutline()
606 	{
607 		return graphOutline;
608 	}
609 
610 	/**
611 	 *
612 	 */
getLibraryPane()613 	public JTabbedPane getLibraryPane()
614 	{
615 		return libraryPane;
616 	}
617 
618 	/**
619 	 *
620 	 */
getUndoManager()621 	public mxUndoManager getUndoManager()
622 	{
623 		return undoManager;
624 	}
625 
626 	/**
627 	 *
628 	 * @param name
629 	 * @param action
630 	 * @return
631 	 */
bind(String name, final Action action)632 	public Action bind(String name, final Action action)
633 	{
634 		return bind(name, action, null);
635 	}
636 
637 	/**
638 	 *
639 	 * @param name
640 	 * @param action
641 	 * @return
642 	 */
643 	@SuppressWarnings("serial")
bind(String name, final Action action, String iconUrl)644 	public Action bind(String name, final Action action, String iconUrl)
645 	{
646 		return new AbstractAction(name, (iconUrl != null) ? new ImageIcon(
647 				BasicGraphEditor.class.getResource(iconUrl)) : null)
648 		{
649 			public void actionPerformed(ActionEvent e)
650 			{
651 				action.actionPerformed(new ActionEvent(getGraphComponent(), e
652 						.getID(), e.getActionCommand()));
653 			}
654 		};
655 	}
656 
657 	/**
658 	 *
659 	 * @param msg
660 	 */
661 	public void status(String msg)
662 	{
663 		statusBar.setText(msg);
664 	}
665 
666 //	/**
667 //	 *
668 //	 */
669 //	public void updateTitle()
670 //	{
671 //		JFrame frame = (JFrame) SwingUtilities.windowForComponent(this);
672 //
673 //		if (frame != null)
674 //		{
675 //			String title = (currentFile != null) ? currentFile
676 //					.getAbsolutePath() : mxResources.get("newDiagram");
677 //
678 //			if (modified)
679 //			{
680 //				title += "*";
681 //			}
682 //
683 //			frame.setTitle(title + " - " + appTitle);
684 //		}
685 //	}
686 
687 	/**
688 	 *
689 	 */
690 	public void about()
691 	{
692 		JFrame frame = (JFrame) SwingUtilities.windowForComponent(this);
693 
694 		if (frame != null)
695 		{
696 			EditorAboutFrame about = new EditorAboutFrame(frame);
697 			about.setModal(true);
698 
699 			// Centers inside the application frame
700 			int x = frame.getX() + (frame.getWidth() - about.getWidth()) / 2;
701 			int y = frame.getY() + (frame.getHeight() - about.getHeight()) / 2;
702 			about.setLocation(x, y);
703 
704 			// Shows the modal dialog and waits
705 			about.setVisible(true);
706 		}
707 	}
708 
709 	/**
710 	 *
711 	 */
712 	public void exit()
713 	{
714 		JFrame frame = (JFrame) SwingUtilities.windowForComponent(this);
715 
716 		if (frame != null)
717 		{
718 			frame.dispose();
719 		}
720 	}
721 
722 	/**
723 	 *
724 	 */
725 	public void setLookAndFeel(String clazz)
726 	{
727 		JFrame frame = (JFrame) SwingUtilities.windowForComponent(this);
728 
729 		if (frame != null)
730 		{
731 			try
732 			{
733 				UIManager.setLookAndFeel(clazz);
734 				SwingUtilities.updateComponentTreeUI(frame);
735 
736 				// Needs to assign the key bindings again
737 				keyboardHandler = new EditorKeyboardHandler(graphComponent);
738 			}
739 			catch (Exception e1)
740 			{
741 				e1.printStackTrace();
742 			}
743 		}
744 	}
745 
746 	/**
747 	 *
748 	 */
749 	public JFrame createFrame(JMenuBar menuBar)
750 	{
751 		JFrame frame = new JFrame();
752 		frame.getContentPane().add(this);
753 		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
754 		frame.setJMenuBar(menuBar);
755 		frame.setSize(870, 640);
756 
757 		// Updates the frame title
758 //		updateTitle();
759 
760 		return frame;
761 	}
762 
763 	/**
764 	 * Creates an action that executes the specified layout.
765 	 *
766 	 * @param key Key to be used for getting the label from mxResources and also
767 	 * to create the layout instance for the commercial graph editor example.
768 	 * @return an action that executes the specified layout
769 	 */
770 	@SuppressWarnings("serial")
771 	public Action graphLayout(final String key, boolean animate)
772 	{
773 		final mxIGraphLayout layout = createLayout(key, animate);
774 
775 		if (layout != null)
776 		{
777 			return new AbstractAction(mxResources.get(key))
778 			{
779 				public void actionPerformed(ActionEvent e)
780 				{
781 					final mxGraph graph = graphComponent.getGraph();
782 					Object cell = graph.getSelectionCell();
783 
784 					if (cell == null
785 							|| graph.getModel().getChildCount(cell) == 0)
786 					{
787 						cell = graph.getDefaultParent();
788 					}
789 
790 					graph.getModel().beginUpdate();
791 					try
792 					{
793 						long t0 = System.currentTimeMillis();
794 						layout.execute(cell);
795 						status("Layout: " + (System.currentTimeMillis() - t0)
796 								+ " ms");
797 					}
798 					finally
799 					{
800 						mxMorphing morph = new mxMorphing(graphComponent, 20,
801 								1.2, 20);
802 
803 						morph.addListener(mxEvent.DONE, new mxIEventListener()
804 						{
805 
806 							public void invoke(Object sender, mxEventObject evt)
807 							{
808 								graph.getModel().endUpdate();
809 							}
810 
811 						});
812 
813 						morph.startAnimation();
814 					}
815 
816 				}
817 
818 			};
819 		}
820 		else
821 		{
822 			return new AbstractAction(mxResources.get(key))
823 			{
824 
825 				public void actionPerformed(ActionEvent e)
826 				{
827 					JOptionPane.showMessageDialog(graphComponent,
828 							mxResources.get("noLayout"));
829 				}
830 
831 			};
832 		}
833 	}
834 
835 	/**
836 	 * Creates a layout instance for the given identifier.
837 	 */
838 	protected mxIGraphLayout createLayout(String ident, boolean animate)
839 	{
840 		mxIGraphLayout layout = null;
841 
842 		if (ident != null)
843 		{
844 			mxGraph graph = graphComponent.getGraph();
845 
846 			if (ident.equals("verticalHierarchical"))
847 			{
848 				layout = new mxHierarchicalLayout(graph);
849 			}
850 			else if (ident.equals("horizontalHierarchical"))
851 			{
852 				layout = new mxHierarchicalLayout(graph, JLabel.WEST);
853 			}
854 			else if (ident.equals("verticalTree"))
855 			{
856 				layout = new mxCompactTreeLayout(graph, false);
857 			}
858 			else if (ident.equals("horizontalTree"))
859 			{
860 				layout = new mxCompactTreeLayout(graph, true);
861 			}
862 			else if (ident.equals("parallelEdges"))
863 			{
864 				layout = new mxParallelEdgeLayout(graph);
865 			}
866 			else if (ident.equals("placeEdgeLabels"))
867 			{
868 				layout = new mxEdgeLabelLayout(graph);
869 			}
870 			else if (ident.equals("organicLayout"))
871 			{
872 				layout = new mxOrganicLayout(graph);
873 			}
874 			if (ident.equals("verticalPartition"))
875 			{
876 				layout = new mxPartitionLayout(graph, false)
877 				{
878 					/**
879 					 * Overrides the empty implementation to return the size of the
880 					 * graph control.
881 					 */
882 					public mxRectangle getContainerSize()
883 					{
884 						return graphComponent.getLayoutAreaSize();
885 					}
886 				};
887 			}
888 			else if (ident.equals("horizontalPartition"))
889 			{
890 				layout = new mxPartitionLayout(graph, true)
891 				{
892 					/**
893 					 * Overrides the empty implementation to return the size of the
894 					 * graph control.
895 					 */
896 					public mxRectangle getContainerSize()
897 					{
898 						return graphComponent.getLayoutAreaSize();
899 					}
900 				};
901 			}
902 			else if (ident.equals("verticalStack"))
903 			{
904 				layout = new mxStackLayout(graph, false)
905 				{
906 					/**
907 					 * Overrides the empty implementation to return the size of the
908 					 * graph control.
909 					 */
910 					public mxRectangle getContainerSize()
911 					{
912 						return graphComponent.getLayoutAreaSize();
913 					}
914 				};
915 			}
916 			else if (ident.equals("horizontalStack"))
917 			{
918 				layout = new mxStackLayout(graph, true)
919 				{
920 					/**
921 					 * Overrides the empty implementation to return the size of the
922 					 * graph control.
923 					 */
924 					public mxRectangle getContainerSize()
925 					{
926 						return graphComponent.getLayoutAreaSize();
927 					}
928 				};
929 			}
930 			else if (ident.equals("circleLayout"))
931 			{
932 				layout = new mxCircleLayout(graph);
933 			}
934 		}
935 
936 		return layout;
937 	}
938 
939 	public static class Config {
940 
941 		private JApplet applet;
942 		private ProxySelector proxySelector;
943 
944 		public Config(JApplet applet /*, HttpClient httpClient*/) {
945 			this.applet = applet;
946 //			this.httpClient = httpClient;
947 			try {
948 				// Proxy configuration - requires java.net.NetPermission getProxySelector
949 				proxySelector = ProxySelector.getDefault();
950 			} catch (Exception e) {
951 				System.err.println("Can't obtain proxy information: "+e);
952 				e.printStackTrace();
953 			}
954 		}
955 
956 		public ProxySelector getProxySelector() {
957 			return proxySelector;
958 		}
959 
960 //		private HttpClient httpClient;
961 //
962 //		public HttpClient getHttpClient() {
963 //			return httpClient;
964 //		}
965 
966 //		public URL getDocumentBase() {
967 //			return applet.getDocumentBase();
968 //		}
969 
970 		public String getDokuHost() {
971 			return applet.getParameter("host");
972 		}
973 
974 		public String getDokuBase() {
975 			return applet.getParameter("dokuBase");
976 		}
977 
978 		public String getImageFormat() {
979 			return applet.getParameter("imageFormat");
980 		}
981 
982 		public String getPalettes() {
983 			return applet.getParameter("palettes");
984 		}
985 
986 		public String getAuthtok() {
987 			return applet.getParameter("authtok");
988 		}
989 
990 		public String getSectok() {
991 			return applet.getParameter("sectok");
992 		}
993 
994 		public String getName() throws DecoderException {
995 			return new String(Hex.decodeHex(applet.getParameter("name").toCharArray()));
996 		}
997 
998 		public String getSessionName() {
999 			return applet.getParameter("sessionName");
1000 		}
1001 
1002 		public String getSessionId() {
1003 			return applet.getParameter("sessionId");
1004 		}
1005 
1006 		private String hex2urlEncoded(String hexStr) throws DecoderException {
1007 			return new String(URLCodec.encodeUrl(null, Hex.decodeHex(hexStr.toCharArray())));
1008 		}
1009 
1010 		public String getCookies() throws DecoderException {
1011 			String cookiesStr = applet.getParameter("cookies");
1012 			if (cookiesStr==null) {
1013 				return null;
1014 			}
1015 
1016 			StringBuilder ret = new StringBuilder();
1017 			StringTokenizer st = new StringTokenizer(cookiesStr, ";");
1018 			while (st.hasMoreTokens()) {
1019 				String tok = st.nextToken();
1020 				int idx = tok.indexOf("=");
1021 				ret.append(hex2urlEncoded(tok.substring(0, idx)));
1022 				ret.append("=");
1023 				ret.append(hex2urlEncoded(tok.substring(idx+1)));
1024 				if (st.hasMoreElements()) {
1025 					ret.append(";");
1026 				}
1027 			}
1028 
1029 			return ret.toString();
1030 		}
1031 
1032 		public boolean isNew() {
1033 			return "yes".equals(applet.getParameter("isNew"));
1034 		}
1035 
1036 	}
1037 
1038 	private Config config;
1039 
1040 	public Config getConfig() {
1041 		return config;
1042 	}
1043 
1044 }
1045