package agg.gui.parser; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.List; import java.util.Vector; //import javax.swing.ImageIcon; import javax.swing.JDesktopPane; import javax.swing.JInternalFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.event.InternalFrameEvent; import javax.swing.event.InternalFrameListener; import agg.editor.impl.EdGraGra; import agg.editor.impl.EdGraph; import agg.editor.impl.EdNode; import agg.gui.IconResource; import agg.gui.editor.GraphCanvas; import agg.gui.editor.GraphEditor; import agg.gui.editor.GraphPanel; import agg.gui.options.ParserGUIOption; import agg.gui.parser.event.StatusMessageEvent; import agg.gui.parser.event.StatusMessageListener; import agg.parser.Parser; import agg.parser.ParserErrorEvent; import agg.parser.ParserEvent; import agg.parser.ParserEventListener; import agg.parser.ParserMessageEvent; import agg.xt_basis.Graph; import agg.xt_basis.OrdinaryMorphism; //****************************************************************************+ /** * This desktop provides a view into the parsing process. There are two windows * available. One shows the host graph, the second shows the stop graph for * compare how close the host graph is. Attention, please check the option to be * sure that the parsing process is set visible. * * @author $Author: olga $ * @version $Id: ParserDesktop.java,v 1.22 2010/09/23 08:20:53 olga Exp $ */ public class ParserDesktop implements InternalFrameListener, ParserEventListener { private static final int STOP_GRAPH = 1; private static final int HOST_GRAPH = 2; private AGGParser aggparser; /** main desktop */ final JDesktopPane desktop = new JDesktopPane(); /** the frame icon for the host graph */ // private ImageIcon hostIcon; /** the frame icon for the stop graph */ // private ImageIcon stopIcon; /** layout of the two graphs */ private EdGraGra layout; /** size of the two graph windows */ private Dimension internalFrameSize; private ParserGUIOption option; private Parser parser; protected JInternalFrame hostFrame; private GraphEditor hostGraphEditor; private EdGraph hostGraphLayout; // private Graph hostGraph; protected JInternalFrame stopFrame; private GraphEditor stopGraphEditor; private EdGraph stopGraphLayout; // private Graph stopGraph; private boolean graphFramesExist; private Vector<StatusMessageListener> listener; private KeyAdapter keyAdapter; private String typedKey; private MouseListener ml; protected JPopupMenu graphMenu = new JPopupMenu("Graph"); protected JMenuItem miLayoutGraph = new JMenuItem("Layout Graph"); protected GraphPanel activeGraphPanel; /** * Creates a empty desktop configured with the option. * * @param option * The option to configure the desktop. */ public ParserDesktop(AGGParser aggparser, ParserGUIOption option) { this(aggparser, option, null, null, null); } /** * Creates a new desktop. This desktop shows the host and stop graph as it * is configured in the option. The layout for the graphs is given by the * graph grammar. * * @param aggparser * the parser instance * @param option * the option to configure the desktop * @param aLayout * the grammar provides the layout for the graphs * @param aHostGraph * the host graph of the parsing process * @param aStopGraph * the stop graph of the parsing process */ public ParserDesktop(final AGGParser aggparser, final ParserGUIOption option, final EdGraGra aLayout, final Graph aHostGraph, final Graph aStopGraph) { this.desktop.setBackground(Color.white); this.desktop.setForeground(Color.white); this.aggparser = aggparser; this.option = option; setInternalFrameSize(new Dimension(200, 200)); this.keyAdapter = new KeyAdapter() { public void keyReleased(KeyEvent e) { performShortKeyEvent(e); } }; this.desktop.addKeyListener(this.keyAdapter); makeGraphMenu(); this.ml = new MouseAdapter() { public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) { if (e.getSource() instanceof GraphCanvas) { ParserDesktop.this.activeGraphPanel = ((GraphCanvas) e.getSource()) .getViewport(); ParserDesktop.this.graphMenu.show(ParserDesktop.this.activeGraphPanel, e.getX(), e.getY()); } } } public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger()) { if (e.getSource() instanceof GraphCanvas) { ParserDesktop.this.activeGraphPanel = ((GraphCanvas) e.getSource()) .getViewport(); ParserDesktop.this.graphMenu.show(ParserDesktop.this.activeGraphPanel, e.getX(), e.getY()); } } } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { ParserDesktop.this.desktop.requestFocusInWindow(); } }; this.desktop.addMouseListener(this.ml); this.listener = new Vector<StatusMessageListener>(); if (aHostGraph != null && aStopGraph != null) { this.makeGraphFrames(); setLayout(aLayout); setStopGraph(aStopGraph); setHostGraph(aHostGraph); } } private void makeGraphFrames() { makeStopGraphFrame(); makeHostGraphFrame(); this.graphFramesExist = true; } private void makeStopGraphFrame() { if (this.stopFrame == null) { // stop graph editor and frame this.stopGraphEditor = new GraphEditor(null); this.stopGraphEditor.setEditMode(agg.gui.editor.EditorConstants.VIEW); this.stopGraphEditor.getGraphPanel().setName(""); this.stopGraphEditor.removeTitlePanel(); this.stopGraphEditor.getGraphPanel().getCanvas().addMouseListener(this.ml); this.stopFrame = new JInternalFrame("Stop Graph", true, false, true, true); this.stopFrame.setFrameIcon(IconResource.getIconFromURL(IconResource .getStopIcon())); this.stopFrame.setBackground(Color.white); this.stopFrame.setForeground(Color.white); this.stopFrame.addInternalFrameListener(this); this.stopFrame.addMouseListener(this.ml); this.stopFrame.addKeyListener(this.keyAdapter); this.stopFrame.setVisible(false); this.stopFrame.setSize(this.internalFrameSize); this.stopFrame.getContentPane().add(this.stopGraphEditor); this.stopFrame.pack(); this.desktop.add(this.stopFrame, Integer.valueOf(STOP_GRAPH)); } } private void makeHostGraphFrame() { if (this.hostFrame == null) { // host graph editor and frame this.hostGraphEditor = new GraphEditor(null); this.hostGraphEditor.setEditMode(agg.gui.editor.EditorConstants.VIEW); this.hostGraphEditor.removeTitlePanel(); this.hostGraphEditor.getGraphPanel().setName(""); this.hostGraphEditor.getGraphPanel().getCanvas().addMouseListener(this.ml); this.hostFrame = new JInternalFrame("Host Graph", true, false, true, true); this.hostFrame.setFrameIcon(IconResource.getIconFromURL(IconResource .getWorkerIcon())); this.hostFrame.setBackground(Color.white); this.hostFrame.setForeground(Color.white); this.hostFrame.addInternalFrameListener(this); this.hostFrame.addMouseListener(this.ml); this.hostFrame.addKeyListener(this.keyAdapter); this.hostFrame.setVisible(false); this.hostFrame.setPreferredSize(new Dimension(600, 400)); this.hostFrame.setLocation(200, 0); this.hostFrame.getContentPane().add(this.hostGraphEditor); this.hostFrame.pack(); this.desktop.add(this.hostFrame, Integer.valueOf(HOST_GRAPH)); } } boolean performShortKeyEvent(KeyEvent e) { int keyCode = e.getKeyCode(); // System.out.println("ParserDesktop:: Shift: "+ e.isShiftDown()+" Ctrl: // "+e.isControlDown()+" Alt: "+ e.isAltDown()); // System.out.println("ParserDesktop:: keyReleased:: key: Code: // "+keyCode+" Char: "+e.getKeyChar()+" Text: // "+KeyEvent.getKeyText(keyCode)/*+" ModifiersText: // "+KeyEvent.getKeyModifiersText(keyCode)*/); if (e.isShiftDown() && e.isAltDown()) { this.typedKey = KeyEvent.getKeyText(keyCode); // System.out.println("ShiftDown() && AltDown:: typedKey: // "+typedKey); if (this.typedKey.equals("S")) this.aggparser.startParser(); else if (this.typedKey.equals("Q")) this.aggparser.stopParser(); else if (this.typedKey.equals("Z")) this.aggparser.backToGUI(); else return false; } return true; } /** * Returns the component of the graph desktop. This component can be * displayed in a frame or panel. * * @return This component is a JDesktopPane. */ public Component getComponent() { return getDesktop(); } // ****************************************************************************+ /** * Returns the desktop with the graphs of this gui. * * @return The JDesktopPane */ public JDesktopPane getDesktop() { return this.desktop; } /** * Sets the new layout for the host and stop graph. The layout is taken from * the graph grammar. * * @param layout * The graph grammar with layout. */ public void setLayout(EdGraGra layout) { this.layout = layout; this.hostGraphLayout = null; } public void setStopLayout(EdGraph layout) { this.stopGraphLayout = layout; } /** * The size of the internal windows is specified here. * * @param internalFrameSize * The size of the new window. */ public void setInternalFrameSize(Dimension internalFrameSize) { this.internalFrameSize = internalFrameSize; } private void setGraph(Graph graph, int graphType) { if (graphType != HOST_GRAPH && graphType != STOP_GRAPH) return; switch (graphType) { case STOP_GRAPH: if (this.stopGraphEditor.getGraph() != null) this.stopGraphEditor.setGraph(null); EdGraph eg = null; if (this.stopGraphLayout != null) { if (this.stopGraphLayout.getBasisGraph() == graph) eg = this.stopGraphLayout; else { eg = new EdGraph(graph, this.layout.getTypeSet()); eg.doDefaultEvolutionaryGraphLayout(20); } } else if (graph != null) { eg = new EdGraph(graph, this.layout.getTypeSet()); eg.doDefaultEvolutionaryGraphLayout(20); } if (eg != null && this.stopGraphLayout != null) eg.setLayoutByBasisObject(this.stopGraphLayout); if (this.option.getParserDisplay() == ParserGUIOption.SHOWHOSTGRAPH + ParserGUIOption.SHOWSTOPGRAPH) this.stopFrame.setVisible(true); else this.stopFrame.setVisible(false); // this.stopGraphLayout.setEditable(false); this.stopGraphEditor.setGraph(this.stopGraphLayout); // stopgege.getGraphPanel().updateGraphics(); break; case HOST_GRAPH: if (this.hostGraphEditor.getGraph() != null) this.hostGraphEditor.setGraph(null); if (this.hostGraphLayout == null && graph != null) { this.hostGraphLayout = new EdGraph(graph, this.layout.getTypeSet()); this.hostGraphLayout.setTransformChangeEnabled(true); this.hostGraphLayout.setLayoutByIndex(this.layout.getGraph(), false); } if (this.option.getParserDisplay() >= ParserGUIOption.SHOWHOSTGRAPH) this.hostFrame.setVisible(true); else this.hostFrame.setVisible(false); // hostGraphLayout.setEditable(false); if (this.hostGraphEditor.getGraph() == null) this.hostGraphEditor.setGraph(this.hostGraphLayout); else this.hostGraphEditor.getGraphPanel().setGraph(this.hostGraphLayout, false); this.hostGraphEditor.getGraphPanel().updateGraphics(); break; default: break; } } /** * Updates a internal frame with a new graph. * * @param om * The morphism holds the new graph. The morphism is necessary to * get the layout information from the old graph. * @param graphType * The graph type distinguish which graph will be updated. */ protected void updateFrame(OrdinaryMorphism om, int graphType) { if (graphType != HOST_GRAPH) return; if (this.hostGraphLayout.getBasisGraph() != om.getImage()) { EdGraph oldLayout = this.hostGraphLayout; this.hostGraphLayout = new EdGraph(om.getImage(), this.layout.getTypeSet()); this.hostGraphLayout.getBasisGraph().setName(""); if (!this.hostGraphLayout.updateLayoutByIsoMorphism(om, oldLayout)) this.hostGraphLayout.setLayoutByIndex(oldLayout, false); this.hostGraphLayout.resolveArcOverlappings(15); } this.hostGraphLayout.setTransformChangeEnabled(true); updateFrame(this.hostFrame, this.hostGraphLayout); } /** * Updates a internal frame with a graph. * * @param theFrame * The internal frame for the graph. * @param graphLayout * The new graph with layout. */ protected void updateFrame(JInternalFrame theFrame, EdGraph graphLayout) { if (theFrame == this.hostFrame) { hostFrameSetAnimationIcon(); this.hostGraphEditor.getGraphPanel().setGraph(graphLayout, false); } else if (theFrame == this.stopFrame) { this.stopGraphEditor.getGraphPanel().setGraph(graphLayout, false); } } /** * Updates an internal frame with a new graph. The internal frame is * selected by the graph type. * * @param graph * The new graph for the internal frame. * @param graphType * The graph type distinguishes the kind of graph. */ protected void updateFrame(Graph graph, int graphType) { if (graphType == HOST_GRAPH) { if (this.hostGraphLayout.getBasisGraph() != graph) { EdGraph eg = new EdGraph(graph, this.layout.getTypeSet()); eg.setLayoutByIndex(this.hostGraphLayout, false); eg.resolveArcOverlappings(15); this.hostGraphLayout = eg; this.hostGraphLayout.setTransformChangeEnabled(true); updateFrame(this.hostFrame, this.hostGraphLayout); } else { this.hostGraphLayout.resolveArcOverlappings(15); updateFrame(this.hostFrame,this. hostGraphLayout); } } } /** * The new host graph is set. A parser creates new graphs if a certain graph * must be copied. * * @param graph * The new graph. */ public void setHostGraph(Graph graph) { // hostGraph = graph; setGraph(graph, HOST_GRAPH); } /** * The new stop graph is set. * * @param graph * The new graph. */ public void setStopGraph(Graph graph) { // stopGraph = graph; setGraph(graph, STOP_GRAPH); } /** * Sets a new parser for the display. All important information like host * graph and so one are taken from the parser. * * @param parser * The parser to display. */ public void setParser(Parser parser) { if (!this.graphFramesExist) { this.makeGraphFrames(); } this.parser = parser; this.parser.addParserEventListener(this); setStopGraph(parser.getStopGraph()); setHostGraph(parser.getHostGraph()); } /** * Sets a new parser for the display. All important information like host * graph and so one are taken from the parser. * * @param parser * The parser to display. * @param om * The morphism holds the copy of the original host graph. */ public void setParser(Parser parser, OrdinaryMorphism om) { if (!this.graphFramesExist) { this.makeGraphFrames(); } this.parser = parser; this.parser.addParserEventListener(this); setStopGraph(parser.getStopGraph()); setHostGraph(om.getOriginal()); } /* * ====================================================================== * Internal Frame Listener * ====================================================================== */ /** * This method is inherited from the InternalFrameListener. But it is not * used. * * @param e * The event from the listener. */ public void internalFrameActivated(InternalFrameEvent e) { if (((JInternalFrame)e.getSource()) == this.hostFrame) { this.hostFrame.toFront(); } else if (((JInternalFrame)e.getSource()) == this.stopFrame) { this.stopFrame.toFront(); } } /** * This method is inherited from the InternalFrameListener. But it is not * used. * * @param e * The event from the listener. */ public void internalFrameClosed(InternalFrameEvent e) { // Invoked when an internal frame has been closed. } /** * This method is inherited from the InternalFrameListener. But it is not * used. * * @param e * The event from the listener. */ public void internalFrameClosing(InternalFrameEvent e) { // Invoked when an internal frame is in the process of being closed. } /** * This method is inherited from the InternalFrameListener. But it is not * used. * * @param e * The event from the listener. */ public void internalFrameDeactivated(InternalFrameEvent e) { } /** * This method is inherited from the InternalFrameListener. But it is not * used. * * @param e * The event from the listener. */ public void internalFrameDeiconified(InternalFrameEvent e) { // Invoked when an internal frame is de-iconified. } /** * This method is inherited from the InternalFrameListener. But it is not * used. * * @param e * The event from the listener. */ public void internalFrameIconified(InternalFrameEvent e) { // Invoked when an internal frame is iconified. } /** * This method is inherited from the InternalFrameListener. But it is not * used. * * @param e * The event from the listener. */ public void internalFrameOpened(InternalFrameEvent e) { // Invoked when a internal frame has been opened. } /** * This method is called if the parser fires events. In this case it is * important after every derivation from the parser to update the gui. * * @param p * The event from the parser. */ public void parserEventOccured(ParserEvent p) { if (p instanceof ParserMessageEvent) { String message = ((ParserMessageEvent) p).getMessage(); Object source = p.getSource(); if (message.indexOf("applied") != -1 || message.indexOf("IsoCopy") != -1) { fireStatusMessageEvent(new StatusMessageEvent(this, "", message)); // System.out.println("parserEventOccured: "+message); if (source instanceof Parser) { updateFrame(((Parser) source).getHostGraph(), HOST_GRAPH); } else if (source instanceof OrdinaryMorphism) { updateFrame((OrdinaryMorphism) source, HOST_GRAPH); } } else if (message.indexOf("Result") != -1) { if (source instanceof Parser) { hostFrameResetIcon(); updateFrame(((Parser) source).getHostGraph(), HOST_GRAPH); } } } else if (p instanceof ParserErrorEvent) { String message = ((ParserErrorEvent) p).getMessage(); fireStatusMessageEvent(new StatusMessageEvent(this, "ERROR", "Error: " + message)); } } public void hostFrameSetAnimationIcon() { this.hostFrame.setFrameIcon(IconResource.getIconFromURL(IconResource .getWorkingIcon())); } public void hostFrameResetIcon() { this.hostFrame.setFrameIcon(IconResource.getIconFromURL(IconResource .getWorkerIcon())); } /** * Here register all listener to receive status messages. The AGG has to * register the status bar here. * * @param l * The listener, e.g. the status bar. */ public void addStatusMessageListener(StatusMessageListener l) { if (!this.listener.contains(l)) this.listener.addElement(l); } private void fireStatusMessageEvent(StatusMessageEvent sme) { for (int i = 0; i < this.listener.size(); i++) this.listener.elementAt(i).newMessage(sme); } public void disposeTestHostGraph(EdGraGra gra) { if (gra.getGraphOf(this.hostGraphLayout.getBasisGraph()) == null) this.hostGraphLayout.dispose(); } private void makeGraphMenu() { this.graphMenu.add(this.miLayoutGraph); this.miLayoutGraph.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (ParserDesktop.this.activeGraphPanel != null && ParserDesktop.this.activeGraphPanel.getGraph() != null) { makeLayout(ParserDesktop.this.activeGraphPanel.getGraph(), ParserDesktop.this.activeGraphPanel .getSize()); ParserDesktop.this.activeGraphPanel.updateGraphics(); } } }); } protected void makeLayout(EdGraph g, Dimension d) { g.updateVisibility(); final List<EdNode> visiblenodes = g.getVisibleNodes(); g.setCurrentLayoutToDefault(false); g.getDefaultGraphLayouter().setEnabled(true); Dimension dim = g.getDefaultGraphLayouter().getNeededPanelSize(visiblenodes); if (dim.width < 350) dim.width = 350; if (dim.width < d.width) dim.width = d.width; if (dim.height < 250) dim.height = 250; if (dim.height < d.height) dim.height = d.height; g.getDefaultGraphLayouter().setPanelSize(dim); g.getDefaultGraphLayouter().allowChangePanelSize(false); g.getDefaultGraphLayouter().setEnabled(true); g.doDefaultEvolutionaryGraphLayout( g.getDefaultGraphLayouter(), 100, 10); } } // End of ParserDesktop.java /* * $Log: ParserDesktop.java,v $ * Revision 1.22 2010/09/23 08:20:53 olga * tuning * * Revision 1.21 2010/03/08 15:43:09 olga * code optimizing * * Revision 1.20 2008/11/19 13:04:17 olga * Parser tuning * * Revision 1.19 2008/11/13 08:26:21 olga * some tests * * Revision 1.18 2008/10/29 09:04:12 olga * new sub packages of the package agg.gui: typeeditor, editor, trafo, cpa, options, treeview, popupmenu, saveload * * Revision 1.17 2008/09/11 09:22:26 olga * Some changes in CPA: new computing of conflicts after an option changed, * Graph layout of overlapping graphs * * Revision 1.16 2008/09/04 07:50:27 olga * GUI extension: hide nodes, edges * * Revision 1.15 2008/05/05 09:11:52 olga * Graph parser - bug fixed. * New AGG feature - Applicability of Rule Sequences - in working. * * Revision 1.14 2008/04/07 09:36:56 olga * Code tuning: refactoring + profiling * Extension: CPA - two new options added * * Revision 1.13 2007/11/19 08:48:41 olga * Some GUI usability mistakes fixed. * Default values in node/edge of a type graph implemented. * Code tuning. * * Revision 1.12 2007/11/05 09:18:21 olga * code tuning * * Revision 1.11 2007/09/24 09:42:39 olga * AGG transformation engine tuning * * Revision 1.10 2007/09/10 13:05:45 olga * In this update: * - package xerces2.5.0 is not used anymore; * - class com.objectspace.jgl.Pair is replaced by the agg own generic class agg.util.Pair; * - bugs fixed in: usage of PACs in rules; match completion; * usage of static method calls in attr. conditions * - graph editing: added some new features * Revision 1.9 2007/07/02 08:27:34 olga Help docu * update, Source tuning * * Revision 1.8 2007/06/13 08:33:07 olga Update: V161 * * Revision 1.7 2007/04/19 14:50:04 olga Loading grammar - tuning * * Revision 1.6 2007/04/19 07:52:46 olga Tuning of: Undo/Redo, Graph layouter, * loading grammars * * Revision 1.5 2007/04/11 10:03:41 olga Undo, Redo tuning, Simple Parser- bug * fixed * * Revision 1.4 2007/03/28 10:01:12 olga - extensive changes of Node/Edge Type * Editor, - first Undo implementation for graphs and Node/edge Type editing and * transformation, - new / reimplemented options for layered transformation, for * graph layouter - enable / disable for NACs, attr conditions, formula - GUI * tuning * * Revision 1.3 2006/12/13 13:33:04 enrico reimplemented code * * Revision 1.2 2006/08/02 09:00:57 olga Preliminary version 1.5.0 with - * multiple node type inheritance, - new implemented evolutionary graph layouter * for graph transformation sequences * * Revision 1.1 2005/08/25 11:56:55 enrico *** empty log message *** * * Revision 1.1 2005/05/30 12:58:03 olga Version with Eclipse * * Revision 1.4 2003/03/05 18:24:09 komm sorted/optimized import statements * * Revision 1.3 2002/11/07 16:03:05 olga Anzeige von Overlap-Graphen in CPA * verbessert * * Revision 1.2 2002/10/02 18:30:55 olga XXX * * Revision 1.1.1.1 2002/07/11 12:17:19 olga Imported sources * * Revision 1.5 2001/07/04 10:40:05 olga Kleine GUI Aenderungen * * Revision 1.4 2001/05/14 11:52:58 olga Parser GUI Optimierung * * Revision 1.3 2001/03/22 15:52:30 olga GUI an den veraenderten GraphEditor * angepasst. * * Revision 1.2 2001/03/08 11:02:46 olga Parser Anbindung gemacht. Stand nach * AGG GUI Reimplementierung. Stand nach der AGG GUI Reimplementierung.Das ist * Stand nach der AGG GUI Reimplementierung und Parser Anbindung. * * Revision 1.1.2.9 2001/01/28 13:14:46 shultzke API fertig * * Revision 1.1.2.8 2001/01/03 09:44:55 shultzke TODO's bis auf laden und * speichern erledigt. Wann meldet sich endlich Michael? * * Revision 1.1.2.7 2001/01/02 12:28:57 shultzke Alle Optionen angebunden * * Revision 1.1.2.6 2001/01/01 21:24:31 shultzke alle Parser fertig inklusive * Layout * * Revision 1.1.2.5 2000/11/08 14:58:02 shultzke parser erste stufe fertig * * Revision 1.1.2.4 2000/11/01 14:55:24 shultzke conflictfree part fast fertig * * Revision 1.1.2.3 2000/11/01 12:19:21 shultzke erste Regelanwendung im parser * CVs: ---------------------------------------------------------------------- * * Revision 1.1.2.2 2000/09/21 14:02:08 shultzke ExcludePair bei nacs erweitert * * Revision 1.1.2.1 2000/09/20 13:28:54 shultzke Parser Desktop entworfen * */