All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.assertj.swing.jide.grids.driver.AbstractComboBoxDriver Maven / Gradle / Ivy

/**
 * 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.
 *
 * Copyright 2012-2015 the original author or authors.
 */
package org.assertj.swing.jide.grids.driver;

import static javax.swing.text.DefaultEditorKit.deletePrevCharAction;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.util.Preconditions.checkNotNull;
import static org.assertj.swing.edt.GuiActionRunner.execute;

import java.awt.Component;

import javax.swing.AbstractButton;
import javax.swing.ComboBoxEditor;
import javax.swing.JComponent;

import org.assertj.core.description.Description;
import org.assertj.core.util.Strings;
import org.assertj.swing.annotation.RunsInEDT;
import org.assertj.swing.core.KeyPressInfo;
import org.assertj.swing.driver.JComponentDriver;
import org.assertj.swing.exception.LocationUnavailableException;
import org.assertj.swing.query.ComponentEnabledQuery;

import com.jidesoft.combobox.AbstractComboBox;
import com.jidesoft.combobox.PopupPanel;
import com.jidesoft.converter.ConverterContext;
import com.jidesoft.converter.ObjectConverter;

/**
 * A driver for an {@link com.jidesoft.combobox.AbstractComboBox}. This is loosely based
 * on the {@link org.assertj.swing.driver.JComboBoxDriver} class so a familiar usage pattern
 * will exist between Swing combo boxes and JIDE combo boxes.
 *
 * @author Peter Murray
 */
public class AbstractComboBoxDriver extends JComponentDriver {

  private static final String EDITABLE_PROPERTY = "editable";

  private static final String SELECTED_INDEX_PROPERTY = "selectedIndex";

  protected AbstractComboBoxCellReader _cellReader;

  public AbstractComboBoxDriver(org.assertj.swing.core.Robot robot) {
    super(robot);
    cellReader(new AbstractComboBoxCellReader());
  }

  /**
   * Deletes the text of the {@code AbstractComboBox}.
   *
   * @param comboBox the target {@code AbstractComboBox}.
   * @throws IllegalStateException if the {@code AbstractComboBox} is disabled.
   * @throws IllegalStateException if the {@code AbstractComboBox} is not showing on the screen.
   */
  @RunsInEDT
  public void deleteText(AbstractComboBox comboBox) {
    selectAllText(comboBox);
    Component editor = accessibleEditorOf(comboBox);
    if (!(editor instanceof JComponent)) {
      return;
    }
    focus(editor);
    invokeAction((JComponent) editor, deletePrevCharAction);
  }

  /**
   * Simulates a user entering the specified text in the {@link com.jidesoft.combobox.AbstractComboBox},
   * replacing any text. This action is executed only if the {@link
   * com.jidesoft.combobox.AbstractComboBox} is editable.
   *
   * @param comboBox the target AbstractComboBox.
   * @param text the text to enter.
   * @throws IllegalStateException if the AbstractComboBox is disabled.
   * @throws IllegalStateException if the AbstractComboBox is not showing on the
   *           screen.
   * @throws IllegalStateException if the AbstractComboBox is not editable.
   */
  @RunsInEDT
  public void replaceText(AbstractComboBox comboBox, String text) {
    checkNotNull(text);
    if (text.isEmpty()) {
      deleteText(comboBox);
    } else {
      selectAllText(comboBox);
      enterText(comboBox, text);
    }
  }

  /**
   * Simulates a user selecting the text in the {@link com.jidesoft.combobox.AbstractComboBox}. This
   * action is executed only if the {@link com.jidesoft.combobox.AbstractComboBox} is editable.
   *
   * @param comboBox the target AbstractComboBox.
   * @throws IllegalStateException if the AbstractComboBox is disabled.
   * @throws IllegalStateException if the AbstractComboBox is not showing on the
   *           screen.
   * @throws IllegalStateException if the AbstractComboBox is not editable.
   */
  @RunsInEDT
  public void selectAllText(AbstractComboBox comboBox) {
    Component editor = accessibleEditorOf(comboBox);
    if (!(editor instanceof JComponent)) {
      return;
    }
    focus(editor);
    invokeAction((JComponent) editor, javax.swing.text.DefaultEditorKit.selectAllAction);
  }

