/*
* 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);
}
}