001    /*
002     * Created on Apr 14, 2008
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005     * in compliance with the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License
010     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011     * or implied. See the License for the specific language governing permissions and limitations under
012     * the License.
013     *
014     * Copyright @2008-2010 the original author or authors.
015     */
016    package org.fest.swing.driver;
017    
018    import static java.lang.String.valueOf;
019    import static org.fest.swing.driver.ModelValueToString.asText;
020    
021    import java.awt.*;
022    
023    import javax.swing.*;
024    
025    import org.fest.swing.annotation.RunsInCurrentThread;
026    import org.fest.swing.cell.JTableCellReader;
027    
028    /**
029     * Understands the default implementation of <code>{@link JTableCellReader}</code>.
030     *
031     * @author Yvonne Wang
032     * @author Alex Ruiz
033     */
034    public class BasicJTableCellReader implements JTableCellReader {
035    
036      private final CellRendererReader rendererReader;
037      private final BasicJComboBoxCellReader comboBoxCellReader = new BasicJComboBoxCellReader();
038    
039      /**
040       * Creates a new </code>{@link BasicJTableCellReader}</code> that uses a
041       * <code>{@link BasicCellRendererReader}</code> to read the value from the cell renderer component in a
042       * <code>JTable</code>.
043       */
044      public BasicJTableCellReader() {
045        this(new BasicCellRendererReader());
046      }
047    
048      /**
049       * Creates a new </code>{@link BasicJTableCellReader}</code>.
050       * @param reader knows how to read values from the cell renderer component in a
051       * <code>JTable</code>.
052       * @throws NullPointerException if <code>reader</code> is <code>null</code>.
053       */
054      public BasicJTableCellReader(CellRendererReader reader) {
055        if (reader == null)
056          throw new NullPointerException("CellRendererReader should not be null");
057        this.rendererReader = reader;
058      }
059    
060      /**
061       * Returns the internal value of a cell in a <code>{@link JTable}</code> as expected in a test. This method first
062       * tries to return the value displayed in the <code>JTable</code>'s cell renderer.
063       * <ul>
064       * <li>if the renderer is a <code>{@link JLabel}</code>, this method returns its text</li>
065       * <li>if the renderer is a <code>{@link JComboBox}</code>, this method returns the value of its selection as a
066       * <code>String</code></li>
067       * <li>if the renderer is a <code>{@link JCheckBox}</code>, this method returns whether it is selected or not</li>
068       * </ul>
069       * If it fails reading the cell renderer, this method will get the value from the <code>toString</code> implementation
070       * of the object stored in the <code>JTable</code>'s model at the specified indices.
071       * <p>
072       * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
073       * responsible for calling this method from the EDT.
074       * </p>
075       * @param table the given <code>JTable</code>.
076       * @param row the row index of the cell.
077       * @param column the column index of the cell.
078       * @return the internal value of a cell in a <code>JTable</code> as expected in a test.
079       */
080      @RunsInCurrentThread
081      public String valueAt(JTable table, int row, int column) {
082        Component c = cellRendererIn(table, row, column);
083        String value = (c != null) ? rendererReader.valueFrom(c) : null;
084        if (value != null) return value;
085        if (c instanceof JLabel) return ((JLabel)c).getText();
086        if (c instanceof JCheckBox) return valueOf(((JCheckBox)c).isSelected());
087        if (c instanceof JComboBox) return valueAsText((JComboBox)c);
088        return asText(table.getValueAt(row, column));
089      }
090    
091      private String valueAsText(JComboBox comboBox) {
092        int selectedIndex = comboBox.getSelectedIndex();
093        if (selectedIndex == -1) return null;
094        return comboBoxCellReader.valueAt(comboBox, selectedIndex);
095      }
096    
097      /**
098       * Returns the font of the cell renderer for the given table cell.
099       * <p>
100       * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
101       * responsible for calling this method from the EDT.
102       * </p>
103       * @param table the given <code>JTable</code>.
104       * @param row the row index of the cell.
105       * @param column the column index of the cell.
106       * @return the font of the cell renderer for the given table cell.
107       */
108      @RunsInCurrentThread
109      public Font fontAt(JTable table, int row, int column) {
110        Component c = cellRendererIn(table, row, column);
111        return c != null ? c.getFont() : null;
112      }
113    
114      /**
115       * Returns the background color of the cell renderer for the given table cell.
116       * <p>
117       * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
118       * responsible for calling this method from the EDT.
119       * </p>
120       * @param table the given <code>JTable</code>.
121       * @param row the row index of the cell.
122       * @param column the column index of the cell.
123       * @return the background color of the cell renderer for the given table cell.
124       */
125      @RunsInCurrentThread
126      public Color backgroundAt(JTable table, int row, int column) {
127        Component c = cellRendererIn(table, row, column);
128        return c != null ? c.getBackground() : null;
129      }
130    
131      /**
132       * Returns the foreground color of the cell renderer for the given table cell.
133       * <p>
134       * <b>Note:</b> This method is <b>not</b> guaranteed to be executed in the event dispatch thread (EDT.) Clients are
135       * responsible for calling this method from the EDT.
136       * </p>
137       * @param table the given <code>JTable</code>.
138       * @param row the row index of the cell.
139       * @param column the column index of the cell.
140       * @return the foreground color of the cell renderer for the given table cell.
141       */
142      @RunsInCurrentThread
143      public Color foregroundAt(JTable table, int row, int column) {
144        Component c = cellRendererIn(table, row, column);
145        return c != null ? c.getForeground() : null;
146      }
147    
148      @RunsInCurrentThread
149      private Component cellRendererIn(final JTable table, final int row, final int column) {
150        return table.prepareRenderer(table.getCellRenderer(row, column), row, column);
151      }
152    }