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