/*
* 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 treemap;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.tree.TreePath;
import ilog.views.chart.IlvChart;
import ilog.views.chart.IlvChartLayout;
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.IlvClusterNode;
import ilog.views.chart.datax.adapter.IlvFlatTableToTableModel;
import ilog.views.chart.datax.adapter.partition.IlvPartitionerFactory;
import ilog.views.chart.datax.adapter.partition.IlvStringPartitionerFactory;
import ilog.views.chart.datax.adapter.partition.IlvUniformScalePartitionerFactory;
import ilog.views.chart.datax.flat.table.IlvDefaultFlatTableModel;
import ilog.views.chart.datax.flat.table.IlvFlatTableModel;
import ilog.views.chart.event.TreemapFocusEvent;
import ilog.views.chart.event.TreemapFocusListener;
import ilog.views.chart.renderer.IlvColorScheme;
import ilog.views.chart.renderer.IlvTreemapChartRenderer;
import ilog.views.util.data.IlvCSVReader;
import ilog.views.util.swing.IlvJSplitPane;
import ilog.views.util.swing.layout.IlvBetterFlowLayout;
import ilog.views.util.swing.table.IlvJTableHeaderWithToolTips;
import ilog.views.util.swing.table.IlvJTableWithToolTips;
import shared.AbstractChartExample;
/**
* Demonstrates the treemap's main features.
*/
public class TreemapDemo extends AbstractChartExample {
// The data source containing the data to be displayed.
IlvTreeTableDataSource dataSource;
// The table displaying the raw data.
JTable rawTable;
JScrollPane rawTableView;
// The columns display used for partitioning.
JTableHeader columnsTable;
int separatorIndex;
// The chooser for the area and color columns.
JComboBox<String> areaColumnChooser;
JComboBox<String> colorColumnChooser;
// The chooser for the labeling mode.
JComboBox<String> labelingChooser;
// The combined treemap and tree-table.
TreemapWithTreeTable trees;
// Intermediate containers.
JSplitPane treesPanel;
static final double treesPanelDefaultDivision = 0.35;
JSplitPane wholePanel;
static final double wholePanelDefaultDivision = 0.6;
// Flags for inhibiting selection propagation.
boolean inhibitSelectionPropToRawTable;
boolean inhibitSelectionPropToTreeTable;
/**
* Initializes the example user interface in the specified container.
*
* @param container
* The <code>contentPane</code> of the <code>JFrame</code>.
*/
Override
public void init(Container container) {
super.init(container);
initDataSource();
initRawTable();
initTreemapWithTreeTable();
initPartitioningControl();
initAreaColumnControl();
initColorColumnControl();
initLabelingControl();
// Initialize the status of toolbar buttons.
trees.treemapPanel.updateEnabledStatuses();
initTableSelectionSynchronization();
// Create some auxiliary labels.
JLabel columnsTableDescription = new JLabel(
"Partition by: (Drag one or two items to the left, before the black separator.)");
JLabel areaColumnChooserDescription = new JLabel("Show as important:");
JLabel colorColumnChooserDescription = new JLabel("Show through color:");
JLabel labelingChooserDescription = new JLabel("Labels:");
// Put the pieces together.
Box columnsTableBox = new Box(BoxLayout.PAGE_AXIS);
{
Box row = new Box(BoxLayout.LINE_AXIS);
row.add(columnsTableDescription);
row.add(Box.createHorizontalGlue());
columnsTableBox.add(row);
}
columnsTableBox.add(columnsTable);
Box areaColumnChooserBox = new Box(BoxLayout.PAGE_AXIS);
{
Box row = new Box(BoxLayout.LINE_AXIS);
row.add(areaColumnChooserDescription);
row.add(Box.createHorizontalGlue());
areaColumnChooserBox.add(row);
}
areaColumnChooserBox.add(areaColumnChooser);
Box colorColumnChooserBox = new Box(BoxLayout.PAGE_AXIS);
{
Box row = new Box(BoxLayout.LINE_AXIS);
row.add(colorColumnChooserDescription);
row.add(Box.createHorizontalGlue());
colorColumnChooserBox.add(row);
}
colorColumnChooserBox.add(colorColumnChooser);
Box labelingChooserBox = new Box(BoxLayout.PAGE_AXIS);
{
Box row = new Box(BoxLayout.LINE_AXIS);
row.add(labelingChooserDescription);
row.add(Box.createHorizontalGlue());
labelingChooserBox.add(row);
}
labelingChooserBox.add(labelingChooser);
Box chooserBoxes = new Box(BoxLayout.LINE_AXIS);
chooserBoxes.add(areaColumnChooserBox);
chooserBoxes.add(Box.createHorizontalStrut(5));
chooserBoxes.add(colorColumnChooserBox);
chooserBoxes.add(Box.createHorizontalStrut(5));
chooserBoxes.add(labelingChooserBox);
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new IlvBetterFlowLayout(FlowLayout.LEADING));
controlPanel.add(columnsTableBox);
controlPanel.add(chooserBoxes);
treesPanel = new IlvJSplitPane(JSplitPane.HORIZONTAL_SPLIT, trees.treetableView, trees.treemapPanel);
treesPanel.setResizeWeight(treesPanelDefaultDivision);
JPanel upperHalf = new JPanel();
upperHalf.setLayout(new BorderLayout());
upperHalf.add(treesPanel, BorderLayout.CENTER);
upperHalf.add(controlPanel, BorderLayout.NORTH);
wholePanel = new IlvJSplitPane(JSplitPane.VERTICAL_SPLIT, upperHalf, rawTableView);
wholePanel.setResizeWeight(wholePanelDefaultDivision);
container.setLayout(new BorderLayout());
container.add(wholePanel, BorderLayout.CENTER);
treesPanel.setDividerLocation(treesPanelDefaultDivision);
wholePanel.setDividerLocation(wholePanelDefaultDivision);
}
// The file containing the data.
// private final String dataFileXML = "data/energy.xml";
private final String dataFileCSV = "data/energy.csv";
// Information about the columns in the Excel data.
private final String[] columnNames = { "Country", "Region", "Population", "GDP", "GDP per Capita", "Ranking", "Year",
"Energy Type", "Production", "Consumption" };
private final Class<?>[] columnTypes = { String.class, String.class, Double.class, Double.class, Double.class,
Integer.class, String.class, String.class, Double.class, Double.class };
/**
* Loads the data into memory and makes it accessible through a data source.
*/
private void initDataSource() {
// Load the data.
IlvFlatTableModel tableData;
// if (false) {
// // Load from the XML file.
// // This takes more memory, but is useful if the original file is an
// // Excel file.
// Workbook data;
// try {
// data = new Workbook(getResourceURL(dataFileXML));
// } catch (IOException e) {
// e.printStackTrace();
// return;
// }
//
// // Extract the first worksheet.
// tableData = data.getWorksheet(0, columnNames, columnTypes, 1);
// } else {
// Load from the CSV file.
// This takes less memory.
TableModel table;
try {
Reader reader = new InputStreamReader(new BufferedInputStream(openStream(getResourceURL(dataFileCSV))), "UTF-8");
try {
IlvCSVReader parser = IlvCSVReader.getInstance('\t', 0);
table = parser.read(reader);
} finally {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
return;
}
// Copy the data into an IlvFlatTableModel, with appropriate
// conversion of values.
int numColumns = table.getColumnCount();
if (numColumns != columnNames.length)
throw new RuntimeException("The columnNames array is not up-to-date.");
IlvDataColumnInfo[] columns = new IlvDataColumnInfo[numColumns];
for (int col = 0; col < numColumns; col++) {
columns[col] = new IlvDefaultDataColumnInfo(columnNames[col], columnTypes[col]);
}
int numRows = table.getRowCount();
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(table.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(table.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 = table.getValueAt(row, col).toString();
tableData.setValueAt(value, row, col);
}
} else {
for (int row = 0; row < numRows; row++) {
Object value = table.getValueAt(row, col);
tableData.setValueAt(value, row, col);
}
}
}
// }
// Set the types of some columns to enumerated. This is a hint to the
// QUALITATIVE color scheme how to distribute the colors.
((IlvDefaultDataColumnInfo) IlvColumnUtilities.getColumnByName(tableData, "Country")).setEnumerated(true);
((IlvDefaultDataColumnInfo) IlvColumnUtilities.getColumnByName(tableData, "Region")).setEnumerated(true);
// Create a data source taking the worksheet as input.
dataSource = new IlvTreeTableDataSource(tableData);
}
/**
* Initializes the raw table view of the data.
*/
private void initRawTable() {
// Create the table view.
IlvFlatTableModel tableData = dataSource.getFlatTableModel();
rawTable = new IlvJTableWithToolTips(new IlvFlatTableToTableModel(tableData));
// Specify the names and proportions of the columns.
TableColumnModel rawTableColumns = new DefaultTableColumnModel();
for (int col = 0; col < columnNames.length; col++) {
TableColumn column = new TableColumn(col, 80);
column.setHeaderValue(columnNames[col]);
rawTableColumns.addColumn(column);
}
rawTable.setColumnModel(rawTableColumns);
// Enable tooltips on the header.
rawTable.setTableHeader(new IlvJTableHeaderWithToolTips(rawTable.getColumnModel()));
// Add scroll bars around it.
rawTableView = new JScrollPane(rawTable);
}
/**
* Initializes the treemap and tree-table views of the data.
*/
private void initTreemapWithTreeTable() {
trees = new TreemapWithTreeTable(dataSource, "Country", new String[0], getResourceURL("resources/treemap.css"));
}
/**
* Creates the columns display used for partitioning.
*/
private void initPartitioningControl() {
columnsTable = new ReorderableTableHeader() {
Override
public void columnDragged(int fromIndex, int toIndex) {
// Enforce a rule that at most 3 columns are used
// for partitioning. More precisely, at most 2
// enumerated columns and at most 1 numeric column.
// Otherwise the partitioned tree model takes up
// too much memory, leading to OutOfMemoryError.
// The limits 2 and 1 are arbitrary.
final int enumColumnsMax = 2;
final int numericColumnsMax = 1;
// We don't want to interfere with the column the user is
// moving. Therefore we count how many columns of each type
// to keep before the separator, excluding toIndex.
int enumColumnsToKeep = enumColumnsMax;
int numericColumnsToKeep = numericColumnsMax;
IlvFlatTableModel model = dataSource.getFlatTableModel();
int col;
for (col = 0; col < getColumnModel().getColumnCount(); col++) {
// Consider only the columns left of the separator.
if ("".equals(getColumnModel().getColumn(col).getIdentifier()))
break;
// Look which column the user is moving.
if (col == toIndex) {
String columnName = (String) getColumnModel().getColumn(col).getIdentifier();
IlvDataColumnInfo column = IlvColumnUtilities.getColumnByName(model, columnName);
if (Number.class.isAssignableFrom(column.getType()))
numericColumnsToKeep -= 1;
else
enumColumnsToKeep -= 1;
}
}
int separator = col;
int moveTarget = separator;
for (col = 0; col < separator; col++) {
// Don't interfere with the column the user is moving.
if (col != toIndex) {
String columnName = (String) getColumnModel().getColumn(col).getIdentifier();
IlvDataColumnInfo column = IlvColumnUtilities.getColumnByName(model, columnName);
if (Number.class.isAssignableFrom(column.getType())) {
if (numericColumnsToKeep > 0) {
numericColumnsToKeep--;
continue;
}
} else {
if (enumColumnsToKeep > 0) {
enumColumnsToKeep--;
continue;
}
}
// Move col behind the separator.
getColumnModel().moveColumn(col, moveTarget);
if (col < toIndex)
toIndex--;
col--;
separator--;
}
}
// Now update the partitioning accordingly.
updatePartitioners();
}
};
final TableColumnModel columnsTableColumns = new DefaultTableColumnModel();
{
TableColumn separatorColumn = new TableColumn(-1, 10);
separatorColumn.setHeaderValue("");
DefaultTableCellRenderer separatorRenderer = new DefaultTableCellRenderer() {
Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
return this;
}
};
separatorRenderer.setBorder(BorderFactory.createLineBorder(Color.black, 3));
separatorColumn.setHeaderRenderer(separatorRenderer);
columnsTableColumns.addColumn(separatorColumn);
}
DefaultTableCellRenderer columnHeaderRenderer =
// Similar to what JTableHeader.UIResourceTableCellRenderer does.
new DefaultTableCellRenderer() {
private Font plainFont = getFont().deriveFont(Font.PLAIN);
private Font boldFont = getFont().deriveFont(Font.BOLD);
Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
setText(value.toString());
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
// Emphasize the columns before the black separator block.
int separator;
for (separator = 0; separator < columnsTableColumns.getColumnCount(); separator++)
if ("".equals(columnsTableColumns.getColumn(separator).getIdentifier()))
break;
setFont(column < separator ? boldFont : plainFont);
return this;
}
};
for (int col = 0; col < columnNames.length; col++) {
String columnName = columnNames[col];
int width = Math.max((new JLabel(columnName)).getPreferredSize().width + 5, 75);
TableColumn column = new TableColumn(col, width);
column.setHeaderValue(columnName);
column.setHeaderRenderer(columnHeaderRenderer);
columnsTableColumns.addColumn(column);
}
columnsTable.setColumnModel(columnsTableColumns);
// Create an invisible JTable with 0 rows so that columnsTable becomes
// functional in JDK >= 1.6.
new JTable(new DefaultTableModel(), columnsTableColumns).setTableHeader(columnsTable);
// Initially select the "Year" and "Country" columns.
{
int chosenColumnIndex = -1;
for (int i = 0; i < columnsTableColumns.getColumnCount(); i++)
if ("Year".equals(columnsTableColumns.getColumn(i).getIdentifier()))
chosenColumnIndex = i;
assert (chosenColumnIndex >= 0);
if (chosenColumnIndex > 0)
columnsTableColumns.moveColumn(chosenColumnIndex, 0);
}
{
int chosenColumnIndex = -1;
for (int i = 1; i < columnsTableColumns.getColumnCount(); i++)
if ("Country".equals(columnsTableColumns.getColumn(i).getIdentifier()))
chosenColumnIndex = i;
assert (chosenColumnIndex >= 1);
if (chosenColumnIndex > 1)
columnsTableColumns.moveColumn(chosenColumnIndex, 1);
}
updatePartitioners();
}
/**
* Creates the chooser for the area column.
*/
private void initAreaColumnControl() {
ArrayList<String> areaColumnChoices = new ArrayList<String>();
areaColumnChoices.add("(all equal area)");
for (int col = 0; col < columnNames.length; col++)
if (columnTypes[col] == Double.class)
areaColumnChoices.add(columnNames[col]);
areaColumnChooser = new JComboBox<String>(areaColumnChoices.toArray(new String[areaColumnChoices.size()]));
areaColumnChooser.addActionListener(new ActionListener() {
Override
public void actionPerformed(ActionEvent event) {
updateAreaColumn();
}
});
areaColumnChooser.setSelectedItem("Consumption");
}
/**
* Creates the chooser for the color column.
*/
private void initColorColumnControl() {
ArrayList<String> colorColumnChoices = new ArrayList<String>();
colorColumnChoices.add("(all same color)");
for (int col = 0; col < columnNames.length; col++)
if (!columnNames[col].equals("Name"))
colorColumnChoices.add(columnNames[col]);
colorColumnChooser = new JComboBox<String>(colorColumnChoices.toArray(new String[colorColumnChoices.size()]));
colorColumnChooser.addActionListener(new ActionListener() {
Override
public void actionPerformed(ActionEvent event) {
updateColorColumn();
}
});
colorColumnChooser.setSelectedItem("Energy Type");
}
/**
* Creates the chooser for the labeling mode.
*/
private void initLabelingControl() {
String[] labelingChoices = { "off", "smart", "1 level", "2 levels", "all" };
labelingChooser = new JComboBox<String>(labelingChoices);
labelingChooser.addActionListener(new ActionListener() {
Override
public void actionPerformed(ActionEvent event) {
updateLabeling();
}
});
labelingChooser.setSelectedItem("smart");
// When the labeling is set to "on", it actually depends on the
// focus level.
IlvChart chart = trees.treemapPanel.getChart();
chart.addTreemapFocusListener(new TreemapFocusListener() {
Override
public void focusChanged(TreemapFocusEvent event) {
updateLabeling();
}
});
}
/**
* Initializes a synchronization between the selection of the table and the
* selection of the tree-table (and thus also with the selection of the
* treemap - it is synchronized through
* <code>TreemapWithTreeTable.initSelectionSynchronization()</code>.
*/
private void initTableSelectionSynchronization() {
final ListSelectionModel tableSelectionModel = rawTable.getSelectionModel();
final ListSelectionModel treetableSelectionModel = trees.treetable.getSelectionModel();
// Ensure that the treetable's selection display is in sync with the
// raw table's selection, as far as single-selection is concerned.
tableSelectionModel.addListSelectionListener(new ListSelectionListener() {
Override
public void valueChanged(ListSelectionEvent event) {
if (inhibitSelectionPropToTreeTable)
return;
if (tableSelectionModel.isSelectionEmpty())
treetableSelectionModel.clearSelection();
else {
TreePath commonPath = null;
int min = tableSelectionModel.getMinSelectionIndex();
int max = tableSelectionModel.getMaxSelectionIndex();
for (int i = min; i <= max; i++)
if (tableSelectionModel.isSelectedIndex(i)) {
// Get the object corresponding to this row by
// accessing the flat-model view.
Object object = dataSource.getFlatModel().getObjects().get(i);
// Get the tree path from the root to that object.
TreePath path = dataSource.getTreeModel().getPath(object);
assert (path != null);
if (commonPath == null)
commonPath = path;
else
commonPath = computeCommonAncestor(commonPath, path);
}
assert (commonPath != null);
TreePath newSelection = commonPath;
try {
inhibitSelectionPropToRawTable = true;
trees.expandParents(newSelection);
int row = trees.treetable.getTree().getRowForPath(newSelection);
trees.ensureVisible(row);
treetableSelectionModel.setSelectionInterval(row, row);
} finally {
inhibitSelectionPropToRawTable = false;
}
}
}
});
// Ensure that the raw table's selection display is in sync with the
// treetable's selection, projecting from cluster nodes onto the tree
// leaves.
treetableSelectionModel.addListSelectionListener(new ListSelectionListener() {
Override
public void valueChanged(ListSelectionEvent event) {
if (inhibitSelectionPropToRawTable)
return;
if (treetableSelectionModel.isSelectionEmpty())
tableSelectionModel.clearSelection();
else {
int selectedRow = treetableSelectionModel.getMinSelectionIndex();
TreePath selectedObjectPath = trees.treetable.getTree().getPathForRow(selectedRow);
assert (selectedObjectPath != null);
try {
inhibitSelectionPropToTreeTable = true;
tableSelectionModel.clearSelection();
// Recurse down to the tree leaves below selectedObjectPath.
selectLeavesInTable(selectedObjectPath);
} finally {
inhibitSelectionPropToTreeTable = false;
}
// Now ensure at least the beginning of the selection is visible.
int viewHeight = rawTableView.getViewport().getHeight();
// = rawTableView.getViewport().getExtentSize().height;
int minIndex = tableSelectionModel.getMinSelectionIndex();
int maxIndex = tableSelectionModel.getMaxSelectionIndex();
Rectangle topRect = rawTable.getCellRect(minIndex, 0, true);
Rectangle bottomRect = rawTable.getCellRect(maxIndex, 0, true);
int combinedHeight = bottomRect.y + bottomRect.height - topRect.y;
topRect.height = Math.min(combinedHeight, viewHeight);
rawTable.scrollRectToVisible(topRect);
}
}
private void selectLeavesInTable(TreePath path) {
Object object = path.getLastPathComponent();
if (object instanceof IlvClusterNode) {
// A tree node with children.
for (Iterator<?> it = dataSource.getTreeModel().getChildren(object).iterator(); it.hasNext();) {
Object child = it.next();
selectLeavesInTable(path.pathByAddingChild(child));
}
} else {
// A leaf.
assert (dataSource.getTreeModel().getChildren(object).isEmpty());
int i = dataSource.getFlatModel().getObjects().indexOf(object);
tableSelectionModel.addSelectionInterval(i, i);
}
}
});
}
/**
* Updates the data source and with it also the treemap and tree-table when a
* particular partitioning has been chosen.
*/
private void updatePartitioners() {
TableColumnModel columnsTableColumns = columnsTable.getColumnModel();
IlvFlatTableModel model = dataSource.getFlatTableModel();
// Take only the columns before the black separator block.
int separator;
for (separator = 0; separator < columnsTableColumns.getColumnCount(); separator++)
if ("".equals(columnsTableColumns.getColumn(separator).getIdentifier()))
break;
separatorIndex = separator;
int count = separator;
IlvPartitionerFactory<?>[] newPartitionerFactories = new IlvPartitionerFactory[count];
for (int col = 0; col < count; col++) {
String columnName = (String) columnsTableColumns.getColumn(col).getIdentifier();
IlvDataColumnInfo column = IlvColumnUtilities.getColumnByName(model, columnName);
// Set the corresponding partitioner.
newPartitionerFactories[col] = (Number.class.isAssignableFrom(column.getType())
? new IlvUniformScalePartitionerFactory(column, 4, 5) : new IlvStringPartitionerFactory(column));
}
// No need to disturb the data source if nothing has changed.
if (!Arrays.equals(dataSource.getPartitionerFactories(), newPartitionerFactories)) {
dataSource.setPartitionerFactories(newPartitionerFactories);
StringBuffer headerLabel = new StringBuffer();
if (count == 0) {
headerLabel.append("No partitioning");
} else {
headerLabel.append("By ");
for (int col = 0; col < count; col++) {
if (col > 0)
headerLabel.append("/");
String columnName = (String) columnsTableColumns.getColumn(col).getIdentifier();
headerLabel.append(columnName);
}
}
trees.treeColumn.setHeaderValue(headerLabel.toString());
trees.treetable.getTableHeader().repaint();
// Clear the history, since it likely contains focus choices that are
// assume the previous partitioning, not this one.
trees.treemapPanel.clearHistory();
}
}
/**
* Updates the treemap when a particular area column has been chosen.
*/
private void updateAreaColumn() {
String columnName = (String) areaColumnChooser.getSelectedItem();
IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) trees.treemapPanel.getChart().getRenderer(0);
if (columnName != null && IlvColumnUtilities.getColumnByName(dataSource.getTreeModel(), columnName) != null)
renderer.setAreaColumnName(columnName);
else
renderer.setAreaColumnName(null);
}
/**
* Updates the treemap when a particular color column has been chosen.
*/
private void updateColorColumn() {
String columnName = (String) colorColumnChooser.getSelectedItem();
IlvChart chart = trees.treemapPanel.getChart();
IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0);
// Reset the LegendLabelFormat, since the previous LegendLabelFormat
// may be a DecimalFormat and therefore not suitable for non-numeric
// columns.
renderer.setLegendLabelFormat(null);
// Set the color column and color scheme.
// Also make a legend appear when suitable.
IlvDataColumnInfo column;
if (columnName != null
&& (column = IlvColumnUtilities.getColumnByName(dataSource.getTreeModel(), columnName)) != null) {
renderer.setColorColumnName(columnName);
if (column.getType() == String.class)
// For non-numeric columns, use "qualitative" colors.
renderer.setColorScheme(IlvTreemapChartRenderer.COLORSCHEME_QUALITATIVE);
else if (column.getName().equals("Profits"))
// For numeric columns with positive and negative values, use
// red for negative and green for positive values. Take care
// that frontier between red and green is exactly at 0.
renderer.setColorScheme(
IlvColorScheme.createAdjustedColorScheme(IlvTreemapChartRenderer.COLORSCHEME_DIVERGING_RED_GREEN, 0.0));
else
// For other numeric columns, use red for low and green for
// high values.
renderer.setColorScheme(
IlvColorScheme.createAdjustedColorScheme(IlvTreemapChartRenderer.COLORSCHEME_DIVERGING_RED_GREEN));
if (Number.class.isAssignableFrom(column.getType())) {
// Ensure there is a legend.
renderer.setLegendLabelFormat(new DecimalFormat("#.##"));
chart.setLegendPosition(IlvChartLayout.EAST);
chart.setLegendVisible(true);
} else {
// Ensure there is no legend.
chart.setLegendVisible(false);
}
} else {
renderer.setColorColumnName(null);
renderer.setColorScheme(IlvTreemapChartRenderer.COLORSCHEME_DEPTH);
// Ensure there is no legend.
chart.setLegendVisible(false);
}
}
/**
* Updates the treemap when a particular labeling mode has been chosen.
*/
private void updateLabeling() {
String labeling = (String) labelingChooser.getSelectedItem();
IlvChart chart = trees.treemapPanel.getChart();
IlvTreemapChartRenderer renderer = (IlvTreemapChartRenderer) chart.getRenderer(0);
if (labeling == "off")
renderer.setAnnotationVisibility(IlvTreemapChartRenderer.VISIBILITY_NONE);
else if (labeling == "smart") {
renderer.setAnnotationVisibility(IlvTreemapChartRenderer.VISIBILITY_SMART);
renderer.setClippedAnnotationVisibility(false);
} else if (labeling == "1 level") {
renderer.setAnnotationVisibility(renderer.getFocusLevel() + 1);
renderer.setClippedAnnotationVisibility(true);
} else if (labeling == "2 levels") {
renderer.setAnnotationVisibility(renderer.getFocusLevel() + 2);
renderer.setClippedAnnotationVisibility(true);
} else if (labeling == "all") {
renderer.setAnnotationVisibility(Integer.MAX_VALUE);
renderer.setClippedAnnotationVisibility(true);
}
}
/**
* Computes and returns the longest common initial segment of two paths
* starting at the same root.
*/
private static TreePath computeCommonAncestor(TreePath path1, TreePath path2) {
int len1 = path1.getPathCount();
int len2 = path2.getPathCount();
if (len1 > len2)
do
path1 = path1.getParentPath();
while (--len1 > len2);
else if (len2 > len1)
do
path2 = path2.getParentPath();
while (--len2 > len1);
assert (path1.getPathCount() == path2.getPathCount());
while (path1.getLastPathComponent() != path2.getLastPathComponent()) {
path1 = path1.getParentPath();
path2 = path2.getParentPath();
}
assert (path1 != null && path1.equals(path2));
return path1;
}
/**
* Opens an URL for read-only access. Like url.openStream(), except that it
* also works for Windows UNC pathnames. See Sun BR #4671171.
*/
private static InputStream openStream(URL url) throws IOException {
if ("file".equals(url.getProtocol()) && !"".equals(url.getHost()))
// Do it directly, avoiding a "Connection refused: connect" error.
return new BufferedInputStream(new FileInputStream("//" + url.getHost() + url.getPath()));
else {
// But note that URLs of the form "jar:file://HOST/...!..." work
// and don't need special treatment.
return url.openStream();
}
}
/**
* Starts the demo, when run as an application.
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
Override
public void run() {
JFrame frame = new JFrame("Treemap sample");
TreemapDemo demo = new TreemapDemo();
demo.init(frame.getContentPane());
demo.setFrameGeometry(1000, 900, true);
frame.setVisible(true);
demo.treesPanel.setDividerLocation(treesPanelDefaultDivision);
demo.wholePanel.setDividerLocation(wholePanelDefaultDivision);
}
});
}
}