/* * Licensed Materials - Property of Rogue Wave Software, Inc. * © Copyright Rogue Wave Software, Inc. 2014, 2015 * © Copyright IBM Corp. 2009, 2014 * © Copyright ILOG 1996, 2009 * All Rights Reserved. * * Note to U.S. Government Users Restricted Rights: * The Software and Documentation were developed at private expense and * are "Commercial Items" as that term is defined at 48 CFR 2.101, * consisting of "Commercial Computer Software" and * "Commercial Computer Software Documentation", as such terms are * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4, * as applicable. */ import ilog.views.diagrammer.IlvDiagrammer; import ilog.views.diagrammer.application.IlvDiagrammerViewBar; import ilog.views.diagrammer.application.IlvDiagrammerAction; import ilog.views.sdm.IlvSDMEngine; import ilog.views.sdm.renderer.graphlayout.IlvGraphLayoutRenderer; import ilog.views.sdm.util.IlvSDMMutableStyleSheet; import ilog.views.graphlayout.IlvGraphLayout; import ilog.views.graphlayout.IlvGraphLayoutReport; import ilog.views.graphlayout.GraphLayoutEvent; import ilog.views.graphlayout.GraphLayoutEventListener; import ilog.views.graphlayout.random.IlvRandomLayout; import ilog.views.IlvGrid; import ilog.views.IlvPoint; import ilog.views.IlvTransformer; import ilog.views.util.IlvProductUtil; import ilog.views.util.swing.IlvSwingUtil; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.net.URL; /** * This is a very simple applet/application that uses the * <code>IlvDiagrammer</code> to perform a grid layout. * It loads a style sheet containing the grid layout specification. * It allows to set various grid layout parameters by using the * <code>IlvSDMMutableStyleSheet</code>. */ public class GridLayoutApplet extends JApplet { { // This sample uses JViews Diagrammer features. When deploying an // application that includes this code, you need to be in possession // of a Rogue Wave JViews Diagrammer Deployment license. IlvProductUtil.DeploymentLicenseRequired( IlvProductUtil.JViews_Diagrammer_Deployment); } /** The diagrammer */ IlvDiagrammer diagrammer = new IlvDiagrammer(); /** A graph layout event listener */ LayoutIterationListener layoutListener = new LayoutIterationListener(); /** The style sheet for temporary changes */ IlvSDMMutableStyleSheet styleSheet = new IlvSDMMutableStyleSheet( diagrammer.getEngine(), true, false); /** An IlvGrid object to help understanding the grid mode */ IlvGrid grid = new LineGrid(); /** The default offset */ static final float DEFAULT_OFFSET = 80.f; /** Text fields for the offset parameters */ JTextField hGridOffset = new JTextField("" + DEFAULT_OFFSET, 5); JTextField vGridOffset = new JTextField("" + DEFAULT_OFFSET, 5); /** A text field to display messages */ JTextField msgLine = new JTextField(); /** * Initializes the applet/application. */ public void init() { // we use the standard diagrammer toolbar IlvDiagrammerViewBar toolbar = new IlvDiagrammerViewBar(); // various settings of the diagrammer diagrammer.setSelectMode(true); diagrammer.setScrollable(true); diagrammer.setEditingAllowed(true); diagrammer.setMinimumZoom(0.02f); diagrammer.setMaximumZoom(10f); diagrammer.getView().setBackground(Color.white); diagrammer.getView().setForeground(SystemColor.windowText); // help recognition of the grid diagrammer.getView().setGrid(grid); grid.setOrigin(new IlvPoint(0, 0)); grid.setColor(new Color(255, 153, 153)); grid.setHorizontalSpacing(80); grid.setVerticalSpacing(80); grid.setActive(false); grid.setVisible(true); // create the file selector JComboBox fileSelector = new JComboBox(); fileSelector.addItem("small"); fileSelector.addItem("medium"); fileSelector.addItem("large"); fileSelector.setToolTipText("Select a sample graph"); fileSelector.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { JComboBox comboBox = (JComboBox)event.getSource(); String fileName = (String)comboBox.getSelectedItem(); loadDataFile(fileName); } }); // create the randomize button JButton randomizeButton = new JButton("Random"); randomizeButton.setToolTipText("Randomize the node positions"); randomizeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { randomize(); }}); // create the layout button JButton layoutButton = new JButton("Layout"); layoutButton.setToolTipText("Perform a grid layout"); layoutButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { // before performing layout, make sure that the values in the text // fields are transfered to the style sheet styleSheet.setAdjusting(true); try { setOffset("horizontalGridOffset", hGridOffset); setOffset("verticalGridOffset", vGridOffset); } finally { styleSheet.setAdjusting(false); } performLayout(); }}); // create the panel for the layout buttons JPanel layoutButtonPanel = new JPanel(); layoutButtonPanel.setLayout(new FlowLayout()); layoutButtonPanel.add(randomizeButton); layoutButtonPanel.add(layoutButton); // create the top panel with the toolbar and the file selector JPanel topPanel = new JPanel(); topPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); topPanel.add(toolbar); topPanel.add(new JLabel("Select graph:")); topPanel.add(fileSelector); // create the bottom panel with the layout buttons and the message line JPanel bottomPanel = new JPanel(); bottomPanel.setLayout(new BorderLayout()); bottomPanel.add(layoutButtonPanel, BorderLayout.NORTH); bottomPanel.add(createParameterPanel(), BorderLayout.CENTER); bottomPanel.add(msgLine, BorderLayout.SOUTH); msgLine.setEditable(false); // put diagrammer, top panel and bottom panel together getContentPane().setLayout(new BorderLayout(0, 0)); getContentPane().add(diagrammer, BorderLayout.CENTER); getContentPane().add(topPanel, BorderLayout.NORTH); getContentPane().add(bottomPanel, BorderLayout.SOUTH); try { // load the main style file diagrammer.setStyleSheet( IlvSwingUtil.getRelativeURL(this, "data/grid.css")); // load a mutable style file that we use for temporary style changes diagrammer.getEngine().setStyleSheets(1, styleSheet.toString()); } catch (Exception e) { showMessage(e.getMessage()); } // load the initial sample grapher loadDataFile("small"); // add the layout listener to the current graph layout. This must be done // here after reading the style file, because before reading the style file, // the layout instance is not yet instantiated. getGraphLayout().addGraphLayoutEventListener(layoutListener); } /** * Called when this applet is being reclaimed in order to destroy * any resources that it has allocated. */ public void destroy() { super.destroy(); // This method is intended to workaround memory management issues // in the Sun JRE. Please refer to the method documentation for more // details and a description of the known issues. IlvSwingUtil.cleanupApplet(); } /** * Creates the layout parameter panel. */ private JPanel createParameterPanel() { JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); // - - - - - - - - - - - - - - - - - // the offset panel with all offsets JPanel offsetPanel = new JPanel(); offsetPanel.setLayout(new GridLayout(2, 2)); // the horizontal grid offsets final JLabel hGridOffsetLabel = new JLabel(" Horizontal:"); offsetPanel.add(hGridOffsetLabel); offsetPanel.add(hGridOffset); hGridOffset.setToolTipText("Select the horizontal grid offset"); hGridOffset.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setOffset("horizontalGridOffset", (JTextField)e.getSource()); } }); // the vertical grid offsets final JLabel vGridOffsetLabel = new JLabel(" Vertical:"); offsetPanel.add(vGridOffsetLabel); offsetPanel.add(vGridOffset); vGridOffset.setToolTipText("Select the vertical grid offset"); vGridOffset.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setOffset("verticalGridOffset", (JTextField)e.getSource()); } }); // - - - - - - - - - - - - - - - - - // the panel with check boxes JPanel checkBoxPanel = new JPanel(); JCheckBox incrementalOption = new JCheckBox("Incremental", false); checkBoxPanel.add(incrementalOption); incrementalOption.setToolTipText("Enable or disable the incremental mode"); incrementalOption.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { setIncrementalMode(e.getStateChange() == ItemEvent.SELECTED); } }); JCheckBox preserveFixedNodesOption = new JCheckBox("Fix Selected", false); checkBoxPanel.add(preserveFixedNodesOption); preserveFixedNodesOption.setToolTipText( "Enable or disable that selected nodes don't move"); preserveFixedNodesOption.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { setSelectedAreFixed(e.getStateChange() == ItemEvent.SELECTED); } }); final JCheckBox showGridOption = new JCheckBox("Show grid", true); checkBoxPanel.add(showGridOption); showGridOption.setToolTipText("Display or hide the grid"); showGridOption.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { showGrid(e.getStateChange() == ItemEvent.SELECTED); } }); // - - - - - - - - - - - - - - - - - // the panel with choice boxes JPanel selectionPanel = new JPanel(); selectionPanel.setLayout(new GridLayout(3, 2)); // horizontal global alignment parameter final JLabel horizAlignmentLabel = new JLabel("Horizontal Alignment:"); final JComboBox hAlignmentChooser = new JComboBox(); selectionPanel.add(horizAlignmentLabel); selectionPanel.add(hAlignmentChooser); hAlignmentChooser.addItem("Center "); hAlignmentChooser.addItem("Left"); hAlignmentChooser.addItem("Right"); hAlignmentChooser.setSelectedIndex(0); hAlignmentChooser.setToolTipText("Select the horizontal alignment mode"); hAlignmentChooser.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { JComboBox comboBox = (JComboBox)event.getSource(); String mode = (String)comboBox.getSelectedItem(); setGlobalHorizontalAlignment(mode); } }); // vertical global alignment parameter final JLabel vertAlignmentLabel = new JLabel("Vertical Alignment:"); final JComboBox vAlignmentChooser = new JComboBox(); selectionPanel.add(vertAlignmentLabel); selectionPanel.add(vAlignmentChooser); vAlignmentChooser.addItem("Center"); vAlignmentChooser.addItem("Top"); vAlignmentChooser.addItem("Bottom"); vAlignmentChooser.setSelectedIndex(0); vAlignmentChooser.setToolTipText("Select the vertical alignment mode"); vAlignmentChooser.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { JComboBox comboBox = (JComboBox)event.getSource(); String mode = (String)comboBox.getSelectedItem(); setGlobalVerticalAlignment(mode); } }); // layout mode JComboBox layoutModeSelector = new JComboBox(); selectionPanel.add(new JLabel("Layout Mode:")); selectionPanel.add(layoutModeSelector); layoutModeSelector.addItem("Grid (fixed width)"); layoutModeSelector.addItem("Grid (fixed height)"); layoutModeSelector.addItem("Rows"); layoutModeSelector.addItem("Columns"); layoutModeSelector.setSelectedIndex(0); layoutModeSelector.setToolTipText("Select the layout mode"); layoutModeSelector.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { JComboBox comboBox = (JComboBox)event.getSource(); String mode = (String)comboBox.getSelectedItem(); setLayoutMode(mode, showGridOption, vGridOffsetLabel, vGridOffset, hGridOffsetLabel, hGridOffset, horizAlignmentLabel, hAlignmentChooser, vertAlignmentLabel, vAlignmentChooser); } }); // - - - - - - - - - - - - - - - - - // put all together panel.add(selectionPanel, BorderLayout.WEST); panel.add(offsetPanel, BorderLayout.EAST); panel.add(checkBoxPanel, BorderLayout.SOUTH); return panel; } /** * Load a sample data file. * @param fileNameBase The base of the filename, excluding the path prefix * and the extension suffix. */ private void loadDataFile(String fileNameBase) { try { showMessage("Reading " + fileNameBase + ".xml ..."); diagrammer.setDataFile( IlvSwingUtil.getRelativeURL(this, "data/" + fileNameBase + ".xml")); showMessage("Reading " + fileNameBase + ".xml done."); } catch (Exception e) { showMessage(e.getMessage()); } } /** * Sets the horizontal or vertical offset from a textfield. */ private void setOffset(String property, JTextField valueSelector) { try { // get the value of the parameter from the valueSelector float value = Float.valueOf(valueSelector.getText().trim()).floatValue(); // write again to be sure the right value is shown valueSelector.setText("" + value); // set the new value of the layout property styleSheet.setDeclaration("GraphLayout", property, "" + value); // sets the grid offset also in the visible grid if (property.equals("horizontalGridOffset")) grid.setHorizontalSpacing(value); if (property.equals("verticalGridOffset")) grid.setVerticalSpacing(value); // redraw the view diagrammer.getView().repaint(); } catch (Exception ex) { showMessage("Illegal " + property + ": " + ex.getMessage()); } } /** * Sets the incremental mode. */ private void setIncrementalMode(boolean flag) { styleSheet.setDeclaration("GraphLayout", "incrementalMode", (flag ? "true" : "false")); } /** * Sets whether nodes specified as fixes (that is, nodes that are selected) * are really fixed. */ private void setSelectedAreFixed(boolean flag) { // don't set preserveFixedNodes because it is automatically set by // the graph layout renderer depending on the existence of the Fixed // property on a node. styleSheet.setDeclaration("node:selected", "Fixed", (flag ? "true" : "false")); } /** * Enables or disabled the display of a grid. */ private void showGrid(boolean show) { boolean visible = grid.isVisible(); if (visible != show) { grid.setVisible(show); diagrammer.getView().repaint(); } } /** * Sets the horizontal alignment. */ private void setGlobalHorizontalAlignment(String mode) { if (mode.equals("Center")) { styleSheet.setDeclaration("GraphLayout", "globalHorizontalAlignment", "CENTER"); } else if (mode.equals("Left")) { styleSheet.setDeclaration("GraphLayout", "globalHorizontalAlignment", "LEFT"); } else if (mode.equals("Right")) { styleSheet.setDeclaration("GraphLayout", "globalHorizontalAlignment", "RIGHT"); } } /** * Sets the vertical alignment. */ private void setGlobalVerticalAlignment(String mode) { if (mode.equals("Center")) { styleSheet.setDeclaration("GraphLayout", "globalVerticalAlignment", "CENTER"); } else if (mode.equals("Top")) { styleSheet.setDeclaration("GraphLayout", "globalVerticalAlignment", "TOP"); } else if (mode.equals("Bottom")) { styleSheet.setDeclaration("GraphLayout", "globalVerticalAlignment", "BOTTOM"); } } /** * Sets the layout mode. */ private void setLayoutMode(String mode, JCheckBox showGridOption, JComponent vGridOffsetLabel, JComponent vGridOffset, JComponent hGridOffsetLabel, JComponent hGridOffset, JComponent horizAlignmentLabel, JComponent hAlignmentChooser, JComponent vertAlignmentLabel, JComponent vAlignmentChooser) { if (mode.equals("Grid (fixed width)")) { vGridOffsetLabel.setEnabled(true); vGridOffset.setEnabled(true); hGridOffsetLabel.setEnabled(true); hGridOffset.setEnabled(true); showGridOption.setEnabled(true); showGrid(showGridOption.isSelected()); horizAlignmentLabel.setEnabled(true); hAlignmentChooser.setEnabled(true); vertAlignmentLabel.setEnabled(true); vAlignmentChooser.setEnabled(true); styleSheet.setDeclaration("GraphLayout", "layoutMode", "TILE_TO_GRID_FIXED_WIDTH"); } else if (mode.equals("Grid (fixed height)")) { vGridOffsetLabel.setEnabled(true); vGridOffset.setEnabled(true); hGridOffsetLabel.setEnabled(true); hGridOffset.setEnabled(true); showGridOption.setEnabled(true); showGrid(showGridOption.isSelected()); horizAlignmentLabel.setEnabled(true); hAlignmentChooser.setEnabled(true); vertAlignmentLabel.setEnabled(true); vAlignmentChooser.setEnabled(true); styleSheet.setDeclaration("GraphLayout", "layoutMode", "TILE_TO_GRID_FIXED_HEIGHT"); } else if (mode.equals("Rows")) { vGridOffsetLabel.setEnabled(false); vGridOffset.setEnabled(false); hGridOffsetLabel.setEnabled(false); hGridOffset.setEnabled(false); showGridOption.setEnabled(false); showGrid(false); horizAlignmentLabel.setEnabled(false); hAlignmentChooser.setEnabled(false); vertAlignmentLabel.setEnabled(true); vAlignmentChooser.setEnabled(true); styleSheet.setDeclaration("GraphLayout", "layoutMode", "TILE_TO_ROWS"); } else if (mode.equals("Columns")) { vGridOffsetLabel.setEnabled(false); vGridOffset.setEnabled(false); hGridOffsetLabel.setEnabled(false); hGridOffset.setEnabled(false); showGridOption.setEnabled(false); showGrid(false); horizAlignmentLabel.setEnabled(true); hAlignmentChooser.setEnabled(true); vertAlignmentLabel.setEnabled(false); vAlignmentChooser.setEnabled(false); styleSheet.setDeclaration("GraphLayout", "layoutMode", "TILE_TO_COLUMNS"); } } /** * Performs the grid layout. * The layout type is stored in the CSS file, therefore we don't need to * set the grid layout explicitely. After loading the graph and the CSS * style sheet, the grid layout is already instantiated. */ private void performLayout() { showMessage("Layout started..."); // initialize the iteration listener layoutListener.initialize(getGraphLayout()); // Perform Grid Layout as node layout. Grid layout always handles nodes // and links at the same time, therefore a separate link layout is not // necessary. if (diagrammer.isNodeLayoutAvailable()) { // perform the layout diagrammer.layoutAllNodes(); // show the layout report information about the return code IlvGraphLayoutReport report = getGraphLayout().getLayoutReport(); if (report != null) { showMessage(report.codeToString(report.getCode()) + "."); } } } /** * Randomize the node positions. */ private void randomize() { // clear previous message showMessage(""); // create a new random layout IlvRandomLayout randomLayout = new IlvRandomLayout(); // save the old layout instance IlvGraphLayout oldLayout = getGraphLayout(); // tell the diagrammer to temporarily use the random layout, which // disabled the grid layout. setGraphLayout(randomLayout); if (diagrammer.isNodeLayoutAvailable()) { // perform the layout diagrammer.layoutAllNodes(); } // restore the old layout instance setGraphLayout(oldLayout); } /** * Returns the graph layout currently used by the diagrammer. */ private IlvGraphLayout getGraphLayout() { IlvGraphLayoutRenderer renderer = (IlvGraphLayoutRenderer)diagrammer.getEngine().getNodeLayoutRenderer(); return renderer == null ? null : renderer.getGraphLayout(); } /** * Sets the graph layout currently used by the diagrammer. */ private void setGraphLayout(IlvGraphLayout layout) { IlvGraphLayoutRenderer renderer = (IlvGraphLayoutRenderer)diagrammer.getEngine().getNodeLayoutRenderer(); if (renderer == null) return; renderer.setGraphLayout(layout); } /** * Displays a message. */ void showMessage(String message) { // the message is displayed in the message line msgLine.setText(message); msgLine.paintImmediately(0, 0, msgLine.getWidth(), msgLine.getHeight()); } /** * Allows you to run the demo as a standalone application. */ public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { GridLayoutApplet applet = new GridLayoutApplet(); applet.init(); JFrame frame = new JFrame("Grid Layout Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(500, 600); frame.getContentPane().add(applet); frame.setVisible(true); } }); } // -------------------------------------------------------------------------- /** * A subclass of ilog.views.IlvGrid that draws lines instead of points. */ private class LineGrid extends IlvGrid { /** * Creates a new grid. * The origin of the grid is the point (0,0). The horizontal * and verical spacing are 10. The grid is active and visible. */ public LineGrid() { super(); } /** * Creates a new grid. * @param color the color of the grid points. * @param origin the coordinates of the upper-left corner of the grid in the * manager coordinates system. * @param hspacing spacing of grid points along the horizontal axis. * @param vspacing spacing of grid points along the vertical axis. * @param visible Specifies whether the grid is visible (<code>true</code>) of invisible. * @param active Specifies whether the grid is active (<code>true</code>) of inactive. * @see IlvManagerView#setGrid */ public LineGrid(Color color, IlvPoint origin, float hspacing, float vspacing, boolean visible, boolean active) { super(color, origin, hspacing, vspacing, visible, active); } /** * Draws the grid. * This method is called by the view (<code>IlvManagerView</code>) * to draw the grid. * @param dst the Graphics object to perform the drawing of the grid. * @param t the transformer used to draw to grid. * @param rect The area where the grid will be drawn. Note that the * grid is drawn only at the intersection of this area with the clipping * area provided in the <code>dst</code> parameter. * When the grid is used in an <code>IlvManagerView</code>, this * parameter is the bounding rectangle of the view. */ protected void draw(Graphics dst, IlvTransformer t, Rectangle rect) { if (!isVisible()) return; Shape oldclip = dst.getClip(); Rectangle theclip = oldclip.getBounds(); Rectangle areaToDraw = theclip.intersection(rect); if (areaToDraw.width == 0 || areaToDraw.height == 0) return; dst.clipRect(areaToDraw.x, areaToDraw.y, areaToDraw.width, areaToDraw.height); // the origin IlvPoint orig = new IlvPoint(); // the spacing parameters IlvPoint spacing = new IlvPoint(getHorizontalSpacing() * getHorizontalShown(), getVerticalSpacing() * getHorizontalShown()); if (t != null) { t.apply(orig); t.apply(spacing); } // in view coords float spacingX = Math.abs(orig.x - spacing.x); float spacingY = Math.abs(orig.y - spacing.y); if (spacingX < 4 || spacingY < 4) return; float minX = areaToDraw.x; float maxX = areaToDraw.x + areaToDraw.width; float minY = areaToDraw.y; float maxY = areaToDraw.y + areaToDraw.height; IlvPoint originPoint = getOrigin(); if (t != null) t.apply(originPoint); int nX = (int)Math.ceil((minX - originPoint.x) / spacingX); int nY = (int)Math.ceil((minY - originPoint.y) / spacingY); float fromX = originPoint.x + nX * spacingX; float fromY = originPoint.y + nY * spacingY; dst.setColor(getColor()); // draw horizontal lines for (double y = fromY; y <= maxY; y += spacingY) dst.drawLine((int)Math.floor(minX), (int)Math.floor(y), (int)Math.floor(maxX), (int)Math.floor(y)); // draw vertical lines for (double x = fromX; x <= maxX; x += spacingX) dst.drawLine((int)Math.floor(x), (int)Math.floor(minY), (int)Math.floor(x), (int)Math.floor(maxY)); dst.setClip(oldclip); } } // -------------------------------------------------------------------------- /** * A graph layout iteration listener. Implementing the interface * GraphLayoutEventListener gives you the possibility to receive * during the layout information about the behavior of the layout * algorithm. This information is contained in the graph layout event. * * In our case, we will simply print a dot each time the method * layoutStepPerformed is called, that is after each iteration of * the Bus Layout algorithm. */ class LayoutIterationListener implements GraphLayoutEventListener { private IlvGraphLayout layout; private String toShow = ""; private static final int MAX_LENGTH = 50; /** * This method is automatically called by the layout algorithm. */ public void layoutStepPerformed(GraphLayoutEvent event) { // the status area has a limited width, so we are forced to // reinitialize the message string if (toShow.length() > MAX_LENGTH) toShow = ""; toShow += "."; showMessage(toShow); } /** * Initialize the listener. * This method must be called before the layout is started. */ void initialize(IlvGraphLayout l) { if (layout != l) { if (layout != null) layout.removeGraphLayoutEventListener(this); layout = l; if (layout != null) layout.addGraphLayoutEventListener(this); } toShow = ""; } } }