  @RunsInEDT
  private static Component accessibleEditorOf(final AbstractComboBox comboBox) {
    return org.assertj.swing.edt.GuiActionRunner.execute(() -> {
      AbstractComboBoxAccessibleEditorValidator.validateEditorIsAccessible(comboBox);
      return comboBox.getEditor().getEditorComponent();
    });
  }

  /**
   * We need to cater for the editor component if we are editable. When typing into an
   * editable AbstractComboBox, the focus will move to the Editor, not the ComboBox
   * instance which will result in AssertJ-Swing failing on waiting for focus to move to the
   * comboBox.
   *
   * @param c the target component.
   * @param keyCodes one or more codes of the keys to press.
   */
  @Override
  @RunsInEDT
  public void pressAndReleaseKeys(Component c, int... keyCodes) {
    Component interactionComponent = getInteractionComponent(c);
    robot.moveMouse(interactionComponent);
    robot.focus(interactionComponent);
    super.pressAndReleaseKeys(interactionComponent, keyCodes);
  }

  /**
   * We need to cater for the editor component if we are editable. When typing into an
   * editable AbstractComboBox, the focus will move to the Editor, not the ComboBox
   * instance which will result in AssertJ-Swing failing on waiting for focus to move to the
   * comboBox.
   *
   * @param c the target component.
   * @param keyPressInfo specifies the key and modifiers to press.
   */
  @Override
  @RunsInEDT
  public void pressAndReleaseKey(Component c, KeyPressInfo keyPressInfo) {
    Component interactionComponent = getInteractionComponent(c);
    super.pressAndReleaseKey(interactionComponent,
                             keyPressInfo.keyCode(),
                             keyPressInfo.modifiers());
  }

  /**
   * We need to cater for the editor component if we are editable. When typing into an
   * editable AbstractComboBox, the focus will move to the Editor, not the ComboBox
   * instance which will result in AssertJ-Swing failing on waiting for focus to move to the
   * comboBox.
   *
   * @param c the target component.
   * @param keyCode the code of the key to press.
   * @param modifiers the given modifiers.
   */
  @Override
  @RunsInEDT
  public void pressAndReleaseKey(Component c, int keyCode, int[] modifiers) {
    Component interactionComponent = getInteractionComponent(c);
    super.pressAndReleaseKey(interactionComponent, keyCode, modifiers);
  }

  @Override
  @RunsInEDT
  public void pressKey(Component c, int keyCode) {
    Component interactionComponent = getInteractionComponent(c);
    super.pressKey(interactionComponent, keyCode);
  }

  @Override
  public void pressKeyWhileRunning(Component c, int keyCode, Runnable runnable) {
    Component interactionComponent = getInteractionComponent(c);
    super.pressKeyWhileRunning(interactionComponent, keyCode, runnable);
  }

  /**
   * Simulates a user releasing the given key on the {@link Component}.
   *
   * @param c the target component.
   * @param keyCode the code of the key to release.
   * @throws IllegalArgumentException if the given code is not a valid key code.
   * @throws IllegalStateException if the Component is disabled, or is not
   *           showing on the screen.
   * @see java.awt.event.KeyEvent
   */
  @Override
  @RunsInEDT
  public void releaseKey(Component c, int keyCode) {
    Component interactionComponent = getInteractionComponent(c);
    super.releaseKey(interactionComponent, keyCode);
  }

  public void requireSelection(AbstractComboBox comboBox, String value) {
    String selectedItem = _cellReader.valueAsText(comboBox, comboBox.getSelectedItem());
    if (selectedItem == null) {
      fail(org.assertj.core.util.Strings.concat("[",
                                                selectedIndexProperty(comboBox),
                                                "] No selection"));
    }
    assertThat(selectedItem).as(selectedIndexProperty(comboBox)).isEqualTo(value);
  }

