/* * 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.Dimension; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.KeyboardFocusManager; 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.awt.event.KeyEvent; import java.util.Comparator; 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.SwingUtilities; import javax.swing.border.TitledBorder; import ilog.views.IlvAccelerator; import ilog.views.IlvDefaultManagerFrame; import ilog.views.IlvGrapher; import ilog.views.IlvGraphic; import ilog.views.IlvHandlesSelection; import ilog.views.IlvLinkImage; import ilog.views.IlvManager; import ilog.views.IlvManagerView; import ilog.views.IlvPoint; import ilog.views.IlvRect; import ilog.views.IlvTransformer; import ilog.views.accelerator.IlvCycleSelectAccelerator; import ilog.views.graphic.IlvZoomableLabel; import ilog.views.interactor.IlvSelectInteractor; import ilog.views.swing.IlvJScrollManagerView; import ilog.views.util.swing.IlvJComboBox; /** * This is a very simple application that shows how to implement * a selection mechanism that uses the keyboard. */ SuppressWarnings("serial") public class KeyboardSelApp extends JRootPane { { // This sample uses JViews Diagrammer features. When deploying an // application that includes this code, you need // a Perforce JViews Diagrammer Deployment license. // IlvProductUtil.DeploymentLicenseRequired( // IlvProductUtil.JViews_Diagrammer_Deployment); } // -------------------------------------------------------------------- IlvGrapher grapher; IlvManagerView mgrview; IlvZoomableLabel node; boolean animate = true; IlvCycleSelectAccelerator[] accelerators; // comparator for the traversal order: x has higher priority Comparator<IlvGraphic> xThenY = new Comparator<IlvGraphic>() { Override public int compare(IlvGraphic a, IlvGraphic b) { IlvManager ma = (IlvManager) a.getGraphicBag(); IlvManager mb = (IlvManager) b.getGraphicBag(); IlvTransformer ta = ma.getTopLevelTransformer(); IlvTransformer tb = mb.getTopLevelTransformer(); IlvRect ra = a.boundingBox(ta); IlvRect rb = b.boundingBox(tb); if (ra.x < rb.x) return -1; if (ra.x > rb.x) return 1; if (ra.width < rb.width) return -1; if (ra.width > rb.width) return 1; if (ra.y < rb.y) return -1; if (ra.y > rb.y) return 1; if (ra.height < rb.height) return -1; if (ra.height > rb.height) return 1; return 0; } }; // comparator for the traversal order: y has higher priority Comparator<IlvGraphic> yThenX = new Comparator<IlvGraphic>() { Override public int compare(IlvGraphic a, IlvGraphic b) { IlvManager ma = (IlvManager) a.getGraphicBag(); IlvManager mb = (IlvManager) b.getGraphicBag(); IlvTransformer ta = ma.getTopLevelTransformer(); IlvTransformer tb = mb.getTopLevelTransformer(); IlvRect ra = a.boundingBox(ta); IlvRect rb = b.boundingBox(tb); if (ra.y < rb.y) return -1; if (ra.y > rb.y) return 1; if (ra.height < rb.height) return -1; if (ra.height > rb.height) return 1; if (ra.x < rb.x) return -1; if (ra.x > rb.x) return 1; if (ra.width < rb.width) return -1; if (ra.width > rb.width) return 1; return 0; } }; // comparator for the traversal order: nesting has highest priority, then x Comparator<IlvGraphic> nestedThenXThenY = new Comparator<IlvGraphic>() { Override public int compare(IlvGraphic a, IlvGraphic b) { IlvGrapher commonBag = IlvGrapher.getLowestCommonGrapher(a, b); if (commonBag != null) { while (a.getGraphicBag() != commonBag) a = (IlvGraphic) a.getGraphicBag(); while (b.getGraphicBag() != commonBag) b = (IlvGraphic) b.getGraphicBag(); } IlvRect ra = a.boundingBox(); IlvRect rb = b.boundingBox(); if (ra.x < rb.x) return -1; if (ra.x > rb.x) return 1; if (ra.width > rb.width) return -1; if (ra.width < rb.width) return 1; if (ra.y < rb.y) return -1; if (ra.y > rb.y) return 1; if (ra.height > rb.height) return -1; if (ra.height < rb.height) return 1; return 0; } }; // comparator for the traversal order: nesting has highest priority, then y Comparator<IlvGraphic> nestedThenYThenX = new Comparator<IlvGraphic>() { Override public int compare(IlvGraphic a, IlvGraphic b) { IlvGrapher commonBag = IlvGrapher.getLowestCommonGrapher(a, b); if (commonBag != null) { while (a.getGraphicBag() != commonBag) a = (IlvGraphic) a.getGraphicBag(); while (b.getGraphicBag() != commonBag) b = (IlvGraphic) b.getGraphicBag(); } IlvRect ra = a.boundingBox(); IlvRect rb = b.boundingBox(); if (ra.y < rb.y) return -1; if (ra.y > rb.y) return 1; if (ra.height > rb.height) return -1; if (ra.height < rb.height) return 1; if (ra.x < rb.x) return -1; if (ra.x > rb.x) return 1; if (ra.width > rb.width) return -1; if (ra.width < rb.width) return 1; return 0; } }; /** * Initializes the application. */ public void init() { // create a grapher grapher = new IlvGrapher(); // create a manager view mgrview = new IlvManagerView(grapher); // create the scroll manager view IlvJScrollManagerView scrollManView = new IlvJScrollManagerView(mgrview); // Some settings on the manager view and on the scroll manager view mgrview.setAntialiasing(true); mgrview.setKeepingAspectRatio(true); mgrview.setBackground(Color.white); mgrview.setForeground(SystemColor.windowText); Color xc = SystemColor.windowText; xc = new Color(255 - xc.getRed(), 255 - xc.getGreen(), 255 - xc.getBlue()); mgrview.setDefaultXORColor(xc); mgrview.setDefaultGhostColor(SystemColor.windowText); mgrview.setZoomFactorRange(0.02, 10.0); // Settings parameters for selection handles IlvHandlesSelection.defaultHandleColor = Color.blue; IlvHandlesSelection.defaultHandleBackgroundColor = Color.blue; IlvHandlesSelection.defaultHandleShape = IlvHandlesSelection.SQUARE_SHAPE; // Install the select interactor mgrview.setInteractor(new IlvSelectInteractor()); // ensure that the manager view receives the TAB key events mgrview.setFocusable(true); mgrview.setFocusCycleRoot(true); mgrview.setFocusTraversalKeysEnabled(false); // add the accelerators accelerators = new IlvCycleSelectAccelerator[4]; IlvCycleSelectAccelerator acc; acc = new IlvCycleSelectAccelerator(KeyEvent.KEY_PRESSED, KeyEvent.VK_TAB, 0) { Override protected boolean endOfSequence(IlvGraphic g) { KeyboardFocusManager.getCurrentKeyboardFocusManager().upFocusCycle(); return true; } }; acc.setForward(true); accelerators[0] = acc; acc = new IlvCycleSelectAccelerator(KeyEvent.KEY_PRESSED, 'F', 0); acc.setForward(true); accelerators[1] = acc; acc = new IlvCycleSelectAccelerator(KeyEvent.KEY_PRESSED, KeyEvent.VK_TAB, KeyEvent.SHIFT_MASK) { Override protected boolean endOfSequence(IlvGraphic g) { KeyboardFocusManager.getCurrentKeyboardFocusManager().upFocusCycle(); KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent(); return true; } }; acc.setForward(false); accelerators[2] = acc; acc = new IlvCycleSelectAccelerator(KeyEvent.KEY_PRESSED, 'B', 0); acc.setForward(false); accelerators[3] = acc; for (int i = 0; i < accelerators.length; i++) grapher.addAccelerator(accelerators[i]); IlvAccelerator acc2 = new IlvAccelerator(KeyEvent.KEY_PRESSED, KeyEvent.VK_TAB, KeyEvent.CTRL_MASK) { Override protected boolean handleEvent(IlvManagerView view) { KeyboardFocusManager.getCurrentKeyboardFocusManager().upFocusCycle(); return true; } }; grapher.addAccelerator(acc2); // Now, fill the grapher createGraph(); // create a check box that allows the selection of expanded subgraphs JCheckBox expandedSubgraphsCheckBox = new JCheckBox("Subgraphs", true); expandedSubgraphsCheckBox.setToolTipText("Allow the selection of expanded subgraphs"); expandedSubgraphsCheckBox.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { for (int i = 0; i < accelerators.length; i++) accelerators[i] .setSelectExpandedSubgraphsAllowed(e.getStateChange() == ItemEvent.SELECTED); } }); // create a check box that allows the selection of nodes JCheckBox nodesCheckBox = new JCheckBox("Nodes", true); nodesCheckBox.setToolTipText("Allow the selection of nodes"); nodesCheckBox.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { for (int i = 0; i < accelerators.length; i++) accelerators[i].setSelectNodesAllowed(e.getStateChange() == ItemEvent.SELECTED); } }); // create a check box that allows the selection of links JCheckBox linksCheckBox = new JCheckBox("Links", false); linksCheckBox.setToolTipText("Allow the selection of links"); linksCheckBox.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { for (int i = 0; i < accelerators.length; i++) accelerators[i].setSelectLinksAllowed(e.getStateChange() == ItemEvent.SELECTED); } }); // create a check box that allows you to descend into subgraphs JCheckBox descendCheckBox = new JCheckBox("Descend into subgraphs", true); descendCheckBox.setToolTipText("Allow the selection cycle to descend into subgraphs"); descendCheckBox.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { for (int i = 0; i < accelerators.length; i++) accelerators[i] .setDescendIntoExpandedSubgraphsAllowed(e.getStateChange() == ItemEvent.SELECTED); } }); // create a combination box for the order mode SuppressWarnings("unchecked") JComboBox<String> orderingBox = new IlvJComboBox(); orderingBox.addItem("unordered"); orderingBox.addItem("x then y"); orderingBox.addItem("y then x"); orderingBox.addItem("nested then x"); orderingBox.addItem("nested then y"); orderingBox.setToolTipText("Select the selection traversal order"); orderingBox.addActionListener(new ActionListener() { Override public void actionPerformed(ActionEvent event) { SuppressWarnings("unchecked") JComboBox<String> comboBox = (JComboBox<String>) event.getSource(); String mode = (String) comboBox.getSelectedItem(); Comparator<IlvGraphic> c = null; if ("unordered".equals(mode)) { c = null; } else if ("x then y".equals(mode)) { c = xThenY; } else if ("y then x".equals(mode)) { c = yThenX; } else if ("nested then x".equals(mode)) { c = nestedThenXThenY; } else if ("nested then y".equals(mode)) { c = nestedThenYThenX; } for (int i = 0; i < accelerators.length; i++) accelerators[i].setComparator(c); } }); JPanel aux = new JPanel(); aux.setLayout(new FlowLayout(FlowLayout.LEADING)); aux.add(new JLabel("Ordering: ")); aux.add(orderingBox); // create the top panel with the toolbar and the pop-up checkbox JPanel topPanel = new JPanel(); topPanel.setLayout(new FlowLayout(FlowLayout.LEADING)); final Dimension d1 = (new JLabel("Allow Selection of")).getPreferredSize(); JPanel leadingPanel = new JPanel() { Override public Dimension getMinimumSize() { return getPreferredSize(); } Override public Dimension getPreferredSize() { Dimension d0 = super.getPreferredSize(); Dimension dd = new Dimension(d1); dd.width += 40; if (d0.width > dd.width) dd.width = d0.width; if (d0.height > dd.height) dd.height = d0.height; return dd; } }; final Dimension d2 = (new JLabel("Further Options")).getPreferredSize(); JPanel trailingPanel = new JPanel() { Override public Dimension getMinimumSize() { return getPreferredSize(); } Override public Dimension getPreferredSize() { Dimension d0 = super.getPreferredSize(); Dimension dd = new Dimension(d2); dd.width += 40; if (d0.width > dd.width) dd.width = d0.width; if (d0.height > dd.height) dd.height = d0.height; return dd; } }; leadingPanel.setBorder(new TitledBorder("Allow Selection of")); leadingPanel.setLayout(new GridLayout(3, 1)); leadingPanel.add(expandedSubgraphsCheckBox); leadingPanel.add(nodesCheckBox); leadingPanel.add(linksCheckBox); trailingPanel.setBorder(new TitledBorder("Further Options")); trailingPanel.setLayout(new GridLayout(2, 1)); trailingPanel.add(descendCheckBox); trailingPanel.add(aux); topPanel.add(leadingPanel); topPanel.add(trailingPanel); // put manager view, top panel and bottom panel together getContentPane().setLayout(new BorderLayout(0, 0)); getContentPane().add(scrollManView, BorderLayout.CENTER); getContentPane().add(topPanel, BorderLayout.NORTH); mgrview.setDoubleBuffering(true); mgrview.setTransformer(new IlvTransformer(1, 0, 0, 1, 0, 0)); } /** * Creates a sample graph. */ private void createGraph() { IlvGraphic[] inner1 = createSubGraph(grapher); IlvGraphic sg1 = (IlvGraphic) inner1[0].getGraphicBag(); IlvGraphic[] inner2 = createSubGraph(grapher); IlvGraphic sg2 = (IlvGraphic) inner2[0].getGraphicBag(); grapher.moveObject(sg1, 220, 20, true); grapher.moveObject(sg2, 221, 140, true); IlvGraphic[] nodes = new IlvGraphic[7]; IlvPoint[] positions = {new IlvPoint(20, 0), new IlvPoint(90, 0), new IlvPoint(90, 60), new IlvPoint(160, 0), new IlvPoint(160, 60), new IlvPoint(160, 120), new IlvPoint(160, 180)}; for (int i = 0; i < nodes.length; i++) { nodes[i] = new IlvZoomableLabel(positions[i], "N", false); setNodeAttributes(nodes[i]); grapher.addNode(nodes[i], 0, true); } alignVertical(nodes[3], inner1[0]); alignVertical(nodes[4], inner1[2]); alignVertical(nodes[5], inner2[0]); alignVertical(nodes[6], inner2[2]); centerVertical(nodes[1], nodes[3], nodes[4]); centerVertical(nodes[2], nodes[5], nodes[6]); centerVertical(nodes[0], nodes[1], nodes[2]); int[] linksFrom = {0, 0, 1, 1, 2, 2, 3, 4, 5, 6}; int[] linksTo = {1, 2, 3, 4, 5, 6, 7, 9, 11, 13}; for (int i = 0; i < linksFrom.length; i++) { int fi = linksFrom[i]; IlvGraphic from = nodes[fi]; int ti = linksTo[i]; IlvGraphic to; if (ti < nodes.length) to = nodes[ti]; else if (ti < nodes.length + inner1.length) to = inner1[ti - nodes.length]; else to = inner2[ti - nodes.length - inner1.length]; IlvLinkImage link = new IlvLinkImage(from, to, true); grapher.addLink(link, 1, true); } } /** * Centers a node between two nodes in y direction. */ private void centerVertical(IlvGraphic node, IlvGraphic a, IlvGraphic b) { IlvRect bbox = a.boundingBox(); double min = bbox.y; bbox = b.boundingBox(); double max = bbox.y + bbox.height; bbox = node.boundingBox(); grapher.moveObject(node, bbox.x, (max + min - bbox.height) / 2, true); } /** * Aligns two nodes in y direction. */ private void alignVertical(IlvGraphic node, IlvGraphic ref) { IlvManager m = (IlvManager) ref.getGraphicBag(); IlvTransformer t = m.getTopLevelTransformer(); IlvRect bbox = ref.boundingBox(t); double y = bbox.y; bbox = node.boundingBox(); grapher.moveObject(node, bbox.x, y, true); } /** * Creates a double nested subgraph. */ private IlvGraphic[] createSubGraph(IlvGrapher parent) { IlvGrapher grapher = new IlvGrapher(); grapher.setSelectionInvariantSubManagerBounds(true); IlvGraphic[] nodes = new IlvGraphic[4]; IlvPoint[] positions = {new IlvPoint(20, 0), new IlvPoint(230, 60), new IlvPoint(20, 60), new IlvPoint(230, 0)}; int[] linksFrom = {0, 2, 5, 7, 0, 3}; int[] linksTo = {4, 6, 1, 3, 2, 1}; IlvGraphic[] inner = createSimpleSubGraph(grapher); for (int i = 0; i < nodes.length; i++) { nodes[i] = new IlvZoomableLabel(positions[i], "N", false); setNodeAttributes(nodes[i]); grapher.addNode(nodes[i], 0, true); } for (int i = 0; i < linksFrom.length; i++) { int fi = linksFrom[i]; IlvGraphic from = (fi < nodes.length ? nodes[fi] : inner[fi - nodes.length]); int ti = linksTo[i]; IlvGraphic to = (ti < nodes.length ? nodes[ti] : inner[ti - nodes.length]); IlvLinkImage link = new IlvLinkImage(from, to, true); grapher.addLink(link, 1, true); } IlvDefaultManagerFrame frame = (IlvDefaultManagerFrame) grapher.getFrame(); frame.setOpaque(true); frame.setBackground(new Color(100, 255, 100)); parent.addNode(grapher, 0, true); return nodes; } /** * Creates a subgraph. */ private IlvGraphic[] createSimpleSubGraph(IlvGrapher parent) { IlvGrapher grapher = new IlvGrapher(); grapher.setSelectionInvariantSubManagerBounds(true); IlvGraphic[] nodes = new IlvGraphic[4]; IlvPoint[] positions = {new IlvPoint(90, 0), new IlvPoint(160, 60), new IlvPoint(90, 60), new IlvPoint(160, 0)}; int[] linksFrom = {0, 2, 0, 3}; int[] linksTo = {3, 1, 2, 1}; for (int i = 0; i < nodes.length; i++) { nodes[i] = new IlvZoomableLabel(positions[i], "N", false); setNodeAttributes(nodes[i]); grapher.addNode(nodes[i], 0, true); } for (int i = 0; i < linksFrom.length; i++) { IlvGraphic from = nodes[linksFrom[i]]; IlvGraphic to = nodes[linksTo[i]]; IlvLinkImage link = new IlvLinkImage(from, to, true); grapher.addLink(link, 1, true); } IlvDefaultManagerFrame frame = (IlvDefaultManagerFrame) grapher.getFrame(); frame.setOpaque(true); frame.setBackground(new Color(255, 200, 200)); parent.addNode(grapher, 0, true); return nodes; } /** * Sets the attributes of a node. */ private void setNodeAttributes(IlvGraphic node) { IlvZoomableLabel zl = (IlvZoomableLabel) node; zl.setAntialiasing(true); zl.setLeftMargin(6); zl.setRightMargin(6); zl.setTopMargin(4); zl.setBottomMargin(4); zl.setBorderOn(true); zl.setBackgroundOn(true); zl.setBackgroundPaint(Color.yellow); } /** * Allows you to run the demo as a standalone application. */ public static void main(String[] arg) { // Sun recommends putting the entire GUI initialization into the // AWT thread SwingUtilities.invokeLater(new Runnable() { Override public void run() { KeyboardSelApp app = new KeyboardSelApp(); app.init(); JFrame frame = new JFrame("Keyboard Selection Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(500, 500); frame.getContentPane().add(app); frame.setVisible(true); } }); } }