weka.gui.ETable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of weka-stable Show documentation
Show all versions of weka-stable Show documentation
The Waikato Environment for Knowledge Analysis (WEKA), a machine
learning workbench. This is the stable version. Apart from bugfixes, this version
does not receive any other updates.
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package weka.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
/**
* A better-looking table than JTable. In particular, on Mac OS this looks more
* like a Cocoa table than the default Aqua LAF manages.
*
* @author Elliott Hughes
*/
public class ETable extends JTable {
/**
* For serialization
*/
private static final long serialVersionUID = -3028630226368293049L;
private final Color MAC_FOCUSED_SELECTED_CELL_HORIZONTAL_LINE_COLOR =
new Color(0x7daaea);
private final Color MAC_UNFOCUSED_SELECTED_CELL_HORIZONTAL_LINE_COLOR =
new Color(0xe0e0e0);
private final Color MAC_UNFOCUSED_SELECTED_CELL_BACKGROUND_COLOR = new Color(
0xc0c0c0);
private final Color MAC_FOCUSED_UNSELECTED_VERTICAL_LINE_COLOR = new Color(
0xd9d9d9);
private final Color MAC_FOCUSED_SELECTED_VERTICAL_LINE_COLOR = new Color(
0x346dbe);
private final Color MAC_UNFOCUSED_UNSELECTED_VERTICAL_LINE_COLOR = new Color(
0xd9d9d9);
private final Color MAC_UNFOCUSED_SELECTED_VERTICAL_LINE_COLOR = new Color(
0xacacac);
private final Color MAC_OS_ALTERNATE_ROW_COLOR = new Color(0.92f, 0.95f,
0.99f);
public ETable() {
// Although it's the JTable default, most systems' tables don't draw a grid
// by default.
// Worse, it's not easy (or possible?) for us to take over grid painting
// ourselves for those LAFs (Metal, for example) that do paint grids.
// The Aqua and GTK LAFs ignore the grid settings anyway, so this causes no
// change there.
setShowGrid(false);
// Tighten the cells up, and enable the manual painting of the vertical grid
// lines.
setIntercellSpacing(new Dimension());
// Table column re-ordering is too badly implemented to enable.
getTableHeader().setReorderingAllowed(false);
if (System.getProperty("os.name").contains("Mac")) {
// Work-around for Apple 4352937.
JLabel.class.cast(getTableHeader().getDefaultRenderer())
.setHorizontalAlignment(SwingConstants.LEADING);
// Use an iTunes-style vertical-only "grid".
setShowHorizontalLines(false);
setShowVerticalLines(true);
}
}
/**
* Paints empty rows too, after letting the UI delegate do its painting.
*/
@Override
public void paint(Graphics g) {
super.paint(g);
paintEmptyRows(g);
}
/**
* Paints the backgrounds of the implied empty rows when the table model is
* insufficient to fill all the visible area available to us. We don't involve
* cell renderers, because we have no data.
*/
protected void paintEmptyRows(Graphics g) {
final int rowCount = getRowCount();
final Rectangle clip = g.getClipBounds();
final int height = clip.y + clip.height;
if (rowCount * rowHeight < height) {
for (int i = rowCount; i <= height / rowHeight; ++i) {
g.setColor(colorForRow(i));
g.fillRect(clip.x, i * rowHeight, clip.width, rowHeight);
}
// Mac OS' Aqua LAF never draws vertical grid lines, so we have to draw
// them ourselves.
if (System.getProperty("os.name").contains("Mac")
&& getShowVerticalLines()) {
g.setColor(MAC_UNFOCUSED_UNSELECTED_VERTICAL_LINE_COLOR);
TableColumnModel columnModel = getColumnModel();
int x = 0;
for (int i = 0; i < columnModel.getColumnCount(); ++i) {
TableColumn column = columnModel.getColumn(i);
x += column.getWidth();
g.drawLine(x - 1, rowCount * rowHeight, x - 1, height);
}
}
}
}
/**
* Changes the behavior of a table in a JScrollPane to be more like the
* behavior of JList, which expands to fill the available space. JTable
* normally restricts its size to just what's needed by its model.
*/
@Override
public boolean getScrollableTracksViewportHeight() {
if (getParent() instanceof JViewport) {
JViewport parent = (JViewport) getParent();
return (parent.getHeight() > getPreferredSize().height);
}
return false;
}
/**
* Returns the appropriate background color for the given row.
*/
protected Color colorForRow(int row) {
return (row % 2 == 0) ? alternateRowColor() : getBackground();
}
private Color alternateRowColor() {
return UIManager.getLookAndFeel().getClass().getName().contains("GTK") ? Color.WHITE
: MAC_OS_ALTERNATE_ROW_COLOR;
}
/**
* Shades alternate rows in different colors.
*/
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row,
int column) {
Component c = super.prepareRenderer(renderer, row, column);
boolean focused = hasFocus();
boolean selected = isCellSelected(row, column);
if (selected) {
if (System.getProperty("os.name").contains("Mac") && focused == false) {
// Native Mac OS renders the selection differently if the table doesn't
// have the focus.
// The Mac OS LAF doesn't imitate this for us.
c.setBackground(MAC_UNFOCUSED_SELECTED_CELL_BACKGROUND_COLOR);
c.setForeground(UIManager.getColor("Table.foreground"));
} else {
c.setBackground(UIManager.getColor("Table.selectionBackground"));
c.setForeground(UIManager.getColor("Table.selectionForeground"));
}
} else {
// Outside of selected rows, we want to alternate the background color.
c.setBackground(colorForRow(row));
c.setForeground(UIManager.getColor("Table.foreground"));
}
if (c instanceof JComponent) {
JComponent jc = (JComponent) c;
// The Java 6 GTK LAF JCheckBox doesn't paint its background by default.
// Sun 5043225 says this is the intended behavior, though presumably not
// when it's being used as a table cell renderer.
if (UIManager.getLookAndFeel().getClass().getName().contains("GTK")
&& c instanceof JCheckBox) {
jc.setOpaque(true);
}
if (getCellSelectionEnabled() == false && isEditing() == false) {
if (System.getProperty("os.name").contains("Mac")) {
// Native Mac OS doesn't draw a border on the selected cell.
// It does however draw a horizontal line under the whole row, and a
// vertical line separating each column.
fixMacOsCellRendererBorder(jc, selected, focused);
} else {
// FIXME: doesn't Windows have row-wide selection focus?
// Hide the cell focus.
jc.setBorder(null);
}
}
initToolTip(jc, row, column);
}
return c;
}
private void fixMacOsCellRendererBorder(JComponent renderer,
boolean selected, boolean focused) {
Border border;
if (selected) {
border =
BorderFactory.createMatteBorder(0, 0, 1, 0,
focused ? MAC_FOCUSED_SELECTED_CELL_HORIZONTAL_LINE_COLOR
: MAC_UNFOCUSED_SELECTED_CELL_HORIZONTAL_LINE_COLOR);
} else {
border = BorderFactory.createEmptyBorder(0, 0, 1, 0);
}
// Mac OS' Aqua LAF never draws vertical grid lines, so we have to draw them
// ourselves.
if (getShowVerticalLines()) {
Color verticalLineColor;
if (focused) {
verticalLineColor =
selected ? MAC_FOCUSED_SELECTED_VERTICAL_LINE_COLOR
: MAC_FOCUSED_UNSELECTED_VERTICAL_LINE_COLOR;
} else {
verticalLineColor =
selected ? MAC_UNFOCUSED_SELECTED_VERTICAL_LINE_COLOR
: MAC_UNFOCUSED_UNSELECTED_VERTICAL_LINE_COLOR;
}
Border verticalBorder =
BorderFactory.createMatteBorder(0, 0, 0, 1, verticalLineColor);
border = BorderFactory.createCompoundBorder(border, verticalBorder);
}
renderer.setBorder(border);
}
/**
* Sets the component's tool tip if the component is being rendered smaller
* than its preferred size. This means that all users automatically get tool
* tips on truncated text fields that show them the full value.
*/
private void initToolTip(JComponent c, int row, int column) {
String toolTipText = null;
if (c.getPreferredSize().width > getCellRect(row, column, false).width) {
toolTipText = getValueAt(row, column).toString();
}
c.setToolTipText(toolTipText);
}
/**
* Places tool tips over the cell they correspond to. MS Outlook does this,
* and it works rather well. Swing will automatically override our suggested
* location if it would cause the tool tip to go off the display.
*/
@Override
public Point getToolTipLocation(MouseEvent e) {
// After a tool tip has been displayed for a cell that has a tool tip, cells
// without tool tips will show an empty tool tip until the tool tip mode
// times out (or the table has a global default tool tip).
// (ToolTipManager.checkForTipChange considers a non-null result from
// getToolTipText *or* a non-null result from getToolTipLocation as implying
// that the tool tip should be displayed. This seems like a bug, but that's
// the way it is.)
if (getToolTipText(e) == null) {
return null;
}
final int row = rowAtPoint(e.getPoint());
final int column = columnAtPoint(e.getPoint());
if (row == -1 || column == -1) {
return null;
}
return getCellRect(row, column, false).getLocation();
}
/**
* Improve the appearance of of a table in a JScrollPane on Mac OS, where
* there's otherwise an unsightly hole.
*/
@Override
protected void configureEnclosingScrollPane() {
super.configureEnclosingScrollPane();
if (System.getProperty("os.name").contains("Mac") == false) {
return;
}
Container p = getParent();
if (p instanceof JViewport) {
Container gp = p.getParent();
if (gp instanceof JScrollPane) {
JScrollPane scrollPane = (JScrollPane) gp;
// Make certain we are the viewPort's view and not, for
// example, the rowHeaderView of the scrollPane -
// an implementor of fixed columns might do this.
JViewport viewport = scrollPane.getViewport();
if (viewport == null || viewport.getView() != this) {
return;
}
// JTable copy & paste above this point; our code below.
// Put a dummy header in the upper-right corner.
final Component renderer =
new JTableHeader().getDefaultRenderer()
.getTableCellRendererComponent(null, "", false, false, -1, 0);
JPanel panel = new JPanel(new BorderLayout());
panel.add(renderer, BorderLayout.CENTER);
scrollPane.setCorner(JScrollPane.UPPER_RIGHT_CORNER, panel);
}
}
}
}