/* * 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.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Point; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.net.MalformedURLException; import java.net.URL; import java.text.MessageFormat; import java.util.Iterator; import java.util.ResourceBundle; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRootPane; import javax.swing.JTextField; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import ilog.views.IlvGraphic; import ilog.views.IlvPoint; import ilog.views.IlvRect; import ilog.views.diagrammer.IlvDiagrammer; import ilog.views.diagrammer.application.IlvDiagrammerAction; import ilog.views.diagrammer.application.IlvDiagrammerPropertySheet; import ilog.views.diagrammer.application.IlvDiagrammerViewBar; import ilog.views.swing.IlvPopupMenuContext; import ilog.views.swing.IlvPopupMenuManager; import ilog.views.swing.IlvSimplePopupMenu; import ilog.views.util.IlvProductUtil; /** * This example shows how to extend a Diagrammer project using the SDK. */ public class DiagrammerExtension extends JRootPane { private static final String projectFile = "data/map.idpr"; private ResourceBundle bundle; // ***************************************** // Creation and initialization of the demo: // ***************************************** /** * The constructor: initializes the resource bundle used to get strings. */ public DiagrammerExtension() { // 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); bundle = ResourceBundle.getBundle("extension"); } /** * The main method called when the sample is run as an application. */ public static void main(final String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { Override public void run() { // Create an instance of the demo class. // DiagrammerExtension demo = new DiagrammerExtension(); // Create the frame. // JFrame frame = new JFrame(demo.getString("FrameTitle")); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); try { // Initialize the demo's GUI inside the frame. // demo.init(frame.getContentPane(), new URL("file:./")); } catch (MalformedURLException e) { e.printStackTrace(); System.exit(1); } // Show the frame. // frame.setLocation(100, 100); frame.pack(); frame.setVisible(true); } }); } /** * Creates all the GUI elements and initializes the extension code. */ public void init(Container contentPane, final URL baseURL) { // Create a simple menu bar: // JMenuBar menubar = new JMenuBar(); JMenu fileMenu = new JMenu(getString("FileMenu")); fileMenu.add(IlvDiagrammerAction.createMenuItem(IlvDiagrammerAction.exit)); menubar.add(fileMenu); JMenu helpMenu = new JMenu(getString("HelpMenu")); IlvDiagrammerAction.about.putValue(IlvDiagrammerAction.ABOUT_APPLICATION_NAME, getString("ApplicationName")); helpMenu.add(IlvDiagrammerAction.createMenuItem(IlvDiagrammerAction.about)); menubar.add(helpMenu); ((JComponent) contentPane).getRootPane().setJMenuBar(menubar); // Create the IlvDiagrammer component: // final IlvDiagrammer diagrammer = new IlvDiagrammer(); diagrammer.setScrollable(true); contentPane.add(diagrammer, BorderLayout.CENTER); // Add a standard Diagrammer toolbar for zooming/panning: // IlvDiagrammerViewBar viewBar = new IlvDiagrammerViewBar(JToolBar.VERTICAL); viewBar.removeAction(IlvDiagrammerAction.select); contentPane.add(viewBar, BorderLayout.LINE_START); // Initialize the pop-up menus. // initPopupMenus(diagrammer); // Create the latitude/longitude fields. // JPanel panel = createLatLongFields(diagrammer); contentPane.add(panel, BorderLayout.AFTER_LAST_LINE); // Load the project. // try { diagrammer.setDataFile(new URL(baseURL, projectFile)); IlvRect bbox = diagrammer.getEngine().getGrapher().computeBBox(null); diagrammer.setPreferredSize(new Dimension((int) bbox.width + 20, (int) bbox.height + 20)); } catch (Exception ex) { ex.printStackTrace(); } } // ***************************************** // Initialize of the pop-up menu: // ***************************************** /** * This method creates the pop-up menus and registers them. */ private void initPopupMenus(IlvDiagrammer diagrammer) { // register the view to handle pop-up menus IlvPopupMenuManager.registerView(diagrammer.getView()); // Create the node pop-up menu JPopupMenu nodeMenu = createNodeLinkPopupMenu(diagrammer, true); // In the CSS, the node pop-up menu is specified in the following way // node { // ... // popupMenuName: "NodePopupMenu"; // } // // Hence we must register a pop-up menu with the name "NodePopupMenu" IlvPopupMenuManager.registerMenu("NodePopupMenu", nodeMenu); // Create the link pop-up menu JPopupMenu linkMenu = createNodeLinkPopupMenu(diagrammer, false); // In the CSS, the link pop-up menu is specified in the following way // link { // ... // popupMenuName: "LinkPopupMenu"; // } // // Hence we must register a pop-up menu with the name "LinkPopupMenu" IlvPopupMenuManager.registerMenu("LinkPopupMenu", linkMenu); // Register the white space menu for the main grapher. // Reason: when clicking in the white space, you are in fact clicking // on the main grapher JPopupMenu whitespaceMenu = createWhiteSpacePopupMenu(diagrammer); diagrammer.getEngine().getGrapher().setPopupMenu(whitespaceMenu); } /** * This method creates the pop-up menu for the nodes and links. */ private JPopupMenu createNodeLinkPopupMenu(final IlvDiagrammer diagrammer, final boolean isNode) { IlvSimplePopupMenu popupMenu = new IlvSimplePopupMenu() { // select only the object that owns the pop-up menu before the pop-up // menu gets displayed Override protected void beforeDisplay(IlvPopupMenuContext context) { // always call super.beforeDisplay first super.beforeDisplay(context); // then the remaining menu preparation beforeNodeLinkPopupDisplay(this, context, diagrammer, isNode); } }; // add a label to contain the title JLabel label = new JLabel(); label.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 5)); popupMenu.add(label); // add the remaining items popupMenu.addActions( (isNode ? "- | { DiagrammerExtension.StatusNormal | DiagrammerExtension.StatusWarning | DiagrammerExtension.StatusAlarm } |" : "") + "- | DiagrammerExtension.Properties", '|', '{', '}', bundle, 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); if (context == null) return; IlvGraphic g = context.getGraphic(); // retrieve the object of the graphic Object obj = (g == null ? null : diagrammer.getEngine().getObject(g)); if (obj == null) return; if (m.getText().equals(getString("StatusNormal"))) diagrammer.setObjectProperty(obj, "status", "Normal"); else if (m.getText().equals(getString("StatusWarning"))) diagrammer.setObjectProperty(obj, "status", "Warning"); else if (m.getText().equals(getString("StatusAlarm"))) diagrammer.setObjectProperty(obj, "status", "Alarm"); else if (m.getText().equals(getString("Properties"))) { // retrieve the position of the pop-up trigger IlvPoint p = context.getPoint(); // show the properties showProperties(diagrammer, obj, (int) p.x, (int) p.y); } } }); return popupMenu; } /** * The actions to be performed before displaying the pop-up menu for nodes or * links. This configures the pop-up menu to display the actual state. */ private void beforeNodeLinkPopupDisplay(IlvSimplePopupMenu popupMenu, IlvPopupMenuContext context, IlvDiagrammer diagrammer, boolean isNode) { // deselect all diagrammer.deselectAll(); // retrieve the graphic IlvGraphic g = context.getGraphic(); // retrieve the object of the graphic Object obj = (g == null ? null : diagrammer.getEngine().getObject(g)); // select the object if (obj != null) diagrammer.setSelected(obj, true); // the title label of the menu String title; if (isNode) { title = ""; Object nodeName = diagrammer.getObjectProperty(obj, "name"); title = MessageFormat.format(getString("NodeFormat"), new Object[] {nodeName}); } else { // fill the label with the name of the link Object sourceName = diagrammer.getObjectProperty(diagrammer.getSourceNode(obj), "name"); Object targetName = diagrammer.getObjectProperty(diagrammer.getTargetNode(obj), "name"); title = MessageFormat.format(getString("LinkFormat"), new Object[] {sourceName, targetName}); } // set the title label in the first entry of the menu JLabel label = (JLabel) popupMenu.getComponent(0); label.setText(title); // update the status if (isNode) { Object status = diagrammer.getObjectProperty(obj, "status"); if ("Normal".equals(status)) popupMenu.getItemForText(getString("StatusNormal")).setSelected(true); else if ("Warning".equals(status)) popupMenu.getItemForText(getString("StatusWarning")).setSelected(true); else if ("Alarm".equals(status)) popupMenu.getItemForText(getString("StatusAlarm")).setSelected(true); } } /** * This method creates the pop-up menu for the white space. */ private JPopupMenu createWhiteSpacePopupMenu(final IlvDiagrammer diagrammer) { // Create the pop-up menu for the white space. This gets associated to // the top level manager. No actions associated with this pop-up menu. // It contains only a text. IlvSimplePopupMenu popupMenu = new IlvSimplePopupMenu() { // deselect all objects before the pop-up menu gets displayed Override protected void beforeDisplay(IlvPopupMenuContext context) { // always call super.beforeDisplay first super.beforeDisplay(context); // then deselect diagrammer.deselectAll(); } }; JLabel label = new JLabel(getString("NoObjectSelected")); label.setBorder(BorderFactory.createEmptyBorder(2, 10, 2, 5)); popupMenu.add(label); return popupMenu; } private IlvDiagrammerPropertySheet propertySheet; private JDialog propertySheetDialog; /** * Displays a property sheet with all the properties of the selected object. */ private void showProperties(final IlvDiagrammer diagrammer, Object object, int x, int y) { if (propertySheet == null) { Window window = SwingUtilities.getWindowAncestor(diagrammer); if (window instanceof Frame) propertySheetDialog = new JDialog((Frame) window); else propertySheetDialog = new JDialog(); propertySheetDialog.setTitle(getString("PropertiesTitle")); propertySheetDialog.setModal(true); propertySheet = new IlvDiagrammerPropertySheet(); propertySheetDialog.getContentPane().add(propertySheet); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5)); JButton close = new JButton(getString("Close")); close.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent e) { propertySheetDialog.setVisible(false); } }); buttonPanel.add(close); propertySheetDialog.getContentPane().add(buttonPanel, BorderLayout.AFTER_LAST_LINE); propertySheetDialog.setSize(300, 300); } Point pos = diagrammer.getLocationOnScreen(); propertySheetDialog.setLocation(pos.x + x + 20, pos.y + y + 20); propertySheetDialog.setVisible(true); } // ******************************************* // Creation of the latitude/longitude fields: // ******************************************* /** * Creates the latitude/longitude fields, and sets up a listener to update * them as the suer moves the mouse over the diagram. */ private JPanel createLatLongFields(final IlvDiagrammer diagrammer) { JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5)); // Create the latitude field. // panel.add(new JLabel(getString("Latitude"))); final JTextField latitudeField = new JTextField(); latitudeField.setColumns(8); panel.add(latitudeField); // Create the longitude field. // panel.add(new JLabel(getString("Longitude"))); final JTextField longitudeField = new JTextField(); longitudeField.setColumns(8); panel.add(longitudeField); // Setup the listener. // diagrammer.getView().addMouseMotionListener(new MouseMotionAdapter() { Override public void mouseMoved(MouseEvent e) { if (ax == 0) { initTransform(diagrammer); } IlvPoint p = new IlvPoint(e.getX(), e.getY()); diagrammer.getView().getTransformer().inverse(p); // p is now in manager coordinates: transform into // latitude and longitude. // double longitude = x0 + ax * p.x; double latitude = y0 + ay * p.y; longitudeField.setText(printDegrees(longitude, "W")); latitudeField.setText(printDegrees(latitude, "N")); } }); return panel; } // Parameters to transform x/y into latitudes/longitudes: // longitude = x0 + ax * x; // latitude = y0 + ay * y; // float ax, ay, x0, y0; /** * Initializes the latitude/longitude -> x/y transformation parameters. */ private void initTransform(final IlvDiagrammer diagrammer) { // We compute transformation parameters based on the // positions of the two first nodes. // Object node1 = null, node2 = null; Iterator<?> it = diagrammer.getAllObjects(); while (it.hasNext()) { Object o = it.next(); if (!diagrammer.isLink(o)) { if (node1 == null) { node1 = o; } else if (node2 == null) { node2 = o; break; } } } float x1 = Float.parseFloat((String) diagrammer.getObjectProperty(node1, "x")); float y1 = Float.parseFloat((String) diagrammer.getObjectProperty(node1, "y")); float lon1 = parseDegrees((String) diagrammer.getObjectProperty(node1, "longitude")); float lat1 = parseDegrees((String) diagrammer.getObjectProperty(node1, "latitude")); float x2 = Float.parseFloat((String) diagrammer.getObjectProperty(node2, "x")); float y2 = Float.parseFloat((String) diagrammer.getObjectProperty(node2, "y")); float lon2 = parseDegrees((String) diagrammer.getObjectProperty(node2, "longitude")); float lat2 = parseDegrees((String) diagrammer.getObjectProperty(node2, "latitude")); ax = (lon2 - lon1) / (x2 - x1); ay = (lat2 - lat1) / (y2 - y1); x0 = lon1 - ax * x1; y0 = lat1 - ay * y1; } /** * Parses a string like "45D30'N" into a floating-point number of degrees. */ private float parseDegrees(String degreesString) { int di = degreesString.indexOf('D'); int degrees = Integer.parseInt(degreesString.substring(0, di)); int si = degreesString.indexOf('\''); int seconds = Integer.parseInt(degreesString.substring(di + 1, si)); return degrees + (float) seconds / 60; } /** * Prints a floating-point number of degrees into a string like "45D30'N". */ private String printDegrees(double degrees, String direction) { return String.valueOf((int) degrees) + "D" + String.valueOf((int) (degrees * 60) % 60) + "'" + direction; } // ***************** // Utility methods: // ***************** // Gets a string from the property file. // private String getString(String key) { return bundle.getString("DiagrammerExtension." + key); } }