  /**
   * Simulates a user entering the specified text in the {@link com.jidesoft.combobox.AbstractComboBox}.
   * This action is executed only if the {@link com.jidesoft.combobox.AbstractComboBox} is editable.
   *
   * @param comboBox the target AbstractComboBox.
   * @param text the text to enter.
   * @throws IllegalStateException if the AbstractComboBox is disabled.
   * @throws IllegalStateException if the AbstractComboBox is not editable or
   *           is not showing on the screen.
   */
  @RunsInEDT
  public void enterText(AbstractComboBox comboBox, String text) {
    inEdtValidateEditorIsAccessible(comboBox);
    focus(comboBox);
    robot.enterText(text);
  }

  @RunsInEDT
  private static void inEdtValidateEditorIsAccessible(final AbstractComboBox comboBox) {
    org.assertj.swing.edt.GuiActionRunner.execute(() -> AbstractComboBoxAccessibleEditorValidator.validateEditorIsAccessible(comboBox));
  }

  /**
   * Asserts that the given {@link com.jidesoft.combobox.AbstractComboBox} is editable.
   *
   * @param comboBox the target AbstractComboBox.
   * @throws AssertionError if the AbstractComboBox is not editable.
   */
  @RunsInEDT
  public void requireEditable(final AbstractComboBox comboBox) {
    assertEditable(comboBox, true);
  }

  /**
   * Asserts that the given {@link com.jidesoft.combobox.AbstractComboBox} is not editable.
   *
   * @param comboBox the given AbstractComboBox.
   * @throws AssertionError if the AbstractComboBox is editable.
   */
  @RunsInEDT
  public void requireNotEditable(AbstractComboBox comboBox) {
    assertEditable(comboBox, false);
  }

  @RunsInEDT
  public void requireNotEnabled(AbstractComboBox comboBox) {
    assertEnabled(comboBox, false);
  }

  @RunsInEDT
  public void requireEnabled(AbstractComboBox comboBox) {
    assertEnabled(comboBox, true);
  }

  @RunsInEDT
  private void assertEditable(AbstractComboBox comboBox, boolean expected) {
    assertThat(AbstractComboBoxEditableQuery.isEditable(comboBox))
                                                                  .as(editableProperty(comboBox)).isEqualTo(expected);
  }

  @RunsInEDT
  private void assertEnabled(AbstractComboBox comboBox, boolean expected) {
    assertThat(ComponentEnabledQuery.isEnabled(comboBox))
                                                         .as(editableProperty(comboBox)).isEqualTo(expected);
  }

  @RunsInEDT
  private static Description editableProperty(AbstractComboBox comboBox) {
    return propertyName(comboBox, EDITABLE_PROPERTY);
  }

  public String getStringRepresentation(AbstractComboBox box, Object o) {
    ObjectConverter converter = box.getConverter();
    ConverterContext context = box.getConverterContext();

    if (converter == null) {
      return String.valueOf(o);
    }
    return converter.toString(o, context);
  }

  AbstractComboBox.EditorComponent getEditor(final AbstractComboBox comboBox) {
    return execute(() -> (AbstractComboBox.EditorComponent) comboBox.getEditor());
  }

  public String getEditorText(final AbstractComboBox comboBox) {
    return execute(() -> ((AbstractComboBox.EditorComponent) comboBox.getEditor()).getText());
  }

  public void requireEditorText(final AbstractComboBox comboBox, String requiredText) {
    robot.waitForIdle();
    String currentText = getEditorText(comboBox);
    assertThat(currentText).as("Editor Text Value").isEqualTo(requiredText);
  }

  @RunsInEDT
  PopupPanel showPopup(final AbstractComboBox comboBox) {
    return comboBox.getPopupPanel();
  }

  public void requireNoSelection(AbstractComboBox comboBox) {
    Object selectedItem = comboBox.getSelectedItem();
    if (selectedItem != null) {
      fail(Strings.concat("No selection is required, but selection value is, ",
                          selectedItem));
    }
  }

