/* * 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 java.util.Stack; 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 link layout. It loads a style sheet * containing the link layout specification. It allows to set various link * layout parameters by using the <code>IlvSDMMutableStyleSheet</code>. */ public class LinkLayoutApp extends JRootPane { private static final long serialVersionUID = -1346987241233770761L; { // 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("sample1"); fileSelector.addItem("sample2"); fileSelector.addItem("sample3"); fileSelector.addItem("sample4"); fileSelector.addItem("sample5"); 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 link layout"); layoutButton.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent evt) { performLayout(); } }); // create the panel for the layout buttons and parameters JPanel layoutPanel = new JPanel(); layoutPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); layoutPanel.add(layoutButton); addFurtherOptions(layoutPanel); // 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(layoutPanel, BorderLayout.NORTH); 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/link.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("sample1"); // 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. getLinkLayout().addGraphLayoutEventListener(layoutListener); } /** * Fill the layout panel with further options. */ private void addFurtherOptions(JPanel layoutPanel) { JPanel panel = new JPanel(); layoutPanel.add(panel); panel.setLayout(new GridLayout(2, 1)); JCheckBox longLinks = new JCheckBox("Long Links", false); longLinks.setToolTipText("Switch between long link/short link mode"); panel.add(longLinks); longLinks.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { setLayoutMode(e.getStateChange() == ItemEvent.SELECTED); } }); JCheckBox orthoLinks = new JCheckBox("Orthogonal Links", true); orthoLinks.setToolTipText("Switch between orthogonal/direct link mode"); panel.add(orthoLinks); orthoLinks.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { setOrthLinkStyle(e.getStateChange() == ItemEvent.SELECTED); } }); panel = new JPanel(); layoutPanel.add(panel); panel.setLayout(new GridLayout(2, 1)); JCheckBox autoLayout = new JCheckBox("Automatic Relayout", false); autoLayout.setToolTipText("Enable or disable automatic relayout when nodes move"); panel.add(autoLayout); autoLayout.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { setAutoLayout(e.getStateChange() == ItemEvent.SELECTED); } }); JCheckBox splineLinks = new JCheckBox("Use Splines", false); splineLinks.setToolTipText("Enable or disable spline links"); panel.add(splineLinks); splineLinks.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { setSplineLinks(e.getStateChange() == ItemEvent.SELECTED); } }); } /** * 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")); diagrammer.fitToContents(); showMessage("Reading " + fileNameBase + ".xml done."); } catch (Exception e) { showMessage(e.getMessage()); } } /** * Sets the layout mode. */ private void setLayoutMode(boolean flag) { setStylesheetDeclaration("LinkLayout", "layoutMode", (flag ? "LONG_LINKS" : "SHORT_LINKS")); } /** * Sets the orthogonal link style or direct link style. */ private void setOrthLinkStyle(final boolean flag) { setStylesheetDeclaration("LinkLayout", "globalLinkStyle", (flag ? "ORTHOGONAL_STYLE" : "DIRECT_STYLE")); setStylesheetDeclaration("link", "crossingMode", (flag ? "TUNNEL_CROSSINGS" : "NO_CROSSINGS")); } /** * Sets the orthogonal mode. */ private void setAutoLayout(boolean flag) { setStylesheetDeclaration("LinkLayout", "enabled", Boolean.toString(flag)); setStylesheetDeclaration("LinkLayout", "autoLayout", Boolean.toString(flag), true); } /** * Sets the spline links. */ private void setSplineLinks(boolean flag) { setStylesheetDeclaration("link", "curved", (flag ? "0.65" : "0")); } /** * modify stylesheet property with delay if a layout is in process * @param selector * @param property * @param value */ private void setStylesheetDeclaration(final String selector, final String property, final String value) { setStylesheetDeclaration(selector, property, value, false); } /** * modify stylesheet property with delay if a layout is in process or force mode * @param selector * @param property * @param value * @param force */ private void setStylesheetDeclaration(final String selector, final String property, final String value, boolean force) { if (force || diagrammer.getEngine().isLayoutRunning()) { layoutListener.addRunnable(new Runnable() { Override public void run() { setStylesheetDeclaration(selector, property, value); } }); } else { styleSheet.setDeclaration(selector, property, value); } } /** * Performs the link layout. The layout type is stored in the CSS file, * therefore we don't need to set the link layout explicitely. After loading * the graph and the CSS style sheet, the link layout is already instantiated. */ private void performLayout() { showMessage("Layout started..."); // initialize the iteration listener layoutListener.initialize(getLinkLayout()); if (diagrammer.isLinkLayoutAvailable()) { // perform the layout diagrammer.layoutLinks(); // show the layout report information about the return code IlvGraphLayoutReport report = getLinkLayout().getLayoutReport(); if (report != null) { showMessage(report.codeToString(report.getCode()) + "."); } } } /** * Returns the link layout currently used by the diagrammer. */ private IlvGraphLayout getLinkLayout() { IlvGraphLayoutRenderer renderer = (IlvGraphLayoutRenderer) diagrammer.getEngine().getLinkLayoutRenderer(); 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()); } /** * Allows you to run the demo as a standalone application. */ public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { Override public void run() { LinkLayoutApp app = new LinkLayoutApp(); app.init(); JFrame frame = new JFrame("Link Layout Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600, 600); 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 * orthogonal link layout algorithm. */ class LayoutIterationListener implements GraphLayoutEventListener { private String toShow = ""; private static final int MAX_LENGTH = 50; private IlvGraphLayout layout; private Stack<Runnable> runnables; /** * 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); // set stylesheet property if there's one pending if (event.isLayoutFinished() && runnables != null && runnables.size() > 0) { runnables.pop().run(); } } /** * Initialize the listener. This method must be called before the layout is * started. */ private void initialize(IlvGraphLayout l) { if (layout != l) { if (layout != null) layout.removeGraphLayoutEventListener(this); layout = l; if (layout != null) layout.addGraphLayoutEventListener(this); } toShow = ""; } /** * add a stylesheet property modification * @param runnable */ private void addRunnable(Runnable runnable) { if (runnables == null) { runnables = new Stack<>(); } runnables.add(runnable); } } }