/**
* Title: AGG<p>
* Description: <p>
* Company: TU Berlin<p>
* @author Olga Runge
* @version 1.0
*/
package agg.gui.treeview.dialog;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import agg.cons.AtomConstraint;
import agg.cons.Evaluable;
import agg.cons.Formula;
import agg.editor.impl.EdArc;
import agg.editor.impl.EdAtomic;
import agg.editor.impl.EdGraph;
import agg.editor.impl.EdGraphObject;
import agg.editor.impl.EdNestedApplCond;
import agg.editor.impl.EdNode;
import agg.editor.impl.EdType;
import agg.editor.impl.EdTypeSet;
import agg.gui.AGGAppl;
import agg.gui.editor.EditorConstants;
import agg.gui.editor.GraphEditor;
import agg.gui.saveload.GraphicsExportJPEG;
import agg.layout.GraphLayouts;
import agg.layout.ZestGraphLayout;
import agg.util.Pair;
import agg.xt_basis.Arc;
import agg.xt_basis.Graph;
import agg.xt_basis.NestedApplCond;
import agg.xt_basis.Node;
import agg.xt_basis.TypeException;
/*
* Formula GUI dialog allows to edit a boolean formula above some evaluable objects.<br>
* The formula is represented by a binary tree graph.<br>
* It can be edited using the graph background and node pop-up menus.
* To hold the graph more compact some simplifications are used <br>
* (Exmpl.: <code>ac</code> is equivalent to <code>EXISTS(ac, true)</code>,
* <code>!ac</code> is equivalent to <code>NOT EXISTS(ac, true)</code>).
* An empty graph means a binary tree graph in which
* all evaluable objects are connected by \"AND\"."
*
*/
@SuppressWarnings("serial")
public class FormulaGraphGUI extends JDialog implements ActionListener, MouseListener {
static final int OP = 0;
static final int OPRND = 1;
static final int TRUE = 2;
static final int FALSE = TRUE;
final JButton apply, cancel, clear, layout;
final JPanel dialogPanel;
JScrollPane scrollPane;
JFrame parFrame;
boolean changed, canceled;
String formula, f;
Formula tmpF;
final List<Object> objs = new Vector<Object>(5,1);
final HashMap<String,Integer> name2indx = new HashMap<String,Integer>();
final GraphEditor gege;
final EdGraph fgraph;
final List<EdNode> subNodes = new Vector<EdNode>(5,1);
final List<EdType> op2type = new Vector<EdType>();
final Hashtable<JMenuItem,EdType> oprnd2type = new Hashtable<JMenuItem,EdType>(5,0.3f);
final Hashtable<EdType,Object> type2obj = new Hashtable<EdType,Object>(5,0.3f);
final JPopupMenu commonMenu = new JPopupMenu("");
final JPopupMenu oprndMenu = new JPopupMenu("");
final JPopupMenu delMenu = new JPopupMenu("");
final JPopupMenu layoutMenu = new JPopupMenu("");
JMenuItem miDel, miRefGraph;
boolean forallDisabled=false;
JMenuItem miForall;
EdNode topNode, node;
EdType edgeType, refEdgeType;
boolean refined;
public FormulaGraphGUI(JFrame parent,
String nameOfOwner,
String title,
String helpStr,
boolean modal) {
super(parent, title, modal);
this.parFrame = parent;
this.formula = "";
this.f = "";
// make info panel
JPanel info = new JPanel(new GridLayout(3,0));
if (nameOfOwner != null && !"".equals(nameOfOwner)) {
JLabel l1 = new JLabel(" The owner of this formula is the "+nameOfOwner);
l1.setForeground(Color.BLUE);
info.add(l1);
}
JLabel l2 = new JLabel(" Use the bg and node pop-up menus to edit the binary tree graph of the formula.");
info.add(l2);
JLabel l3 = new JLabel(helpStr);
info.add(l3);
// make a graph editor to edit a formula graph
this.gege = new GraphEditor();
// this.gege.setPreferredSize(new Dimension(300,300));
((JPanel) this.gege.getGraphPanel().getCanvas()).addMouseListener(this);
this.gege.setEditMode(agg.gui.editor.EditorConstants.MOVE);
this.gege.getGraphPanel().getCanvas().setEdgeAnchorVisible(false);
this.gege.setTitle(" ");
this.fgraph = new EdGraph(new Graph());
this.fgraph.getBasisGraph().setName(" ");
createOpTypes(this.fgraph.getTypeSet());
createEdgeTypes(this.fgraph.getTypeSet());
this.miDel = this.addDelete(this.delMenu);
addLayout(this.layoutMenu);
// make buttons panel
JPanel buttons = new JPanel(new GridBagLayout());
this.layout = new JButton("Layout");
this.layout.setToolTipText("Tree Graph Layout");
this.layout.addActionListener(this);
this.clear = new JButton("Clear");
this.clear.addActionListener(this);
this.apply = new JButton("Apply");
this.apply.addActionListener(this);
this.cancel = new JButton("Cancel");
this.cancel.addActionListener(this);
constrainBuild(buttons, this.clear, 0, 0, 1, 1, GridBagConstraints.BOTH,
GridBagConstraints.CENTER, 1.0, 0.0, 5, 10, 5, 15);
// constrainBuild(buttons, layout, 1, 0, 1, 1, GridBagConstraints.BOTH,
// GridBagConstraints.CENTER, 1.0, 0.0, 5, 15, 5, 15);
constrainBuild(buttons, this.apply, 2, 0, 1, 1, GridBagConstraints.BOTH,
GridBagConstraints.CENTER, 1.0, 0.0, 5, 15, 5, 15);
constrainBuild(buttons, this.cancel, 3, 0, 1, 1, GridBagConstraints.BOTH,
GridBagConstraints.CENTER, 1.0, 0.0, 5, 15, 5, 10);
// make common dialog panel
this.dialogPanel = new JPanel(new GridBagLayout());
this.dialogPanel.setPreferredSize(new Dimension(200, 200));
constrainBuild(this.dialogPanel, info, 0, 0, 1, 1, GridBagConstraints.BOTH,
GridBagConstraints.CENTER, 1.0, 0.0, 5, 5, 5, 5);
constrainBuild(this.dialogPanel, this.gege, 0, 1, 1, 1, GridBagConstraints.BOTH,
GridBagConstraints.CENTER, 1.0, 1.0, 5, 5, 5, 5);
constrainBuild(this.dialogPanel, buttons, 0, 2, 1, 1, GridBagConstraints.BOTH,
GridBagConstraints.CENTER, 1.0, 0.0, 5, 5, 5, 5);
getContentPane().setLayout(new BorderLayout());
scrollPane = new JScrollPane(this.dialogPanel);
scrollPane.setPreferredSize(new Dimension(500, 500));
getContentPane().add(scrollPane, BorderLayout.CENTER);
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); // HIDE_ON_CLOSE
this.pack();
}
public void setVisible(boolean b) {
this.doZestTreeLayout(this.fgraph);
super.setVisible(b);
}
public void setExportJPEG(final GraphicsExportJPEG jpg) {
if (this.gege != null)
this.gege.setExportJPEG(jpg);
}
/**
* Disable the <code>FORALL</code> menu item.
*/
public void disableFORALL(boolean b) {
this.forallDisabled = b;
}
public void doZestTreeLayout(final EdGraph g) {
String algorithm = GraphLayouts.TREE_VERTICAL_LAYOUT;
if (this.parFrame != null && this.parFrame instanceof AGGAppl) {
ZestGraphLayout zestGL = ((AGGAppl)this.parFrame).getGraGraEditor().getZestGraphLayouter();
if (zestGL != null && !g.isEmpty()) {
zestGL.setGraph(g);
zestGL.setAlgorithm(algorithm);
zestGL.setGraphDimension(
new Dimension(this.gege.getGraphPanel().getCanvas().getSize().width-20,
this.gege.getGraphPanel().getCanvas().getSize().height-20));
// zestGL.setGraphDimension(new Dimension(400,800));
if (zestGL.applyLayout())
this.gege.updateGraphics(true);
}
}
}
/**
* Implements actions of buttons: Layout, Clear, Apply, Cancel
* and of operation buttons.
*/
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Layout")) {
doZestTreeLayout(this.fgraph);
}
else if (e.getActionCommand().equals("Clear")) {
clear();
}
else if (e.getActionCommand().equals("Apply")) {
setFormulaText();
if ("".equals(this.formula)) {
this.f = "";
}
this.changed = true;
setVisible(false);
}
else if (e.getActionCommand().equals("Cancel")) {
setVisible(false);
this.canceled = true;
}
}
/**
* Return the formula string with indexes of GACs ( not the names!).
* This formula string is then used to create a new Formula instance for the given list of GACs.
*/
public String getFormula() {
if ("".equals(this.f))
return "true";
else
return this.f;
}
public EdGraph getFormulaGraph() {
return this.fgraph;
}
public boolean isChanged() {
return this.changed;
}
public boolean isCanceled() {
return this.canceled;
}
/**
* Set the lists of evaluable objects to be used as variables of the specified formula string.
* All needed internal structures will be rebuild.
*/
public void setVars(List<String> vars, List<Evaluable> varObjs, String formulaStr) {
this.commonMenu.removeAll();
this.oprndMenu.removeAll();
Vector<String> s = new Vector<String>();
for (int i = 0; i < vars.size(); i++) {
String name = vars.get(i);
s.add(name);
this.objs.add(name);
EdType t = this.createOprndNodeType(this.fgraph.getTypeSet(), name);
addOprndNodeType(this.commonMenu, t, i+1);
addOprndNodeType(this.oprndMenu, t, i+1);
this.name2indx.put(t.getTypeName(), Integer.valueOf(i+1));
}
this.commonMenu.addSeparator();
this.commonMenu.addSeparator();
this.addOpNodeTypes(this.commonMenu);
this.commonMenu.addSeparator();
this.commonMenu.addSeparator();
this.addDelete(this.commonMenu);
this.oprndMenu.addSeparator();
this.oprndMenu.addSeparator();
this.addDelete(this.oprndMenu);
if (s.isEmpty()) {
clear();
} else {
this.formula = formulaStr;
fillFromString(formulaStr);
Formula form = new Formula(varObjs, this.f);
formula2graph(form, this.fgraph);
}
this.gege.setGraph(this.fgraph);
}
/**
* Set the list of GACs to be used as variables of the specified formula string.
* All needed internal structures will be rebuild.
* Note: The elements of the objList can be of the type <code>EdNestedApplCond</code> or
* <code>EdAtomic</code> only.
*/
public void setVarsAsObjs(List<?> objList, String formulaStr) {
this.commonMenu.removeAll();
this.oprndMenu.removeAll();
boolean allowRefGraph = false;
Vector<Evaluable> vec = new Vector<Evaluable>();
Vector<String> s = new Vector<String>();
for (int i = 0; i < objList.size(); i++) {
if (objList.get(i) instanceof EdNestedApplCond) {
allowRefGraph = true;
EdNestedApplCond obj = (EdNestedApplCond) objList.get(i);
vec.add(obj.getNestedMorphism());
s.add(obj.getNestedMorphism().getName());
this.objs.add(obj.getNestedMorphism());
EdType t = this.createOprndNodeType(this.fgraph.getTypeSet(), obj.getNestedMorphism().getName());
if (t != null) {
addOprndNodeType(this.commonMenu, t, i+1);
addOprndNodeType(this.oprndMenu, t, i+1);
this.name2indx.put(t.getTypeName(), Integer.valueOf(i+1));
this.type2obj.put(t, obj.getNestedMorphism());
}
}
else if (objList.get(i) instanceof EdAtomic) {
EdAtomic obj = (EdAtomic) objList.get(i);
vec.add(obj.getBasisAtomic());
s.add(obj.getBasisAtomic().getAtomicName());
this.objs.add(obj.getBasisAtomic());
EdType t = this.createOprndNodeType(this.fgraph.getTypeSet(), obj.getBasisAtomic().getAtomicName());
if (t != null) {
addOprndNodeType(this.commonMenu, t, i+1);
addOprndNodeType(this.oprndMenu, t, i+1);
this.name2indx.put(t.getTypeName(), Integer.valueOf(i+1));
this.type2obj.put(t, obj.getBasisAtomic());
}
}
}
this.commonMenu.addSeparator();
this.commonMenu.addSeparator();
this.addOpNodeTypes(this.commonMenu);
this.commonMenu.addSeparator();
this.commonMenu.addSeparator();
this.addDelete(this.commonMenu);
this.oprndMenu.addSeparator();
this.oprndMenu.addSeparator();
this.addDelete(this.oprndMenu);
if (allowRefGraph) {
this.miRefGraph(this.delMenu);
}
if (s.isEmpty()) {
clear();
} else {
this.formula = formulaStr;
fillFromString(formulaStr);
Formula form = new Formula(vec, this.f);
formula2graph(form, this.fgraph);
}
this.gege.setGraph(this.fgraph);
}
private List<EdNode> addRefGraphOf(final Formula form, final EdNode refNode) {
List<EdNode> list = new Vector<EdNode>(5,1);
EdGraph refGraph = new EdGraph(new Graph());
this.createOpTypes(refGraph.getTypeSet());
// create an edge type to connect nodes
refGraph.getTypeSet().createArcType("", EditorConstants.SOLID, Color.BLACK);
this.formula2graph(form, refGraph);
Hashtable<EdGraphObject,EdGraphObject> go2go = new Hashtable<EdGraphObject,EdGraphObject>();
int x = refNode.getX();
int y = refNode.getY()+40;
Vector<EdNode> v = refGraph.getNodes();
for (int i=0; i<v.size(); i++) {
EdNode go = v.get(i);
EdType t = this.fgraph.getTypeSet().getTypeForName(go.getTypeName());
if (t == null)
t = this.fgraph.getTypeSet().createNodeType(go.getTypeName(), EditorConstants.RECT, Color.BLUE);
try {
EdNode n1 = this.fgraph.addNode(x, y, t, true);
n1.getBasisNode().setContextUsage(go.getBasisNode().getContextUsage());
this.subNodes.add(n1);
if (this.type2obj.get(go.getType()) != null)
this.type2obj.put(t, this.type2obj.get(go.getType()));
if (go.getInArcsCount() == 0) { // top of refinement formula graph
EdArc ref = this.fgraph.addArc(this.refEdgeType, refNode, n1, null, true);
ref.getBasisArc().setContextUsage(-1);
this.refined = true;
}
if (go.getOutArcsCount() == 0)
list.add(n1);
go2go.put(go, n1);
} catch (TypeException ex) {}
}
Vector<EdArc> v1 = refGraph.getArcs();
for (int i=0; i<v1.size(); i++) {
EdArc go = v1.get(i);
EdNode src = (EdNode)go2go.get(go.getSource());
EdNode tar = (EdNode)go2go.get(go.getTarget());
int dx = go.getTarget().getX() - go.getSource().getX();
int dy = go.getTarget().getY() - go.getSource().getY();
tar.setXY(src.getX()+dx, src.getY()+dy);
try {
this.fgraph.addArc(this.edgeType, src, tar, null, true);
} catch (TypeException ex) {}
}
return list;
}
/**
* Build formula-graph from the given Formula object.
*/
private void formula2graph(final Formula form, final EdGraph graph) {
String tname = null;
EdNode n = null;
EdType t = null;
int op = form.getOperation();
switch (op) {
case Formula.NOP:
if (form.getFirst() != null) {
if (form.getFirst() instanceof Formula) {
formula2graph((Formula) form.getFirst(), graph);
}
else if (form.getFirst() instanceof NestedApplCond) {
tname = ((NestedApplCond) form.getFirst()).getName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
this.objs.add(form.getFirst());
this.type2obj.put(t, form.getFirst());
}
n = addNode(graph, t, OPRND);
this.type2obj.put(t, form.getFirst());
}
else if (form.getFirst() instanceof AtomConstraint) {
tname = ((AtomConstraint) form.getFirst()).getAtomicName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
this.objs.add(form.getFirst());
this.type2obj.put(t, form.getFirst());
}
n = addNode(graph, t, OPRND);
}
}
break;
case Formula.NOT:
if (form.getFirst() != null) {
t = graph.getTypeSet().getNodeTypeForName("NOT");
n = addNode(graph, t, OP);
if (n != null) {
this.node = n;
if (form.getFirst() instanceof Formula) {
formula2graph((Formula) form.getFirst(), graph);
} else if (form.getFirst() instanceof NestedApplCond) {
tname = ((NestedApplCond) form.getFirst()).getName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
} else if (form.getFirst() instanceof AtomConstraint) {
tname = ((AtomConstraint) form.getFirst()).getAtomicName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
}
}
}
break;
case Formula.AND:
t = graph.getTypeSet().getNodeTypeForName("AND");
n = addNode(graph, t, OP);
if (n != null) {
this.node = n;
if (form.getFirst() != null) {
if (form.getFirst() instanceof Formula) {
formula2graph((Formula) form.getFirst(), graph);
this.node = n;
} else if (form.getFirst() instanceof NestedApplCond) {
tname = ((NestedApplCond) form.getFirst()).getName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
} else if (form.getFirst() instanceof AtomConstraint) {
tname = ((AtomConstraint) form.getSecond()).getAtomicName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
}
}
if (form.getSecond() != null) {
if (form.getSecond() instanceof Formula) {
formula2graph((Formula) form.getSecond(), graph);
} else if (form.getSecond() instanceof NestedApplCond) {
tname = ((NestedApplCond) form.getSecond()).getName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
} else if (form.getSecond() instanceof AtomConstraint) {
tname = ((AtomConstraint) form.getSecond()).getAtomicName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
}
}
}
break;
case Formula.OR:
t = graph.getTypeSet().getNodeTypeForName("OR");
n = addNode(graph, t, OP);
if (n != null) {
this.node = n;
if (form.getFirst() != null) {
if (form.getFirst() instanceof Formula) {
formula2graph((Formula) form.getFirst(), graph);
this.node = n;
} else if (form.getFirst() instanceof NestedApplCond) {
tname = ((NestedApplCond) form.getFirst()).getName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
} else if (form.getFirst() instanceof AtomConstraint) {
tname = ((AtomConstraint) form.getFirst()).getAtomicName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
}
}
if (form.getSecond() != null) {
if (form.getFirst() instanceof Formula) {
formula2graph((Formula) form.getSecond(), graph);
} else if (form.getSecond() instanceof NestedApplCond) {
tname = ((NestedApplCond) form.getSecond()).getName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
} else if (form.getSecond() instanceof AtomConstraint) {
tname = ((AtomConstraint) form.getSecond()).getAtomicName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
}
}
}
break;
case Formula.FORALL:
if (form.getFirst() != null) {
t = graph.getTypeSet().getNodeTypeForName("FORALL");
n = addNode(graph, t, OP);
if (n != null)
this.node = n;
if (form.getFirst() instanceof Formula) {
formula2graph((Formula) form.getFirst(), graph);
}
else if (form.getFirst() instanceof NestedApplCond) {
tname = ((NestedApplCond) form.getFirst()).getName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
} else if (form.getFirst() instanceof AtomConstraint) {
tname = ((AtomConstraint) form.getFirst()).getAtomicName();
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
t = this.createOprndNodeType(graph.getTypeSet(), tname);
}
n = addNode(graph, t, OPRND);
}
}
break;
case Formula.TRUE:
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
String st = "true";
t = this.createOpNodeType(graph.getTypeSet(), st);
}
n = addNode(graph, t, TRUE);
break;
case Formula.FALSE:
t = graph.getTypeSet().getNodeTypeForName(tname);
if (t == null) {
String sf = "false";
t = this.createOpNodeType(graph.getTypeSet(), sf);
}
n = addNode(graph, t, FALSE);
break;
}
}
/**
* Extend working formula string.
* If i=-1, then concatenate s, otherwise - i.
*/
private void add2formula(String s, int i) {
if (i == -1) {
this.f = this.f.concat(s);
}
else {
this.f = this.f.concat(String.valueOf(i));
}
}
/**
* Empty graph and formula string;
*/
void clear() {
try {
this.fgraph.deleteAll();
this.gege.updateGraphics();
} catch (TypeException ex) {}
this.f = "";
this.formula = "";
this.topNode = null;
this.node = null;
}
/**
* Set working formula string.
*/
private void fillFromString(String str) {
String s = str.replaceAll(" ", "");
String s2 = s.replace("(T)", "T");
while (s2.indexOf("(T)") >= 0) {
String s3 = s2.replace("(T)", "T");
s2 = s3;
}
s = s2;
StringCharacterIterator i = new StringCharacterIterator(s);
char c = i.current();
while (c != CharacterIterator.DONE) {
if (c == '&' || c == '|'
|| c == '!' || c == '$'
|| c == 'A' || c == 'E'
|| c == 'T' || c == 'F'
|| c == ' ' || c == ','
|| c == '(' || c == ')') {
add2formula(String.valueOf(c), -1);
i.next();
} else if (c >= '0' && c <= '9') {
String cs = "";
int v = 0;
while (c >= '0' && c <= '9') {
cs = cs.concat(String.valueOf(c));
v = v * 10 + (c - '0');
c = i.next();
}
v--;
if (v < 0 /*|| v >= list.getModel().getSize()*/)
return;
int num = Integer.valueOf(cs).intValue();
if (this.objs.size() > 0 && ((num-1) < this.objs.size())) {
Object obj = this.objs.get(num-1);
if (obj instanceof String)
add2formula((String) obj, num);
else if (obj instanceof NestedApplCond) {
add2formula(((NestedApplCond)obj).getName(), num);
}
else if (obj instanceof AtomConstraint) {
add2formula(((AtomConstraint)obj).getAtomicName(), num);
}
}
} else if (c == 'f' || c == 't') {
String cs = String.valueOf(c);
char c1 = c;
while (i.current() >= 'a' && i.current() <= 'z') {
c1 = i.next();
if (c1 != CharacterIterator.DONE) {
cs = cs.concat(String.valueOf(c1));
}
}
add2formula(String.valueOf(cs), -1);
}
c = i.current();
}
}
private void constrainBuild(Container container, Component component,
int grid_x, int grid_y, int grid_width, int grid_height, int fill,
int anchor, double weight_x, double weight_y, int top, int left,
int bottom, int right) {
GridBagConstraints c = new GridBagConstraints();
c.gridx = grid_x;
c.gridy = grid_y;
c.gridwidth = grid_width;
c.gridheight = grid_height;
c.fill = fill;
c.anchor = anchor;
c.weightx = weight_x;
c.weighty = weight_y;
c.insets = new Insets(top, left, bottom, right);
((GridBagLayout) container.getLayout()).setConstraints(component, c);
container.add(component);
}
/**
* Create <code>operation</code> types.
*/
private void createOpTypes(final EdTypeSet types) {
// create node types which represent operators of a formula
EdType t = types.createNodeType("NOT", EditorConstants.ROUNDRECT, Color.RED);
this.op2type.add(t);
t = types.createNodeType("AND", EditorConstants.ROUNDRECT, Color.BLACK);
this.op2type.add(t);
t = types.createNodeType("OR", EditorConstants.ROUNDRECT, Color.BLACK);
this.op2type.add(t);
t = types.createNodeType("FORALL", EditorConstants.ROUNDRECT, Color.BLACK);
this.op2type.add(t);
}
private EdType createOpNodeType(final EdTypeSet types, String name) {
EdType t = types.createNodeType(name, EditorConstants.RECT, Color.BLACK);
return t;
}
private void createEdgeTypes(final EdTypeSet types) {
// create an edge type to connect nodes
if (this.edgeType == null)
this.edgeType = types.createArcType("", EditorConstants.SOLID, Color.BLACK);
// create an edge type to connect refinement nodes
if (this.refEdgeType == null)
this.refEdgeType = types.createArcType("", EditorConstants.SOLID, Color.BLUE);
}
/**
* Create a new type with the specified name which corresponds to the name
* of the appropriate GAC.
*/
private EdType createOprndNodeType(final EdTypeSet types, String name) {
EdType t = types.createNodeType(name, EditorConstants.RECT, Color.BLUE);
return t;
}
/**
* Add a new <code>GAC</code> menu item to the specified pop-up menu.
* The name of the specified type is the name of an appropriate GAC.
*/
private JMenuItem addOprndNodeType(final JPopupMenu m, final EdType t, int indx) {
JMenuItem mi = m.add(new JMenuItem(t.getName()));
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Integer.valueOf(((JMenuItem)e.getSource()).getActionCommand()).intValue();
addNode(FormulaGraphGUI.this.fgraph, FormulaGraphGUI.this.oprnd2type.get(e.getSource()), OPRND);
} catch (NumberFormatException ex) {
addNode(FormulaGraphGUI.this.fgraph, FormulaGraphGUI.this.oprnd2type.get(e.getSource()), OP);
}
}
});
if ("FORALL".equals(t.getName()))
this.miForall = mi;
if (indx == -1)
mi.setActionCommand(" ");
else
mi.setActionCommand(String.valueOf(indx));
this.oprnd2type.put(mi, t);
return mi;
}
/**
* Add <code>operation</code> menu items to the specified pop-up menu.
*/
private void addOpNodeTypes(final JPopupMenu m) {
for (int i=0; i<this.op2type.size(); i++) {
EdType t = this.op2type.get(i);
addOprndNodeType(m, t, -1);
}
}
/**
* Add <code>Show/Hide</code> menu item to the specified pop-up menu.
* It allows to show/hide the formula graph tree of a node which represents an application condition.
*/
private void miRefGraph(final JPopupMenu m) {
this.miRefGraph = new JMenuItem("Show View of Refinement Formula Graph");
this.miRefGraph.setActionCommand("show");
m.addSeparator();
m.addSeparator();
m.add(this.miRefGraph);
this.miRefGraph.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (FormulaGraphGUI.this.node != null) {
Object obj = FormulaGraphGUI.this.type2obj.get(FormulaGraphGUI.this.node.getType());
if (obj != null
&& obj instanceof NestedApplCond
&& ((NestedApplCond)obj).getName().equals(FormulaGraphGUI.this.node.getTypeName())) {
FormulaGraphGUI.this.tmpF = ((NestedApplCond)obj).getFormula();
if ("show".equals(FormulaGraphGUI.this.miRefGraph.getActionCommand())) {
// addRefGraphOf(tmpF, node);
doRefine(FormulaGraphGUI.this.tmpF, FormulaGraphGUI.this.node);
FormulaGraphGUI.this.gege.updateGraphics(true);
// doZestTreeLayout(this.fgraph);
FormulaGraphGUI.this.miRefGraph.setText("Hide View of Refinement Formula Graph");
FormulaGraphGUI.this.miRefGraph.setActionCommand("hide");
}
else if ("hide".equals(FormulaGraphGUI.this.miRefGraph.getActionCommand())) {
if (FormulaGraphGUI.this.node.getBasisNode().getOutgoingArcs().hasNext()) {
Node n = (Node)FormulaGraphGUI.this.node.getBasisNode().getOutgoingArcs().next().getTarget();
EdGraphObject go = FormulaGraphGUI.this.fgraph.findNode(n);
if (go != null) {
deleteNode((EdNode)go);
FormulaGraphGUI.this.gege.updateGraphics(true);
FormulaGraphGUI.this.miRefGraph.setText("Show View of Refinement Formula Graph");
FormulaGraphGUI.this.miRefGraph.setActionCommand("show");
}
}
}
}
}
}
});
}
void doRefine(final Formula form, final EdNode refNode) {
List<EdNode> list = addRefGraphOf(form, refNode);
for (int i=0; i<list.size(); i++) {
EdNode n = list.get(i);
Object obj = this.type2obj.get(n.getType());
if (obj != null) {
if (obj instanceof NestedApplCond
&& ((NestedApplCond)obj).getName().equals(n.getTypeName())) {
Formula form1 = ((NestedApplCond)obj).getFormula();
doRefine(form1, n);
}
}
}
}
private void enableRefGraph(boolean enable, String action) {
if (this.miRefGraph == null)
return;
this.miRefGraph.setEnabled(enable);
if ("show".equals(action)) {
this.miRefGraph.setText("Show View of Refinement Formula Graph");
this.miRefGraph.setActionCommand("show");
}
else if ("hide".equals(action)) {
this.miRefGraph.setText("Hide View of Refinement Formula Graph");
this.miRefGraph.setActionCommand("hide");
}
}
/**
* Add <code>Delete</code> menu item to the specified pop-up menu.
*/
private JMenuItem addDelete(final JPopupMenu m) {
JMenuItem mi = m.add(new JMenuItem("Delete"));
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (FormulaGraphGUI.this.node != null) {
deleteNode(FormulaGraphGUI.this.node);
FormulaGraphGUI.this.fgraph.updateGraph();
FormulaGraphGUI.this.gege.updateGraphics();
}
}
});
return mi;
}
/**
* Add <code>Graph Layout</code> menu item to the specified pop-up menu.
*/
private JMenuItem addLayout(final JPopupMenu m) {
JMenuItem mi = m.add(new JMenuItem("Graph Layout"));
mi.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
doZestTreeLayout(FormulaGraphGUI.this.fgraph);
}
});
return mi;
}
/**
* Delete the specified node from the formula-graph.
* All edges and nodes of its subtree will be deleted, too.
*/
private void deleteNode(final EdNode n) {
if (n.getInArcsCount() == 1) {
try {
this.fgraph.delSelectedArc(this.fgraph.getIncomingArcs(n).get(0));
} catch (TypeException ex) {}
}
Vector<EdArc> outs = this.fgraph.getOutgoingArcs(n);
for (int i=0; i<outs.size(); i++) {
EdNode n1 = (EdNode) outs.get(i).getTarget();
deleteNode(n1);
}
try {
this.subNodes.remove(n);
this.fgraph.delSelectedNode(n);
} catch (TypeException ex) {}
}
private void deleteRefinement() {
boolean del = true;
while (del) {
Vector<EdNode> list = this.fgraph.getNodes();
del = false;
for (int i=0; i<list.size(); i++) {
EdNode n = list.get(i);
del = deleteRefOfNode(n);
if (del)
break;
}
}
}
/**
* Delete the refinement of the specified node from the formula-graph.
*/
private boolean deleteRefOfNode(final EdNode n) {
boolean res = false;
Vector<EdArc> outs = this.fgraph.getOutgoingArcs(n);
for (int i=0; i<outs.size(); i++) {
EdNode n1 = (EdNode) outs.get(i).getTarget();
if (this.subNodes.contains(n1)) {
deleteNode(n1);
res = true;
}
}
return res;
}
/*
* Add a top node if the formula-graph is empty,
* otherwise add an operation or a GAC node.
* Returns a new node or null.
*
* @param t type of the node
* @param kind 0 is for an operation node, 1 - for a GAC node
*/
EdNode addNode(final EdGraph graph, final EdType t, int kind) {
if (this.fgraph == graph && graph.isEmpty()) {
return addTopNode(graph, t, kind);
}
if (this.node != null) {
try {
int dx = 50;
int dy = 40;
// add node
int x = this.node.getX();
int y = this.node.getY() + dy;
if (this.node.getOutArcsCount() == 0) {
if (this.node.getTypeName().equals("AND")
|| this.node.getTypeName().equals("OR")) {
if (x-60 > 0)
x = x - dx;
else
x = dx/2;
}
} else if (this.node.getOutArcsCount() == 1) {
x = x + dx;
} else {
return null;
}
EdNode n = graph.addNode(x, y, t, true);
n.getBasisNode().setContextUsage(kind);
// add edge
EdType arcType = this.edgeType;
if (graph != this.fgraph) {
arcType = graph.getTypeSet().getArcTypeForName("");
}
// EdArc a =
graph.addArc(arcType, this.node, n, null, true);
this.gege.updateGraphics();
return n;
} catch (TypeException ex) {}
}
return null;
}
/**
* If formula-graph is empty, add and return the top node,
* otherwise return null.
* @param t type of the node
* @param kind 0 is for an operation node, 1 - for a GAC node
*/
private EdNode addTopNode(final EdGraph graph, final EdType t, int kind) {
try {
int x = this.gege.getGraphPanel().getWidth()/2;
int y = 50;
EdNode n = graph.addNode(x, y, t, true);
n.getBasisNode().setContextUsage(kind);
this.topNode = n;
this.gege.updateGraphics();
return n;
} catch (TypeException ex) {}
return null;
}
private void resetTopNode() {
if (!this.fgraph.getNodes().isEmpty()) {
Vector<EdNode> list = this.fgraph.getNodes();
for (int i=0; i<list.size(); i++) {
EdNode n = list.get(i);
if (n.getBasisNode().getNumberOfIncomingArcs() == 0) {
this.topNode = n;
return;
}
}
}
}
/** not implemented
*/
public void mouseClicked(MouseEvent e) {
}
/** not implemented
*/
public void mouseEntered(MouseEvent e) {
}
/** not implemented
*/
public void mouseExited(MouseEvent e) {
}
/**
* Pick a node of the formula-graph.
*/
public void mousePressed(MouseEvent e) {
EdGraphObject go = this.gege.getGraph().getPicked(e.getX(), e.getY());
if (go != null && go.isNode())
this.node = (EdNode)go;
else
this.node = null;
if (this.fgraph.isEmpty()
|| e.isPopupTrigger()) {
if (this.fgraph.hasSelection())
this.fgraph.deselectAll();
if (e.getX() > this.getSize().width-50
|| e.getY() > this.getSize().height)
showPopupMenu(this.node, this.getSize().width/3, this.getSize().height/2);
else
showPopupMenu(this.node, e.getX(), e.getY());
}
}
/**
* Show appropriate pop-up menu.
*/
public void mouseReleased(MouseEvent e) {
if (this.fgraph.isEmpty()
|| e.isPopupTrigger()) {
if (this.fgraph.hasSelection())
this.fgraph.deselectAll();
if (e.getX() > this.getSize().width-50
|| e.getY() > this.getSize().height)
showPopupMenu(this.node, this.getSize().width/3, this.getSize().height/4);
else
showPopupMenu(this.node, e.getX(), e.getY());
}
}
/*
* Show appropriate pop-up menu depending of context in which it is called.
* The context can be an empty graph or a graph node.
*/
private void showPopupMenu(final EdNode n, int x, int y) {
if (this.miForall != null)
this.miForall.setEnabled(!this.forallDisabled);
if (this.fgraph.isEmpty()) {
this.commonMenu.show(this.gege.getGraphPanel(), x, y);
}
else if (n == null) {
this.layoutMenu.show(this.gege.getGraphPanel(), x, y);
}
else {
int c = n.getOutArcsCount();
switch (c) {
case 0:
if (this.subNodes.contains(n))
this.miDel.setEnabled(false);
else
this.miDel.setEnabled(true);
if (n.getBasisNode().getContextUsage() == OP) {
if (n.getTypeName().equals("FORALL"))
this.oprndMenu.show(this.gege.getGraphPanel(), x+5, y+5);
else
this.commonMenu.show(this.gege.getGraphPanel(), x+5, y+5);
}
else if (n.getBasisNode().getContextUsage() == OPRND) {
if (this.hasRefGraph(n))
enableRefGraph(true, "show");
else
enableRefGraph(false, "show");
this.delMenu.show(this.gege.getGraphPanel(), x+5, y+5);
}
else if (n.getBasisNode().getContextUsage() == TRUE) {
enableRefGraph(false, "");
this.delMenu.show(this.gege.getGraphPanel(), x+5, y+5);
}
else if (n.getBasisNode().getContextUsage() == FALSE) {
enableRefGraph(false, "");
this.delMenu.show(this.gege.getGraphPanel(), x+5, y+5);
}
break;
case 1:
if (this.subNodes.contains(n))
return;
if (n.getBasisNode().getContextUsage() == OPRND) {
// if (n.getBasisNode().getOutgoingArcs().next().getContextUsage() == -1) {
if (n.getBasisNode().getOutgoingArcs().next().getType() == this.refEdgeType.getBasisType()) {
enableRefGraph(true, "hide");
}
else
enableRefGraph(false, "hide");
} else {
enableRefGraph(false, "show");
}
this.miDel.setEnabled(true);
if (n.getTypeName().equals("AND")
|| n.getTypeName().equals("OR")) {
this.commonMenu.show(this.gege.getGraphPanel(), x+5, y+5);
}
else {
this.delMenu.show(this.gege.getGraphPanel(), x+5, y+5);
}
break;
case 2:
if (this.subNodes.contains(n))
return;
enableRefGraph(false, "show");
this.miDel.setEnabled(true);
this.delMenu.show(this.gege.getGraphPanel(), x+5, y+5);
break;
}
}
}
private boolean hasRefGraph(EdNode n) {
Object obj = this.type2obj.get(n.getType());
if (obj != null) {
if (obj instanceof NestedApplCond) {
String fstr = ((NestedApplCond)obj).getFormulaText();
if ("".equals(fstr) || "true".equals(fstr) || "false".equals(fstr))
return false;
else
return true;
}
}
return false;
}
/**
* Convert recursively the formula-graph to a new formula-string.<br>
* Result pair of strings contains two representations:
* the first string shows the names,
* the second string - the indexes of the GACs.
*/
private Pair<String,String> graph2text(final Node n) {
Node n1 = null;
String s = "";
String s1 = "";
int c = n.getNumberOfOutgoingArcs();
switch (c) {
case 0:
s = n.getType().getName();
if ("true".equals(s)) {
s = "T";
s1 = "T";
}
else if ("false".equals(s)) {
s = "F";
s1 = "F";
}
else if (this.name2indx.get(n.getType().getName()) != null) {
s1 = String.valueOf(this.name2indx.get(n.getType().getName()).intValue());
} else {
s1 = n.getType().getName();
}
break;
case 1:
if (n.getOutgoingArcs().next().getContextUsage() == -1) {
s = n.getType().getName();
if (this.name2indx.get(n.getType().getName()) != null) {
s1 = String.valueOf(this.name2indx.get(n.getType().getName()).intValue());
} else {
s1 = n.getType().getName();
}
break;
}
n1 = (Node)n.getOutgoingArcs().next().getTarget();
if (n.getType().getName().equals("NOT")) {
Pair<String,String> p = graph2text(n1);
s = " !"+p.first;
s1 = " !"+p.second;
}
else if (n.getType().getName().equals("FORALL")) {
Pair<String,String> p1 = graph2text(n1);
s = " FORALL"+"("+p1.first+")";
s1 = " A"+"("+p1.second+")";
}
else {
Pair<String,String> p = graph2text(n1);
s = n.getType().getName()+"("+p.first+")";
s1 = n.getType().getName()+"("+p.second+")";
}
break;
case 2:
Iterator<Arc> outs = n.getOutgoingArcs();
n1 = (Node)outs.next().getTarget();
Node n2 = (Node)outs.next().getTarget();
if (n.getType().getName().equals("AND")) {
Pair<String,String> p1 = graph2text(n1);
Pair<String,String> p2 = graph2text(n2);
s = "("+p1.first+" & "+p2.first+")";
s1 = "("+p1.second+" & "+p2.second+")";
}
else if (n.getType().getName().equals("OR")) {
Pair<String,String> p1 = graph2text(n1);
Pair<String,String> p2 = graph2text(n2);
s = "("+p1.first+" | "+p2.first+")";
s1 = "("+p1.second+" | "+p2.second+")";
}
break;
}
return new Pair<String,String>(s, s1);
}
/*
* If the formula-graph is not empty, convert the graph to a new formula-string.
*/
private void setFormulaText() {
if (this.topNode.getBasisNode().getNumberOfOutgoingArcs() == 0
&& this.fgraph.getNodes().size() > 1) {
this.resetTopNode();
}
if (this.topNode != null) {
if (this.refined) {
this.deleteRefinement();
this.refined = false;
}
Pair<String,String> p = graph2text(this.topNode.getBasisNode());
String s = p.first;
String s1 = p.second;
s = s.replaceAll("this", "$");
s1 = s1.replaceAll("this", "$");
this.formula = s;
this.f = s1;
// System.out.println(this.f);
// System.out.println(this.formula);
}
}
}