001 /* 002 * Created on Sep 10, 2007 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 @2007-2010 the original author or authors. 015 */ 016 package org.fest.swing.fixture; 017 018 import static org.fest.swing.core.MouseButton.LEFT_BUTTON; 019 import static org.fest.swing.core.MouseButton.RIGHT_BUTTON; 020 021 import java.awt.Component; 022 import java.util.regex.Pattern; 023 024 import javax.swing.JTable; 025 026 import org.fest.swing.cell.JTableCellReader; 027 import org.fest.swing.cell.JTableCellWriter; 028 import org.fest.swing.core.MouseButton; 029 import org.fest.swing.core.MouseClickInfo; 030 import org.fest.swing.data.TableCell; 031 import org.fest.swing.driver.JTableDriver; 032 import org.fest.swing.exception.ActionFailedException; 033 import org.fest.swing.exception.ComponentLookupException; 034 035 /** 036 * Understands functional testing of single cells in <code>{@link JTable}</code>s: 037 * <ul> 038 * <li>user input simulation</li> 039 * <li>state verification</li> 040 * <li>property value query</li> 041 * </ul> 042 * <p> 043 * Example: 044 * <pre> 045 * // import static org.fest.swing.data.TableCell.row; 046 * {@link JTableCellFixture} cell = dialog.{@link JTableFixture table}("records").cell({@link TableCell#row(int) row}(3).column(0)); 047 * cell.select().showPopupMenu(); 048 * </pre> 049 * </p> 050 * 051 * @author Alex Ruiz 052 * @author Yvonne Wang 053 * 054 * @see TableCell 055 */ 056 public class JTableCellFixture implements ItemFixture { 057 058 private final JTableFixture table; 059 private final TableCell cell; 060 061 /** 062 * Creates a new <code>{@link JTableCellFixture}</code>. 063 * @param table handles the <code>JTable</code> containing the cell in this fixture. 064 * @param cell row and column indices of the table cell to be managed by this fixture. 065 * @throws NullPointerException if <code>table</code> is <code>null</code>. 066 * @throws NullPointerException if <code>cell</code> is <code>null</code>. 067 */ 068 protected JTableCellFixture(JTableFixture table, TableCell cell) { 069 validateNotNull(table); 070 validateNotNull(cell); 071 this.table = table; 072 this.cell = cell; 073 } 074 075 private void validateNotNull(JTableFixture newTable) { 076 if (newTable == null) throw new NullPointerException("The JTableFixture should not be null"); 077 } 078 079 private void validateNotNull(TableCell newCell) { 080 if (newCell == null) throw new NullPointerException("The TableCell should not be null"); 081 } 082 083 JTableFixture table() { return table; } 084 TableCell cell() { return cell; } 085 086 /** 087 * Simulates a user selecting this fixture's table cell. 088 * @return this fixture. 089 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 090 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 091 */ 092 public JTableCellFixture select() { 093 table.selectCell(cell); 094 return this; 095 } 096 097 /** 098 * Simulates a user clicking this fixture's table cell. 099 * @return this fixture. 100 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 101 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 102 */ 103 public JTableCellFixture click() { 104 table.click(cell, LEFT_BUTTON); 105 return this; 106 } 107 108 /** 109 * Simulates a user clicking this fixture's table cell. 110 * @param mouseClickInfo specifies the button to click and the times the button should be clicked. 111 * @return this fixture. 112 * @throws NullPointerException if the given <code>MouseClickInfo</code> is <code>null</code>. 113 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 114 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 115 */ 116 public JTableCellFixture click(MouseClickInfo mouseClickInfo) { 117 table.click(cell, mouseClickInfo); 118 return this; 119 } 120 121 /** 122 * Simulates a user double-clicking this fixture's table cell. 123 * @return this fixture. 124 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 125 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 126 */ 127 public JTableCellFixture doubleClick() { 128 return click(LEFT_BUTTON, 2); 129 } 130 131 /** 132 * Simulates a user right-clicking this fixture's table cell. 133 * @return this fixture. 134 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 135 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 136 */ 137 public JTableCellFixture rightClick() { 138 return click(RIGHT_BUTTON); 139 } 140 141 /** 142 * Simulates a user clicking a cell in this fixture's table cell once, using the specified mouse button. 143 * @param button the mouse button to use. 144 * @return this fixture. 145 * @throws NullPointerException if the given <code>MouseButton</code> is <code>null</code>. 146 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 147 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 148 */ 149 public JTableCellFixture click(MouseButton button) { 150 table.click(cell, button); 151 return this; 152 } 153 154 private JTableCellFixture click(MouseButton button, int times) { 155 table.click(cell, button, times); 156 return this; 157 } 158 159 /** 160 * Starts editing this fixture's table cell. This method should be called <strong>before</strong> manipulating the 161 * <code>{@link Component}</code> returned by <code>{@link #editor()}</code>. 162 * <p> 163 * This method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that 164 * created this fixture. 165 * </p> 166 * @return this fixture. 167 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 168 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 169 * @throws IllegalStateException if this cell is not editable. 170 * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds. 171 * @throws ActionFailedException if this writer is unable to handle the underlying cell editor. 172 * @see JTableFixture#cellWriter(JTableCellWriter) 173 * @see JTableCellWriter 174 * @see #editor() 175 */ 176 public JTableCellFixture startEditing() { 177 driver().startCellEditing(target(), cell); 178 return this; 179 } 180 181 /** 182 * Stops editing this fixture's table cell. This method should be called <strong>after</strong> manipulating the 183 * <code>{@link Component}</code> returned by <code>{@link #editor()}</code>. 184 * <p> 185 * This method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that 186 * created this fixture. 187 * </p> 188 * @return this fixture. 189 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 190 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 191 * @throws IllegalStateException if this cell is not editable. 192 * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds. 193 * @throws ActionFailedException if this writer is unable to handle the underlying cell editor. 194 * @see JTableFixture#cellWriter(JTableCellWriter) 195 * @see JTableCellWriter 196 * @see #editor() 197 */ 198 public JTableCellFixture stopEditing() { 199 driver().stopCellEditing(target(), cell); 200 return this; 201 } 202 203 /** 204 * Cancels editing this fixture's table cell. This method should be called <strong>after</strong> manipulating the 205 * <code>{@link Component}</code> returned by <code>{@link #editor()}</code>. 206 * <p> 207 * 208 * <pre> 209 * TableCellFixture cell = table.cell(row(6).column(8)); 210 * Component editor = cell.editor(); 211 * // assume editor is a JTextField 212 * JTextComponentFixture editorFixture = new JTextComponentFixture(robot, (JTextField) editor); 213 * cell.{@link #startEditing()}; 214 * editorFixture.enterText("Hello"); 215 * // discard any entered value 216 * cell.cancelEditing(); 217 * </pre> 218 * 219 * </p> 220 * <p> 221 * This method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that 222 * created this fixture. 223 * </p> 224 * @return this fixture. 225 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 226 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 227 * @throws IllegalStateException if this cell is not editable. 228 * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds. 229 * @throws ActionFailedException if this writer is unable to handle the underlying cell editor. 230 * @see JTableFixture#cellWriter(JTableCellWriter) 231 * @see JTableCellWriter 232 * @see #editor() 233 */ 234 public JTableCellFixture cancelEditing() { 235 driver().cancelCellEditing(target(), cell); 236 return this; 237 } 238 239 /** 240 * Returns the editor of this fixture's table cell. To manipulate the editor (e.g. wrapping it with a 241 * <code>ComponentFixture</code>,) the method <code>{@link #startEditing()}</code> should be called first. To 242 * apply any changes back to the table cell, the method <code>{@link #stopEditing()}</code> should be called. This 243 * method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that created 244 * this fixture. 245 * <p> 246 * Example: 247 * 248 * <pre> 249 * TableCellFixture cell = table.cell(row(6).column(8)); 250 * Component editor = cell.editor(); 251 * // assume editor is a JTextField 252 * JTextComponentFixture editorFixture = new JTextComponentFixture(robot, (JTextField) editor); 253 * cell.{@link #startEditing()}; 254 * editorFixture.enterText("Hello"); 255 * cell.{@link #stopEditing()}; 256 * </pre> 257 * 258 * </p> 259 * @return the editor of this fixture's table cell. 260 * @see JTableFixture#cellWriter(JTableCellWriter) 261 * @see JTableCellWriter 262 */ 263 public Component editor() { 264 return driver().cellEditor(target(), cell); 265 } 266 267 /** 268 * Enters the given value to this fixture's table cell. This method starts cell edition, enters the given value and 269 * stops cell edition. To change the value of a cell, only a call to this method is necessary. If you need more 270 * flexibility, you can retrieve the cell editor with <code>{@link #editor()}</code>. 271 * <p> 272 * This method uses the <code>{@link JTableCellWriter}</code> from the <code>{@link JTableFixture}</code> that 273 * created this fixture. 274 * </p> 275 * @param value the value to enter in the cell. 276 * @return this fixture. 277 * @throws IllegalStateException if this fixture's <code>JTable</code> is disabled. 278 * @throws IllegalStateException if this fixture's <code>JTable</code> is not showing on the screen. 279 * @throws IllegalStateException if this cell is not editable. 280 * @throws IndexOutOfBoundsException if any of the indices (row and column) is out of bounds. 281 * @throws ActionFailedException if this driver's <code>JTableCellValueReader</code> is unable to enter the given 282 * value. 283 * @see JTableFixture#cellWriter(JTableCellWriter) 284 * @see JTableCellWriter 285 */ 286 public JTableCellFixture enterValue(String value) { 287 driver().enterValueInCell(target(), cell, value); 288 return this; 289 } 290 291 private JTableDriver driver() { return table.driver(); } 292 private JTable target() { return table.target; } 293 294 /** 295 * Asserts that the value of this fixture's table cell matches the given value. 296 * @param value the expected value of this fixture's table cell. It can be a regular expression. 297 * @return this fixture. 298 * @throws AssertionError if the value of this fixture's table cell does not match the expected one. 299 */ 300 public JTableCellFixture requireValue(String value) { 301 table.requireCellValue(cell, value); 302 return this; 303 } 304 305 /** 306 * Asserts that the value of this fixture's table cell matches the given regular expression pattern. 307 * @param pattern the regular expression pattern to match. 308 * @return this fixture. 309 * @throws NullPointerException if the given regular expression pattern is <code>null</code>. 310 * @throws AssertionError if the value of this fixture's table cell does not match the expected the given regular 311 * expression pattern. 312 * @since 1.2 313 */ 314 public JTableCellFixture requireValue(Pattern pattern) { 315 table.requireCellValue(cell, pattern); 316 return this; 317 } 318 319 /** 320 * Returns a fixture that verifies the font of this fixture's table cell. This method uses the 321 * <code>{@link JTableCellReader}</code> from the <code>{@link JTableFixture}</code> that created this fixture. 322 * @return a fixture that verifies the font of this fixture's table cell. 323 * @see JTableFixture#cellReader(JTableCellReader) 324 * @see JTableCellReader 325 */ 326 public FontFixture font() { 327 return table.fontAt(cell); 328 } 329 330 /** 331 * Returns a fixture that verifies the background color of this fixture's table cell. This method uses the 332 * <code>{@link JTableCellReader}</code> from the <code>{@link JTableFixture}</code> that created this fixture. 333 * @return a fixture that verifies the background color of this fixture's table cell. 334 * @see JTableFixture#cellReader(JTableCellReader) 335 * @see JTableCellReader 336 */ 337 public ColorFixture background() { 338 return table.backgroundAt(cell); 339 } 340 341 /** 342 * Returns a fixture that verifies the foreground color of this fixture's table cell. This method uses the 343 * <code>{@link JTableCellReader}</code> from the <code>{@link JTableFixture}</code> that created this fixture. 344 * @return a fixture that verifies the foreground color of this fixture's table cell. 345 * @see JTableFixture#cellReader(JTableCellReader) 346 * @see JTableCellReader 347 */ 348 public ColorFixture foreground() { 349 return table.foregroundAt(cell); 350 } 351 352 /** 353 * Returns the <code>String</code> representation of the value of this fixture's table cell. This method uses the 354 * <code>{@link JTableCellReader}</code> from the <code>{@link JTableFixture}</code> that created this fixture. 355 * @return the <code>String</code> representation of the value of this fixture's table cell. 356 * @see JTableFixture#cellReader(JTableCellReader) 357 * @see JTableCellReader 358 */ 359 public String value() { 360 return table.valueAt(cell); 361 } 362 363 /** 364 * Simulates a user dragging this fixture's table cell. 365 * @return this fixture. 366 */ 367 public JTableCellFixture drag() { 368 table.drag(cell); 369 return this; 370 } 371 372 /** 373 * Simulates a user dropping into this fixture's table cell. 374 * @return this fixture. 375 */ 376 public JTableCellFixture drop() { 377 table.drop(cell); 378 return this; 379 } 380 381 /** 382 * Shows a pop-up menu using this fixture's table cell as the invoker of the pop-up menu. 383 * @return a fixture that manages the displayed pop-up menu. 384 * @throws ComponentLookupException if a pop-up menu cannot be found. 385 */ 386 public JPopupMenuFixture showPopupMenu() { 387 return table.showPopupMenuAt(cell); 388 } 389 390 /** 391 * Asserts that this fixture's table cell is editable. 392 * @return this fixture. 393 * @throws AssertionError if this fixture's table cell is not editable. 394 */ 395 public JTableCellFixture requireEditable() { 396 table.requireEditable(cell); 397 return this; 398 } 399 400 401 /** 402 * Asserts that this fixture's table cell is not editable. 403 * @return this fixture. 404 * @throws AssertionError if this fixture's table cell is editable. 405 */ 406 public JTableCellFixture requireNotEditable() { 407 table.requireNotEditable(cell); 408 return this; 409 } 410 411 /** 412 * Returns the row index of this fixture's table cell. 413 * @return the row index of this fixture's table cell. 414 */ 415 public int row() { return cell.row; } 416 417 /** 418 * Returns the column index of this fixture's table cell. 419 * @return the column index of this fixture's table cell. 420 */ 421 public int column() { return cell.column; } 422 423 }