/* * 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.IlvGrapher; import ilog.views.IlvManager; import ilog.views.IlvGraphic; import ilog.views.IlvGraphicBag; import ilog.views.IlvLinkImage; import ilog.views.IlvGraphicEnumeration; import ilog.views.IlvObjectWithSelection; import ilog.views.IlvApplyObject; import ilog.views.graphic.linkbundle.IlvLinkBundle; import ilog.views.sdm.IlvSDMEngine; import ilog.views.sdm.util.IlvSDMMutableStyleSheet; import ilog.views.graphlayout.IlvGraphModel; import ilog.views.graphlayout.IlvGrapherAdapter; import ilog.views.graphlayout.IlvInappropriateLinkException; import ilog.views.util.IlvProductUtil; import ilog.views.util.swing.IlvSwingUtil; import ilog.views.swing.IlvPopupMenuManager; import ilog.views.swing.IlvPopupMenuContext; import ilog.views.swing.IlvSimplePopupMenu; import javax.swing.*; import java.util.*; 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 link layout on * bundles of links. * It loads a style sheet containing the link bundle specification. * It allows you to set various link layout parameters by using the * <code>IlvSDMMutableStyleSheet</code>. */ public class LinkBundleApplet extends JApplet { { // This sample uses JViews Diagrammer features. When deploying an // application that includes this code, you need // a Rogue Wave JViews Diagrammer Deployment license. IlvProductUtil.DeploymentLicenseRequired( IlvProductUtil.JViews_Diagrammer_Deployment); } /** The diagrammer */ IlvDiagrammer diagrammer = new IlvDiagrammer(); /** The style sheet for temporary changes */ IlvSDMMutableStyleSheet styleSheet = new IlvSDMMutableStyleSheet( diagrammer.getEngine(), true, false); /** Whether bundles are currently expanded */ boolean expandedState = true; /** * 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); // for the pop-up menu // register view view to the pop-up manager IlvPopupMenuManager.registerView(diagrammer.getView()); // register the menus under different names IlvPopupMenuManager.registerMenu("COLLAPSE_BUNDLE", createCollapseMenu()); IlvPopupMenuManager.registerMenu("EXPAND_BUNDLE", createExpandMenu()); // create the file selector JComboBox cssSelector = new JComboBox(); cssSelector.addItem("Composite links"); cssSelector.addItem("Simple links"); cssSelector.addItem("Nested bundles"); cssSelector.setToolTipText("Select a sample graph"); cssSelector.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { JComboBox comboBox = (JComboBox)event.getSource(); String cssName = (String)comboBox.getSelectedItem(); if ("Composite links".equals(cssName)) cssName = "composite"; else if ("Simple links".equals(cssName)) cssName = "flat"; else if ("Nested bundles".equals(cssName)) cssName = "nested"; loadCSS(cssName); } }); // create the layout button JButton layoutButton = new JButton("Layout"); layoutButton.setToolTipText("Perform a link layout"); layoutButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { }}); // 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 CSS:")); topPanel.add(cssSelector); // create the bottom panel with the further options JPanel bottomPanel = new JPanel(); JPanel bottomPanel1 = new JPanel(); JPanel bottomPanel2 = new JPanel(); bottomPanel.setLayout(new GridLayout(2,0)); bottomPanel1.setLayout(new FlowLayout(FlowLayout.LEFT)); bottomPanel2.setLayout(new FlowLayout(FlowLayout.LEFT)); bottomPanel.add(bottomPanel1); bottomPanel.add(bottomPanel2); addFurtherOptions(bottomPanel1, bottomPanel2); // 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); // prepare the mutual style sheet styleSheet.setDeclaration("link", "singleConnectionPoint", "false"); styleSheet.setDeclaration("Subobject#LinkBundleA", "singleConnectionPoint", "false"); styleSheet.setDeclaration("Subobject#LinkBundleB", "singleConnectionPoint", "false"); styleSheet.setDeclaration("link", "offset", "5"); styleSheet.setDeclaration("Subobject#LinkBundleA", "offset", "5"); styleSheet.setDeclaration("Subobject#LinkBundleB", "offset", "5"); styleSheet.setDeclaration("link", "frame", "+BundleFrame"); styleSheet.setDeclaration("Subobject#LinkBundleA", "frame", "+BundleFrameA"); styleSheet.setDeclaration("Subobject#LinkBundleB", "frame", "+BundleFrameB"); styleSheet.setDeclaration("Subobject#BundleFrame", "margin", "3"); styleSheet.setDeclaration("Subobject#BundleFrameA", "margin", "3"); styleSheet.setDeclaration("Subobject#BundleFrameB", "margin", "3"); styleSheet.setDeclaration("link", "collapsed", "false"); // load the CSS file loadCSS("composite"); // load the initial sample grapher loadDataFile("sample1"); } /** * 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 work around memory management issues // in the Sun JRE. See the method documentation for more // details and a description of the known issues. IlvSwingUtil.cleanupApplet(); } /** * Fill the bottom panels with further options. */ private void addFurtherOptions(JPanel bottomPanel1, JPanel bottomPanel2) { // ---------------------------------------- // Link style bottomPanel1.add(new JLabel("Link Style:")); JComboBox linkStyleChooser = new JComboBox(); bottomPanel1.add(linkStyleChooser); linkStyleChooser.setToolTipText("Select the link shape"); linkStyleChooser.addItem("Orthogonal"); linkStyleChooser.addItem("Direct"); linkStyleChooser.addItem("Straight"); linkStyleChooser.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent event) { if (event.getStateChange() == event.DESELECTED) return; String styleName = (String)event.getItem(); if (styleName.equals("Orthogonal")) setLinkStyle("ORTHOGONAL_STYLE"); else if (styleName.equals("Direct")) setLinkStyle("DIRECT_STYLE"); else if (styleName.equals("Straight")) setLinkStyle("STRAIGHT_STYLE"); else throw new RuntimeException("Unsupported link style: " + styleName); } }); // ---------------------------------------- // Single connection point JCheckBox singleConnectionPointCheckbox = new JCheckBox("Single connection point", false); bottomPanel1.add(singleConnectionPointCheckbox); singleConnectionPointCheckbox.setToolTipText("Enables the single connection point mode"); singleConnectionPointCheckbox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { styleSheet.setDeclaration("link", "singleConnectionPoint", "true"); styleSheet.setDeclaration("Subobject#LinkBundleA", "singleConnectionPoint", "true"); styleSheet.setDeclaration("Subobject#LinkBundleB", "singleConnectionPoint", "true"); } else if (e.getStateChange() == ItemEvent.DESELECTED) { styleSheet.setDeclaration("link", "singleConnectionPoint", "false"); styleSheet.setDeclaration("Subobject#LinkBundleA", "singleConnectionPoint", "false"); styleSheet.setDeclaration("Subobject#LinkBundleB", "singleConnectionPoint", "false"); } } }); // -------------------------------------------- // Offset JLabel offsetLabel = new JLabel("Offset:"); String tooltip = "Sets the offset between the sublinks of the bundles."; offsetLabel.setToolTipText(tooltip); bottomPanel1.add(offsetLabel); final JTextField offsetField = new JTextField("5.0 "); offsetField.setToolTipText(tooltip); bottomPanel1.add(offsetField); offsetField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { final float value = Float.valueOf(offsetField.getText().trim()).floatValue(); offsetField.setText("" + value); styleSheet.setDeclaration("link", "offset", "" + value); styleSheet.setDeclaration("Subobject#LinkBundleA", "offset", "" + value); styleSheet.setDeclaration("Subobject#LinkBundleB", "offset", "" + value); }}); // ----------------------------------------------- // Link Bundle Frame final JPanel bundleFramePanel = new JComfortPanel(); final JLabel marginLabel = new JLabel("Frame margin:"); tooltip = "Sets the margin"; marginLabel.setToolTipText(tooltip); final JTextField marginField = new JTextField("3.0 "); marginField.setToolTipText(tooltip); marginField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { final float value = Float.valueOf(marginField.getText().trim()).floatValue(); marginField.setText("" + value); styleSheet.setDeclaration("Subobject#BundleFrame", "margin", "" + value); styleSheet.setDeclaration("Subobject#BundleFrameA", "margin", "" + value); styleSheet.setDeclaration("Subobject#BundleFrameB", "margin", "" + value); }}); final JCheckBox bundleFrameCheckbox = new JCheckBox("Bundle frame", true); bundleFrameCheckbox.setToolTipText("Enables the use of a frame around the link bundles"); bundleFrameCheckbox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { // specify the new link style option if (e.getStateChange() == ItemEvent.SELECTED) { styleSheet.setDeclaration("link", "frame", "+BundleFrame"); styleSheet.setDeclaration("Subobject#LinkBundleA", "frame", "+BundleFrameA"); styleSheet.setDeclaration("Subobject#LinkBundleB", "frame", "+BundleFrameB"); marginLabel.setEnabled(true); marginField.setEnabled(true); } else if (e.getStateChange() == ItemEvent.DESELECTED) { styleSheet.setDeclaration("link", "frame", ""); styleSheet.setDeclaration("Subobject#LinkBundleA", "frame", ""); styleSheet.setDeclaration("Subobject#LinkBundleB", "frame", ""); marginLabel.setEnabled(false); marginField.setEnabled(false); } } }); bundleFramePanel.add(bundleFrameCheckbox); bundleFramePanel.add(marginLabel); bundleFramePanel.add(marginField); bottomPanel2.add(bundleFramePanel); // ---------------------------------------- // Expand/collapse button final JButton expandCollapseButton = new JButton("Collapse"); bottomPanel2.add(expandCollapseButton); refreshExpandCollapseButton(expandCollapseButton, expandedState); expandCollapseButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { expandedState = !expandedState; refreshExpandCollapseButton(expandCollapseButton, expandedState); bundleFramePanel.setEnabled(expandedState); if (expandedState && !bundleFrameCheckbox.isSelected()) { marginLabel.setEnabled(false); marginField.setEnabled(false); } styleSheet.setAdjusting(true); try { if (expandedState) styleSheet.setDeclaration("link", "collapsed", "false"); else styleSheet.setDeclaration("link", "collapsed", "true"); // remove all declatation about individual expand or collapse. // This is only needed because the pop-up menus introduce such // declarations ArrayList individualLinkSelectors = new ArrayList(); Iterator iter = styleSheet.getRuleSelectors(); while (iter.hasNext()) { String selector = (String)iter.next(); // need to collect selectors first to avoid concurrent modifications if (selector.startsWith("#link")) individualLinkSelectors.add(selector); } iter = individualLinkSelectors.iterator(); while (iter.hasNext()) { String selector = (String)iter.next(); styleSheet.removeDeclaration(selector, "collapsed"); } } finally { styleSheet.setAdjusting(false); } }}); } /** * Refreshes the button for expanding/collapsing link bundles. */ private void refreshExpandCollapseButton(JButton button, boolean expand) { button.setText(expand ? "Collapse" : "Expand"); button.setToolTipText(expand ? "Collapse the link bundles to show the overview link" : "Expand the link bundles to show the sublinks"); } /** * 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 { diagrammer.setDataFile( IlvSwingUtil.getRelativeURL(this, "data/" + fileNameBase + ".xml")); diagrammer.fitToContents(); } catch (Exception e) { } } /** * Load a CSS file. * @param fileNameBase The base of the filename, excluding the path prefix * and the extension suffix. */ private void loadCSS(String fileNameBase) { try { // load the main style file diagrammer.setStyleSheet( IlvSwingUtil.getRelativeURL(this, "data/" + fileNameBase + ".css")); // load a mutable style file that we use for temporary style changes diagrammer.getEngine().setStyleSheets(1, styleSheet.toString()); } catch (Exception e) { } } /** * Sets the orithogonal link style or direct link style. */ private void setLinkStyle(String style) { if (style.equals("STRAIGHT_STYLE")) { styleSheet.setDeclaration("LinkLayout", "enabled", "false"); deleteIntermediateLinkPoints(false); } else { styleSheet.setDeclaration("LinkLayout", "enabled", "true"); styleSheet.setDeclaration("LinkLayout", "globalLinkStyle", style); } } private void deleteIntermediateLinkPoints(boolean redraw) { // remove all intermediate points from all links IlvGrapher grapher = diagrammer.getEngine().getGrapher(); IlvGraphModel graphModel = new IlvGrapherAdapter(grapher); IlvGraphicEnumeration e = grapher.getObjects(); IlvGraphic g; while (e.hasMoreElements()) { g = e.nextElement(); if (grapher.isLink(g)) { IlvLinkImage link = (IlvLinkImage)g; try { graphModel.reshapeLink(link, null, null, 0, 0, null, redraw); } catch (IlvInappropriateLinkException ex) { ex.printStackTrace(); } } } } private JPopupMenu createCollapseMenu() { return createMenu(true); } private JPopupMenu createExpandMenu() { return createMenu(false); } private JPopupMenu createMenu(boolean collapse) { // create the action listener for the pop-up menu ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { // retrieve the selected menu item JMenuItem m = (JMenuItem)e.getSource(); // retrieve the graphic that has this pop-up menu IlvPopupMenuContext context = IlvPopupMenuManager.getPopupMenuContext(m); IlvGraphic graphic = context.getGraphic(); // do the action if (m.getText().equals("Collapse")) { if (graphic instanceof IlvLinkBundle) { IlvLinkBundle bundle = (IlvLinkBundle)graphic; collapse(bundle, true); } } if (m.getText().equals("Expand")) { // the expand menu is on the overview link if (graphic.getGraphicBag() instanceof IlvLinkBundle) { IlvLinkBundle ownerBundle = (IlvLinkBundle)graphic.getGraphicBag(); if (ownerBundle.getOverviewLink() == graphic) { graphic = ownerBundle; } } if (graphic instanceof IlvLinkBundle) { IlvLinkBundle bundle = (IlvLinkBundle)graphic; collapse(bundle, false); } } } }; IlvSimplePopupMenu menu = new IlvSimplePopupMenu( "Menu1", collapse ? "Collapse" : "Expand", null, actionListener) { // configure checkbox of the pop-up before it gets displayed protected void beforeDisplay(IlvPopupMenuContext context) { // always call super.beforeDisplay first super.beforeDisplay(context); // retrieve the graphic IlvGraphic graphic = context.getGraphic(); // deselect all objects in the manager IlvGraphicBag bag = graphic.getGraphicBag(); while (bag != null && !(bag instanceof IlvManager)) { bag = ((IlvGraphic)bag).getGraphicBag(); } if (bag instanceof IlvManager) ((IlvManager)bag).deSelectAll(true, true); // select this graphic; bag = graphic.getGraphicBag(); if (bag instanceof IlvLinkBundle) { IlvLinkBundle ownerBundle = (IlvLinkBundle)graphic.getGraphicBag(); if (ownerBundle.getOverviewLink() == graphic) { graphic = ownerBundle; bag = graphic.getGraphicBag(); } } if (bag instanceof IlvObjectWithSelection) { ((IlvObjectWithSelection)bag).setSelected(graphic, true, true); } } }; return menu; } /** * Collapse or expand an individual link by adding a rule to the * mutable style sheet about the specific link. This works only for * the top level bundles, not for nested bundles. */ private void collapse(IlvLinkBundle link, boolean collapse) { // only top level bundles can have a collapse/expand menu in SDM Object linkModelObj = diagrammer.getEngine().getObject(link); if (linkModelObj == null) return; String id = diagrammer.getID(linkModelObj); styleSheet.setDeclaration("#" + id, "collapsed", collapse ? "true" : "false" ); } /** * 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() { LinkBundleApplet applet = new LinkBundleApplet(); applet.init(); JFrame frame = new JFrame("Link Bundle Sample"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(550, 650); frame.getContentPane().add(applet); frame.setVisible(true); } }); } private static class JComfortPanel extends JPanel { public void setEnabled(boolean enabled) { Component[] components = getComponents(); for (int i = 0; i < components.length; i++) components[i].setEnabled(enabled); } } }