  @RunsInEDT
  void dropDownVisibleThroughComponent(AbstractComboBox comboBox, boolean visible) {
    if (visible) {
      if (!comboBox.isPopupVisible()) {
        clickPopupButton(comboBox);
      }
    } else {
      if (comboBox.isPopupVisible()) {
        comboBox.hidePopup();
      }
    }
    robot.waitForIdle();
  }

  int validateIndex(AbstractComboBox comboBox, int index) {
    int itemCount = size(comboBox);
    if (index >= 0 && index < itemCount) {
      return index;
    }
    throw new LocationUnavailableException(Strings.concat("Item index (",
                                                          java.lang.String.valueOf(index),
                                                          ") should be between [0] and [",
                                                          String.valueOf(itemCount - 1),
                                                          "] (inclusive)"));
  }

  /**
   * Converts an object that may be present in the ComboBox into a String representation.
   *
   * @param comboBox The comboBox to convert the object for.
   * @param o The object to convert into a String.
   * @return The object passed in converted in to a String so that it would appear as it
   *         would to a user selecting the value in the ComboBox.
   */
  protected String convertElementToString(AbstractComboBox comboBox, Object o) {
    if (o == null) {
      return null;
    }

    if (o instanceof String) {
      return (String) o;
    }

    ObjectConverter converter = comboBox.getConverter();
    if (converter != null) {
      return converter.toString(o, comboBox.getConverterContext());
    }
    return o.toString();
  }

  protected boolean isDropDownVisible(AbstractComboBox comboBox) {
    return comboBox.isPopupVisible();
  }

  protected int size(AbstractComboBox comboBox) {
    return comboBox.getModel().getSize();
  }

  protected Object itemAt(AbstractComboBox comboBox, int index) {
    return comboBox.getModel().getElementAt(index);
  }

  protected boolean areEqual(AbstractComboBox combo, Object o1, Object o2) {
    String s1 = getStringRepresentation(combo, o1);
    String s2 = getStringRepresentation(combo, o2);

    return s1.equals(s2);
  }

  protected String selectedIndexProperty(AbstractComboBox comboBox) {
    return propertyName(comboBox, SELECTED_INDEX_PROPERTY).toString();
  }

  /**
   * Updates the implementation of {@link AbstractComboBoxCellReader} to use
   * when comparing internal values of a {@link com.jidesoft.combobox.ListComboBox} and the values expected
   * in a test.
   *
   * @param newCellReader the new ListComboBoxCellValueReader to use.
   * @throws IllegalArgumentException if newCellReader is null.
   */
  public void cellReader(AbstractComboBoxCellReader newCellReader) {
    // TODO move this back to CommonConditions.validateCellReader()
    // validateCellReader(newCellReader);
    if (newCellReader == null) {
      throw new NullPointerException("Cell reader should not be null");
    }
    _cellReader = newCellReader;
  }

  @RunsInEDT
  public void clickPopupButton(final AbstractComboBox comboBox) {
    AbstractButton button = comboBox.getPopupButton();
    robot.moveMouse(button);
    robot.click(button);
    robot.waitForIdle();
  }

  /**
   * Obtains the component that the user will interact with, which could be the actual
   * combo box, or the editor component, depending upon the state of the combo box.
   *
   * @param c The Component to obtain the interactive component from.
   * @return The {@link java.awt.Component} that the user is to interact with.
   */
  @RunsInEDT
  protected Component getInteractionComponent(Component c) {
    if (c instanceof AbstractComboBox) {
      AbstractComboBox combo = (AbstractComboBox) c;
      if (combo.isEditable()) {
        ComboBoxEditor editor = combo.getEditor();
        return editor.getEditorComponent();
      }
    }
    return c;
  }

  @RunsInEDT
  public void requirePopupVisible(final AbstractComboBox target, boolean visible) {
    Boolean isVisible = execute(() -> target.isPopupVisible());
    assertThat(isVisible).as("Popup Visibility").isEqualTo(visible);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy