You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by tv...@apache.org on 2009/03/16 17:16:58 UTC
svn commit: r754926 [20/38] - in /incubator/pivot/tags/v1.0: ./ charts-test/
charts-test/src/ charts-test/src/pivot/ charts-test/src/pivot/charts/
charts-test/src/pivot/charts/test/ charts/ charts/lib/ charts/src/
charts/src/pivot/ charts/src/pivot/cha...
Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePane.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePane.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePane.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePane.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,988 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+import pivot.collections.ArrayList;
+import pivot.collections.Sequence;
+import pivot.util.ListenerList;
+
+/**
+ * Container that arranges components in a two-dimensional grid, optionally
+ * spanning multiple rows and columns.
+ *
+ * @author tvolkert
+ */
+public class TablePane extends Container {
+ /**
+ * Represents a table pane row.
+ *
+ * @author tvolkert
+ */
+ public static final class Row implements Sequence<Component> {
+ private int height;
+ private boolean relative;
+ private boolean selected;
+
+ private ArrayList<Component> cells = new ArrayList<Component>();
+
+ private TablePane tablePane = null;
+
+ public Row() {
+ this(-1, false, false);
+ }
+
+ public Row(int height) {
+ this(height, false, false);
+ }
+
+ public Row(int height, boolean relative) {
+ this(height, relative, false);
+ }
+
+ public Row(int height, boolean relative, boolean selected) {
+ this.height = height;
+ this.relative = relative;
+ this.selected = selected;
+ }
+
+ /**
+ * Returns the table pane with which this row is associated.
+ *
+ * @return
+ * The row's table pane, or <tt>null</tt> if the row does not
+ * currently belong to a table.
+ */
+ public TablePane getTablePane() {
+ return tablePane;
+ }
+
+ /**
+ * Sets the table pane with which this row is associated.
+ *
+ * @param tablePane
+ * The row's table pane, or <tt>null</tt> if the row does not
+ * currently belong to a table.
+ */
+ private void setTablePane(TablePane tablePane) {
+ this.tablePane = tablePane;
+ }
+
+ /**
+ * Returns the row height.
+ *
+ * @return
+ * The height of the row.
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * Returns the relative flag.
+ *
+ * @return
+ * <tt>true</tt> if the row height is relative, <tt>false</tt> if it
+ * is fixed.
+ */
+ public boolean isRelative() {
+ return relative;
+ }
+
+ /**
+ * Set the row height.
+ *
+ * @param height
+ * The absolute height of the row.
+ */
+ public void setHeight(int height) {
+ setHeight(height, false);
+ }
+
+ /**
+ * Set the row height.
+ *
+ * @param height
+ * The encoded height of the row. If the string ends with the '*'
+ * character, it is treated as a relative value. Otherwise, it is
+ * considered an absolute value.
+ */
+ public void setHeight(String height) {
+ boolean relative = false;
+
+ if (height.endsWith(RELATIVE_SIZE_INDICATOR)) {
+ relative = true;
+ height = height.substring(0, height.length() - 1);
+ }
+
+ setHeight(Integer.parseInt(height), relative);
+ }
+
+ /**
+ * Sets the row height.
+ *
+ * @param height
+ * The height of the row.
+ *
+ * @param relative
+ * <tt>true</tt> if the row height is relative, <tt>false</tt> if it
+ * is fixed.
+ */
+ public void setHeight(int height, boolean relative) {
+ int previousHeight = this.height;
+ boolean previousRelative = this.relative;
+
+ if (previousHeight != height
+ || previousRelative != relative) {
+ this.height = height;
+ this.relative = relative;
+
+ if (tablePane != null) {
+ tablePane.tablePaneListeners.rowHeightChanged(this,
+ previousHeight, previousRelative);
+ }
+ }
+ }
+
+ /**
+ * Returns the selected flag.
+ *
+ * @return
+ * <tt>true</tt> if the row is selected, <tt>false</tt> if it is not
+ */
+ public boolean isSelected() {
+ return selected;
+ }
+
+ /**
+ * Sets the selected flag.
+ *
+ * @param selected
+ * <tt>true</tt> to set the row as selected, <tt>false</tt> to set
+ * it as not selected
+ */
+ public void setSelected(boolean selected) {
+ if (selected != this.selected) {
+ this.selected = selected;
+
+ if (tablePane != null) {
+ tablePane.tablePaneListeners.rowSelectedChanged(this);
+ }
+ }
+ }
+
+ public int add(Component component) {
+ int i = getLength();
+ insert(component, i);
+
+ return i;
+ }
+
+ public void insert(Component component, int index) {
+ if (index < 0
+ || index > cells.getLength()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ if (component != null
+ && tablePane != null) {
+ // Add the component to the table pane
+ tablePane.add(component);
+
+ // Attach the attributes
+ component.setAttributes(new TablePaneAttributes());
+ }
+
+ cells.insert(component, index);
+
+ if (tablePane != null) {
+ // Notify table pane listeners
+ tablePane.tablePaneListeners.cellInserted(this, index);
+ }
+ }
+
+ public Component update(int index, Component component) {
+ Component previousComponent = cells.get(index);
+
+ if (component != null
+ && tablePane != null) {
+ // Add the component to the table pane
+ tablePane.add(component);
+
+ // Attach the attributes
+ component.setAttributes(new TablePaneAttributes());
+ }
+
+ cells.update(index, component);
+
+ if (previousComponent != null
+ && tablePane != null) {
+ // Detach the attributes
+ component.setAttributes(null);
+ }
+
+ if (tablePane != null
+ && component != previousComponent) {
+ // Notify table pane listeners
+ tablePane.tablePaneListeners.cellUpdated(this, index,
+ previousComponent);
+ }
+
+ if (previousComponent != null
+ && tablePane != null) {
+ // Remove the component from the table pane
+ tablePane.remove(component);
+ }
+
+ return previousComponent;
+ }
+
+ public int remove(Component component) {
+ int index = indexOf(component);
+ if (index != -1) {
+ remove(index, 1);
+ }
+
+ return index;
+ }
+
+ public Sequence<Component> remove(int index, int count) {
+ Sequence<Component> removed = cells.remove(index, count);
+
+ if (tablePane != null) {
+ for (int i = 0, n = removed.getLength(); i < n; i++) {
+ Component component = removed.get(i);
+ if (component != null) {
+ component.setAttributes(null);
+ }
+ }
+
+ // Notify table pane listeners
+ tablePane.tablePaneListeners.cellsRemoved(this, index, removed);
+
+ for (int i = 0, n = removed.getLength(); i < n; i++) {
+ Component component = removed.get(i);
+ if (component != null) {
+ tablePane.remove(component);
+ }
+ }
+ }
+
+ return removed;
+ }
+
+ public Component get(int index) {
+ return cells.get(index);
+ }
+
+ public int indexOf(Component component) {
+ return cells.indexOf(component);
+ }
+
+ public int getLength() {
+ return cells.getLength();
+ }
+ }
+
+ /**
+ * Represents a table pane column.
+ *
+ * @author tvolkert
+ */
+ public static class Column {
+ private TablePane tablePane = null;
+
+ private int width;
+ private boolean relative;
+ private boolean selected;
+
+ public Column() {
+ this(-1, false, false);
+ }
+
+ public Column(int width) {
+ this(width, false, false);
+ }
+
+ public Column(int width, boolean relative) {
+ this(width, relative, false);
+ }
+
+ public Column(int width, boolean relative, boolean selected) {
+ this.width = width;
+ this.relative = relative;
+ this.selected = selected;
+ }
+
+ /**
+ * Returns the table pane with which this column is associated.
+ *
+ * @return
+ * The column's table pane, or <tt>null</tt> if the column does not
+ * currently belong to a table.
+ */
+ public TablePane getTablePane() {
+ return tablePane;
+ }
+
+ /**
+ * Sets the table pane with which this column is associated.
+ *
+ * @param tablePane
+ * The column's table pane, or <tt>null</tt> if the column does not
+ * currently belong to a table.
+ */
+ private void setTablePane(TablePane tablePane) {
+ this.tablePane = tablePane;
+ }
+
+ /**
+ * Returns the column width.
+ *
+ * @return
+ * The width of the column.
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * Returns the relative flag.
+ *
+ * @return
+ * <tt>true</tt> if the column width is relative, <tt>false</tt> if it
+ * is fixed.
+ */
+ public boolean isRelative() {
+ return relative;
+ }
+
+ /**
+ * Set the column width.
+ *
+ * @param width
+ * The absolute width of the column.
+ */
+ public void setWidth(int width) {
+ setWidth(width, false);
+ }
+
+ /**
+ * Set the column width.
+ *
+ * @param width
+ * The encoded width of the row. If the string ends with the '*'
+ * character, it is treated as a relative value. Otherwise, it is
+ * considered an absolute value.
+ */
+ public void setWidth(String width) {
+ boolean relative = false;
+
+ if (width.endsWith(RELATIVE_SIZE_INDICATOR)) {
+ relative = true;
+ width = width.substring(0, width.length() - 1);
+ }
+
+ setWidth(Integer.parseInt(width), relative);
+ }
+
+ /**
+ * Sets the column width.
+ *
+ * @param width
+ * The width of the column.
+ *
+ * @param relative
+ * <tt>true</tt> if the column width is relative, <tt>false</tt> if it
+ * is fixed.
+ */
+ public void setWidth(int width, boolean relative) {
+ int previousWidth = this.width;
+ boolean previousRelative = this.relative;
+
+ if (previousWidth != width
+ || previousRelative != relative) {
+ this.width = width;
+ this.relative = relative;
+
+ if (tablePane != null) {
+ tablePane.tablePaneListeners.columnWidthChanged(this,
+ previousWidth, previousRelative);
+ }
+ }
+ }
+
+ /**
+ * Returns the selected flag.
+ *
+ * @return
+ * <tt>true</tt> if the column is selected, <tt>false</tt> if it is not
+ */
+ public boolean isSelected() {
+ return selected;
+ }
+
+ /**
+ * Sets the selected flag.
+ *
+ * @param selected
+ * <tt>true</tt> to set the column as selected, <tt>false</tt> to set
+ * it as not selected
+ */
+ public void setSelected(boolean selected) {
+ if (selected != this.selected) {
+ this.selected = selected;
+
+ if (tablePane != null) {
+ tablePane.tablePaneListeners.columnSelectedChanged(this);
+ }
+ }
+ }
+ }
+
+ /**
+ * Defines table pane component attributes.
+ *
+ * @author gbrown
+ */
+ protected static class TablePaneAttributes extends Attributes {
+ private int rowSpan = 1;
+ private int columnSpan = 1;
+
+ public int getRowSpan() {
+ return rowSpan;
+ }
+
+ public void setRowSpan(int rowSpan) {
+ int previousRowSpan = this.rowSpan;
+ this.rowSpan = rowSpan;
+
+ Component component = getComponent();
+ TablePane tablePane = (TablePane)component.getParent();
+ if (tablePane != null) {
+ tablePane.tablePaneAttributeListeners.rowSpanChanged(tablePane,
+ component, previousRowSpan);
+ }
+ }
+
+ public int getColumnSpan() {
+ return columnSpan;
+ }
+
+ public void setColumnSpan(int columnSpan) {
+ int previousColumnSpan = this.columnSpan;
+ this.columnSpan = columnSpan;
+
+ Component component = getComponent();
+ TablePane tablePane = (TablePane)component.getParent();
+ if (tablePane != null) {
+ tablePane.tablePaneAttributeListeners.columnSpanChanged(tablePane,
+ component, previousColumnSpan);
+ }
+ }
+ }
+
+ /**
+ * Table pane skin interface. Table pane skins must implement
+ * this interface to facilitate additional communication between the
+ * component and the skin.
+ *
+ * @author tvolkert
+ */
+ public interface Skin {
+ public int getRowAt(int y);
+ public Bounds getRowBounds(int row);
+ public int getColumnAt(int x);
+ public Bounds getColumnBounds(int column);
+ }
+
+ /**
+ * Class that manages a table pane's row list. Callers get access to the
+ * row sequence via {@link TablePane#getRows()}.
+ *
+ * @author tvolkert
+ */
+ public final class RowSequence implements Sequence<Row> {
+ private RowSequence() {
+ }
+
+ public int add(Row row) {
+ int i = getLength();
+ insert(row, i);
+
+ return i;
+ }
+
+ public void insert(Row row, int index) {
+ if (row == null) {
+ throw new IllegalArgumentException("row is null.");
+ }
+
+ if (row.getTablePane() != null) {
+ throw new IllegalArgumentException
+ ("row is already in use by another table pane.");
+ }
+
+ rows.insert(row, index);
+ row.setTablePane(TablePane.this);
+
+ for (int i = 0, n = row.getLength(); i < n; i++) {
+ Component component = row.get(i);
+
+ // Add each component in the row to the table pane
+ TablePane.this.add(component);
+
+ // Attach attributes to each row component
+ component.setAttributes(new TablePaneAttributes());
+ }
+
+ // Notify listeners
+ tablePaneListeners.rowInserted(TablePane.this, index);
+ }
+
+ public Row update(int index, Row row) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int remove(Row row) {
+ int index = indexOf(row);
+ if (index != -1) {
+ remove(index, 1);
+ }
+
+ return index;
+ }
+
+ public Sequence<Row> remove(int index, int count) {
+ Sequence<Row> removed = rows.remove(index, count);
+
+ if (count > 0) {
+ for (int i = 0, n = removed.getLength(); i < n; i++) {
+ Row row = removed.get(i);
+
+ row.setTablePane(null);
+
+ for (int j = 0, m = row.getLength(); j < m; j++) {
+ Component component = row.get(j);
+
+ if (component != null) {
+ // Detach attributes from each row component
+ component.setAttributes(null);
+
+ // Remove each component in the row from the table pane
+ TablePane.this.remove(component);
+ }
+ }
+ }
+
+ tablePaneListeners.rowsRemoved(TablePane.this, index, removed);
+ }
+
+ return removed;
+ }
+
+ public Row get(int index) {
+ return rows.get(index);
+ }
+
+ public int indexOf(Row row) {
+ return rows.indexOf(row);
+ }
+
+ public int getLength() {
+ return rows.getLength();
+ }
+ }
+
+ /**
+ * Class that manages a table pane's column list. Callers get access to the
+ * column sequence via {@link TablePane#getColumns()}.
+ *
+ * @author tvolkert
+ */
+ public final class ColumnSequence implements Sequence<Column> {
+ private ColumnSequence() {
+ }
+
+ public int add(Column column) {
+ int i = getLength();
+ insert(column, i);
+
+ return i;
+ }
+
+ public void insert(Column column, int index) {
+ if (column == null) {
+ throw new IllegalArgumentException("column is null.");
+ }
+
+ if (column.getTablePane() != null) {
+ throw new IllegalArgumentException
+ ("column is already in use by another table pane.");
+ }
+
+ columns.insert(column, index);
+ column.setTablePane(TablePane.this);
+
+ // Notify listeners
+ tablePaneListeners.columnInserted(TablePane.this, index);
+ }
+
+ public Column update(int index, Column column) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int remove(Column column) {
+ int index = indexOf(column);
+ if (index != -1) {
+ remove(index, 1);
+ }
+
+ return index;
+ }
+
+ public Sequence<Column> remove(int index, int count) {
+ Sequence<Column> removed = columns.remove(index, count);
+
+ if (count > 0) {
+ for (int i = 0, n = removed.getLength(); i < n; i++) {
+ removed.get(i).setTablePane(null);
+ }
+
+ tablePaneListeners.columnsRemoved(TablePane.this, index, removed);
+ }
+
+ return removed;
+ }
+
+ public Column get(int index) {
+ return columns.get(index);
+ }
+
+ public int indexOf(Column column) {
+ return columns.indexOf(column);
+ }
+
+ public int getLength() {
+ return columns.getLength();
+ }
+ }
+
+ /**
+ * Internal listener list.
+ */
+ private static class TablePaneListenerList extends ListenerList<TablePaneListener>
+ implements TablePaneListener {
+ public void rowInserted(TablePane tablePane, int index) {
+ for (TablePaneListener listener : this) {
+ listener.rowInserted(tablePane, index);
+ }
+ }
+
+ public void rowsRemoved(TablePane tablePane, int index,
+ Sequence<TablePane.Row> rows) {
+ for (TablePaneListener listener : this) {
+ listener.rowsRemoved(tablePane, index, rows);
+ }
+ }
+
+ public void rowHeightChanged(TablePane.Row row, int previousHeight,
+ boolean previousRelative) {
+ for (TablePaneListener listener : this) {
+ listener.rowHeightChanged(row, previousHeight, previousRelative);
+ }
+ }
+
+ public void rowSelectedChanged(TablePane.Row row) {
+ for (TablePaneListener listener : this) {
+ listener.rowSelectedChanged(row);
+ }
+ }
+
+ public void columnInserted(TablePane tablePane, int index) {
+ for (TablePaneListener listener : this) {
+ listener.columnInserted(tablePane, index);
+ }
+ }
+
+ public void columnsRemoved(TablePane tablePane, int index,
+ Sequence<TablePane.Column> columns) {
+ for (TablePaneListener listener : this) {
+ listener.columnsRemoved(tablePane, index, columns);
+ }
+ }
+
+ public void columnWidthChanged(TablePane.Column column, int previousWidth,
+ boolean previousRelative) {
+ for (TablePaneListener listener : this) {
+ listener.columnWidthChanged(column, previousWidth, previousRelative);
+ }
+ }
+
+ public void columnSelectedChanged(TablePane.Column column) {
+ for (TablePaneListener listener : this) {
+ listener.columnSelectedChanged(column);
+ }
+ }
+
+ public void cellInserted(TablePane.Row row, int column) {
+ for (TablePaneListener listener : this) {
+ listener.cellInserted(row, column);
+ }
+ }
+
+ public void cellsRemoved(TablePane.Row row, int column,
+ Sequence<Component> removed) {
+ for (TablePaneListener listener : this) {
+ listener.cellsRemoved(row, column, removed);
+ }
+ }
+
+ public void cellUpdated(TablePane.Row row, int column,
+ Component previousComponent) {
+ for (TablePaneListener listener : this) {
+ listener.cellUpdated(row, column, previousComponent);
+ }
+ }
+ }
+
+ private static class TablePaneAttributeListenerList extends ListenerList<TablePaneAttributeListener>
+ implements TablePaneAttributeListener {
+ public void rowSpanChanged(TablePane tablePane, Component component,
+ int previousRowSpan) {
+ for (TablePaneAttributeListener listener : this) {
+ listener.rowSpanChanged(tablePane, component, previousRowSpan);
+ }
+ }
+
+ public void columnSpanChanged(TablePane tablePane, Component component,
+ int previousColumnSpan) {
+ for (TablePaneAttributeListener listener : this) {
+ listener.columnSpanChanged(tablePane, component, previousColumnSpan);
+ }
+ }
+ }
+
+ private ArrayList<Row> rows = null;
+ private RowSequence rowSequence = new RowSequence();
+
+ private ArrayList<Column> columns = null;
+ private ColumnSequence columnSequence = new ColumnSequence();
+
+ private TablePaneListenerList tablePaneListeners = new TablePaneListenerList();
+ private TablePaneAttributeListenerList tablePaneAttributeListeners = new TablePaneAttributeListenerList();
+
+ public static final String RELATIVE_SIZE_INDICATOR = "*";
+
+ /**
+ * Creates a new <tt>TablePane</tt> with empty row and column sequences.
+ */
+ public TablePane() {
+ this(new ArrayList<Column>());
+ }
+
+ /**
+ * Creates a new <tt>TablePane</tt> with the specified columns.
+ *
+ * @param columns
+ * The column sequence to use. A copy of this sequence will be made
+ */
+ public TablePane(Sequence<Column> columns) {
+ if (columns == null) {
+ throw new IllegalArgumentException("columns is null");
+ }
+
+ this.rows = new ArrayList<Row>();
+ this.columns = new ArrayList<Column>(columns);
+
+ installSkin(TablePane.class);
+ }
+
+ @Override
+ protected void setSkin(pivot.wtk.Skin skin) {
+ if (!(skin instanceof TablePane.Skin)) {
+ throw new IllegalArgumentException("Skin class must implement "
+ + TablePane.Skin.class.getName());
+ }
+
+ super.setSkin(skin);
+ }
+
+ /**
+ * Returns the table pane row sequence.
+ *
+ * @return
+ * The table pane row sequence
+ */
+ public RowSequence getRows() {
+ return rowSequence;
+ }
+
+ /**
+ * Returns the index of the row at a given location.
+ *
+ * @param y
+ * The y-coordinate of the row to identify.
+ *
+ * @return
+ * The row index, or <tt>-1</tt> if there is no row at the given
+ * y-coordinate.
+ */
+ public int getRowAt(int y) {
+ TablePane.Skin tablePaneSkin = (TablePane.Skin)getSkin();
+ return tablePaneSkin.getRowAt(y);
+ }
+
+ /**
+ * Returns the table pane column sequence.
+ *
+ * @return
+ * The table pane column sequence
+ */
+ public ColumnSequence getColumns() {
+ return columnSequence;
+ }
+
+ /**
+ * Returns the index of the column at a given location.
+ *
+ * @param x
+ * The x-coordinate of the column to identify.
+ *
+ * @return
+ * The column index, or <tt>-1</tt> if there is no column at the given
+ * x-coordinate.
+ */
+ public int getColumnAt(int x) {
+ TablePane.Skin tablePaneSkin = (TablePane.Skin)getSkin();
+ return tablePaneSkin.getColumnAt(x);
+ }
+
+ /**
+ * Gets the component at the specified cell in this table pane.
+ *
+ * @param rowIndex
+ * The row index of the cell
+ *
+ * @param columnIndex
+ * The column index of the cell
+ *
+ * @return
+ * The component in the specified cell, or <tt>null</tt> if the cell is
+ * empty
+ */
+ public Component getCellComponent(int rowIndex, int columnIndex) {
+ Row row = rows.get(rowIndex);
+
+ Component component = null;
+
+ if (row.getLength() > columnIndex) {
+ component = row.get(columnIndex);
+ }
+
+ return component;
+ }
+
+ /**
+ * Sets the component at the specified cell in this table pane.
+ *
+ * @param row
+ * The row index of the cell
+ *
+ * @param column
+ * The column index of the cell
+ *
+ * @param component
+ * The component to place in the specified cell, or <tt>null</tt> to empty
+ * the cell
+ */
+ public void setCellComponent(int row, int column, Component component) {
+ rows.get(row).update(column, component);
+ }
+
+ /**
+ * Overrides the base method to check whether or not a cell component is
+ * being removed, and fires the appropriate event in that case.
+ *
+ * @param index
+ * The index at which components were removed
+ *
+ * @param count
+ * The number of components removed
+ *
+ * @return
+ * The sequence of components that were removed
+ */
+ @Override
+ public Sequence<Component> remove(int index, int count) {
+ for (int i = index, n = index + count; i < n; i++) {
+ Component component = get(i);
+ if (component.getAttributes() != null) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ // Call the base method to remove the components
+ return super.remove(index, count);
+ }
+
+ /**
+ * Gets this component's table pane listener list.
+ *
+ * @return
+ * The table pane listeners on this component
+ */
+ public ListenerList<TablePaneListener> getTablePaneListeners() {
+ return tablePaneListeners;
+ }
+
+ /**
+ * Gets this component's table pane attribute listener list.
+ *
+ * @return
+ * The table pane attribute listeners on this component
+ */
+ public ListenerList<TablePaneAttributeListener> getTablePaneAttributeListeners() {
+ return tablePaneAttributeListeners;
+ }
+
+ public static int getRowSpan(Component component) {
+ TablePaneAttributes tablePaneAttributes = (TablePaneAttributes)component.getAttributes();
+ return (tablePaneAttributes == null) ? -1 : tablePaneAttributes.getRowSpan();
+ }
+
+ public static void setRowSpan(Component component, int rowSpan) {
+ TablePaneAttributes tablePaneAttributes = (TablePaneAttributes)component.getAttributes();
+ if (tablePaneAttributes == null) {
+ throw new UnsupportedOperationException();
+ }
+
+ tablePaneAttributes.setRowSpan(rowSpan);
+ }
+
+ public static int getColumnSpan(Component component) {
+ TablePaneAttributes tablePaneAttributes = (TablePaneAttributes)component.getAttributes();
+ return (tablePaneAttributes == null) ? -1 : tablePaneAttributes.getColumnSpan();
+ }
+
+ public static void setColumnSpan(Component component, int columnSpan) {
+ TablePaneAttributes tablePaneAttributes = (TablePaneAttributes)component.getAttributes();
+ if (tablePaneAttributes == null) {
+ throw new UnsupportedOperationException();
+ }
+
+ tablePaneAttributes.setColumnSpan(columnSpan);
+ }
+}
Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePaneAttributeListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePaneAttributeListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePaneAttributeListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePaneAttributeListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+/**
+ * Table pane attribute listener interface.
+ *
+ * @author gbrown
+ */
+public interface TablePaneAttributeListener {
+ /**
+ * Called when a component's row span attribute has changed.
+ *
+ * @param tablePane
+ * @param component
+ * @param previousRowSpan
+ */
+ public void rowSpanChanged(TablePane tablePane, Component component,
+ int previousRowSpan);
+
+ /**
+ * Called when a component's column span attribute has changed.
+ *
+ * @param tablePane
+ * @param component
+ * @param previousColumnSpan
+ */
+ public void columnSpanChanged(TablePane tablePane, Component component,
+ int previousColumnSpan);
+}
Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePaneListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePaneListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePaneListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TablePaneListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+import pivot.collections.Sequence;
+
+/**
+ * Table pane listener interface.
+ *
+ * @author gbrown
+ */
+public interface TablePaneListener {
+ /**
+ * Called when a row has been inserted into a table pane.
+ *
+ * @param tablePane
+ * @param index
+ */
+ public void rowInserted(TablePane tablePane, int index);
+
+ /**
+ * Called when rows have been removed from a table pane.
+ *
+ * @param tablePane
+ * @param index
+ * @param rows
+ */
+ public void rowsRemoved(TablePane tablePane, int index,
+ Sequence<TablePane.Row> rows);
+
+ /**
+ * Called when a row's height has changed.
+ *
+ * @param row
+ * @param previousHeight
+ * @param previousRelative
+ */
+ public void rowHeightChanged(TablePane.Row row, int previousHeight,
+ boolean previousRelative);
+
+ /**
+ * Called when a row's selected state has changed.
+ *
+ * @param row
+ */
+ public void rowSelectedChanged(TablePane.Row row);
+
+ /**
+ * Called when a column has been inserted into a table pane.
+ *
+ * @param tablePane
+ * @param index
+ */
+ public void columnInserted(TablePane tablePane, int index);
+
+ /**
+ * Called when column's have been removed from a table pane.
+ *
+ * @param tablePane
+ * @param index
+ * @param columns
+ */
+ public void columnsRemoved(TablePane tablePane, int index,
+ Sequence<TablePane.Column> columns);
+
+ /**
+ * Called when a column's width has changed.
+ *
+ * @param column
+ * @param previousWidth
+ * @param previousRelative
+ */
+ public void columnWidthChanged(TablePane.Column column, int previousWidth,
+ boolean previousRelative);
+
+ /**
+ * Called when a column's selected state has changed.
+ *
+ * @param column
+ */
+ public void columnSelectedChanged(TablePane.Column column);
+
+ /**
+ * Called when a cell has been inserted into a table pane.
+ *
+ * @param row
+ * @param column
+ */
+ public void cellInserted(TablePane.Row row, int column);
+
+ /**
+ * Called when cell's have been removed from a table pane.
+ *
+ * @param row
+ * @param column
+ * @param removed
+ */
+ public void cellsRemoved(TablePane.Row row, int column,
+ Sequence<Component> removed);
+
+ /**
+ * Called when a cell has been updated in a table pane.
+ *
+ * @param row
+ * @param column
+ * @param previousComponent
+ */
+ public void cellUpdated(TablePane.Row row, int column,
+ Component previousComponent);
+}
Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableView.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableView.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableView.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableView.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,1422 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+import java.util.Comparator;
+
+import pivot.collections.ArrayList;
+import pivot.collections.Dictionary;
+import pivot.collections.List;
+import pivot.collections.ListListener;
+import pivot.collections.Sequence;
+import pivot.serialization.JSONSerializer;
+import pivot.util.ListenerList;
+import pivot.util.Vote;
+import pivot.wtk.content.TableViewCellRenderer;
+import pivot.wtk.content.TableViewHeaderData;
+
+/**
+ * Component that displays a sequence of items partitioned into columns,
+ * optionally allowing a user to select one or more rows.
+ *
+ * @author gbrown
+ */
+@ComponentInfo(icon="TableView.png")
+public class TableView extends Component {
+ /**
+ * Contains information about a table column.
+ *
+ * @author gbrown
+ */
+ public static class Column {
+ private TableView tableView = null;
+
+ private String name = null;
+ private Object headerData = null;
+ private int width = 0;
+ private boolean relative = false;
+ private SortDirection sortDirection = null;
+ private Object filter = null;
+ private CellRenderer cellRenderer = DEFAULT_CELL_RENDERER;
+
+ private static final CellRenderer DEFAULT_CELL_RENDERER = new TableViewCellRenderer();
+
+ /**
+ * Default column width.
+ */
+ public static final int DEFAULT_WIDTH = 100;
+
+ /**
+ * Creates an empty column.
+ */
+ public Column() {
+ this(null, null, DEFAULT_WIDTH, false);
+ }
+
+ /**
+ * Creates a new column with no header data and a fixed default width.
+ *
+ * @param name
+ * The column name.
+ */
+ public Column(String name) {
+ this(name, null, DEFAULT_WIDTH, false);
+ }
+
+ /**
+ * Creates a new column with a fixed default width.
+ *
+ * @param name
+ * The column name.
+ *
+ * @param headerData
+ * The column header data.
+ */
+ public Column(String name, Object headerData) {
+ this(name, headerData, DEFAULT_WIDTH, false);
+ }
+
+ /**
+ * Creates a new column with a fixed width.
+ *
+ * @param name
+ * The column name.
+ *
+ * @param headerData
+ * The column header data.
+ *
+ * @param width
+ * The width of the column.
+ */
+ public Column(String name, Object headerData, int width) {
+ this(name, headerData, width, false);
+ }
+
+ /**
+ * Creates a new column.
+ *
+ * @param name
+ * The column name.
+ *
+ * @param headerData
+ * The column header data.
+ *
+ * @param width
+ * The width of the column.
+ *
+ * @param relative
+ * If <tt>true</tt>, specifies a relative column width; otherwise,
+ * specifies a fixed column width.
+ */
+ public Column(String name, Object headerData, int width, boolean relative) {
+ if (width < 0) {
+ throw new IllegalArgumentException("width is negative.");
+ }
+
+ this.name = name;
+ this.headerData = headerData;
+ this.width = width;
+ this.relative = relative;
+ }
+
+ /**
+ * Returns the table view with which this column is associated.
+ *
+ * @return
+ * The column's table view, or <tt>null</tt> if the column does not
+ * currently belong to a table.
+ */
+ public TableView getTableView() {
+ return tableView;
+ }
+
+ /**
+ * Sets the table view with which this column is associated.
+ *
+ * @param tableView
+ * The column's table view, or <tt>null</tt> if the column does not
+ * currently belong to a table.
+ */
+ private void setTableView(TableView tableView) {
+ this.tableView = tableView;
+ }
+
+ /**
+ * Returns the column name.
+ *
+ * @return
+ * The column name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the column name.
+ *
+ * @param name
+ * The column name.
+ */
+ public void setName(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name is null.");
+ }
+
+ String previousName = this.name;
+
+ if (previousName != name) {
+ this.name = name;
+
+ if (tableView != null) {
+ tableView.tableViewColumnListeners.columnNameChanged(this,
+ previousName);
+ }
+ }
+ }
+
+ /**
+ * Returns the column header data.
+ *
+ * @return
+ * The column header data, or <tt>null</tt> if the column has no
+ * header data.
+ */
+ public Object getHeaderData() {
+ return headerData;
+ }
+
+ /**
+ * Sets the column header data.
+ *
+ * @param headerData
+ * The column header data, or <tt>null</tt> for no header data.
+ */
+ public void setHeaderData(Object headerData) {
+ Object previousHeaderData = this.headerData;
+
+ if (previousHeaderData != headerData) {
+ this.headerData = headerData;
+
+ if (tableView != null) {
+ tableView.tableViewColumnListeners.columnHeaderDataChanged(this,
+ previousHeaderData);
+ }
+ }
+ }
+
+ /**
+ * Returns the column width.
+ *
+ * @return
+ * The width of the column.
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * Returns the relative flag.
+ *
+ * @return
+ * <tt>true</tt> if the column width is relative, <tt>false</tt> if it
+ * is fixed.
+ */
+ public boolean isRelative() {
+ return relative;
+ }
+
+ /**
+ * Set the column width.
+ *
+ * @param width
+ * The absolute width of the column.
+ */
+ public void setWidth(int width) {
+ setWidth(width, false);
+ }
+
+ /**
+ * Set the column width.
+ *
+ * @param width
+ * The encoded width of the row. If the string ends with the '*'
+ * character, it is treated as a relative value. Otherwise, it is
+ * considered an absolute value.
+ */
+ public void setWidth(String width) {
+ boolean relative = false;
+
+ if (width.endsWith("*")) {
+ relative = true;
+ width = width.substring(0, width.length() - 1);
+ }
+
+ setWidth(Integer.parseInt(width), relative);
+ }
+
+ /**
+ * Sets the column width.
+ *
+ * @param width
+ * The width of the column.
+ *
+ * @param relative
+ * <tt>true</tt> if the column width is relative, <tt>false</tt> if it
+ * is fixed.
+ */
+ public void setWidth(int width, boolean relative) {
+ int previousWidth = this.width;
+ boolean previousRelative = this.relative;
+
+ if (previousWidth != width
+ || previousRelative != relative) {
+ this.width = width;
+ this.relative = relative;
+
+ if (tableView != null) {
+ tableView.tableViewColumnListeners.columnWidthChanged(this,
+ previousWidth, previousRelative);
+ }
+ }
+ }
+
+ /**
+ * Returns the column's sort direction.
+ *
+ * @return
+ * The column's sort direction, or <tt>null</tt> if the column is not
+ * sorted.
+ */
+ public SortDirection getSortDirection() {
+ return sortDirection;
+ }
+
+ /**
+ * Sets the column's sort direction.
+ *
+ * @param sortDirection
+ * The column's sort direction, or <tt>null</tt> to specify no
+ * sort direction
+ */
+ public void setSortDirection(SortDirection sortDirection) {
+ SortDirection previousSortDirection = this.sortDirection;
+
+ if (previousSortDirection != sortDirection) {
+ this.sortDirection = sortDirection;
+
+ if (tableView != null) {
+ tableView.tableViewColumnListeners.columnSortDirectionChanged(this,
+ previousSortDirection);
+ }
+ }
+ }
+
+ /**
+ * Sets the column's sort direction.
+ *
+ * @param sortDirection
+ * The column's sort direction, or <tt>null</tt> to specify no
+ * sort direction
+ */
+ public final void setSortDirection(String sortDirection) {
+ setSortDirection(sortDirection == null ? (SortDirection)null :
+ SortDirection.decode(sortDirection));
+ }
+
+ /**
+ * Returns the column's filter.
+ *
+ * @return
+ * The column's filter, or <tt>null</tt> if the column does not have
+ * a filter.
+ */
+ public Object getFilter() {
+ return filter;
+ }
+
+ /**
+ * Sets the column's filter.
+ *
+ * @param filter
+ * The column's filter, or <tt>null</tt> for no filter.
+ */
+ public void setFilter(Object filter) {
+ Object previousFilter = this.filter;
+
+ if (previousFilter != filter) {
+ this.filter = filter;
+
+ if (tableView != null) {
+ tableView.tableViewColumnListeners.columnFilterChanged(this,
+ previousFilter);
+ }
+ }
+ }
+
+ /**
+ * Returns the column's cell renderer.
+ *
+ * @return
+ * The cell renderer that is used to draw the contents of this column.
+ */
+ public CellRenderer getCellRenderer() {
+ return cellRenderer;
+ }
+
+ /**
+ * Sets the column's cell renderer.
+ *
+ * @param cellRenderer
+ * The cell renderer that is used to draw the contents of this column.
+ */
+ public void setCellRenderer(CellRenderer cellRenderer) {
+ if (cellRenderer == null) {
+ throw new IllegalArgumentException("cellRenderer is null.");
+ }
+
+ CellRenderer previousCellRenderer = this.cellRenderer;
+
+ if (previousCellRenderer != cellRenderer) {
+ this.cellRenderer = cellRenderer;
+
+ if (tableView != null) {
+ tableView.tableViewColumnListeners.columnCellRendererChanged(this,
+ previousCellRenderer);
+ }
+ }
+ }
+ }
+
+ /**
+ * Enumeration defining supported selection modes.
+ */
+ public enum SelectMode {
+ /**
+ * Selection is disabled.
+ */
+ NONE,
+
+ /**
+ * A single index may be selected at a time.
+ */
+ SINGLE,
+
+ /**
+ * Multiple indexes may be concurrently selected.
+ */
+ MULTI;
+
+ public static SelectMode decode(String value) {
+ return valueOf(value.toUpperCase());
+ }
+ }
+
+ /**
+ * Table cell renderer interface.
+ *
+ * @author gbrown
+ */
+ public interface CellRenderer extends Renderer {
+ public void render(Object value, TableView tableView, TableView.Column column,
+ boolean rowSelected, boolean rowHighlighted, boolean rowDisabled);
+ }
+
+ /**
+ * Table view skin interface. Table view skins must implement this.
+ *
+ * @author gbrown
+ */
+ public interface Skin {
+ public int getRowAt(int y);
+ public int getColumnAt(int x);
+ public Bounds getRowBounds(int rowIndex);
+ public Bounds getColumnBounds(int columnIndex);
+ public Bounds getCellBounds(int rowIndex, int columnIndex);
+ }
+
+ /**
+ * Compares two rows. The dictionary values must implement
+ * {@link Comparable}.
+ * <p>
+ * TODO Allow a caller to sort on multiple columns.
+ */
+ public static class RowComparator implements Comparator<Dictionary<String, ?>> {
+ private String columnName = null;
+ private SortDirection sortDirection = null;
+
+ public RowComparator(String columnName, SortDirection sortDirection) {
+ this.columnName = columnName;
+ this.sortDirection = sortDirection;
+ }
+
+ @SuppressWarnings("unchecked")
+ public int compare(Dictionary<String, ?> row1, Dictionary<String, ?> row2) {
+ Comparable<Object> comparable = (Comparable<Object>)row1.get(columnName);
+ Object value = row2.get(columnName);
+
+ return (comparable.compareTo(value)) * (sortDirection == SortDirection.ASCENDING ? 1 : -1);
+ }
+ }
+
+ /**
+ * Default sort handler class. Sorts rows using {@link RowComparator}.
+ */
+ public static class SortHandler implements TableViewHeaderPressListener {
+ @SuppressWarnings("unchecked")
+ public void headerPressed(TableViewHeader tableViewHeader, int index) {
+ TableView tableView = tableViewHeader.getTableView();
+ TableView.ColumnSequence columns = tableView.getColumns();
+ TableView.Column column = columns.get(index);
+
+ Object headerData = column.getHeaderData();
+ if (!(headerData instanceof TableViewHeaderData)) {
+ headerData = new TableViewHeaderData((String)headerData);
+ column.setHeaderData(headerData);
+ }
+
+ SortDirection sortDirection = column.getSortDirection();
+
+ if (sortDirection == null
+ || sortDirection == SortDirection.DESCENDING) {
+ sortDirection = SortDirection.ASCENDING;
+ } else {
+ sortDirection = SortDirection.DESCENDING;
+ }
+
+ List<Dictionary<String, ?>> tableData =
+ (List<Dictionary<String, ?>>)tableView.getTableData();
+ tableData.setComparator(new TableView.RowComparator(column.getName(), sortDirection));
+
+ for (int i = 0, n = columns.getLength(); i < n; i++) {
+ column = columns.get(i);
+ column.setSortDirection(i == index ? sortDirection : null);
+ }
+ }
+ }
+
+ /**
+ * Column sequence implementation.
+ *
+ * @author gbrown
+ */
+ public final class ColumnSequence implements Sequence<Column> {
+ public int add(Column column) {
+ int i = getLength();
+ insert(column, i);
+
+ return i;
+ }
+
+ public void insert(Column column, int index) {
+ if (column == null) {
+ throw new IllegalArgumentException("column is null.");
+ }
+
+ if (column.getTableView() != null) {
+ throw new IllegalArgumentException("column is already in use by another table view.");
+ }
+
+ columns.insert(column, index);
+ column.setTableView(TableView.this);
+
+ tableViewColumnListeners.columnInserted(TableView.this, index);
+ }
+
+ public Column update(int index, Column column) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int remove(Column column) {
+ int index = indexOf(column);
+ if (index != -1) {
+ remove(index, 1);
+ }
+
+ return index;
+ }
+
+ public Sequence<Column> remove(int index, int count) {
+ Sequence<Column> removed = columns.remove(index, count);
+
+ if (count > 0) {
+ for (int i = 0, n = removed.getLength(); i < n; i++) {
+ removed.get(i).setTableView(null);
+ }
+
+ tableViewColumnListeners.columnsRemoved(TableView.this, index, removed);
+ }
+
+ return removed;
+ }
+
+ public Column get(int index) {
+ return columns.get(index);
+ }
+
+ public int indexOf(Column column) {
+ return columns.indexOf(column);
+ }
+
+ public int getLength() {
+ return columns.getLength();
+ }
+ }
+
+ /**
+ * List event handler.
+ *
+ * @author gbrown
+ */
+ private class ListHandler implements ListListener<Object> {
+ public void itemInserted(List<Object> list, int index) {
+ int m = selectedRanges.insertIndex(index);
+
+ // Notify listeners that items were inserted
+ tableViewRowListeners.rowInserted(TableView.this, index);
+
+ // If any spans were modified, notify listeners of selection change
+ if (m > 0) {
+ tableViewSelectionListeners.selectionChanged(TableView.this);
+ }
+ }
+
+ public void itemsRemoved(List<Object> list, int index, Sequence<Object> items) {
+ if (items == null) {
+ // All items were removed; clear the selection and notify
+ // listeners
+ selectedRanges.clear();
+ tableViewRowListeners.rowsRemoved(TableView.this, index, -1);
+ tableViewSelectionListeners.selectionChanged(TableView.this);
+ } else {
+ int count = items.getLength();
+
+ int s = selectedRanges.getLength();
+ int m = selectedRanges.removeIndexes(index, count);
+
+ // Notify listeners that items were removed
+ tableViewRowListeners.rowsRemoved(TableView.this, index, count);
+
+ // If any selection values were removed or any spans were modified,
+ // notify listeners of selection change
+ if (s != selectedRanges.getLength()
+ || m > 0) {
+ tableViewSelectionListeners.selectionChanged(TableView.this);
+ }
+ }
+ }
+
+ public void itemUpdated(List<Object> list, int index, Object previousItem) {
+ tableViewRowListeners.rowUpdated(TableView.this, index);
+ }
+
+ public void comparatorChanged(List<Object> list,
+ Comparator<Object> previousComparator) {
+ if (list.getComparator() != null) {
+ int s = selectedRanges.getLength();
+ selectedRanges.clear();
+
+ tableViewRowListeners.rowsSorted(TableView.this);
+
+ if (s > 0) {
+ tableViewSelectionListeners.selectionChanged(TableView.this);
+ }
+ }
+ }
+ }
+
+ /**
+ * Table view listener list.
+ *
+ * @author gbrown
+ */
+ private static class TableViewListenerList extends ListenerList<TableViewListener>
+ implements TableViewListener {
+ public void tableDataChanged(TableView tableView, List<?> previousTableData) {
+ for (TableViewListener listener : this) {
+ listener.tableDataChanged(tableView, previousTableData);
+ }
+ }
+
+ public void selectModeChanged(TableView tableView, SelectMode previousSelectMode) {
+ for (TableViewListener listener : this) {
+ listener.selectModeChanged(tableView, previousSelectMode);
+ }
+ }
+ }
+
+ /**
+ * Table view column listener list.
+ *
+ * @author gbrown
+ */
+ private static class TableViewColumnListenerList extends ListenerList<TableViewColumnListener>
+ implements TableViewColumnListener {
+ public void columnInserted(TableView tableView, int index) {
+ for (TableViewColumnListener listener : this) {
+ listener.columnInserted(tableView, index);
+ }
+ }
+
+ public void columnsRemoved(TableView tableView, int index, Sequence<TableView.Column> columns) {
+ for (TableViewColumnListener listener : this) {
+ listener.columnsRemoved(tableView, index, columns);
+ }
+ }
+
+ public void columnNameChanged(Column column, String previousName) {
+ for (TableViewColumnListener listener : this) {
+ listener.columnNameChanged(column, previousName);
+ }
+ }
+
+ public void columnHeaderDataChanged(Column column, Object previousHeaderData) {
+ for (TableViewColumnListener listener : this) {
+ listener.columnHeaderDataChanged(column, previousHeaderData);
+ }
+ }
+
+ public void columnWidthChanged(Column column, int previousWidth, boolean previousRelative) {
+ for (TableViewColumnListener listener : this) {
+ listener.columnWidthChanged(column, previousWidth, previousRelative);
+ }
+ }
+
+ public void columnSortDirectionChanged(Column column, SortDirection previousSortDirection) {
+ for (TableViewColumnListener listener : this) {
+ listener.columnSortDirectionChanged(column, previousSortDirection);
+ }
+ }
+
+ public void columnFilterChanged(Column column, Object previousFilter) {
+ for (TableViewColumnListener listener : this) {
+ listener.columnFilterChanged(column, previousFilter);
+ }
+ }
+
+ public void columnCellRendererChanged(Column column, TableView.CellRenderer previousCellRenderer) {
+ for (TableViewColumnListener listener : this) {
+ listener.columnCellRendererChanged(column, previousCellRenderer);
+ }
+ }
+ }
+
+ /**
+ * Table view item listener list.
+ *
+ * @author gbrown
+ */
+ private static class TableViewRowListenerList extends ListenerList<TableViewRowListener>
+ implements TableViewRowListener {
+ public void rowInserted(TableView tableView, int index) {
+ for (TableViewRowListener listener : this) {
+ listener.rowInserted(tableView, index);
+ }
+ }
+
+ public void rowsRemoved(TableView tableView, int index, int count) {
+ for (TableViewRowListener listener : this) {
+ listener.rowsRemoved(tableView, index, count);
+ }
+ }
+
+ public void rowUpdated(TableView tableView, int index) {
+ for (TableViewRowListener listener : this) {
+ listener.rowUpdated(tableView, index);
+ }
+ }
+
+ public void rowsSorted(TableView tableView) {
+ for (TableViewRowListener listener : this) {
+ listener.rowsSorted(tableView);
+ }
+ }
+ }
+
+
+ /**
+ * List view item state listener list.
+ *
+ * @author gbrown
+ */
+ private static class TableViewRowStateListenerList extends ListenerList<TableViewRowStateListener>
+ implements TableViewRowStateListener {
+ public Vote previewRowDisabledChange(TableView tableView, int index) {
+ Vote vote = Vote.APPROVE;
+
+ for (TableViewRowStateListener listener : this) {
+ vote = vote.tally(listener.previewRowDisabledChange(tableView, index));
+ }
+
+ return vote;
+ }
+
+ public void rowDisabledChangeVetoed(TableView tableView, int index, Vote reason) {
+ for (TableViewRowStateListener listener : this) {
+ listener.rowDisabledChangeVetoed(tableView, index, reason);
+ }
+ }
+
+ public void rowDisabledChanged(TableView tableView, int index) {
+ for (TableViewRowStateListener listener : this) {
+ listener.rowDisabledChanged(tableView, index);
+ }
+ }
+ }
+
+ /**
+ * Table view selection listener list.
+ *
+ * @author gbrown
+ */
+ private static class TableViewSelectionListenerList extends ListenerList<TableViewSelectionListener>
+ implements TableViewSelectionListener {
+ public void selectionChanged(TableView tableView) {
+ for (TableViewSelectionListener listener : this) {
+ listener.selectionChanged(tableView);
+ }
+ }
+ }
+
+ /**
+ * Table view selection detail listener list.
+ *
+ * @author gbrown
+ */
+ private static class TableViewSelectionDetailListenerList extends ListenerList<TableViewSelectionDetailListener>
+ implements TableViewSelectionDetailListener {
+ public void selectedRangeAdded(TableView tableView, int rangeStart, int rangeEnd) {
+ for (TableViewSelectionDetailListener listener : this) {
+ listener.selectedRangeAdded(tableView, rangeStart, rangeEnd);
+ }
+ }
+
+ public void selectedRangeRemoved(TableView tableView, int rangeStart, int rangeEnd) {
+ for (TableViewSelectionDetailListener listener : this) {
+ listener.selectedRangeRemoved(tableView, rangeStart, rangeEnd);
+ }
+ }
+
+ public void selectionReset(TableView tableView, Sequence<Span> previousSelection) {
+ for (TableViewSelectionDetailListener listener : this) {
+ listener.selectionReset(tableView, previousSelection);
+ }
+ }
+ }
+
+ private ArrayList<Column> columns = new ArrayList<Column>();
+ private ColumnSequence columnSequence = new ColumnSequence();
+
+ private List<?> tableData = null;
+ private ListHandler tableDataHandler = new ListHandler();
+
+ private SpanSequence selectedRanges = new SpanSequence();
+ private SelectMode selectMode = SelectMode.SINGLE;
+
+ private ArrayList<Integer> disabledIndexes = new ArrayList<Integer>();
+
+ private TableViewListenerList tableViewListeners = new TableViewListenerList();
+ private TableViewColumnListenerList tableViewColumnListeners =
+ new TableViewColumnListenerList();
+ private TableViewRowListenerList tableViewRowListeners = new TableViewRowListenerList();
+ private TableViewRowStateListenerList tableViewRowStateListeners =
+ new TableViewRowStateListenerList();
+ private TableViewSelectionListenerList tableViewSelectionListeners
+ = new TableViewSelectionListenerList();
+ private TableViewSelectionDetailListenerList tableViewSelectionDetailListeners
+ = new TableViewSelectionDetailListenerList();
+
+ /**
+ * Creates a new table view populated with an empty array list.
+ */
+ public TableView() {
+ this(new ArrayList<Object>());
+ }
+
+ /**
+ * Creates a new table view populated with the given table data.
+ *
+ * @param tableData
+ */
+ public TableView(List<?> tableData) {
+ setTableData(tableData);
+ installSkin(TableView.class);
+ }
+
+ @Override
+ protected void setSkin(pivot.wtk.Skin skin) {
+ if (!(skin instanceof TableView.Skin)) {
+ throw new IllegalArgumentException("Skin class must implement "
+ + TableView.Skin.class.getName());
+ }
+
+ super.setSkin(skin);
+ }
+
+ /**
+ * Returns the table column sequence.
+ *
+ * @return
+ * The table column sequence.
+ */
+ public ColumnSequence getColumns() {
+ return columnSequence;
+ }
+
+ /**
+ * Returns the table data.
+ *
+ * @return
+ * The data currently presented by the table view.
+ */
+ public List<?> getTableData() {
+ return this.tableData;
+ }
+
+ /**
+ * Sets the table data. Clears any existing selection state.
+ *
+ * @param tableData
+ * The data to be presented by the table.
+ */
+ @SuppressWarnings("unchecked")
+ public void setTableData(List<?> tableData) {
+ if (tableData == null) {
+ throw new IllegalArgumentException("tableData is null.");
+ }
+
+ List<?> previousTableData = this.tableData;
+
+ if (previousTableData != tableData) {
+ if (previousTableData != null) {
+ // Clear any existing selection
+ clearSelection();
+
+ ((List<Object>)previousTableData).getListListeners().remove(tableDataHandler);
+ }
+
+ ((List<Object>)tableData).getListListeners().add(tableDataHandler);
+
+ // Update the list data and fire change event
+ this.tableData = tableData;
+ tableViewListeners.tableDataChanged(this, previousTableData);
+ }
+ }
+
+ /**
+ * Sets the table data. Clears any existing selection state.
+ *
+ * @param tableData
+ * A JSON string (must begin with <tt>[</tt> and end with <tt>]</tt>)
+ * denoting the data to be presented by this table.
+ */
+ public void setTableData(String tableData) {
+ if (tableData == null) {
+ throw new IllegalArgumentException("tableData is null.");
+ }
+
+ setTableData(JSONSerializer.parseList(tableData));
+ }
+
+ /**
+ * When in single-select mode, returns the currently selected index.
+ *
+ * @return
+ * The currently selected index.
+ */
+ public int getSelectedIndex() {
+ if (selectMode != SelectMode.SINGLE) {
+ throw new IllegalStateException("Table view is not in single-select mode.");
+ }
+
+ return (selectedRanges.getLength() == 0) ? -1 : selectedRanges.get(0).getStart();
+ }
+
+ /**
+ * Sets the selection to a single index.
+ *
+ * @param index
+ * The index to select, or <tt>-1</tt> to clear the selection.
+ */
+ public void setSelectedIndex(int index) {
+ ArrayList<Span> selectedRanges = new ArrayList<Span>();
+
+ if (index >= 0) {
+ selectedRanges.add(new Span(index, index));
+ }
+
+ setSelectedRanges(selectedRanges);
+ }
+
+ /**
+ * Returns the table's current selection.
+ */
+ public Sequence<Span> getSelectedRanges() {
+ // Return a copy of the selection list (including copies of the
+ // list contents)
+ ArrayList<Span> selectedRanges = new ArrayList<Span>();
+
+ for (int i = 0, n = this.selectedRanges.getLength(); i < n; i++) {
+ selectedRanges.add(new Span(this.selectedRanges.get(i)));
+ }
+
+ return selectedRanges;
+ }
+
+ /**
+ * Sets the selection to the given span sequence. Any overlapping or
+ * connecting spans will be consolidated, and the resulting selection will
+ * be sorted in ascending order.
+ *
+ * @param selectedRanges
+ * The new selection
+ */
+ public void setSelectedRanges(Sequence<Span> selectedRanges) {
+ if (selectedRanges == null) {
+ throw new IllegalArgumentException("selectedRanges is null.");
+ }
+
+ if (selectMode == SelectMode.NONE) {
+ throw new IllegalArgumentException("Selection is not enabled.");
+ }
+
+ if (selectMode == SelectMode.SINGLE) {
+ int n = selectedRanges.getLength();
+
+ if (n > 1) {
+ throw new IllegalArgumentException("Selection length is greater than 1.");
+ } else {
+ if (n > 0) {
+ Span selectedRange = selectedRanges.get(0);
+
+ if (selectedRange.getLength() > 1) {
+ throw new IllegalArgumentException("Selected range length is greater than 1.");
+ }
+ }
+ }
+ }
+
+ // Update the selection
+ SpanSequence ranges = new SpanSequence();
+
+ for (int i = 0, n = selectedRanges.getLength(); i < n; i++) {
+ Span range = selectedRanges.get(i);
+
+ if (range == null) {
+ throw new IllegalArgumentException("range is null.");
+ }
+
+ if (range.getStart() < 0 || range.getEnd() >= tableData.getLength()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ ranges.add(range);
+ }
+
+ SpanSequence previousSelectedRanges = this.selectedRanges;
+ this.selectedRanges = ranges;
+
+ // Notify listeners
+ tableViewSelectionDetailListeners.selectionReset(this, previousSelectedRanges);
+ tableViewSelectionListeners.selectionChanged(this);
+ }
+
+ /**
+ * Returns the first selected index.
+ *
+ * @return
+ * The first selected index, or <tt>-1</tt> if nothing is selected.
+ */
+ public int getFirstSelectedIndex() {
+ return (selectedRanges.getLength() > 0) ?
+ selectedRanges.get(0).getStart() : -1;
+ }
+
+ /**
+ * Returns the last selected index.
+ *
+ * @return
+ * The last selected index, or <tt>-1</tt> if nothing is selected.
+ */
+ public int getLastSelectedIndex() {
+ return (selectedRanges.getLength() > 0) ?
+ selectedRanges.get(selectedRanges.getLength() - 1).getEnd() : -1;
+ }
+
+ /**
+ * Adds a single index to the selection.
+ *
+ * @param index
+ * The index to add.
+ */
+ public void addSelectedIndex(int index) {
+ addSelectedRange(index, index);
+ }
+
+ /**
+ * Adds a range of indexes to the selection.
+ *
+ * @param rangeStart
+ * The first index in the range.
+ *
+ * @param rangeEnd
+ * The last index in the range.
+ */
+ public void addSelectedRange(int rangeStart, int rangeEnd) {
+ addSelectedRange(new Span(rangeStart, rangeEnd));
+ }
+
+ /**
+ * Adds a range of indexes to the selection.
+ *
+ * @param range
+ * The range to add.
+ */
+ public void addSelectedRange(Span range) {
+ if (selectMode != SelectMode.MULTI) {
+ throw new IllegalStateException("Table view is not in multi-select mode.");
+ }
+
+ if (range == null) {
+ throw new IllegalArgumentException("range is null.");
+ }
+
+ if (range.getStart() < 0 || range.getEnd() >= tableData.getLength()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ selectedRanges.add(range);
+
+ tableViewSelectionDetailListeners.selectedRangeAdded(this,
+ range.getStart(), range.getEnd());
+ tableViewSelectionListeners.selectionChanged(this);
+ }
+
+ /**
+ * Removes a single index from the selection.
+ *
+ * @param index
+ * The index to remove.
+ */
+ public void removeSelectedIndex(int index) {
+ removeSelectedRange(index, index);
+ }
+
+ /**
+ * Removes a range of indexes from the selection.
+ *
+ * @param rangeStart
+ * The start of the range to remove.
+ *
+ * @param rangeEnd
+ * The end of the range to remove.
+ */
+ public void removeSelectedRange(int rangeStart, int rangeEnd) {
+ removeSelectedRange(new Span(rangeStart, rangeEnd));
+ }
+
+ /**
+ * Removes a range of indexes from the selection.
+ *
+ * @param range
+ * The range to remove.
+ */
+ public void removeSelectedRange(Span range) {
+ if (selectMode != SelectMode.MULTI) {
+ throw new IllegalStateException("Table view is not in multi-select mode.");
+ }
+
+ if (range == null) {
+ throw new IllegalArgumentException("range is null.");
+ }
+
+ if (range.getStart() < 0 || range.getEnd() >= tableData.getLength()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ selectedRanges.remove(range);
+
+ tableViewSelectionDetailListeners.selectedRangeRemoved(this,
+ range.getStart(), range.getEnd());
+ tableViewSelectionListeners.selectionChanged(this);
+ }
+
+ /**
+ * Clears the selection.
+ */
+ public void clearSelection() {
+ if (selectedRanges.getLength() > 0) {
+ SpanSequence previousSelectedSpans = this.selectedRanges;
+ selectedRanges = new SpanSequence();
+
+ tableViewSelectionDetailListeners.selectionReset(this, previousSelectedSpans);
+ tableViewSelectionListeners.selectionChanged(this);
+ }
+ }
+
+ /**
+ * Returns the selection state of a given index.
+ *
+ * @param index
+ * The index whose selection state is to be tested.
+ *
+ * @return <tt>true</tt> if the index is selected; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isIndexSelected(int index) {
+ return isRangeSelected(index, index);
+ }
+
+ /**
+ * Returns the selection state of a given range.
+ *
+ * @param rangeStart
+ * The first index in the range.
+ *
+ * @param rangeEnd
+ * The last index in the range.
+ *
+ * @return <tt>true</tt> if the entire range is selected; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isRangeSelected(int rangeStart, int rangeEnd) {
+ return isRangeSelected(new Span(rangeStart, rangeEnd));
+ }
+
+ /**
+ * Returns the selection state of a given range.
+ *
+ * @param range
+ * The range whose selection state is to be tested.
+ *
+ * @return <tt>true</tt> if the entire range is selected; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isRangeSelected(Span range) {
+ boolean selected = false;
+
+ if (range == null) {
+ throw new IllegalArgumentException("range is null.");
+ }
+
+ if (range.getStart() < 0 || range.getEnd() >= tableData.getLength()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ // Locate the span in the selection
+ int i = selectedRanges.indexOf(range);
+
+ // If the selected span contains the given span, it is considered
+ // selected
+ if (i >= 0) {
+ Span selectedSpan = selectedRanges.get(i);
+ selected = selectedSpan.contains(range);
+ }
+
+ return selected;
+ }
+
+ /**
+ * Returns the current selection mode.
+ */
+ public SelectMode getSelectMode() {
+ return selectMode;
+ }
+
+ /**
+ * Sets the selection mode. Clears the selection if the mode has changed.
+ *
+ * @param selectMode
+ * The new selection mode.
+ */
+ public void setSelectMode(SelectMode selectMode) {
+ if (selectMode == null) {
+ throw new IllegalArgumentException("selectMode is null.");
+ }
+
+ SelectMode previousSelectMode = this.selectMode;
+
+ if (previousSelectMode != selectMode) {
+ // Clear any current selection
+ clearSelection();
+
+ // Update the selection mode
+ this.selectMode = selectMode;
+
+ // Fire select mode change event
+ tableViewListeners.selectModeChanged(this, previousSelectMode);
+ }
+ }
+
+ public void setSelectMode(String selectMode) {
+ if (selectMode == null) {
+ throw new IllegalArgumentException("selectMode is null.");
+ }
+
+ setSelectMode(SelectMode.decode(selectMode));
+ }
+
+ /**
+ * Returns the disabled state of a given row.
+ *
+ * @param index
+ * The index of the row whose disabled state is to be tested.
+ *
+ * @return
+ * <tt>true</tt> if the row is disabled; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isRowDisabled(int index) {
+ return (Sequence.Search.binarySearch(disabledIndexes, index) >= 0);
+ }
+
+ /**
+ * Sets the disabled state of a row.
+ *
+ * @param index
+ * The index of the row whose disabled state is to be set.
+ *
+ * @param disabled
+ * <tt>true</tt> to disable the row; <tt>false</tt>, otherwise.
+ */
+ public void setRowDisabled(int index, boolean disabled) {
+ int i = Sequence.Search.binarySearch(disabledIndexes, index);
+
+ if ((i < 0 && disabled)
+ || (i >= 0 && !disabled)) {
+ Vote vote = tableViewRowStateListeners.previewRowDisabledChange(this, index);
+ if (vote.isApproved()) {
+ if (disabled) {
+ disabledIndexes.insert(index, -(i + 1));
+ } else {
+ disabledIndexes.remove(i, 1);
+ }
+
+ tableViewRowStateListeners.rowDisabledChanged(this, index);
+ } else {
+ tableViewRowStateListeners.rowDisabledChangeVetoed(this, index, vote);
+ }
+ }
+ }
+
+ public Sequence<Integer> getDisabledIndexes() {
+ ArrayList<Integer> disabledIndexes = new ArrayList<Integer>();
+
+ for (int i = 0, n = this.disabledIndexes.getLength(); i < n; i++) {
+ disabledIndexes.add(this.disabledIndexes.get(i));
+ }
+
+ return disabledIndexes;
+ }
+
+ /**
+ * Returns the index of the row at a given location.
+ *
+ * @param y
+ * The y-coordinate of the row to identify.
+ *
+ * @return
+ * The row index, or <tt>-1</tt> if there is no row at the given
+ * y-coordinate.
+ */
+ public int getRowAt(int y) {
+ TableView.Skin tableViewSkin = (TableView.Skin)getSkin();
+ return tableViewSkin.getRowAt(y);
+ }
+
+ /**
+ * Returns the index of the column at a given location.
+ *
+ * @param x
+ * The x-coordinate of the column to identify.
+ *
+ * @return
+ * The column index, or <tt>-1</tt> if there is no column at the given
+ * x-coordinate.
+ */
+ public int getColumnAt(int x) {
+ TableView.Skin tableViewSkin = (TableView.Skin)getSkin();
+ return tableViewSkin.getColumnAt(x);
+ }
+
+ /**
+ * Returns the bounding area of a given row.
+ *
+ * @param rowIndex
+ * The row index.
+ *
+ * @return
+ * The bounding area of the row.
+ */
+ public Bounds getRowBounds(int rowIndex) {
+ TableView.Skin tableViewSkin = (TableView.Skin)getSkin();
+ return tableViewSkin.getRowBounds(rowIndex);
+ }
+
+ /**
+ * Returns the bounding area of a given column.
+ *
+ * @param columnIndex
+ * The column index.
+ *
+ * @return
+ * The bounding area of the column.
+ */
+ public Bounds getColumnBounds(int columnIndex) {
+ TableView.Skin tableViewSkin = (TableView.Skin)getSkin();
+ return tableViewSkin.getColumnBounds(columnIndex);
+ }
+
+ /**
+ * Returns the bounding area of a given cell.
+ *
+ * @param rowIndex
+ * The row index of the cell.
+ *
+ * @param columnIndex
+ * The column index of the cell.
+ *
+ * @return
+ * The bounding area of the cell.
+ */
+ public Bounds getCellBounds(int rowIndex, int columnIndex) {
+ TableView.Skin tableViewSkin = (TableView.Skin)getSkin();
+ return tableViewSkin.getCellBounds(rowIndex, columnIndex);
+ }
+
+ public ListenerList<TableViewListener> getTableViewListeners() {
+ return tableViewListeners;
+ }
+
+ public ListenerList<TableViewColumnListener> getTableViewColumnListeners() {
+ return tableViewColumnListeners;
+ }
+
+ public ListenerList<TableViewRowListener> getTableViewRowListeners() {
+ return tableViewRowListeners;
+ }
+
+ public ListenerList<TableViewRowStateListener> getTableViewRowStateListeners() {
+ return tableViewRowStateListeners;
+ }
+
+ public ListenerList<TableViewSelectionListener> getTableViewSelectionListeners() {
+ return tableViewSelectionListeners;
+ }
+
+ public ListenerList<TableViewSelectionDetailListener> getTableViewSelectionDetailListeners() {
+ return tableViewSelectionDetailListeners;
+ }
+}
Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableView.png
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableView.png?rev=754926&view=auto
==============================================================================
Binary file - no diff available.
Propchange: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableView.png
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableViewColumnListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableViewColumnListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableViewColumnListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TableViewColumnListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+import pivot.collections.Sequence;
+
+/**
+ * Table view column listener interface.
+ *
+ * @author gbrown
+ */
+public interface TableViewColumnListener {
+ /**
+ * Called when a column is inserted into a table view's column sequence.
+ *
+ * @param tableView
+ * @param index
+ */
+ public void columnInserted(TableView tableView, int index);
+
+ /**
+ * Called when columns are removed from a table view's column sequence.
+ *
+ * @param tableView
+ * @param index
+ * @param columns
+ */
+ public void columnsRemoved(TableView tableView, int index, Sequence<TableView.Column> columns);
+
+ /**
+ * Called when a column's name has changed.
+ *
+ * @param column
+ * @param previousName
+ */
+ public void columnNameChanged(TableView.Column column, String previousName);
+
+ /**
+ * Called when a column's header data has changed.
+ *
+ * @param column
+ * @param previousHeaderData
+ */
+ public void columnHeaderDataChanged(TableView.Column column, Object previousHeaderData);
+
+ /**
+ * Called when a column's width has changed.
+ *
+ * @param column
+ * @param previousWidth
+ * @param previousRelative
+ */
+ public void columnWidthChanged(TableView.Column column, int previousWidth, boolean previousRelative);
+
+ /**
+ * Called when a column's sort direction has changed.
+ *
+ * @param column
+ * @param previousSortDirection
+ */
+ public void columnSortDirectionChanged(TableView.Column column, SortDirection previousSortDirection);
+
+ /**
+ * Called when a column's filter has changed.
+ *
+ * @param column
+ * @param previousFilter
+ */
+ public void columnFilterChanged(TableView.Column column, Object previousFilter);
+
+ /**
+ * Called when a column's cell renderer has changed.
+ *
+ * @param column
+ * @param previousCellRenderer
+ */
+ public void columnCellRendererChanged(TableView.Column column, TableView.CellRenderer previousCellRenderer);
+}