/*
* Licensed Materials - Property of Rogue Wave Software, Inc.
* © Copyright Rogue Wave Software, Inc. 2014, 2017
* © 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.Component;
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.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRootPane;
import javax.swing.JTextField;
import ilog.views.IlvGrapher;
import ilog.views.IlvGraphic;
import ilog.views.IlvGraphicBag;
import ilog.views.IlvGraphicEnumeration;
import ilog.views.IlvLinkImage;
import ilog.views.IlvManager;
import ilog.views.IlvObjectWithSelection;
import ilog.views.diagrammer.IlvDiagrammer;
import ilog.views.diagrammer.application.IlvDiagrammerViewBar;
import ilog.views.graphic.linkbundle.IlvLinkBundle;
import ilog.views.graphlayout.IlvGraphModel;
import ilog.views.graphlayout.IlvGrapherAdapter;
import ilog.views.graphlayout.IlvInappropriateLinkException;
import ilog.views.sdm.util.IlvSDMMutableStyleSheet;
import ilog.views.swing.IlvPopupMenuContext;
import ilog.views.swing.IlvPopupMenuManager;
import ilog.views.swing.IlvSimplePopupMenu;
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 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 LinkBundleApp extends JRootPane {
{
// 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 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);
// 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<String> cssSelector = new JComboBox<String>();
cssSelector.addItem("Composite links");
cssSelector.addItem("Simple links");
cssSelector.addItem("Nested bundles");
cssSelector.setToolTipText("Select a sample graph");
cssSelector.addActionListener(new ActionListener() {
Override
public void actionPerformed(ActionEvent event) {
SuppressWarnings("unchecked")
JComboBox<String> comboBox = (JComboBox<String>) 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() {
Override
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");
}
/**
* Fill the bottom panels with further options.
*/
private void addFurtherOptions(JPanel bottomPanel1, JPanel bottomPanel2) {
// ----------------------------------------
// Link style
bottomPanel1.add(new JLabel("Link Style:"));
JComboBox<String> linkStyleChooser = new JComboBox<String>();
bottomPanel1.add(linkStyleChooser);
linkStyleChooser.setToolTipText("Select the link shape");
linkStyleChooser.addItem("Orthogonal");
linkStyleChooser.addItem("Direct");
linkStyleChooser.addItem("Straight");
linkStyleChooser.addItemListener(new ItemListener() {
Override
public void itemStateChanged(ItemEvent event) {
if (event.getStateChange() == ItemEvent.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() {
Override
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() {
Override
public void actionPerformed(ActionEvent event) {
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() {
Override
public void actionPerformed(ActionEvent event) {
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() {
Override
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() {
Override
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
List<String> individualLinkSelectors = new ArrayList<String>();
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);
}
Iterator<String> iter2 = individualLinkSelectors.iterator();
while (iter2.hasNext()) {
String selector = iter2.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() {
Override
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
Override
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() {
Override
public void run() {
LinkBundleApp app = new LinkBundleApp();
app.init();
JFrame frame = new JFrame("Link Bundle Sample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(550, 650);
frame.getContentPane().add(app);
frame.setVisible(true);
}
});
}
private static class JComfortPanel extends JPanel {
Override
public void setEnabled(boolean enabled) {
Component[] components = getComponents();
for (int i = 0; i < components.length; i++)
components[i].setEnabled(enabled);
}
}
}