/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package edu.mit.csail.sdg.alloy4viz; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.JSplitPane; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.tree.TreePath; import edu.mit.csail.sdg.alloy4.Listener; import edu.mit.csail.sdg.alloy4.OurBorder; import edu.mit.csail.sdg.alloy4.OurCombobox; import edu.mit.csail.sdg.alloy4.OurCheckbox; import edu.mit.csail.sdg.alloy4.OurTree; import edu.mit.csail.sdg.alloy4.OurUtil; import edu.mit.csail.sdg.alloy4.Util; import edu.mit.csail.sdg.alloy4graph.DotColor; import edu.mit.csail.sdg.alloy4graph.DotPalette; import edu.mit.csail.sdg.alloy4graph.DotShape; import edu.mit.csail.sdg.alloy4graph.DotStyle; /** GUI panel for making customization changes. * * <p><b>Thread Safety:</b> Can be called only by the AWT event thread. */ public final class VizCustomizationPanel extends JPanel { /** This ensures the class can be serialized reliably. */ private static final long serialVersionUID = 0; /** The TREE NODE representing the root of the customization panel. */ private static final Object ROOT = new Object(); /** The TREE NODE representing the GENERAL OPTIONS panel. */ private static final Object GENERAL = new Object(); /** The TREE NODE representing the GENERAL NODES panel. */ private static final Object NODES = new Object(); /** The TREE NODE representing the GENERAL EDGES panel. */ private static final Object EDGES = new Object(); /** This is the VizState object that this customization panel will customize. */ private final VizState vizState; /** This is the background color for the upper-half of the customization panel. */ private static final Color wcolor = new Color(0.9f, 0.9f, 0.9f); /** This is the upper-half of the customization panel. */ private final JPanel zoomPane; /** The JSplitPane separating this customization panel with the main graph panel. */ private final JSplitPane divider; /** If it's an instance of AlloyElement, that means it's the latest selected type/set/relation. * If it's GENERAL, NODES, or EDGES, that means the latest selected panel is * the General Graph Settings, Default Type+Set, or Default Relation panels respectively. * All else, that means the zoom panel is empty. */ private Object lastElement = null; //=============================================================================================================// /** Constructs a customization panel. * @param divider - the JSplitPane separating the left-customization-half with the right-graph-half * @param vizState - the VizState object that will be customized by this customization panel */ public VizCustomizationPanel(JSplitPane divider, VizState vizState) { this.divider = divider; this.vizState = vizState; setBorder(null); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); zoomPane = new JPanel(); zoomPane.setBorder(new OurBorder(false,false,true,false)); zoomPane.setLayout(new BoxLayout(zoomPane, BoxLayout.Y_AXIS)); zoomPane.setAlignmentX(0f); zoomPane.setBackground(wcolor); remakeAll(); } //=============================================================================================================// /** This method selects a particular treenode and shows the details of a particular Type/Set/Relation. * <p> * If x is an instance of AlloyElement, that means it's the latest selected type/set/relation. * If x is GENERAL, NODES, or EDGES, that means the latest selected panel is * the General Graph Settings, Default Type+Set, or Default Relation panels respectively. */ private void zoom(Object x) { lastElement = x; zoomPane.removeAll(); if (x instanceof AlloyNodeElement) makeNodeOptionsPanel(zoomPane, (AlloyNodeElement)x); else if (x instanceof AlloyRelation) makeEdgeOptionsPanel(zoomPane, (AlloyRelation)x); else if (x == GENERAL) createGeneralWidget(zoomPane); else if (x == NODES) createDefaultNodeWidget(zoomPane); else if (x == EDGES) createDefaultEdgeWidget(zoomPane); else { // The following 2 lines make sure the panel doesn't get too small on Mac zoomPane.add(OurUtil.makeH(wcolor, new JLabel(" "), (Object)null)); zoomPane.add(OurUtil.makeH(new Dimension(250, 200), wcolor, (Object)null)); } Dimension dim = zoomPane.getPreferredSize(); if (divider!=null && divider.getDividerLocation()<dim.width) divider.setDividerLocation(dim.width); if (divider!=null && divider.getDividerLocation()>dim.width) dim.width=divider.getDividerLocation(); dim.height = 150; zoomPane.setPreferredSize(dim); dim.width = 450; zoomPane.setMinimumSize(dim); zoomPane.repaint(); validate(); } //=============================================================================================================// /** Regenerate all the customization widgets based on the latest settings. */ public void remakeAll() { // Make the tree final OurTree tree = new OurTree(12) { private static final long serialVersionUID = 0; private final AlloyModel old = vizState.getOriginalModel(), now = vizState.getCurrentModel(); private final boolean hidePrivate = vizState.hidePrivate(), hideMeta = vizState.hideMeta(); { do_start(); setRootVisible(false); setShowsRootHandles(false); listeners.add(new Listener() { public Object do_action(Object sender, Event event) { return null; } public Object do_action(Object sender, Event event, Object arg) { zoom(arg); return null; } }); } @Override public String convertValueToText(Object value, boolean sel, boolean expand, boolean leaf, int i, boolean focus) { if (value==GENERAL) return "<html><b>general graph settings</b></html>"; if (value==NODES) return "<html><b>types and sets</b></html>"; if (value==EDGES) return "<html><b>relations</b></html>"; if (value instanceof AlloyType) { AlloyType x = (AlloyType)value; if (vizState.getCurrentModel().hasType(x)) return "<html><b>sig</b> "+typename(x)+"</html>"; return "<html><b>sig</b> "+typename(x)+" <font color=\"#808080\">(projected)</font></html>"; } if (value instanceof AlloySet) return "<html><b>set</b> "+ ((AlloySet)value).getName() + "</html>"; if (value instanceof AlloyRelation) return value.toString(); else return ""; } @Override public List<?> do_ask(Object parent) { ArrayList<Object> ans = new ArrayList<Object>(); if (parent==ROOT) { ans.add(GENERAL); ans.add(NODES); ans.add(EDGES); } else if (parent==NODES) { ans.add(AlloyType.UNIV); } else if (parent==EDGES) { for (AlloyRelation rel: vizState.getCurrentModel().getRelations()) if (!(hidePrivate && rel.isPrivate) && !(hideMeta && rel.isMeta)) ans.add(rel); } else if (parent instanceof AlloyType) { AlloyType type = (AlloyType)parent; for (AlloySet s:now.getSets()) if (!(hidePrivate && s.isPrivate) && !(hideMeta && s.isMeta) && s.getType().equals(type)) ans.add(s); if (!type.isEnum) for(AlloyType t: old.getDirectSubTypes(type)) if (!(hidePrivate && t.isPrivate) && !(hideMeta && t.isMeta)) if (now.hasType(t) || vizState.canProject(t)) ans.add(t); } return ans; } @Override public boolean do_isDouble(Object object) { return object==NODES || object==EDGES; } @Override public Object do_root() { return ROOT; } }; // Pre-expand the entire tree. TreePath last = null; for(int i=0; i<tree.getRowCount(); i++) { tree.expandRow(i); if (lastElement!=null && last==null) {last=tree.getPathForRow(i); if (lastElement!=last.getLastPathComponent()) last=null;} } // Show the current element if found, else show the GENERAL OPTIONS if (last!=null) { zoom(lastElement); } else { last = tree.getPathForRow(0); zoom(GENERAL); } tree.scrollPathToVisible(last); tree.setSelectionPath(last); JScrollPane scroll = OurUtil.scrollpane(tree, Color.BLACK, Color.WHITE, new OurBorder(false, false, false, Util.onMac())); scroll.setAlignmentX(0f); scroll.getVerticalScrollBar().setUnitIncrement(50); removeAll(); add(zoomPane); add(scroll); validate(); } //=============================================================================================================// /** Generates the node settings widgets for the given type or set, and add them to "parent". */ private void makeNodeOptionsPanel(final JPanel answer, final AlloyNodeElement elt) { final boolean enabled = !(elt instanceof AlloyType) || (vizState.getCurrentModel().hasType((AlloyType)elt)); answer.add(makelabel( (elt instanceof AlloyType) ? (" "+typename((AlloyType)elt)) : (" "+elt) )); final JTextField labelText = OurUtil.textfield(vizState.label.get(elt), 10); labelText.setMaximumSize(new Dimension(100, 25)); labelText.addKeyListener(new KeyAdapter() { @Override public final void keyReleased(KeyEvent e) { vizState.label.put(elt, labelText.getText()); } }); labelText.addActionListener(new ActionListener() { public final void actionPerformed(ActionEvent e) { vizState.label.put(elt, labelText.getText()); } }); labelText.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { vizState.label.put(elt, labelText.getText()); } }); final AlloyModel model = vizState.getCurrentModel(); final AlloyNodeElement elt2; if (elt instanceof AlloyType) elt2=model.getSuperType((AlloyType)elt); else if (elt instanceof AlloySet) elt2=((AlloySet)elt).getType(); else elt2=null; JComboBox color = new OurCombobox(true, DotColor.valuesWithout(DotColor.MAGIC), 100, 35, vizState.nodeColor.get(elt)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { if (value==null) return "Inherit"; else return ((DotColor)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { if (value==null) value=vizState.nodeColor.resolve(elt2); return value==null ? null : ((DotColor)value).getIcon(vizState.getNodePalette()); } @Override public void do_changed(Object value) { vizState.nodeColor.put(elt, (DotColor)value); } }; JComboBox shape = new OurCombobox(true, DotShape.values(), 125, 35, vizState.shape.get(elt)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { if (value==null) return "Inherit"; else return ((DotShape)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { if (value==null) value=vizState.shape.resolve(elt2); return value==null ? null : ((DotShape)value).getIcon(); } @Override public void do_changed(Object value) { vizState.shape.put(elt, (DotShape)value); } }; JComboBox style = new OurCombobox(true, DotStyle.values(), 95, 35, vizState.nodeStyle.get(elt)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { if (value==null) return "Inherit"; else return ((DotStyle)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { if (value==null) value=vizState.nodeStyle.resolve(elt2); return value==null ? null : ((DotStyle)value).getIcon(); } @Override public void do_changed(Object value) { vizState.nodeStyle.put(elt, (DotStyle)value); } }; // answer.add(OurUtil.makeH(10, labelText, wcolor, color, style, shape, 2, null)); if (elt instanceof AlloyType) { JPanel vis = vizState.nodeVisible .pick(elt, "Show", "Display members as nodes"); JPanel con = vizState.hideUnconnected.pick(elt, "Hide unconnected nodes", "Hide nodes without arcs"); JPanel num = vizState.number .pick(elt, "Number nodes", "Attach atom number to node label as suffix"); JPanel proj = null; if (vizState.canProject((AlloyType)elt)) proj = new OurCheckbox("Project over this sig", "Click here to " + (enabled?"":"un") + "project over this signature", enabled ? OurCheckbox.ALL_OFF : OurCheckbox.ALL_ON) { private static final long serialVersionUID = 0; public Icon do_action() { if (enabled) projectAlloyType((AlloyType)elt); else deprojectAlloyType((AlloyType)elt); lastElement = elt; return enabled ? ALL_ON : ALL_OFF; } }; labelText.setEnabled(enabled && !vizState.useOriginalName()); color.setEnabled(enabled); shape.setEnabled(enabled); style.setEnabled(enabled); vis.setEnabled(enabled); con.setEnabled(enabled); num.setEnabled(enabled && !vizState.useOriginalName()); JPanel a=OurUtil.makeVR(wcolor,vis,num),b; if (proj!=null) b=OurUtil.makeVR(wcolor, con, proj); else b=OurUtil.makeVR(wcolor, con); answer.add(OurUtil.makeHT(wcolor, 15,a,15,b,2,null)); } else { JPanel vis = vizState.nodeVisible .pick(elt, "Show", "Include members of set as nodes"); JPanel attr = vizState.showAsAttr .pick(elt, "Show in relation attributes", "Show set membership in relation attributes"); JPanel lab = vizState.showAsLabel .pick(elt, "Show as labels", "Show membership in set by labeling nodes"); JPanel con = vizState.hideUnconnected.pick(elt, "Hide unconnected nodes", "Hide nodes without arcs"); JPanel a=OurUtil.makeVR(wcolor,vis,lab), b=OurUtil.makeVR(wcolor, con, attr); answer.add(OurUtil.makeHT(wcolor, 15,a,15,b,2,null)); } } //=============================================================================================================// /** Generates the edge settings widgets for the given relation, and add them to "parent". */ private void makeEdgeOptionsPanel(final JPanel parent, final AlloyRelation rel) { final JTextField labelText = OurUtil.textfield(vizState.label.get(rel), 10); labelText.setMaximumSize(new Dimension(100, 25)); labelText.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { vizState.label.put(rel, labelText.getText()); } }); labelText.addActionListener(new ActionListener() { public final void actionPerformed(ActionEvent e) { vizState.label.put(rel, labelText.getText()); } }); labelText.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { vizState.label.put(rel, labelText.getText()); } }); final JLabel weightLabel = OurUtil.label("Weight:"); final JSpinner weightSpinner = new JSpinner(new SpinnerNumberModel(vizState.weight.get(rel), 0, 999, 1)); weightSpinner.setMaximumSize(weightSpinner.getPreferredSize()); weightSpinner.setToolTipText("A higher weight will cause the edge to be shorter and straighter."); weightSpinner.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { vizState.weight.put(rel, (Integer) (weightSpinner.getValue())); } }); weightSpinner.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { vizState.weight.put(rel, (Integer) (weightSpinner.getValue())); } @Override public void mousePressed(MouseEvent e) { vizState.weight.put(rel, (Integer) (weightSpinner.getValue())); } @Override public void mouseReleased(MouseEvent e) { vizState.weight.put(rel, (Integer) (weightSpinner.getValue())); } }); weightSpinner.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { vizState.weight.put(rel, (Integer) (weightSpinner.getValue())); } }); JPanel weightPanel = OurUtil.makeH(weightLabel, 5, weightSpinner); weightPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); weightPanel.setAlignmentY(0.5f); weightPanel.setToolTipText("A higher weight will cause the edge to be shorter and straighter."); OurCombobox color = new OurCombobox(true, DotColor.valuesWithout(DotColor.WHITE), 110, 35, vizState.edgeColor.get(rel)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { return value==null ? "Inherit" : ((DotColor)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { if (value==null) value=vizState.edgeColor.get(null); return value==null ? null : ((DotColor)value).getIcon(vizState.getEdgePalette()); } @Override public void do_changed(Object value) { vizState.edgeColor.put(rel, (DotColor)value); } }; OurCombobox style = new OurCombobox(true, DotStyle.values(), 105, 35, vizState.edgeStyle.get(rel)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { return value==null ? "Inherit" : ((DotStyle)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { if (value==null) value=vizState.edgeStyle.get(null); return value==null ? null : ((DotStyle)value).getIcon(); } @Override public void do_changed(Object value) { vizState.edgeStyle.put(rel, (DotStyle)value); } }; JPanel visible = vizState.edgeVisible.pick(rel, "Show as arcs", "Show relation as arcs"); JPanel attr = vizState.attribute .pick(rel, "Show as attribute", "Additionally display this relation as an attribute on the nodes' labels"); JPanel back = vizState.layoutBack .pick(rel, "Layout backwards", "Layout graph as if arcs were reversed"); JPanel merge = vizState.mergeArrows.pick(rel, "Merge arrows", "Merge opposing arrows between the same nodes as one bidirectional arrow"); JPanel constraint = vizState.constraint .pick(rel, "Influence layout", "Whether this edge influences the graph layout"); JPanel panel1 = OurUtil.makeVR(wcolor, visible, attr, constraint); JPanel panel2 = OurUtil.makeVR(wcolor, back, merge); parent.add(makelabel("<html> " + Util.encode(rel.toString()) + "</html>")); parent.add(OurUtil.makeH(10, labelText, wcolor, 5, color, 5, style, 3, weightPanel, 2, null)); parent.add(OurUtil.makeHT(wcolor, 10, panel1, 15, panel2, 2, null)); } //=============================================================================================================// /** Generates the "general graph settings" widgets, and add them to "parent". */ private void createGeneralWidget(JPanel parent) { final List<Integer> fontSizes = Util.asList(9,10,11,12,14,16,18,20,22,24,26,28,32,36,40,44,48,54,60,66,72); JLabel nLabel = OurUtil.label("Node Color Palette:"); JLabel eLabel = OurUtil.label("Edge Color Palette:"); JLabel aLabel = OurUtil.label("Use original atom names:"); JLabel pLabel = OurUtil.label("Hide private sigs/relations:"); JLabel mLabel = OurUtil.label("Hide meta sigs/relations:"); JLabel fLabel = OurUtil.label("Font Size:"); JComboBox fontSize = new OurCombobox(false, fontSizes.toArray(), 60, 32, vizState.getFontSize()) { private static final long serialVersionUID = 0; @Override public void do_changed(Object value) { if (fontSizes.contains(value)) vizState.setFontSize((Integer)value); } }; JComboBox nodepal = new OurCombobox(false, DotPalette.values(), 100, 32, vizState.getNodePalette()) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { return ((DotPalette)value).getDisplayedText(); } @Override public void do_changed(Object value) { vizState.setNodePalette((DotPalette)value); } }; JComboBox edgepal = new OurCombobox(false, DotPalette.values(), 100, 32, vizState.getEdgePalette()) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { return ((DotPalette)value).getDisplayedText(); } @Override public void do_changed(Object value) { vizState.setEdgePalette((DotPalette)value); } }; JPanel name = new OurCheckbox("", "Whether the visualizer should use the original atom names as-is.", vizState.useOriginalName() ? OurCheckbox.ON : OurCheckbox.OFF) { private static final long serialVersionUID = 0; public Icon do_action() { boolean x = vizState.useOriginalName(); vizState.useOriginalName(!x); return (!x ? ON : OFF); } }; JPanel priv = new OurCheckbox("", "Whether the visualizer should hide private sigs, sets, and relations by default.", vizState.hidePrivate() ? OurCheckbox.ON : OurCheckbox.OFF) { private static final long serialVersionUID = 0; public Icon do_action() { boolean x = vizState.hidePrivate(); vizState.hidePrivate(!x); remakeAll(); return (!x ? ON : OFF); } }; JPanel meta = new OurCheckbox("", "Whether the visualizer should hide meta sigs, sets, and relations by default.", vizState.hideMeta() ? OurCheckbox.ON : OurCheckbox.OFF) { private static final long serialVersionUID = 0; public Icon do_action() { boolean x = vizState.hideMeta(); vizState.hideMeta(!x); remakeAll(); return (!x ? ON : OFF); } }; parent.add(makelabel(" General Graph Settings:")); parent.add(OurUtil.makeH(wcolor, new Dimension(6, 6))); parent.add(OurUtil.makeH(wcolor, 25, nLabel, 5, nodepal, 8, aLabel, 5, name, 2, null)); parent.add(OurUtil.makeH(wcolor, 25, eLabel, 5, edgepal, 8, fLabel, 5, fontSize, 2, null)); parent.add(OurUtil.makeH(wcolor, 25, pLabel, 5, priv, 2, null)); parent.add(OurUtil.makeH(wcolor, 25, mLabel, 5, meta, 2, null)); } //=============================================================================================================// /** Generates the "default type and set settings" widgets, and add them to "parent". */ private void createDefaultNodeWidget(JPanel parent) { JComboBox color = new OurCombobox(false, DotColor.valuesWithout(DotColor.MAGIC), 110, 35, vizState.nodeColor.get(null)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { return ((DotColor)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { return ((DotColor)value).getIcon(vizState.getNodePalette()); } @Override public void do_changed(Object value) { vizState.nodeColor.put(null, (DotColor)value); } }; JComboBox shape = new OurCombobox(false, DotShape.values(), 135, 35, vizState.shape.get(null)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { return ((DotShape)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { return ((DotShape)value).getIcon(); } @Override public void do_changed(Object value) { vizState.shape.put(null, (DotShape)value); } }; JComboBox style = new OurCombobox(false, DotStyle.values(), 110, 35, vizState.nodeStyle.get(null)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { return ((DotStyle)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { return ((DotStyle)value).getIcon(); } @Override public void do_changed(Object value) { vizState.nodeStyle.put(null, (DotStyle)value); } }; JPanel vis = vizState.nodeVisible .pick("Show", "Show members of type as nodes"); JPanel hide = vizState.hideUnconnected.pick("Hide unconnected nodes", "Hide nodes without arcs"); JPanel num = vizState.number .pick("Number nodes", "Attach atom number to node label as suffix"); JPanel label= vizState.showAsLabel .pick("Show as labels", "Show members as labels"); JPanel attr = vizState.showAsAttr .pick("Show in relation attributes", "Show set membership of endpoints when relation attributes are enabled"); parent.add(makelabel(" Default Type and Set Settings:")); parent.add(OurUtil.makeH(wcolor, 10, color, 7, style, 7, shape, 2, null)); JPanel a=OurUtil.makeVL(wcolor, vis, num, label), b=OurUtil.makeVL(wcolor, hide, attr); parent.add(OurUtil.makeHT(wcolor, 10, a, 10, b, 2, null)); } //=============================================================================================================// /** Generates the "default relation settings" widgets, and add them to "parent". */ private void createDefaultEdgeWidget(JPanel parent) { JComboBox colorComboE = new OurCombobox(false, DotColor.valuesWithout(DotColor.WHITE), 110, 35, vizState.edgeColor.get(null)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { return ((DotColor)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { return ((DotColor)value).getIcon(vizState.getEdgePalette()); } @Override public void do_changed(Object value) { vizState.edgeColor.put(null, (DotColor)value); } }; JComboBox outlineComboE = new OurCombobox(false, DotStyle.values(), 110, 35, vizState.edgeStyle.get(null)) { private static final long serialVersionUID = 0; @Override public String do_getText(Object value) { return ((DotStyle)value).getDisplayedText(); } @Override public Icon do_getIcon(Object value) { return ((DotStyle)value).getIcon(); } @Override public void do_changed(Object value) { vizState.edgeStyle.put(null, (DotStyle)value); } }; JPanel dispCBE = vizState.edgeVisible.pick("Show as arcs", "Show relations as arcs"); JPanel mergeCBE = vizState.mergeArrows.pick("Merge arrows", "Merge opposing arrows of the same relation"); JPanel constraintCBE = vizState.constraint .pick("Influence layout", "Whether this edge influences the graph layout"); JPanel attrCBE = vizState.attribute .pick("Show as attributes", "Show relations as attributes on nodes"); JPanel laybackCBE = vizState.layoutBack .pick("Layout backwards", "Layout graph as if arcs were reversed"); parent.add(makelabel(" Default Relation Settings:")); parent.add(OurUtil.makeH(wcolor, 10, colorComboE, 8, outlineComboE, 2, null)); JPanel a=OurUtil.makeVL(wcolor, dispCBE, attrCBE, constraintCBE, 10), b=OurUtil.makeVL(wcolor, laybackCBE, mergeCBE); parent.add(OurUtil.makeHT(wcolor, 10, a, 10, b, 2, null)); } //=============================================================================================================// /** Convenient helper method that returns a description of an AlloyType (and what it extends). */ private String typename(AlloyType type) { if (type.equals(AlloyType.UNIV)) return "univ"; AlloyType sup=vizState.getOriginalModel().getSuperType(type); if (sup!=null && !sup.equals(AlloyType.UNIV)) return type.getName()+" extends "+sup.getName(); return type.getName(); } /** Generates a black JLabel for the given String. */ private static JLabel makelabel(String label) { return OurUtil.label(label, OurUtil.getVizFont().deriveFont(Font.BOLD)); } /** Project over the given type if we are allowed to. */ private void projectAlloyType(AlloyType type) { vizState.project(type); remakeAll(); } /** Unproject over the given type if it is currently projected. */ private void deprojectAlloyType(AlloyType type) { vizState.deproject(type); remakeAll(); } }