/* * 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. */ package accessibility; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Font; import java.awt.KeyboardFocusManager; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.print.PageFormat; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; import javax.swing.AbstractAction; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JPanel; import javax.swing.JRadioButtonMenuItem; import javax.swing.JToolBar; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.border.BevelBorder; import javax.swing.table.TableModel; import org.w3c.dom.Document; import org.w3c.dom.Element; import ilog.views.chart.IlvChart; import ilog.views.chart.IlvChartRenderer; import ilog.views.chart.IlvScale; import ilog.views.chart.accessibility.IlvAccessibleDataObject; import ilog.views.chart.accessibility.IlvAccessibleDataPoint; import ilog.views.chart.accessibility.IlvAccessibleDataSet; import ilog.views.chart.accessibility.IlvChartAreaAccessible; import ilog.views.chart.accessibility.IlvChartAreaAccessibleHierarchy; import ilog.views.chart.accessibility.IlvDefaultChartAreaAccessibleHierarchy; import ilog.views.chart.data.IlvDataSet; import ilog.views.chart.data.IlvDataSetPoint; import ilog.views.chart.data.IlvTreeTableDataSource; import ilog.views.chart.datax.IlvColumnUtilities; import ilog.views.chart.datax.IlvDataColumnInfo; import ilog.views.chart.datax.IlvDefaultDataColumnInfo; import ilog.views.chart.datax.adapter.partition.IlvPartitionerFactory; import ilog.views.chart.datax.adapter.partition.IlvStringPartitionerFactory; import ilog.views.chart.datax.flat.table.IlvDefaultFlatTableModel; import ilog.views.chart.graphic.IlvDataLabelAnnotation; import ilog.views.chart.interactor.IlvChartAreaNavigationMode; import ilog.views.chart.interactor.IlvChartAreaSelectionManager; import ilog.views.chart.interactor.IlvChartCycleSelectInteractor; import ilog.views.chart.print.IlvChartPrintableDocument; import ilog.views.chart.renderer.IlvSimpleValueColorScheme; import ilog.views.chart.renderer.IlvTreemapChartRenderer; import ilog.views.util.IlvImageUtil; import ilog.views.util.data.IlvCSVReader; import ilog.views.util.internal.IlvURLUtil; import ilog.views.util.styling.IlvStylingException; import ilog.views.util.swing.border.IlvEtchedLineBorder; import ilog.views.util.swing.layout.IlvBetterFlowLayout; import shared.AbstractChartExample; import shared.PDFGenerator; /** * A class that demonstrates accessibility features, such as - keyboard * navigation, - redundant colors. */ public class AccessibilityDemo extends AbstractChartExample { /** * The chart at the center of the frame. */ IlvChart chart; /** * True if keyboard navigation can select the x scale. */ boolean xScaleSelectable; /** * True if keyboard navigation can select the y scale. */ boolean yScaleSelectable; /** * The hierarchy of selectable elements of the chart area. */ IlvDefaultChartAreaAccessibleHierarchy hierarchy; /** * The manager that keeps track of and displays the current selection. */ IlvChartAreaSelectionManager selectionManager; /** * The chart interactor that reacts on keyboard events by moving around the * current selection or the focus. */ IlvChartCycleSelectInteractor interactor; /** * The name of the project that the chart displays. */ String project; /** * The status bar at the bottom of the frame. In this sample, it displays the * currently focused component and, inside the chart area, the currently * selected element. */ JLabel statusBar; // ========================== Keyboard Navigation ========================== /** * Specifies whether keyboard navigation can select the x scale. */ private void setXScaleSelectable(boolean selectable) { IlvScale scale = chart.getXScale(); if (scale != null) hierarchy.setSelectable(scale, selectable); } /** * Specifies whether keyboard navigation can select the y scale. */ private void setYScaleSelectable(boolean selectable) { IlvScale scale = chart.getYScale(0); if (scale != null) hierarchy.setSelectable(scale, selectable); } /** * Creates the keyboard navigation interactor that uses the given mode and * makes use of the <code>hierarchy</code> and <code>selectionManager</code> * objects. */ private IlvChartCycleSelectInteractor createInteractor(IlvChartAreaNavigationMode mode) { // This sample uses a customized hierarchy. // Therefore, instead of letting the interactor create its own, new // hierarchy object, reuse the customized one. IlvChartCycleSelectInteractor interactor = new IlvChartCycleSelectInteractor(mode) { Override public IlvChartAreaAccessibleHierarchy createAccessibleHierarchy(IlvChart chart) { return hierarchy; } }; interactor.setSelectionManager(selectionManager); return interactor; } /** * Installs a custom focus traversal on the given component. This means that: * - The user can assign the focus to the component, by repeatedly pressing * Tab or Shift-Tab. - The component has its own way of managing "focus" * inside itself. - The user needs to press Ctrl-Tab or Shift-Ctrl-Tab instead * of Tab or Shift-Tab in order to move the focus outside the component. */ private void installCustomFocusTraversal(Component component) { // So that the user can assign the focus to the component, it must // be enabled. // This statement is not needed in this sample, because the components // are enabled anyway. // component.setEnabled(true); // So that the user can assign the focus to the component, it must // be focusable. component.setFocusable(true); // If the component is a Container, and the user should use Ctrl-Tab // or Shift-Ctrl-Tab instead of Tab or Shift-Tab in order to leave // the component, you would have to designate it as a "focus cycle root". // component.setFocusCycleRoot(true); // Disable the AWT default actions for Tab and Shift-Tab on the component. component.setFocusTraversalKeysEnabled(false); // Enable similar actions for Ctrl-Tab and Shift-Ctrl-Tab instead. component.addKeyListener(new KeyAdapter() { private KeyStroke CTRL_TAB = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.CTRL_MASK); private KeyStroke SHIFT_CTRL_TAB = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_MASK | KeyEvent.CTRL_MASK); // Override keyPressed, not keyTyped, because these two KeyStrokes // are defined through a key code, not through a key char. Override public void keyPressed(KeyEvent event) { KeyStroke key = KeyStroke.getKeyStrokeForEvent(event); if (CTRL_TAB.equals(key)) { // Moves the focus outside of the chart area component, to the // next focusable component. KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(); event.consume(); } else if (SHIFT_CTRL_TAB.equals(key)) { // Moves the focus outside of the chart area component, to the // previous focusable component. KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent(); event.consume(); } } }); } // ---------------------- Displaying the current focus ---------------------- /** * Displays the currently focused GUI element in the status bar. */ private void updateFocusOwnerDisplay() { Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); String text = "<none>"; if (focusOwner != null) { // First piece of text: The class name of the focus owner. Class<?> focusOwnerClass = focusOwner.getClass(); while (focusOwnerClass.isAnonymousClass()) // such as // javax.swing.JToolBar$1.class focusOwnerClass = focusOwnerClass.getSuperclass(); text = focusOwnerClass.getName(); text = text.substring(text.lastIndexOf('.') + 1).replace('$', '.'); // More detailed information for buttons. if (focusOwner instanceof AbstractButton) { AbstractButton button = (AbstractButton) focusOwner; if (button.getText() != null) { text += "(\"" + button.getText() + "\")"; } else if (button.getAction() != null) { String name = (String) button.getAction().getValue(Action.NAME); String shortDescription = (String) button.getAction().getValue(Action.SHORT_DESCRIPTION); text += "(\"" + (shortDescription != null ? shortDescription : name) + "\")"; } } // For the chart area, add details about the selected element. else if (focusOwner instanceof IlvChart.Area) { IlvChartAreaAccessible selection = selectionManager.getSelection(); if (selection != null) { if (selection instanceof IlvScale) { text += " " + (((IlvScale) selection).getAxis().isXAxis() ? "X scale" : "Y scale"); } else if (selection instanceof IlvChartRenderer) { text += " " + selection; } else if (selection instanceof IlvAccessibleDataSet) { IlvDataSet ds = ((IlvAccessibleDataSet) selection).getDataSet(); text += " Data Set: " + ds.getName(); } else if (selection instanceof IlvAccessibleDataPoint) { IlvDataSetPoint dp = ((IlvAccessibleDataPoint) selection).getDataPoint(); text += " Data Point: " + dp.getDataSet().getName() + ", Point #" + dp.getIndex() + " (" + dp.getXData() + "," + dp.getYData() + ")"; } else if (selection instanceof IlvAccessibleDataObject) { text += " Data Object: " + ((IlvAccessibleDataObject) selection).getObject(); } else { text += " " + selection; } } } statusBar.setText("Focus: " + System.currentTimeMillis() + " " + text); } } /** * Installs a notification that makes sure that the focus owner display gets * updated when the focus owner changes. */ private void installFocusOwnerListener() { // Get notified when the focus owner changes. KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener("focusOwner", new PropertyChangeListener() { Override public void propertyChange(PropertyChangeEvent event) { updateFocusOwnerDisplay(); } }); } /** * Creates an IlvChartAreaSelectionManager that makes sure that the focus * owner (and selection) display gets updated when the selection in the chart * area changes. */ private IlvChartAreaSelectionManager createSelectionManager() { return new IlvChartAreaSelectionManager() { Override public void setSelection(IlvChartAreaAccessible selection) { super.setSelection(selection); // After the selection has changed, update the focus owner display. updateFocusOwnerDisplay(); } }; } // ------------------- Keyboard Navigation Initialization ------------------- /** * Initializes the keyboard navigation. */ private void initKeyboardNavigation() { xScaleSelectable = true; yScaleSelectable = true; hierarchy = new IlvDefaultChartAreaAccessibleHierarchy(chart); setXScaleSelectable(xScaleSelectable); setYScaleSelectable(yScaleSelectable); selectionManager = createSelectionManager(); interactor = createInteractor(IlvChartCycleSelectInteractor.TRAVERSE_ALL); chart.addInteractor(interactor); // Enable custom handling of Tab, Shift-Tab, etc. in the chart area. // Optionally you could do the same thing for the legend as well. // The chart component itself can stay non-focusable. installCustomFocusTraversal(chart.getChartArea()); installFocusOwnerListener(); } // ============================ Several Projects ============================ /** * The list of projects that can be displayed in this sample. */ static String[] allProjects = { "data/influenza-by-year.icpr -- polyline chart", // "../gallery/data/wheat-by-year.icpr -- polyline chart", "data/french-parliament.icpr -- clustered bar chart", "data/influenza-by-age.icpr -- stacked area chart", "data/wheat-by-state.icpr -- pie chart", "data/income-per-county.csv -- treemap chart", // "../gallery/data/countries.icpr -- radar chart", // "../gallery/data/currency-exchange.icpr -- high-low chart", // "../gallery/data/earthquakes-alaska.icpr -- bubble chart", // "../gallery/data/hertzsprung-russell.icpr -- scatter chart", // "../gallery/data/xor-circuit.icpr -- stair chart", // "../gallery/data/yagi-antenna.icpr -- polar chart", }; /** * Loads the specified project. * * @param projectLabel * A string from <code>allProjects</code>. */ private void loadProject(String projectLabel) { String filename = projectLabel.substring(0, projectLabel.indexOf(" -- ")); URL url = getResourceURL(filename); URL projectUrl = (filename.endsWith(".icpr") ? url : null); try { // Put the chart's type into a default state. When the chart's // configuration was read from a CSS file, this is automatic. // But when we have changed the chart type through the API, we // have to do it explicitly. if (chart.getType() == IlvChart.TREEMAP) chart.setType(IlvChart.CARTESIAN); chart.setProject(projectUrl); } catch (IOException e) { System.err.println("Cannot load " + filename); e.printStackTrace(); } catch (IlvStylingException e) { System.err.println("Cannot load the style of " + filename); e.printStackTrace(); } // Treemap projects need special handling because here they are not // specified through a .icpr file. if (projectLabel.endsWith(" -- treemap chart")) loadTreemapProject(url); // Remember the chosen project, for the display of the menu. project = projectLabel; } /** * Loads the treemap project. * * @param url * The URL of the data file. */ private void loadTreemapProject(URL url) { // Read the CSV file into memory. TableModel tableModel; try { InputStream stream = IlvURLUtil.openStream(url); Reader reader = new InputStreamReader(new BufferedInputStream(stream), "ASCII"); try { tableModel = IlvCSVReader.getInstance(IlvCSVReader.COMMA, 0).read(reader); } finally { reader.close(); } } catch (IOException e) { e.printStackTrace(); chart.setDataSource(null); return; } // Information about the columns in the CSV file (name and type). String[] columnNames = { "State", "County code", "State Abbrev", "County name", "Returns", "Exemptions", "Adjusted gross income", "Wages and salaries", "Dividends", "Interest", // Extra, computed columns. "Wages and salaries percentage", "Dividends percentage", "Interest percentage" }; Class<?>[] columnTypes = { String.class, String.class, String.class, String.class, Double.class, Double.class, Double.class, Double.class, Double.class, Double.class }; final int County_code_COLUMN = 1; final int County_name_COLUMN = 3; final int Adjusted_gross_income_COLUMN = 6; final int Wages_and_salaries_COLUMN = 7; final int Dividends_COLUMN = 8; final int Interest_COLUMN = 9; final int Wages_and_salaries_percentage_COLUMN = 10; final int Dividends_percentage_COLUMN = 11; final int Interest_percentage_COLUMN = 12; // Copy the data into an IlvFlatTableModel, with appropriate // conversion of values. int numColumns = tableModel.getColumnCount(); IlvDataColumnInfo[] columns = new IlvDataColumnInfo[columnNames.length]; for (int col = 0; col < numColumns; col++) { columns[col] = new IlvDefaultDataColumnInfo(columnNames[col], columnTypes[col]); } for (int col = numColumns; col < columnNames.length; col++) { columns[col] = new IlvDefaultDataColumnInfo(columnNames[col], Double.class); } int numRows = tableModel.getRowCount(); IlvDefaultFlatTableModel tableData = new IlvDefaultFlatTableModel(numRows, columns); for (int col = 0; col < numColumns; col++) { if (columnTypes[col] == Double.class) { for (int row = 0; row < numRows; row++) { double value = Double.parseDouble(tableModel.getValueAt(row, col).toString()); tableData.setDoubleAt(value, row, col); } } else if (columnTypes[col] == Integer.class) { for (int row = 0; row < numRows; row++) { int value = (int) Double.parseDouble(tableModel.getValueAt(row, col).toString()); tableData.setValueAt(new Integer(value), row, col); } } else if (columnTypes[col] == String.class) { for (int row = 0; row < numRows; row++) { String value = tableModel.getValueAt(row, col).toString(); tableData.setValueAt(value, row, col); } } else { for (int row = 0; row < numRows; row++) { Object value = tableModel.getValueAt(row, col); tableData.setValueAt(value, row, col); } } } // Remove the suffix " County" from the county names. for (int row = 0; row < numRows; row++) { String countyName = (String) tableData.getValueAt(row, County_name_COLUMN); if (countyName.endsWith(" County")) tableData.setValueAt(countyName.substring(0, countyName.length() - 7), row, County_name_COLUMN); } // Fill the computed column values. for (int row = 0; row < numRows; row++) { double agi = ((Double) tableData.getValueAt(row, Adjusted_gross_income_COLUMN)).doubleValue(); double wd = ((Double) tableData.getValueAt(row, Wages_and_salaries_COLUMN)).doubleValue(); double d = ((Double) tableData.getValueAt(row, Dividends_COLUMN)).doubleValue(); double i = ((Double) tableData.getValueAt(row, Interest_COLUMN)).doubleValue(); tableData.setValueAt(new Double(wd / agi), row, Wages_and_salaries_percentage_COLUMN); tableData.setValueAt(new Double(d / agi), row, Dividends_percentage_COLUMN); tableData.setValueAt(new Double(i / agi), row, Interest_percentage_COLUMN); } // Remove the rows with county code 0, because these are per-state // summary rows. for (int row = 0; row < tableData.getRowCount();) { if ("0".equals(tableData.getValueAt(row, County_code_COLUMN))) tableData.removeRow(row); else row++; } // Create a data source taking the model as input. IlvTreeTableDataSource dataSource = new IlvTreeTableDataSource(tableData); dataSource.setPartitionerFactories(new IlvPartitionerFactory[] { new IlvStringPartitionerFactory(IlvColumnUtilities.getColumnByName(tableData, "State")) }); /* * Customize the chart. */ chart.setType(IlvChart.TREEMAP); // Add a header label. chart.setHeaderText("Income from interests in the U.S. 2008"); chart.getHeader().setFont(new Font("Dialog", Font.PLAIN, 30)); chart.setDataSource(dataSource); IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0); renderer.setAreaColumnName("Adjusted gross income"); // Customize the color of the objects. // Set the column which determines the color. renderer.setColorColumnName("Interest percentage"); renderer.setColorScheme( IlvSimpleValueColorScheme.createAdjustedColorScheme(IlvTreemapChartRenderer.COLORSCHEME_AVERAGE_BLUE_YELLOW)); // Add a label to each rectangle, and arrange to avoid label overlaps. renderer.setLabelColumnName("County name"); renderer.setAnnotation(new IlvDataLabelAnnotation()); renderer.setClippedAnnotationVisibility(false); renderer.setAnnotationVisibility(IlvTreemapChartRenderer.VISIBILITY_SMART); } // ================================ Printing ================================ /** * Creates the document to be printed. */ Override protected IlvChartPrintableDocument createPrintableDocument() { return new IlvChartPrintableDocument("accessibility", chart, PageFormat.LANDSCAPE, null); } // ============================= PDF Generation ============================= /** * Creates the XSL-FO element to be shown in the PDF. */ Override protected Element createFOElement(Document document, PDFGenerator pdfgen) { return createFOElementForChart(chart, document, pdfgen); } // =========================== GUI Initialization =========================== private AbstractAction exitAction; /** * Initializes the user interface of the sample's frame. */ Override public void init(Container container) { super.init(container); // Allocate the components. chart = new IlvChart(); initKeyboardNavigation(); loadProject(allProjects[0]); JToolBar toolbar = createToolBar(); exitAction = new AbstractAction("Exit") { Override public void actionPerformed(ActionEvent event) { quit(); System.exit(0); } }; JButton exitButton = new JButton(exitAction); statusBar = new JLabel(" "); statusBar.setBorder(new BevelBorder(BevelBorder.LOWERED)); // Put them together. container.setLayout(new BorderLayout()); container.add(toolbar, BorderLayout.NORTH); { JPanel middlePanel = new JPanel(); middlePanel.setLayout(new BorderLayout()); middlePanel.add(chart, BorderLayout.CENTER); { JPanel buttonBar = new JPanel(); buttonBar.setLayout(new IlvBetterFlowLayout()); buttonBar.setBorder(new IlvEtchedLineBorder()); buttonBar.add(exitButton); middlePanel.add(buttonBar, BorderLayout.SOUTH); } container.add(middlePanel, BorderLayout.CENTER); } container.add(statusBar, BorderLayout.SOUTH); // Add a menu bar. { JMenuBar menuBar = new JMenuBar(); menuBar.add(createFileMenu()); menuBar.add(createSelectableElementsMenu()); menuBar.add(createNavigationModeMenu()); menuBar.add(createRenderingMenu()); menuBar.add(createLAFMenu()); setMenuBar(menuBar); } } // -------------------------------- Tool Bar -------------------------------- /** * Populates the specified toolbar. */ Override protected void populateToolBar(JToolBar toolbar) { super.populateToolBar(toolbar); addPrintingToToolBar(toolbar); } // ---------------------------------- Menu ---------------------------------- private JMenu createFileMenu() { JMenu menu = new JMenu("File"); menu = createProjectChooserMenu(menu); if (isPrintingConfigured()) { menu.addSeparator(); ImageIcon icon; try { icon = new ImageIcon(IlvImageUtil.loadImageFromFile(AbstractChartExample.class, "PrintPreview24.gif")); } catch (java.io.IOException e) { System.err.println("Cannot load PrintPreview24.gif"); icon = null; } initPrinting(); Action action = new AbstractAction("Print...", icon) { Override public void actionPerformed(ActionEvent event) { printPreview(); } }; menu.add(action); } menu.addSeparator(); menu.add(exitAction); return menu; } private JMenu createProjectChooserMenu(JMenu menu) { ButtonGroup group = new ButtonGroup(); for (final String projectLabel : allProjects) { String labelWithoutDirectory = projectLabel.substring(projectLabel.lastIndexOf('/') + 1); JRadioButtonMenuItem item = new JRadioButtonMenuItem(labelWithoutDirectory); item.setSelected(projectLabel.equals(project)); item.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent event) { if (((JRadioButtonMenuItem) event.getSource()).isSelected()) { loadProject(projectLabel); } } }); group.add(item); menu.add(item); } return menu; } private JMenu createSelectableElementsMenu() { JMenu menu = new JMenu("Selectable Elements"); { JCheckBoxMenuItem item = new JCheckBoxMenuItem("X Scale"); item.setSelected(xScaleSelectable); item.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent event) { boolean checked = ((JCheckBoxMenuItem) event.getSource()).isSelected(); setXScaleSelectable(checked); } }); menu.add(item); } { JCheckBoxMenuItem item = new JCheckBoxMenuItem("Y Scale"); item.setSelected(yScaleSelectable); item.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent event) { boolean checked = ((JCheckBoxMenuItem) event.getSource()).isSelected(); setYScaleSelectable(checked); } }); menu.add(item); } return menu; } private JMenu createNavigationModeMenu() { JMenu menu = new JMenu("Navigation Mode"); ButtonGroup group = new ButtonGroup(); IlvChartAreaNavigationMode[] modes = { IlvChartCycleSelectInteractor.TRAVERSE_ALL, IlvChartCycleSelectInteractor.BY_LEVEL }; String[] labels = { "Traverse all", "By level" }; for (int i = 0; i < modes.length; i++) { final IlvChartAreaNavigationMode mode = modes[i]; JRadioButtonMenuItem item = new JRadioButtonMenuItem(labels[i]); item.setSelected(interactor.getMode() == mode); item.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent event) { if (((JRadioButtonMenuItem) event.getSource()).isSelected()) { // We cannot change the mode of a IlvChartCycleSelectInteractor. // Instead, we have to create a new instance. chart.removeInteractor(interactor); interactor = createInteractor(mode); chart.addInteractor(interactor); chart.repaint(); } } }); group.add(item); menu.add(item); } return menu; } private JMenu createRenderingMenu() { JMenu menu = new JMenu("Selection Rendering"); ButtonGroup group = new ButtonGroup(); int[] renderingModes = { IlvChartAreaSelectionManager.SHOW_HANDLES, IlvChartAreaSelectionManager.SHOW_HIGHLIGHT }; String[] labels = { "Handles", "Highlight" }; for (int i = 0; i < renderingModes.length; i++) { final int renderingMode = renderingModes[i]; JRadioButtonMenuItem item = new JRadioButtonMenuItem(labels[i]); item.setSelected(selectionManager.getRenderingMode() == renderingMode); item.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent event) { if (((JRadioButtonMenuItem) event.getSource()).isSelected()) { selectionManager.setRenderingMode(renderingMode); chart.repaint(); } } }); group.add(item); menu.add(item); } return menu; } // ============================== Main Program ============================== public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { Override public void run() { JFrame frame = new JFrame("Accessibility in a Chart"); AccessibilityDemo demo = new AccessibilityDemo(); demo.init(frame.getContentPane()); demo.setFrameGeometry(800, 600, true); frame.setVisible(true); } }); } }