/* * 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. */ package treemap; import java.awt.Color; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.faces.event.ActionEvent; import javax.faces.event.ValueChangeEvent; import javax.swing.tree.TreePath; import ilog.views.chart.IlvChart; import ilog.views.chart.IlvDisplayPoint; import ilog.views.chart.IlvStyle; import ilog.views.chart.data.IlvDataSource; import ilog.views.chart.datax.adapter.IlvClusterNode; import ilog.views.chart.event.TreemapFocusEvent; import ilog.views.chart.event.TreemapFocusListener; import ilog.views.chart.graphic.IlvDataRenderingHint; import ilog.views.chart.renderer.IlvTreemapChartRenderer; /** * A treemap that manages selection. */ public class TreemapWithHistory implements Serializable { // The treemap chart. private IlvChart chart; // The focuses that can be reached through the back button. private LinkedList<TreePath> /* of TreePath */ history; // The focuses that can be reached through the forward button. private LinkedList<TreePath> /* of TreePath */ future; // The path to the selected object, or null for none. private TreePath selection; // A rendering hint that highlights a rectangle. private IlvDataRenderingHint highlightRendering; // Selection state of the buttons private boolean backButtonEnabled; private boolean chooseButtonEnabled; private boolean outButtonEnabled; private boolean forwardButtonEnabled; // selection listeners private List<SelectionListener> listeners; // ======================================================================== /** * Creates a new <code>TreemapWithHistory</code> instance. * * @param dataSource * The data source to set. */ public TreemapWithHistory(IlvDataSource dataSource) { chart = new IlvChart(IlvChart.TREEMAP); chart.setUsingEventThread(false); chart.setDataSource(dataSource); initSelection(); initHistory(); } /** * Returns the encapsulated treemap chart. * * @return The treemap chart. */ public IlvChart getChart() { return chart; } // ============================ The Selection ============================ /** * Initializes the support for the selection. */ private void initSelection() { // Create an object that describes how to render a selected rectangle. // Here we make it draw a yellow, three pixels wide border. highlightRendering = new IlvDataRenderingHint() { final IlvStyle style1 = new IlvStyle(3.0f, Color.yellow).setFillOn(false); Override public IlvStyle getStyle(IlvDisplayPoint dp, IlvStyle defaultStyle) { // IlvDisplayObjectArea da = (IlvDisplayObjectArea) dp; if (style1.isFillOn()) return style1; else return style1.setFillOn(true).setFillPaint(defaultStyle.getFillPaint()); } }; // Initially no rectangle is selected. selection = null; } /** * The selection event. * * @param event * The value change event. */ public void selectionChanged(ValueChangeEvent event) { TreePath path = (TreePath) event.getNewValue(); if (path != null) setSelection(path); } /** * Returns the path to the selected object, or null for none. * * @return Current selection */ public TreePath getSelection() { return selection; } /** * Changes the selection. * * @param newSelection * The new selection to set. */ public void setSelection(TreePath newSelection) { if (!(newSelection != null ? newSelection.equals(selection) : selection == null)) { TreePath oldSelection = selection; selection = newSelection; IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0); // Remove the rendering hint for the old selected rectangle. if (oldSelection != null) renderer.setRenderingHint(oldSelection.getLastPathComponent(), null); // Enable the rendering hint for the new selected rectangle. if (newSelection != null) renderer.setRenderingHint(newSelection.getLastPathComponent(), highlightRendering); updateEnabledStatuses(); // update synchronized components fireSelectionChanged(newSelection); } } // ============================= The History ============================= /** * Back action listener. * * @param event * The action event */ public void backActionListener(ActionEvent event) { if (history.size() > 0) { TreePath last = history.removeLast(); IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0); TreePath current = renderer.getFocus(); future.addFirst(current); renderer.setFocus(last); // fireSubtreeChanged(last); updateEnabledStatuses(); } } private boolean shouldChooseActionEnabled() { if (selection != null) { IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0); TreePath current = renderer.getFocus(); return (current == null || (current.isDescendant(selection) && !current.equals(selection))); } else return false; } /** * Choose action listener. * * @param event * The action event */ public void chooseActionListener(ActionEvent event) { if (shouldChooseActionEnabled()) { TreePath next = selection; IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0); TreePath current = renderer.getFocus(); history.addLast(current); renderer.setFocus(next); // fireSubtreeChanged(next); updateEnabledStatuses(); } } private boolean shouldOutActionEnabled() { IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0); TreePath current = renderer.getFocus(); return (current != null && current.getPathCount() > 1); } /** * Out action listener. * * @param event * The action event */ public void outActionListener(ActionEvent event) { if (shouldOutActionEnabled()) { IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0); TreePath current = renderer.getFocus(); TreePath next = current.getParentPath(); if (next.getParentPath() == null) // model's root? next = null; history.addLast(current); renderer.setFocus(next); // fireSubtreeChanged(next); updateEnabledStatuses(); } } /** * forward action listener. * * @param event * The action event */ public void forwardActionListener(ActionEvent event) { if (future.size() > 0) { TreePath next = future.removeFirst(); IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0); TreePath current = renderer.getFocus(); history.addLast(current); renderer.setFocus(next); // fireSubtreeChanged(next); updateEnabledStatuses(); } } /** * Initializes the history and the actions that modify or notify the history. */ private void initHistory() { history = new LinkedList<TreePath>(); future = new LinkedList<TreePath>(); // Add an interactor that will drill-down on a rectangle when the user // double-clicks on it. // This interactor works in parallel to the selectInteractor above. /* * IlvChartInteractor doubleClickInteractor = new IlvChartPickInteractor() { * protected boolean isPickingEvent(MouseEvent event) { return * (event.getID() == MouseEvent.MOUSE_PRESSED && event.getClickCount() == * 2); } }; doubleClickInteractor.setConsumeEvents(false); // for * selectInteractor doubleClickInteractor.addChartInteractionListener( new * ChartInteractionListener() { public void * interactionPerformed(ChartInteractionEvent event) { // Get the rectangle * on which the user clicked. IlvDisplayObjectArea da = * (IlvDisplayObjectArea)event.getDisplayPoint(); setSelection(da != null ? * da.getPath() : null); chooseAction.actionPerformed(null); } }); * chart.addInteractor(doubleClickInteractor); */ // Add a listener that will avoid "blank screen" situations by // resetting the focus when some changes in the tree model have the // consequence that the current focus no longer is in the tree model. chart.addTreemapFocusListener(new TreemapFocusListener() { Override public void focusChanged(TreemapFocusEvent event) { if (event.getType() == TreemapFocusEvent.FOCUS_DELETED) { TreePath oldFocus = event.getOldFocus(); IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0); TreePath newFocus; if (oldFocus.getLastPathComponent() instanceof IlvClusterNode) // It'd tricky to find the new IlvClusterNode // corresponding to the old one. newFocus = null; else newFocus = renderer.getTreeModel().getPath(oldFocus.getLastPathComponent()); renderer.setFocus(newFocus); // fireSubtreeChanged(newFocus); updateEnabledStatuses(); } } }); } /** * Updates the selection state of the navigation buttons. */ public void updateEnabledStatuses() { backButtonEnabled = history.size() > 0; chooseButtonEnabled = shouldChooseActionEnabled(); outButtonEnabled = shouldOutActionEnabled(); forwardButtonEnabled = future.size() > 0; } /** * Adds a selection listener. * * @param listener * The listener to add. */ public void addSelectionListener(SelectionListener listener) { if (listeners == null) listeners = new ArrayList<TreemapWithHistory.SelectionListener>(); if (!listeners.contains(listener)) listeners.add(listener); } /** * Remove a selection listener. * * @param listener * The listener to remove. */ public void removeSelectionListener(SelectionListener listener) { if (listeners.contains(listener)) listeners.remove(listener); } /** * Broacast an event that involves a sub tree to the registered listeners. * * @param treepath * The new selection. */ protected void fireSelectionChanged(TreePath treepath) { if (listeners != null) for (Iterator<SelectionListener> iter = listeners.iterator(); iter.hasNext();) { SelectionListener listener = iter.next(); listener.selectionChanged(treepath); } } /** * Clears the history's contents. */ public void clearHistory() { history.clear(); future.clear(); updateEnabledStatuses(); } /** * Returns <code>true</code> if the back button is disabled, * <code>false</code> otherwise. * * @return <code>true</code> if the back button is disabled, * <code>false</code> otherwise. */ public boolean isBackButtonDisabled() { return !backButtonEnabled; } /** * Returns <code>true</code> if the choose button is disabled, * <code>false</code> otherwise. * * @return <code>true</code> if the choose button is disabled, * <code>false</code> otherwise. */ public boolean isChooseButtonDisabled() { return !chooseButtonEnabled; } /** * Returns <code>true</code> if the forward button is disabled, * <code>false</code> otherwise. * * @return <code>true</code> if the forward button is disabled, * <code>false</code> otherwise. */ public boolean isForwardButtonDisabled() { return !forwardButtonEnabled; } /** * Returns <code>true</code> if the out button is disabled, <code>false</code> * otherwise. * * @return <code>true</code> if the out button is disabled, <code>false</code> * otherwise. */ public boolean isOutButtonDisabled() { return !outButtonEnabled; } /** * This interface defines a listener to register on a * <code>TreemapWithHistory</code>. */ public static interface SelectionListener { /** * Action called when the selection has changed. * * @param subtree * The sub tree affected by this event. */ public void selectionChanged(TreePath subtree); } }