/* * Licensed Materials - Property of Perforce Software, Inc. * © Copyright Perforce Software, Inc. 2014, 2021 * © 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 java.awt.BorderLayout; import java.awt.Color; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.SystemColor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.JTextField; import ilog.views.diagrammer.IlvDiagrammer; import ilog.views.diagrammer.application.IlvDiagrammerViewBar; import ilog.views.graphlayout.GraphLayoutEvent; import ilog.views.graphlayout.GraphLayoutEventListener; import ilog.views.graphlayout.IlvGraphLayout; import ilog.views.graphlayout.IlvGraphLayoutReport; import ilog.views.sdm.renderer.graphlayout.IlvGraphLayoutRenderer; import ilog.views.sdm.util.IlvSDMMutableStyleSheet; import ilog.views.util.IlvProductUtil; import ilog.views.util.swing.IlvSwingUtil; /** * This is a very simple application that uses the * <code>IlvDiagrammer</code> to perform a bus layout. It loads a style sheet * containing the bus layout specification. It allows to set various bus layout * parameters by using the <code>IlvSDMMutableStyleSheet</code>. */ public class BusLayoutApp extends JRootPane { { // This sample uses JViews Diagrammer features. When deploying an // application that includes this code, you need to be in possession // of a Perforce 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(); /** A text field to display messages */ JTextField msgLine = new JTextField(); /** The style sheet for temporary changes */ IlvSDMMutableStyleSheet styleSheet = new IlvSDMMutableStyleSheet(diagrammer.getEngine(), true, false); /** * Initializes the 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.02); diagrammer.setMaximumZoom(10); diagrammer.getView().setBackground(Color.white); diagrammer.getView().setForeground(SystemColor.windowText); // create the file selector JComboBox<String> fileSelector = new JComboBox<String>(); fileSelector.addItem("small"); fileSelector.addItem("medium"); fileSelector.addItem("large"); fileSelector.setToolTipText("Select a sample graph"); fileSelector.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent event) { SuppressWarnings("unchecked") JComboBox<String> comboBox = (JComboBox<String>) event.getSource(); String fileName = (String) comboBox.getSelectedItem(); loadDataFile(fileName); } }); // create the layout button JButton layoutButton = new JButton("Layout"); layoutButton.setToolTipText("Perform a bus layout"); layoutButton.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent evt) { performLayout(); } }); // create the panel for the layout buttons JPanel layoutButtonPanel = new JPanel(); layoutButtonPanel.setLayout(new FlowLayout()); layoutButtonPanel.add(layoutButton); addFurtherCheckboxes(layoutButtonPanel); // 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/bus.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); } /** * Adds further checkboxes near the layout button. */ private void addFurtherCheckboxes(JPanel panel) { // some space panel.add(new JLabel(" ")); JCheckBox incrementalOption = new JCheckBox("Incremental", false); panel.add(incrementalOption); incrementalOption.setToolTipText("Enable or disable the incremental mode"); incrementalOption.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { setIncrementalMode(e.getStateChange() == ItemEvent.SELECTED); } }); JCheckBox preserveFixedNodesOption = new JCheckBox("Fix Selected", false); panel.add(preserveFixedNodesOption); preserveFixedNodesOption.setToolTipText("Enable or disable that selected nodes don't move"); preserveFixedNodesOption.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { setSelectedAreFixed(e.getStateChange() == ItemEvent.SELECTED); } }); } /** * Creates the layout parameter panel. */ private JPanel createParameterPanel() { JPanel panel = new JPanel(); panel.setLayout(new GridLayout(3, 2)); // alignment paranter JComboBox<String> vAlignmentSelector = new JComboBox<String>(); panel.add(new JLabel("Vertical Alignment:")); panel.add(vAlignmentSelector); vAlignmentSelector.setToolTipText("Select the vertical alignment"); vAlignmentSelector.addItem("Center"); vAlignmentSelector.addItem("Top"); vAlignmentSelector.addItem("Bottom"); vAlignmentSelector.setSelectedIndex(0); vAlignmentSelector.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent event) { SuppressWarnings("unchecked") JComboBox<String> comboBox = (JComboBox<String>) event.getSource(); String alignment = (String) comboBox.getSelectedItem(); setVerticalAlignment(alignment); } }); // ordering of the nodes JComboBox<String> orderSelector = new JComboBox<String>(); panel.add(new JLabel("Node Order:")); panel.add(orderSelector); orderSelector.setToolTipText("Select the node ordering"); orderSelector.addItem("Arbitrary"); orderSelector.addItem("By label"); orderSelector.addItem("By height"); orderSelector.setSelectedIndex(2); orderSelector.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent event) { SuppressWarnings("unchecked") JComboBox<String> comboBox = (JComboBox<String>) event.getSource(); String ordering = (String) comboBox.getSelectedItem(); setOrdering(ordering); } }); // flow direction parameter JComboBox<String> flowDirectionSelector = new JComboBox<String>(); panel.add(new JLabel("Node Flow Direction:")); panel.add(flowDirectionSelector); flowDirectionSelector.addItem("Left to right"); flowDirectionSelector.addItem("Alternate"); flowDirectionSelector.setSelectedIndex(0); flowDirectionSelector.setToolTipText("Select the node flow direction"); flowDirectionSelector.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent event) { SuppressWarnings("unchecked") JComboBox<String> comboBox = (JComboBox<String>) event.getSource(); String flow = (String) comboBox.getSelectedItem(); setFlowDirection(flow); } }); 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 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")); } /** * Sets the vertical node alignment. */ private void setVerticalAlignment(String alignment) { if (alignment.equals("Center")) styleSheet.setDeclaration("GraphLayout", "globalVerticalAlignment", "CENTER"); else if (alignment.equals("Top")) styleSheet.setDeclaration("GraphLayout", "globalVerticalAlignment", "TOP"); else if (alignment.equals("Bottom")) styleSheet.setDeclaration("GraphLayout", "globalVerticalAlignment", "BOTTOM"); } /** * Sets the node ordering mode. */ private void setOrdering(String ordering) { if (ordering.equals("Arbitrary")) styleSheet.setDeclaration("GraphLayout", "ordering", "NO_ORDERING"); else if (ordering.equals("By label")) styleSheet.setDeclaration("GraphLayout", "ordering", "ORDER_BY_INDEX"); else if (ordering.equals("By height")) styleSheet.setDeclaration("GraphLayout", "ordering", "ORDER_BY_HEIGHT"); } /** * Sets the flow direction of nodes. */ private void setFlowDirection(String flow) { if (flow.equals("Left to right")) styleSheet.setDeclaration("GraphLayout", "flowDirection", "LEFT_TO_RIGHT"); else if (flow.equals("Alternate")) styleSheet.setDeclaration("GraphLayout", "flowDirection", "ALTERNATE"); } /** * Performs the bus layout. The layout type is stored in the CSS file, * therefore we don't need to set the bus layout explicitely. After loading * the graph and the CSS style sheet, the bus layout is already instantiated. */ private void performLayout() { showMessage("Layout started..."); // initialize the iteration listener layoutListener.initialize(getGraphLayout()); // Perform Bus Layout as node layout. Bus 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()) + "."); } } } /** * Returns the graph layout currently used by the diagrammer. */ private IlvGraphLayout getGraphLayout() { IlvGraphLayoutRenderer renderer = (IlvGraphLayoutRenderer) diagrammer.getEngine().getNodeLayoutRenderer(); return renderer == null ? null : renderer.getGraphLayout(); } /** * 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()); } /** * Runs the demo as a standalone application. */ public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { Override public void run() { BusLayoutApp app = new BusLayoutApp(); app.init(); JFrame frame = new JFrame("Bus Layout Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400, 500); frame.getContentPane().add(app); frame.setVisible(true); } }); } // -------------------------------------------------------------------------- /** * 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. */ Override 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 = ""; } } }