package com.vistatec.ocelot.tm.gui.match; import java.awt.Component; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.event.KeyEvent; import javax.swing.JComponent; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.event.ChangeEvent; import javax.swing.event.TableModelEvent; import com.vistatec.ocelot.segment.model.SegmentVariant; /** * Table used in TM panels. It is configured in order to react to the following * keystrokes: * <ul> * <li>ALT+Arrow UP: moves selection to the previous row;</li> * <li>ALT+Arrow DOWN: moves selection to the next row;</li> * </ul> * Moreover it resizes its rows height by fitting them to their contents each * time table data or table margins change. */ public class TmTable extends JTable { /** Serial version UID. */ private static final long serialVersionUID = -8088882927665970088L; /** * Constructor. */ public TmTable() { init(); } /** * Initializes the table. */ private void init() { getSelectionModel().setSelectionMode( ListSelectionModel.SINGLE_SELECTION); setDefaultRenderer(SegmentVariant.class, new SegmentVariantCellRenderer()); setDefaultRenderer(String.class, new AlternateRowsColorRenderer()); setDefaultRenderer(Integer.class, new AlternateRowsColorRenderer()); setTableHeader(null); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.ALT_MASK), "selectPreviousRow"); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put( KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.ALT_MASK), "selectNextRow"); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( KeyStroke.getKeyStroke("DOWN"), "none"); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( KeyStroke.getKeyStroke("UP"), "none"); getModel().addTableModelListener(this); getColumnModel().addColumnModelListener(this); } /** * Updates the rows height in order to fit their content. */ private void updateRowHeights() { if (getColumnModel().getColumnCount() != getModel().getColumnCount()) { // We haven't finished building the column model, so there's no // point in calculating // the row height yet. return; } if (getRowCount() > 0) { FontMetrics fontMetrics = getFontMetrics(getFont()); for (int row = 0; row < getRowCount(); row++) { int rowHeight = fontMetrics.getHeight(); for (int col = 0; col < getColumnCount(); col++) { rowHeight = getPreferredHeightForCell(row, col, rowHeight); } setRowHeight(row, rowHeight); } } } /** * Gets the preferred renderer height for the cell identified by row and column parameters. * @param row the row index * @param column the column index * @param previousHeight the previous preferred height * @return the preferred height for this cell. */ private int getPreferredHeightForCell(int row, int column, int previousHeight) { Object value = getModel().getValueAt(row, column); Component comp = getCellRenderer(row, column) .getTableCellRendererComponent(this, value, true, true, row, column); comp.setFont(getFont()); FontMetrics metrics = getFontMetrics(getFont()); comp.setSize(new Dimension(getColumnModel().getColumn(column) .getWidth(), metrics.getHeight())); return Math.max(previousHeight, comp.getPreferredSize().height); } /* * (non-Javadoc) * @see javax.swing.JTable#tableChanged(javax.swing.event.TableModelEvent) */ @Override public void tableChanged(TableModelEvent e) { super.tableChanged(e); updateRowHeights(); } /* * (non-Javadoc) * @see javax.swing.JTable#columnMarginChanged(javax.swing.event.ChangeEvent) */ @Override public void columnMarginChanged(ChangeEvent e) { super.columnMarginChanged(e); updateRowHeights(); } }