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 [35/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/skin/terra/TerraTableViewHeaderSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/skin/terra/TerraTableViewHeaderSkin.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/skin/terra/TerraTableViewHeaderSkin.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/skin/terra/TerraTableViewHeaderSkin.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,797 @@
+/*
+ * 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.skin.terra;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+
+import pivot.collections.Sequence;
+import pivot.wtk.Component;
+import pivot.wtk.ComponentMouseListener;
+import pivot.wtk.ComponentMouseButtonListener;
+import pivot.wtk.Cursor;
+import pivot.wtk.Dimensions;
+import pivot.wtk.Display;
+import pivot.wtk.Mouse;
+import pivot.wtk.Point;
+import pivot.wtk.Bounds;
+import pivot.wtk.SortDirection;
+import pivot.wtk.TableView;
+import pivot.wtk.TableViewColumnListener;
+import pivot.wtk.TableViewHeader;
+import pivot.wtk.TableViewHeaderListener;
+import pivot.wtk.Theme;
+import pivot.wtk.media.Image;
+import pivot.wtk.skin.ComponentSkin;
+
+/**
+ * Table view header skin.
+ *
+ * @author gbrown
+ */
+public class TerraTableViewHeaderSkin extends ComponentSkin
+ implements TableViewHeader.Skin, TableViewHeaderListener, TableViewColumnListener {
+ private class SortIndicatorImage extends Image {
+ private SortDirection sortDirection = null;
+
+ public SortIndicatorImage(SortDirection sortDirection) {
+ this.sortDirection = sortDirection;
+ }
+
+ public int getWidth() {
+ return 7;
+ }
+
+ public int getHeight() {
+ return 4;
+ }
+
+ public Dimensions getPreferredSize() {
+ return new Dimensions(getPreferredWidth(-1), getPreferredHeight(-1));
+ }
+
+ public void paint(Graphics2D graphics) {
+ GeneralPath shape = new GeneralPath();
+
+ switch (sortDirection) {
+ case ASCENDING: {
+ shape.moveTo(0, 3);
+ shape.lineTo(3, 0);
+ shape.lineTo(6, 3);
+ break;
+ }
+
+ case DESCENDING: {
+ shape.moveTo(0, 0);
+ shape.lineTo(3, 3);
+ shape.lineTo(6, 0);
+ break;
+ }
+ }
+
+ shape.closePath();
+
+ graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+
+ graphics.setStroke(new BasicStroke(0));
+ graphics.setPaint(borderColor);
+
+ graphics.draw(shape);
+ graphics.fill(shape);
+ }
+ }
+
+ private class ResizeHandler
+ implements ComponentMouseListener, ComponentMouseButtonListener {
+ TableView.Column column = null;
+ int headerX = 0;
+ int offset = 0;
+
+ public static final int MINIMUM_COLUMN_WIDTH = 2;
+
+ public ResizeHandler(TableView.Column column, int headerX, int offset) {
+ assert (!column.isRelative()) : "Relative width columns cannot be resized.";
+
+ this.column = column;
+ this.headerX = headerX;
+ this.offset = offset;
+ }
+
+ public boolean mouseMove(Component component, int x, int y) {
+ int columnWidth = Math.max(x - headerX + offset, MINIMUM_COLUMN_WIDTH);
+ column.setWidth(columnWidth, false);
+
+ return false;
+ }
+
+ public void mouseOver(Component component) {
+ }
+
+ public void mouseOut(Component component) {
+ }
+
+ public boolean mouseDown(Component component, Mouse.Button button, int x, int y) {
+ return false;
+ }
+
+ public boolean mouseUp(Component component, Mouse.Button button, int x, int y) {
+ Mouse.setCursor(component.getCursor());
+
+ assert (component instanceof Display);
+ component.getComponentMouseListeners().remove(this);
+ component.getComponentMouseButtonListeners().remove(this);
+
+ resizing = false;
+ Mouse.setCursor(getComponent().getCursor());
+
+ return false;
+ }
+
+ public void mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
+ }
+ }
+
+ private Font font;
+ private Color color;
+ private Color disabledColor;
+ private Color backgroundColor;
+ private Color disabledBackgroundColor;
+ private Color borderColor;
+ private Color disabledBorderColor;
+ private boolean headersPressable;
+ private boolean columnsResizable;
+ private boolean includeTrailingVerticalGridLine;
+
+ // Derived colors
+ private Color bevelColor;
+ private Color pressedBevelColor;
+ private Color disabledBevelColor;
+
+ private int pressedHeaderIndex = -1;
+ private boolean resizing = false;
+
+ private static final int SORT_INDICATOR_PADDING = 2;
+ private static final int RESIZE_HANDLE_SIZE = 6;
+
+ protected SortIndicatorImage sortAscendingImage = new SortIndicatorImage(SortDirection.ASCENDING);
+ protected SortIndicatorImage sortDescendingImage = new SortIndicatorImage(SortDirection.DESCENDING);
+
+ public TerraTableViewHeaderSkin() {
+ TerraTheme theme = (TerraTheme)Theme.getTheme();
+
+ font = theme.getFont();
+ color = theme.getColor(1);
+ disabledColor = theme.getColor(7);
+ backgroundColor = theme.getColor(10);
+ disabledBackgroundColor = theme.getColor(10);
+ borderColor = theme.getColor(7);
+ disabledBorderColor = theme.getColor(7);
+ headersPressable = true;
+ columnsResizable = true;
+ includeTrailingVerticalGridLine = false;
+
+ // Set the derived colors
+ bevelColor = TerraTheme.brighten(backgroundColor);
+ pressedBevelColor = TerraTheme.darken(backgroundColor);
+ disabledBevelColor = disabledBackgroundColor;
+ }
+
+ public void install(Component component) {
+ super.install(component);
+
+ TableViewHeader tableViewHeader = (TableViewHeader)component;
+ tableViewHeader.getTableViewHeaderListeners().add(this);
+
+ TableView tableView = tableViewHeader.getTableView();
+ if (tableView != null) {
+ tableView.getTableViewColumnListeners().add(this);
+ }
+ }
+
+ public void uninstall() {
+ TableViewHeader tableViewHeader = (TableViewHeader)getComponent();
+ tableViewHeader.getTableViewHeaderListeners().remove(this);
+
+ TableView tableView = tableViewHeader.getTableView();
+ if (tableView != null) {
+ tableView.getTableViewColumnListeners().remove(this);
+ }
+
+ super.uninstall();
+ }
+
+ public int getPreferredWidth(int height) {
+ int preferredWidth = 0;
+
+ TableViewHeader tableViewHeader = (TableViewHeader)getComponent();
+ TableView tableView = tableViewHeader.getTableView();
+
+ if (tableView != null) {
+ TableView.ColumnSequence columns = tableView.getColumns();
+
+ int n = columns.getLength();
+ int gridLineStop = includeTrailingVerticalGridLine ? n : n - 1;
+
+ for (int i = 0; i < n; i++) {
+ TableView.Column column = columns.get(i);
+
+ if (!column.isRelative()) {
+ preferredWidth += column.getWidth();
+
+ // Include space for vertical gridlines
+ if (i < gridLineStop) {
+ preferredWidth++;
+ }
+ }
+ }
+ }
+
+ return preferredWidth;
+ }
+
+ public int getPreferredHeight(int width) {
+ int preferredHeight = 0;
+
+ TableViewHeader tableViewHeader = (TableViewHeader)getComponent();
+ TableView tableView = tableViewHeader.getTableView();
+
+ if (tableView != null) {
+ TableView.ColumnSequence columns = tableView.getColumns();
+ TableViewHeader.DataRenderer dataRenderer = tableViewHeader.getDataRenderer();
+
+ for (int i = 0, n = columns.getLength(); i < n; i++) {
+ TableView.Column column = columns.get(i);
+ dataRenderer.render(column.getHeaderData(), tableViewHeader, false);
+ preferredHeight = Math.max(preferredHeight, dataRenderer.getPreferredHeight(-1));
+ }
+
+ // Include the bottom border
+ preferredHeight++;
+ }
+
+ return preferredHeight;
+ }
+
+ public Dimensions getPreferredSize() {
+ return new Dimensions(getPreferredWidth(-1), getPreferredHeight(-1));
+ }
+
+ public void layout() {
+ // No-op
+ }
+
+ public void paint(Graphics2D graphics) {
+ int width = getWidth();
+ int height = getHeight();
+
+ TableViewHeader tableViewHeader = (TableViewHeader)getComponent();
+
+ Color backgroundColor = null;
+ Color bevelColor = null;
+ Color borderColor = null;
+
+ if (tableViewHeader.isEnabled()) {
+ backgroundColor = this.backgroundColor;
+ bevelColor = this.bevelColor;
+ borderColor = this.borderColor;
+ } else {
+ backgroundColor = disabledBackgroundColor;
+ bevelColor = disabledBevelColor;
+ borderColor = disabledBorderColor;
+ }
+
+ // Paint the background
+ graphics.setPaint(backgroundColor);
+ graphics.fillRect(0, 0, width, height);
+
+ // Draw all lines with a 1px solid stroke
+ graphics.setStroke(new BasicStroke());
+
+ // Paint the bevel
+ Line2D bevelLine = new Line2D.Double(0, 0, width, 0);
+ graphics.setPaint(bevelColor);
+ graphics.draw(bevelLine);
+
+ // Paint the border
+ Line2D borderLine = new Line2D.Double(0, height - 1, width, height - 1);
+ graphics.setPaint(borderColor);
+ graphics.draw(borderLine);
+
+ // Paint the content
+ TableView tableView = tableViewHeader.getTableView();
+
+ if (tableView != null) {
+ TableView.ColumnSequence columns = tableView.getColumns();
+ Sequence<Integer> columnWidths =
+ TerraTableViewSkin.getColumnWidths(columns, getWidth());
+
+ TableViewHeader.DataRenderer dataRenderer = tableViewHeader.getDataRenderer();
+
+ int cellX = 0;
+ for (int columnIndex = 0, columnCount = columns.getLength();
+ columnIndex < columnCount; columnIndex++) {
+ TableView.Column column = columns.get(columnIndex);
+ int columnWidth = columnWidths.get(columnIndex);
+
+ // Paint the pressed bevel
+ if (columnIndex == pressedHeaderIndex) {
+ bevelLine = new Line2D.Double(cellX, 0, cellX + columnWidth, 0);
+ graphics.setPaint(pressedBevelColor);
+ graphics.draw(bevelLine);
+ }
+
+ // Paint the header data
+ Object headerData = column.getHeaderData();
+ dataRenderer.render(headerData, tableViewHeader, false);
+ dataRenderer.setSize(columnWidth, height - 1);
+
+ Graphics2D rendererGraphics = (Graphics2D)graphics.create(cellX, 0,
+ columnWidth, height - 1);
+ dataRenderer.paint(rendererGraphics);
+ rendererGraphics.dispose();
+
+ // Draw the sort image
+ Image sortImage = null;
+ SortDirection sortDirection = column.getSortDirection();
+
+ if (sortDirection != null) {
+ switch (sortDirection) {
+ case ASCENDING: {
+ sortImage = sortAscendingImage;
+ break;
+ }
+
+ case DESCENDING: {
+ sortImage = sortDescendingImage;
+ break;
+ }
+ }
+ }
+
+ if (sortImage != null) {
+ int sortImageMargin = sortImage.getWidth()
+ + SORT_INDICATOR_PADDING * 2;
+
+ if (columnWidth >= dataRenderer.getPreferredWidth(-1) + sortImageMargin) {
+ Graphics2D sortImageGraphics = (Graphics2D)graphics.create();
+ sortImageGraphics.translate(cellX + columnWidth - sortImageMargin,
+ (height - sortImage.getHeight()) / 2);
+ sortImage.paint(sortImageGraphics);
+ sortImageGraphics.dispose();
+ }
+ }
+
+ // Draw the divider
+ cellX += columnWidth;
+
+ Line2D dividerLine = new Line2D.Double(cellX, 0, cellX, height - 1);
+ graphics.setPaint(borderColor);
+ graphics.draw(dividerLine);
+
+ cellX++;
+ }
+ }
+ }
+
+ public int getHeaderAt(int x) {
+ if (x < 0) {
+ throw new IllegalArgumentException("x is negative");
+ }
+
+ int index = -1;
+
+ TableViewHeader tableViewHeader = (TableViewHeader)getComponent();
+ TableView tableView = tableViewHeader.getTableView();
+
+ if (tableView != null) {
+ Sequence<Integer> columnWidths =
+ TerraTableViewSkin.getColumnWidths(tableView.getColumns(), getWidth());
+
+ int i = 0;
+ int n = columnWidths.getLength();
+ int columnX = 0;
+ while (i < n
+ && x > columnX) {
+ columnX += (columnWidths.get(i) + 1);
+ i++;
+ }
+
+ if (x <= columnX) {
+ index = i - 1;
+ }
+ }
+
+ return index;
+ }
+
+ public Bounds getHeaderBounds(int index) {
+ Bounds headerBounds = null;
+
+ TableViewHeader tableViewHeader = (TableViewHeader)getComponent();
+ TableView tableView = tableViewHeader.getTableView();
+
+ if (tableView != null) {
+ Sequence<Integer> columnWidths =
+ TerraTableViewSkin.getColumnWidths(tableView.getColumns(), getWidth());
+
+ if (index < 0
+ || index >= columnWidths.getLength()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ int cellX = 0;
+ for (int i = 0; i < index; i++) {
+ cellX += (columnWidths.get(i) + 1);
+ }
+
+ headerBounds = new Bounds(cellX, 0, columnWidths.get(index), getHeight() - 1);
+ }
+
+ return headerBounds;
+ }
+
+ @Override
+ public boolean isFocusable() {
+ return false;
+ }
+
+ public Font getFont() {
+ return font;
+ }
+
+ public void setFont(Font font) {
+ if (font == null) {
+ throw new IllegalArgumentException("font is null.");
+ }
+
+ this.font = font;
+ invalidateComponent();
+ }
+
+ public final void setFont(String font) {
+ if (font == null) {
+ throw new IllegalArgumentException("font is null.");
+ }
+
+ setFont(Font.decode(font));
+ }
+
+ public Color getColor() {
+ return color;
+ }
+
+ public void setColor(Color color) {
+ if (color == null) {
+ throw new IllegalArgumentException("color is null.");
+ }
+
+ this.color = color;
+ repaintComponent();
+ }
+
+ public final void setColor(String color) {
+ if (color == null) {
+ throw new IllegalArgumentException("color is null.");
+ }
+
+ setColor(decodeColor(color));
+ }
+
+ public Color getDisabledColor() {
+ return disabledColor;
+ }
+
+ public void setDisabledColor(Color disabledColor) {
+ if (disabledColor == null) {
+ throw new IllegalArgumentException("disabledColor is null.");
+ }
+
+ this.disabledColor = disabledColor;
+ repaintComponent();
+ }
+
+ public final void setDisabledColor(String disabledColor) {
+ if (disabledColor == null) {
+ throw new IllegalArgumentException("disabledColor is null.");
+ }
+
+ setDisabledColor(decodeColor(disabledColor));
+ }
+
+ public Color getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public void setBackgroundColor(Color backgroundColor) {
+ if (backgroundColor == null) {
+ throw new IllegalArgumentException("backgroundColor is null.");
+ }
+
+ this.backgroundColor = backgroundColor;
+ bevelColor = TerraTheme.brighten(backgroundColor);
+ pressedBevelColor = TerraTheme.darken(backgroundColor);
+ repaintComponent();
+ }
+
+ public final void setBackgroundColor(String backgroundColor) {
+ if (backgroundColor == null) {
+ throw new IllegalArgumentException("backgroundColor is null.");
+ }
+
+ setBackgroundColor(decodeColor(backgroundColor));
+ }
+
+ public Color getDisabledBackgroundColor() {
+ return disabledBackgroundColor;
+ }
+
+ public void setDisabledBackgroundColor(Color disabledBackgroundColor) {
+ if (disabledBackgroundColor == null) {
+ throw new IllegalArgumentException("disabledBackgroundColor is null.");
+ }
+
+ this.disabledBackgroundColor = disabledBackgroundColor;
+ disabledBevelColor = disabledBackgroundColor;
+ repaintComponent();
+ }
+
+ public final void setDisabledBackgroundColor(String disabledBackgroundColor) {
+ if (disabledBackgroundColor == null) {
+ throw new IllegalArgumentException("disabledBackgroundColor is null.");
+ }
+
+ setDisabledBackgroundColor(decodeColor(disabledBackgroundColor));
+ }
+
+ public Color getBorderColor() {
+ return borderColor;
+ }
+
+ public void setBorderColor(Color borderColor) {
+ if (borderColor == null) {
+ throw new IllegalArgumentException("borderColor is null.");
+ }
+
+ this.borderColor = borderColor;
+ repaintComponent();
+ }
+
+ public final void setBorderColor(String borderColor) {
+ if (borderColor == null) {
+ throw new IllegalArgumentException("borderColor is null.");
+ }
+
+ setBorderColor(decodeColor(borderColor));
+ }
+
+ public Color getDisabledBorderColor() {
+ return disabledBorderColor;
+ }
+
+ public void setDisabledBorderColor(Color disabledBorderColor) {
+ if (disabledBorderColor == null) {
+ throw new IllegalArgumentException("disabledBorderColor is null.");
+ }
+
+ this.disabledBorderColor = disabledBorderColor;
+ repaintComponent();
+ }
+
+ public final void setDisabledBorderColor(String disabledBorderColor) {
+ if (disabledBorderColor == null) {
+ throw new IllegalArgumentException("disabledBorderColor is null.");
+ }
+
+ setDisabledBorderColor(decodeColor(disabledBorderColor));
+ }
+
+ public boolean getHeadersPressable() {
+ return headersPressable;
+ }
+
+ public void setHeadersPressable(boolean headersPressable) {
+ this.headersPressable = headersPressable;
+
+ pressedHeaderIndex = -1;
+ repaintComponent();
+ }
+
+ public boolean getColumnsResizable() {
+ return columnsResizable;
+ }
+
+ public void setColumnsResizable(boolean columnsResizable) {
+ this.columnsResizable = columnsResizable;
+ }
+
+ public boolean getIncludeTrailingVerticalGridLine() {
+ return includeTrailingVerticalGridLine;
+ }
+
+ public void setIncludeTrailingVerticalGridLine(boolean includeTrailingVerticalGridLine) {
+ this.includeTrailingVerticalGridLine = includeTrailingVerticalGridLine;
+ invalidateComponent();
+ }
+
+ @Override
+ public void enabledChanged(Component component) {
+ super.enabledChanged(component);
+
+ pressedHeaderIndex = -1;
+ repaintComponent();
+ }
+
+ @Override
+ public boolean mouseMove(Component component, int x, int y) {
+ boolean consumed = super.mouseMove(component, x, y);
+
+ if (!resizing) {
+ TableViewHeader tableViewHeader = (TableViewHeader)getComponent();
+ TableView tableView = tableViewHeader.getTableView();
+
+ if (tableView != null) {
+ int headerIndex = getHeaderAt(x);
+
+ Cursor cursor = tableViewHeader.getCursor();
+ if (headerIndex != -1
+ && columnsResizable) {
+ Bounds headerBounds = getHeaderBounds(headerIndex);
+ TableView.Column column = tableView.getColumns().get(headerIndex);
+
+ if (!column.isRelative()
+ && x > headerBounds.x + headerBounds.width - RESIZE_HANDLE_SIZE) {
+ cursor = Cursor.RESIZE_EAST;
+ }
+ }
+
+ Mouse.setCursor(cursor);
+ }
+ }
+
+ return consumed;
+ }
+
+ @Override
+ public void mouseOut(Component component) {
+ super.mouseOut(component);
+
+ if (pressedHeaderIndex != -1) {
+ repaintComponent(getHeaderBounds(pressedHeaderIndex));
+ pressedHeaderIndex = -1;
+ }
+ }
+
+ @Override
+ public boolean mouseDown(Component component, Mouse.Button button, int x, int y) {
+ boolean consumed = super.mouseDown(component, button, x, y);
+
+ TableViewHeader tableViewHeader = (TableViewHeader)getComponent();
+ TableView tableView = tableViewHeader.getTableView();
+
+ if (tableView != null) {
+ int headerIndex = getHeaderAt(x);
+
+ if (headerIndex != -1) {
+ Bounds headerBounds = getHeaderBounds(headerIndex);
+ TableView.Column column = tableView.getColumns().get(headerIndex);
+
+ if (columnsResizable
+ && !column.isRelative()
+ && x > headerBounds.x + headerBounds.width - RESIZE_HANDLE_SIZE) {
+ // Begin drag
+ Display display = tableViewHeader.getDisplay();
+ Point headerCoordinates = tableViewHeader.mapPointToAncestor(display,
+ headerBounds.x, 0);
+ ResizeHandler dragHandler = new ResizeHandler(column, headerCoordinates.x,
+ headerBounds.x + headerBounds.width - x);
+
+ display.getComponentMouseListeners().add(dragHandler);
+ display.getComponentMouseButtonListeners().add(dragHandler);
+
+ resizing = true;
+ Mouse.setCursor(Cursor.RESIZE_EAST);
+ } else if (headersPressable) {
+ pressedHeaderIndex = headerIndex;
+ repaintComponent(getHeaderBounds(pressedHeaderIndex));
+ }
+ }
+ }
+
+ return consumed;
+ }
+
+ @Override
+ public boolean mouseUp(Component component, Mouse.Button button, int x, int y) {
+ boolean consumed = super.mouseUp(component, button, x, y);
+
+ if (pressedHeaderIndex != -1) {
+ repaintComponent(getHeaderBounds(pressedHeaderIndex));
+ }
+
+ return consumed;
+ }
+
+ @Override
+ public void mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
+ TableViewHeader tableViewHeader = (TableViewHeader)getComponent();
+
+ if (pressedHeaderIndex != -1
+ && headersPressable) {
+ tableViewHeader.pressHeader(pressedHeaderIndex);
+ }
+
+ pressedHeaderIndex = -1;
+ }
+
+ // Table view header events
+ public void tableViewChanged(TableViewHeader tableViewHeader,
+ TableView previousTableView) {
+ if (previousTableView != null) {
+ previousTableView.getTableViewColumnListeners().remove(this);
+ }
+
+ TableView tableView = tableViewHeader.getTableView();
+ if (tableView != null) {
+ tableView.getTableViewColumnListeners().add(this);
+ }
+
+ invalidateComponent();
+ }
+
+ public void dataRendererChanged(TableViewHeader tableViewHeader,
+ TableViewHeader.DataRenderer previousDataRenderer) {
+ invalidateComponent();
+ }
+
+ // Table view column events
+ public void columnInserted(TableView tableView, int index) {
+ invalidateComponent();
+ }
+
+ public void columnsRemoved(TableView tableView, int index, Sequence<TableView.Column> columns) {
+ invalidateComponent();
+ }
+
+ public void columnNameChanged(TableView.Column column, String previousName) {
+ // No-op
+ }
+
+ public void columnHeaderDataChanged(TableView.Column column, Object previousHeaderData) {
+ invalidateComponent();
+ }
+
+ public void columnWidthChanged(TableView.Column column, int previousWidth, boolean previousRelative) {
+ invalidateComponent();
+ }
+
+ public void columnSortDirectionChanged(TableView.Column column, SortDirection previousSortDirection) {
+ repaintComponent();
+ }
+
+ public void columnFilterChanged(TableView.Column column, Object previousFilter) {
+ // No-op
+ }
+
+ public void columnCellRendererChanged(TableView.Column column, TableView.CellRenderer previousCellRenderer) {
+ // No-op
+ }
+}
Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/skin/terra/TerraTableViewSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/skin/terra/TerraTableViewSkin.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/skin/terra/TerraTableViewSkin.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/skin/terra/TerraTableViewSkin.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,1000 @@
+/*
+ * 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.skin.terra;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+
+import pivot.collections.ArrayList;
+import pivot.collections.List;
+import pivot.collections.Sequence;
+import pivot.util.Vote;
+import pivot.wtk.Component;
+import pivot.wtk.Dimensions;
+import pivot.wtk.Keyboard;
+import pivot.wtk.Mouse;
+import pivot.wtk.Bounds;
+import pivot.wtk.SortDirection;
+import pivot.wtk.Span;
+import pivot.wtk.TableView;
+import pivot.wtk.TableViewListener;
+import pivot.wtk.TableViewColumnListener;
+import pivot.wtk.TableViewRowListener;
+import pivot.wtk.TableViewRowStateListener;
+import pivot.wtk.TableViewSelectionDetailListener;
+import pivot.wtk.Theme;
+import pivot.wtk.skin.ComponentSkin;
+
+/**
+ * Table view skin.
+ * <p>
+ * NOTE This skin assumes a fixed renderer height.
+ * <p>
+ * TODO Add disableMouseSelection style to support the case where selection
+ * should be enabled but the caller wants to implement the management of it;
+ * e.g. changing a message's flag state in an email client.
+ *
+ * @author gbrown
+ */
+public class TerraTableViewSkin extends ComponentSkin implements TableView.Skin,
+ TableViewListener, TableViewColumnListener, TableViewRowListener,
+ TableViewRowStateListener, TableViewSelectionDetailListener {
+ private Font font;
+ private Color color;
+ private Color disabledColor;
+ private Color backgroundColor;
+ private Color selectionColor;
+ private Color selectionBackgroundColor;
+ private Color inactiveSelectionColor;
+ private Color inactiveSelectionBackgroundColor;
+ private Color highlightBackgroundColor;
+ private Color alternateRowColor;
+ private Color gridColor;
+ private boolean showHorizontalGridLines;
+ private boolean showVerticalGridLines;
+ private boolean showHighlight;
+ private boolean includeTrailingVerticalGridLine;
+
+ private int highlightedIndex = -1;
+
+ public TerraTableViewSkin() {
+ TerraTheme theme = (TerraTheme)Theme.getTheme();
+ font = theme.getFont();
+ color = theme.getColor(1);
+ disabledColor = theme.getColor(7);
+ backgroundColor = theme.getColor(4);
+ selectionColor = theme.getColor(4);
+ selectionBackgroundColor = theme.getColor(19);
+ inactiveSelectionColor = theme.getColor(1);
+ inactiveSelectionBackgroundColor = theme.getColor(9);
+ highlightBackgroundColor = theme.getColor(10);
+ alternateRowColor = theme.getColor(11);
+ gridColor = theme.getColor(11);
+ showHorizontalGridLines = true;
+ showVerticalGridLines = true;
+ showHighlight = true;
+ includeTrailingVerticalGridLine = false;
+ }
+
+ public void install(Component component) {
+ super.install(component);
+
+ TableView tableView = (TableView)component;
+ tableView.getTableViewListeners().add(this);
+ tableView.getTableViewColumnListeners().add(this);
+ tableView.getTableViewRowListeners().add(this);
+ tableView.getTableViewRowStateListeners().add(this);
+ tableView.getTableViewSelectionDetailListeners().add(this);
+ }
+
+ public void uninstall() {
+ TableView tableView = (TableView)getComponent();
+ tableView.getTableViewListeners().remove(this);
+ tableView.getTableViewColumnListeners().remove(this);
+ tableView.getTableViewRowListeners().remove(this);
+ tableView.getTableViewRowStateListeners().remove(this);
+ tableView.getTableViewSelectionDetailListeners().remove(this);
+
+ super.uninstall();
+ }
+
+ public int getPreferredWidth(int height) {
+ int preferredWidth = 0;
+
+ TableView tableView = (TableView)getComponent();
+ TableView.ColumnSequence columns = tableView.getColumns();
+
+ int n = columns.getLength();
+ int gridLineStop = includeTrailingVerticalGridLine ? n : n - 1;
+
+ for (int i = 0; i < n; i++) {
+ TableView.Column column = columns.get(i);
+
+ if (!column.isRelative()) {
+ preferredWidth += column.getWidth();
+
+ // Include space for vertical gridlines; even if we are
+ // not painting them, the header does
+ if (i < gridLineStop) {
+ preferredWidth++;
+ }
+ }
+ }
+
+ return preferredWidth;
+ }
+
+ public int getPreferredHeight(int width) {
+ int preferredHeight = 0;
+
+ TableView tableView = (TableView)getComponent();
+
+ int n = tableView.getTableData().getLength();
+ preferredHeight = getRowHeight() * n;
+
+ return preferredHeight;
+ }
+
+ public Dimensions getPreferredSize() {
+ return new Dimensions(getPreferredWidth(-1), getPreferredHeight(-1));
+ }
+
+ public void layout() {
+ // No-op
+ }
+
+ @SuppressWarnings("unchecked")
+ public void paint(Graphics2D graphics) {
+ TableView tableView = (TableView)getComponent();
+ List<Object> tableData = (List<Object>)tableView.getTableData();
+ TableView.ColumnSequence columns = tableView.getColumns();
+
+ int width = getWidth();
+ int height = getHeight();
+
+ int rowHeight = getRowHeight();
+ Sequence<Integer> columnWidths = getColumnWidths();
+
+ // Paint the background
+ graphics.setPaint(backgroundColor);
+ graphics.fillRect(0, 0, width, height);
+
+ // Paint the list contents
+ int rowStart = 0;
+ int rowEnd = tableData.getLength() - 1;
+
+ // Ensure that we only paint items that are visible
+ Rectangle clipBounds = graphics.getClipBounds();
+ if (clipBounds != null) {
+ rowStart = Math.max(rowStart, (int)Math.floor(clipBounds.y
+ / (double)rowHeight));
+ rowEnd = Math.min(rowEnd, (int)Math.ceil((clipBounds.y
+ + clipBounds.height) / (double)rowHeight) - 1);
+ }
+
+ int rowY = rowStart * rowHeight;
+
+ for (int rowIndex = rowStart; rowIndex <= rowEnd; rowIndex++) {
+ Object rowData = tableData.get(rowIndex);
+ boolean rowHighlighted = (rowIndex == highlightedIndex
+ && Mouse.getButtons() == 0
+ && tableView.getSelectMode() != TableView.SelectMode.NONE);
+ boolean rowSelected = tableView.isIndexSelected(rowIndex);
+ boolean rowDisabled = tableView.isRowDisabled(rowIndex);
+
+ Color rowBackgroundColor = null;
+
+ if (rowSelected) {
+ rowBackgroundColor = (tableView.isFocused())
+ ? this.selectionBackgroundColor : inactiveSelectionBackgroundColor;
+ } else {
+ if (rowHighlighted && showHighlight && !rowDisabled) {
+ rowBackgroundColor = highlightBackgroundColor;
+ } else {
+ if (alternateRowColor != null
+ && rowIndex % 2 > 0) {
+ rowBackgroundColor = alternateRowColor;
+ }
+ }
+ }
+
+ if (rowBackgroundColor != null) {
+ graphics.setPaint(rowBackgroundColor);
+ graphics.fillRect(0, rowY, width, rowHeight);
+ }
+
+ // Paint the cells
+ int cellX = 0;
+
+ for (int columnIndex = 0, columnCount = columns.getLength();
+ columnIndex < columnCount; columnIndex++) {
+ TableView.Column column = columns.get(columnIndex);
+
+ TableView.CellRenderer cellRenderer = column.getCellRenderer();
+
+ int columnWidth = columnWidths.get(columnIndex);
+
+ Graphics2D rendererGraphics = (Graphics2D)graphics.create(cellX, rowY,
+ columnWidth, rowHeight);
+
+ cellRenderer.render(rowData, tableView, column, rowSelected,
+ rowHighlighted, rowDisabled);
+ cellRenderer.setSize(columnWidth, rowHeight - 1);
+ cellRenderer.paint(rendererGraphics);
+
+ rendererGraphics.dispose();
+
+ cellX += columnWidth + 1;
+ }
+
+ rowY += rowHeight;
+ }
+
+ // Set the grid stroke and color
+ graphics.setStroke(new BasicStroke());
+ graphics.setPaint(gridColor);
+
+ // Paint the vertical grid lines
+ if (showVerticalGridLines) {
+ int gridX = 0;
+
+ for (int columnIndex = 0, columnCount = columns.getLength();
+ columnIndex < columnCount; columnIndex++) {
+ gridX += columnWidths.get(columnIndex);
+
+ graphics.drawLine(gridX, 0, gridX, height);
+ gridX++;
+ }
+ }
+
+ // Paint the horizontal grid line
+ if (showHorizontalGridLines) {
+ for (int rowIndex = rowStart; rowIndex <= rowEnd; rowIndex++) {
+ if (rowIndex > 0) {
+ int gridY = rowIndex * rowHeight;
+ graphics.drawLine(0, gridY, width, gridY);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the table row height, which is determined as the maximum
+ * preferred height of all cell renderers.
+ *
+ * @return
+ * The height of one table row.
+ */
+ public int getRowHeight() {
+ int rowHeight = 0;
+
+ TableView tableView = (TableView)getComponent();
+ TableView.ColumnSequence columns = tableView.getColumns();
+
+ for (int i = 0, n = columns.getLength(); i < n; i++) {
+ TableView.Column column = columns.get(i);
+ TableView.CellRenderer cellRenderer = column.getCellRenderer();
+
+ rowHeight = Math.max(rowHeight, cellRenderer.getPreferredHeight(-1));
+ }
+
+ rowHeight++;
+
+ return rowHeight;
+ }
+
+ /**
+ * Returns the column widths for this table.
+ *
+ * @return
+ * The widths of all columns based on the current overall width.
+ */
+ public Sequence<Integer> getColumnWidths() {
+ TableView tableView = (TableView)getComponent();
+
+ return getColumnWidths(tableView.getColumns(), getWidth());
+ }
+
+ /**
+ * Returns the column widths, determined by applying relative size values
+ * to the available width.
+ *
+ * TODO Cache these values and recalculate only when size changes.
+ *
+ * @param columns
+ * The columns whose widths are to be determined.
+ *
+ * @param width
+ * The total available width for the columns.
+ *
+ * @return
+ * The widths of all columns based on the current overall width.
+ */
+ public static Sequence<Integer> getColumnWidths(TableView.ColumnSequence columns, int width) {
+ int fixedWidth = 0;
+ int relativeWidth = 0;
+
+ int n = columns.getLength();
+
+ for (int i = 0; i < n; i++) {
+ TableView.Column column = columns.get(i);
+
+ if (column.isRelative()) {
+ relativeWidth += column.getWidth();
+ } else {
+ fixedWidth += column.getWidth();
+ }
+ }
+
+ fixedWidth += n - 1;
+ int variableWidth = Math.max(width - fixedWidth, 0);
+
+ ArrayList<Integer> columnWidths = new ArrayList<Integer>(columns.getLength());
+
+ for (int i = 0; i < n; i++) {
+ TableView.Column column = columns.get(i);
+
+ if (column.isRelative()) {
+ int columnWidth = (int)Math.round((double)(column.getWidth()
+ * variableWidth) / (double)relativeWidth);
+ columnWidths.add(columnWidth);
+ } else {
+ columnWidths.add(column.getWidth());
+ }
+ }
+
+ return columnWidths;
+ }
+
+ // Table view skin methods
+ @SuppressWarnings("unchecked")
+ public int getRowAt(int y) {
+ if (y < 0) {
+ throw new IllegalArgumentException("y is negative");
+ }
+
+ TableView tableView = (TableView)getComponent();
+ List<Object> tableData = (List<Object>)tableView.getTableData();
+
+ int rowIndex = (y / getRowHeight());
+
+ if (rowIndex >= tableData.getLength()) {
+ rowIndex = -1;
+ }
+
+ return rowIndex;
+ }
+
+ public int getColumnAt(int x) {
+ if (x < 0) {
+ throw new IllegalArgumentException("x is negative");
+ }
+
+ Sequence<Integer> columnWidths = getColumnWidths();
+
+ int i = 0;
+ int n = columnWidths.getLength();
+ int columnX = 0;
+ while (i < n
+ && x > columnX) {
+ columnX += (columnWidths.get(i) + 1);
+ i++;
+ }
+
+ int columnIndex = -1;
+
+ if (x <= columnX) {
+ columnIndex = i - 1;
+ }
+
+ return columnIndex;
+ }
+
+ public Bounds getRowBounds(int rowIndex) {
+ int rowHeight = getRowHeight();
+ return new Bounds(0, rowIndex * rowHeight, getWidth(), rowHeight);
+ }
+
+ public Bounds getColumnBounds(int columnIndex) {
+ Sequence<Integer> columnWidths = getColumnWidths();
+ int columnCount = columnWidths.getLength();
+
+ if (columnIndex < 0
+ || columnIndex >= columnCount) {
+ throw new IndexOutOfBoundsException("Column index out of bounds: " +
+ columnIndex);
+ }
+
+ int columnX = 0;
+ for (int i = 0; i < columnIndex; i++) {
+ columnX += (columnWidths.get(i) + 1);
+ }
+
+ return new Bounds(columnX, 0, columnWidths.get(columnIndex), getHeight());
+ }
+
+ @SuppressWarnings("unchecked")
+ public Bounds getCellBounds(int rowIndex, int columnIndex) {
+ TableView tableView = (TableView)getComponent();
+ List<Object> tableData = (List<Object>)tableView.getTableData();
+ Sequence<Integer> columnWidths = getColumnWidths();
+
+ if (rowIndex < 0
+ || rowIndex >= tableData.getLength()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ if (columnIndex < 0
+ || columnIndex >= columnWidths.getLength()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+
+ int rowHeight = getRowHeight();
+
+ int cellX = 0;
+ for (int i = 0; i < columnIndex; i++) {
+ cellX += (columnWidths.get(i) + 1);
+ }
+
+ return new Bounds(cellX, rowIndex * rowHeight,
+ columnWidths.get(columnIndex), rowHeight);
+ }
+
+ @Override
+ public boolean isFocusable() {
+ TableView tableView = (TableView)getComponent();
+ return (tableView.getSelectMode() != TableView.SelectMode.NONE);
+ }
+
+ public Font getFont() {
+ return font;
+ }
+
+ public void setFont(Font font) {
+ if (font == null) {
+ throw new IllegalArgumentException("font is null.");
+ }
+
+ this.font = font;
+ invalidateComponent();
+ }
+
+ public final void setFont(String font) {
+ if (font == null) {
+ throw new IllegalArgumentException("font is null.");
+ }
+
+ setFont(Font.decode(font));
+ }
+
+ public Color getColor() {
+ return color;
+ }
+
+ public void setColor(Color color) {
+ if (color == null) {
+ throw new IllegalArgumentException("color is null.");
+ }
+
+ this.color = color;
+ repaintComponent();
+ }
+
+ public final void setColor(String color) {
+ if (color == null) {
+ throw new IllegalArgumentException("color is null.");
+ }
+
+ setColor(decodeColor(color));
+ }
+
+ public Color getDisabledColor() {
+ return disabledColor;
+ }
+
+ public void setDisabledColor(Color disabledColor) {
+ if (disabledColor == null) {
+ throw new IllegalArgumentException("disabledColor is null.");
+ }
+
+ this.disabledColor = disabledColor;
+ repaintComponent();
+ }
+
+ public final void setDisabledColor(String disabledColor) {
+ if (disabledColor == null) {
+ throw new IllegalArgumentException("disabledColor is null.");
+ }
+
+ setDisabledColor(decodeColor(disabledColor));
+ }
+
+ public Color getBackgroundColor() {
+ return backgroundColor;
+ }
+
+ public void setBackgroundColor(Color backgroundColor) {
+ if (backgroundColor == null) {
+ throw new IllegalArgumentException("backgroundColor is null.");
+ }
+
+ this.backgroundColor = backgroundColor;
+ repaintComponent();
+ }
+
+ public final void setBackgroundColor(String backgroundColor) {
+ if (backgroundColor == null) {
+ throw new IllegalArgumentException("backgroundColor is null.");
+ }
+
+ setBackgroundColor(decodeColor(backgroundColor));
+ }
+
+
+ public Color getSelectionColor() {
+ return selectionColor;
+ }
+
+ public void setSelectionColor(Color selectionColor) {
+ if (selectionColor == null) {
+ throw new IllegalArgumentException("selectionColor is null.");
+ }
+
+ this.selectionColor = selectionColor;
+ repaintComponent();
+ }
+
+ public final void setSelectionColor(String selectionColor) {
+ if (selectionColor == null) {
+ throw new IllegalArgumentException("selectionColor is null.");
+ }
+
+ setSelectionColor(decodeColor(selectionColor));
+ }
+
+ public Color getSelectionBackgroundColor() {
+ return selectionBackgroundColor;
+ }
+
+ public void setSelectionBackgroundColor(Color selectionBackgroundColor) {
+ if (selectionBackgroundColor == null) {
+ throw new IllegalArgumentException("selectionBackgroundColor is null.");
+ }
+
+ this.selectionBackgroundColor = selectionBackgroundColor;
+ repaintComponent();
+ }
+
+ public final void setSelectionBackgroundColor(String selectionBackgroundColor) {
+ if (selectionBackgroundColor == null) {
+ throw new IllegalArgumentException("selectionBackgroundColor is null.");
+ }
+
+ setSelectionBackgroundColor(decodeColor(selectionBackgroundColor));
+ }
+
+ public Color getInactiveSelectionColor() {
+ return inactiveSelectionColor;
+ }
+
+ public void setInactiveSelectionColor(Color inactiveSelectionColor) {
+ if (inactiveSelectionColor == null) {
+ throw new IllegalArgumentException("inactiveSelectionColor is null.");
+ }
+
+ this.inactiveSelectionColor = inactiveSelectionColor;
+ repaintComponent();
+ }
+
+ public final void setInactiveSelectionColor(String inactiveSelectionColor) {
+ if (inactiveSelectionColor == null) {
+ throw new IllegalArgumentException("inactiveSelectionColor is null.");
+ }
+
+ setInactiveSelectionColor(decodeColor(inactiveSelectionColor));
+ }
+
+ public Color getInactiveSelectionBackgroundColor() {
+ return inactiveSelectionBackgroundColor;
+ }
+
+ public void setInactiveSelectionBackgroundColor(Color inactiveSelectionBackgroundColor) {
+ if (inactiveSelectionBackgroundColor == null) {
+ throw new IllegalArgumentException("inactiveSelectionBackgroundColor is null.");
+ }
+
+ this.inactiveSelectionBackgroundColor = inactiveSelectionBackgroundColor;
+ repaintComponent();
+ }
+
+ public final void setInactiveSelectionBackgroundColor(String inactiveSelectionBackgroundColor) {
+ if (inactiveSelectionBackgroundColor == null) {
+ throw new IllegalArgumentException("inactiveSelectionBackgroundColor is null.");
+ }
+
+ setInactiveSelectionBackgroundColor(decodeColor(inactiveSelectionBackgroundColor));
+ }
+
+ public Color getHighlightBackgroundColor() {
+ return highlightBackgroundColor;
+ }
+
+ public void setHighlightBackgroundColor(Color highlightBackgroundColor) {
+ if (highlightBackgroundColor == null) {
+ throw new IllegalArgumentException("highlightBackgroundColor is null.");
+ }
+
+ this.highlightBackgroundColor = highlightBackgroundColor;
+ repaintComponent();
+ }
+
+ public final void setHighlightBackgroundColor(String highlightBackgroundColor) {
+ if (highlightBackgroundColor == null) {
+ throw new IllegalArgumentException("highlightBackgroundColor is null.");
+ }
+
+ setHighlightBackgroundColor(decodeColor(highlightBackgroundColor));
+ }
+
+ public Color getAlternateRowColor() {
+ return alternateRowColor;
+ }
+
+ public void setAlternateRowColor(Color alternateRowColor) {
+ this.alternateRowColor = alternateRowColor;
+ repaintComponent();
+ }
+
+ public final void setAlternateRowColor(String alternateRowColor) {
+ if (alternateRowColor == null) {
+ throw new IllegalArgumentException("alternateRowColor is null.");
+ }
+
+ setAlternateRowColor(decodeColor(alternateRowColor));
+ }
+
+ public Color getGridColor() {
+ return gridColor;
+ }
+
+ public void setGridColor(Color gridColor) {
+ if (gridColor == null) {
+ throw new IllegalArgumentException("gridColor is null.");
+ }
+
+ this.gridColor = gridColor;
+ repaintComponent();
+ }
+
+ public final void setGridColor(String gridColor) {
+ if (gridColor == null) {
+ throw new IllegalArgumentException("gridColor is null.");
+ }
+
+ setGridColor(decodeColor(gridColor));
+ }
+
+ public boolean getShowHorizontalGridLines() {
+ return showHorizontalGridLines;
+ }
+
+ public void setShowHorizontalGridLines(boolean showHorizontalGridLines) {
+ this.showHorizontalGridLines = showHorizontalGridLines;
+ repaintComponent();
+ }
+
+ public boolean getShowVerticalGridLines() {
+ return showVerticalGridLines;
+ }
+
+ public void setShowVerticalGridLines(boolean showVerticalGridLines) {
+ this.showVerticalGridLines = showVerticalGridLines;
+ repaintComponent();
+ }
+
+ public boolean getShowHighlight() {
+ return showHighlight;
+ }
+
+ public void setShowHighlight(boolean showHighlight) {
+ this.showHighlight = showHighlight;
+ repaintComponent();
+ }
+
+ public boolean getIncludeTrailingVerticalGridLine() {
+ return includeTrailingVerticalGridLine;
+ }
+
+ public void setIncludeTrailingVerticalGridLine(boolean includeTrailingVerticalGridLine) {
+ this.includeTrailingVerticalGridLine = includeTrailingVerticalGridLine;
+ invalidateComponent();
+ }
+
+ @Override
+ public boolean mouseMove(Component component, int x, int y) {
+ boolean consumed = super.mouseMove(component, x, y);
+
+ int previousHighlightedIndex = this.highlightedIndex;
+ highlightedIndex = getRowAt(y);
+
+ if (previousHighlightedIndex != highlightedIndex) {
+ if (previousHighlightedIndex != -1) {
+ repaintComponent(getRowBounds(previousHighlightedIndex));
+ }
+
+ if (highlightedIndex != -1) {
+ repaintComponent(getRowBounds(highlightedIndex));
+ }
+ }
+
+ return consumed;
+ }
+
+ @Override
+ public void mouseOut(Component component) {
+ super.mouseOut(component);
+
+ if (highlightedIndex != -1) {
+ Bounds rowBounds = getRowBounds(highlightedIndex);
+ repaintComponent(rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height);
+ }
+
+ highlightedIndex = -1;
+ }
+
+ @Override
+ public void mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
+ TableView tableView = (TableView)getComponent();
+
+ if (isFocusable()) {
+ tableView.requestFocus();
+ }
+
+ int rowIndex = getRowAt(y);
+
+ if (rowIndex >= 0
+ && !tableView.isRowDisabled(rowIndex)) {
+ TableView.SelectMode selectMode = tableView.getSelectMode();
+
+ if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)
+ && selectMode == TableView.SelectMode.MULTI) {
+ // Select the range
+ int startIndex = tableView.getFirstSelectedIndex();
+ int endIndex = tableView.getLastSelectedIndex();
+ Span selectedRange = (rowIndex > startIndex) ?
+ new Span(startIndex, rowIndex) : new Span(rowIndex, endIndex);
+
+ ArrayList<Span> selectedRanges = new ArrayList<Span>();
+ Sequence<Integer> disabledIndexes = tableView.getDisabledIndexes();
+ if (disabledIndexes.getLength() == 0) {
+ selectedRanges.add(selectedRange);
+ } else {
+ // TODO Split the range by the disabled indexes; for now,
+ // just return
+ return;
+ }
+
+ tableView.setSelectedRanges(selectedRanges);
+ } else if (Keyboard.isPressed(Keyboard.Modifier.CTRL)
+ && selectMode == TableView.SelectMode.MULTI) {
+ // Toggle the item's selection state
+ if (tableView.isIndexSelected(rowIndex)) {
+ tableView.removeSelectedIndex(rowIndex);
+ } else {
+ tableView.addSelectedIndex(rowIndex);
+ }
+ } else {
+ // Select the row
+ if ((selectMode == TableView.SelectMode.SINGLE
+ && tableView.getSelectedIndex() != rowIndex)
+ || selectMode == TableView.SelectMode.MULTI) {
+ tableView.setSelectedIndex(rowIndex);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean mouseWheel(Component component, Mouse.ScrollType scrollType, int scrollAmount,
+ int wheelRotation, int x, int y) {
+ if (highlightedIndex != -1) {
+ Bounds rowBounds = getRowBounds(highlightedIndex);
+ repaintComponent(rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height);
+ }
+
+ highlightedIndex = -1;
+
+ return super.mouseWheel(component, scrollType, scrollAmount, wheelRotation, x, y);
+ }
+
+ @Override
+ public boolean keyPressed(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
+ boolean consumed = super.keyPressed(component, keyCode, keyLocation);
+
+ TableView tableView = (TableView)getComponent();
+
+ switch (keyCode) {
+ case Keyboard.KeyCode.UP: {
+ int index = tableView.getFirstSelectedIndex();
+
+ do {
+ index--;
+ } while (index >= 0
+ && tableView.isRowDisabled(index));
+
+ if (index >= 0) {
+ if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)
+ && tableView.getSelectMode() == TableView.SelectMode.MULTI) {
+ tableView.addSelectedIndex(index);
+ } else {
+ tableView.setSelectedIndex(index);
+ }
+
+ tableView.scrollAreaToVisible(getRowBounds(index));
+ }
+
+ consumed = true;
+ break;
+ }
+
+ case Keyboard.KeyCode.DOWN: {
+ int index = tableView.getLastSelectedIndex();
+ int count = tableView.getTableData().getLength();
+
+ do {
+ index++;
+ } while (index < count
+ && tableView.isRowDisabled(index));
+
+ if (index < count) {
+ if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)
+ && tableView.getSelectMode() == TableView.SelectMode.MULTI) {
+ tableView.addSelectedIndex(index);
+ } else {
+ tableView.setSelectedIndex(index);
+ }
+
+ tableView.scrollAreaToVisible(getRowBounds(index));
+ }
+
+ consumed = true;
+ break;
+ }
+ }
+
+ // Clear the highlight
+ if (highlightedIndex != -1) {
+ highlightedIndex = -1;
+ repaintComponent(getRowBounds(highlightedIndex));
+ }
+
+ return consumed;
+ }
+
+ // Component state events
+ @Override
+ public void enabledChanged(Component component) {
+ super.enabledChanged(component);
+
+ repaintComponent();
+ }
+
+ @Override
+ public void focusedChanged(Component component, boolean temporary) {
+ super.focusedChanged(component, temporary);
+
+ repaintComponent();
+ }
+
+ // Table view events
+ public void tableDataChanged(TableView tableView, List<?> previousTableData) {
+ invalidateComponent();
+ }
+
+ public void selectModeChanged(TableView tableView, TableView.SelectMode previousSelectMode) {
+ // No-op
+ }
+
+ // Table view column events
+ public void columnInserted(TableView tableView, int index) {
+ invalidateComponent();
+ }
+
+ public void columnsRemoved(TableView tableView, int index, Sequence<TableView.Column> columns) {
+ invalidateComponent();
+ }
+
+ public void columnNameChanged(TableView.Column column, String previousName) {
+ invalidateComponent();
+ }
+
+ public void columnHeaderDataChanged(TableView.Column column, Object previousHeaderData) {
+ // No-op
+ }
+
+ public void columnWidthChanged(TableView.Column column, int previousWidth, boolean previousRelative) {
+ invalidateComponent();
+ }
+
+ public void columnSortDirectionChanged(TableView.Column column, SortDirection previousSortDirection) {
+ // No-op
+ // TODO Repaint; paint a "selection" color for the sorted column
+ }
+
+ public void columnFilterChanged(TableView.Column column, Object previousFilter) {
+ // No-op
+ }
+
+ public void columnCellRendererChanged(TableView.Column column, TableView.CellRenderer previousCellRenderer) {
+ invalidateComponent();
+ }
+
+ // Table view row events
+ public void rowInserted(TableView tableView, int index) {
+ invalidateComponent();
+ }
+
+ public void rowsRemoved(TableView tableView, int index, int count) {
+ invalidateComponent();
+ }
+
+ public void rowUpdated(TableView tableView, int index) {
+ repaintComponent(getRowBounds(index));
+ }
+
+ public void rowsSorted(TableView tableView) {
+ repaintComponent();
+ }
+
+ // Table view row state events
+
+ public Vote previewRowDisabledChange(TableView tableView, int index) {
+ return Vote.APPROVE;
+ }
+
+ public void rowDisabledChangeVetoed(TableView tableView, int index, Vote reason) {
+ // No-op
+ }
+
+ public void rowDisabledChanged(TableView tableView, int index) {
+ repaintComponent(getRowBounds(index));
+ }
+
+ // Table view selection detail events
+ public void selectedRangeAdded(TableView tableView, int rangeStart, int rangeEnd) {
+ // Repaint the area containing the added selection
+ int rowHeight = getRowHeight();
+ repaintComponent(0, rangeStart * rowHeight,
+ getWidth(), (rangeEnd - rangeStart + 1) * rowHeight);
+ }
+
+ public void selectedRangeRemoved(TableView tableView, int rangeStart, int rangeEnd) {
+ // Repaint the area containing the removed selection
+ int rowHeight = getRowHeight();
+ repaintComponent(0, rangeStart * rowHeight,
+ getWidth(), (rangeEnd - rangeStart + 1) * rowHeight);
+ }
+
+ public void selectionReset(TableView tableView, Sequence<Span> previousSelectedRanges) {
+ // TODO Repaint only the area that changed (intersection of previous
+ // and new selection)
+ repaintComponent();
+ }
+}