/* * Copyright (C) 2014 The Android Open Source Project * * 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. */ package com.android.tools.idea.tests.gui.framework.fixture.layout; import com.android.tools.idea.tests.gui.framework.fixture.MessageDialogFixture; import com.intellij.android.designer.model.RadViewComponent; import com.intellij.android.designer.propertyTable.AttributeProperty; import com.intellij.designer.model.Property; import com.intellij.designer.propertyTable.RadPropertyTable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.ThrowableComputable; import org.fest.swing.core.MouseButton; import org.fest.swing.core.Robot; import org.fest.swing.core.matcher.JTextComponentMatcher; import org.fest.swing.data.TableCell; import org.fest.swing.driver.ComponentDriver; import org.fest.swing.driver.JTableDriver; import org.fest.swing.edt.GuiActionRunner; import org.fest.swing.edt.GuiTask; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.table.TableModel; import javax.swing.text.JTextComponent; import java.awt.event.KeyEvent; import static com.android.tools.idea.tests.gui.framework.GuiTests.waitUntilFound; import static com.android.tools.idea.tests.gui.framework.GuiTests.waitUntilGone; import static org.fest.assertions.Assertions.assertThat; import static org.junit.Assert.*; /** * Fixture representing a property in the property sheet */ public class PropertyFixture { @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final Robot myRobot; @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) private final PropertySheetFixture myPropertySheetFixture; private final Property myProperty; private final LayoutEditorComponentFixture myComponent; public PropertyFixture(@NotNull Robot robot, @NotNull PropertySheetFixture propertySheetFixture, @NotNull LayoutEditorComponentFixture component, @NotNull Property property) { myRobot = robot; myPropertySheetFixture = propertySheetFixture; myComponent = component; myProperty = property; } /** * Requires the property display name to be the given name */ public PropertyFixture requireDisplayName(@NotNull String name) throws Exception { assertEquals(name, myProperty.getName()); return this; } /** * Requires the property value to be the given value */ public PropertyFixture requireValue(@NotNull String value) throws Exception { assertEquals(value, getValue()); return this; } /** * Reads the current value from the property */ @SuppressWarnings("unchecked") @NotNull public String getValue() throws Exception { /* TODO: Read via the UI property widget instead This should do the trick, but still needs some timing debugging: TableCell cell = findTableCell(true); assertNotNull(cell); JTableDriver tableDriver = new JTableDriver(myRobot); String value = tableDriver.value(getTable(), cell); return value == null ? "<null>" : value; */ return ApplicationManager.getApplication().runReadAction(new ThrowableComputable<String,Exception>() { @Override public String compute() throws Exception { Object value = myProperty.getValue(myComponent.getComponent()); return value == null ? "<null>" : value.toString(); } }); } public void requireXmlValue(@Nullable String expectedValue) { assertThat(myProperty).isInstanceOf(AttributeProperty.class); AttributeProperty attributeProperty = (AttributeProperty)myProperty; RadViewComponent component = myComponent.getComponent(); String namespace = attributeProperty.getNamespace(component, false); String value = component.getTag().getAttributeValue(attributeProperty.getName(), namespace); assertEquals(expectedValue, value); } @Nullable private TableCell findTableCell(boolean requireExists) { RadPropertyTable table = getTable(); TableModel model = table.getModel(); int rowCount = model.getRowCount(); int columnCount = model.getColumnCount(); for (int row = 0; row < rowCount; row++) { for (int column = 0; column < columnCount; column++) { Object valueAt = model.getValueAt(row, column); if (valueAt == myProperty) { return TableCell.row(row).column(1); } } } if (requireExists) { fail("Could not find property " + myProperty + " in the property table!"); } return null; } private RadPropertyTable getTable() { return myPropertySheetFixture.getPropertyTablePanel().getPropertyTable(); } /** Types in the given value into the property */ @SuppressWarnings("unchecked") public void enterValue(@NotNull String value) { enterValue(value, null); } /** Types in the given value into the property, and checks that the value is rejected */ @SuppressWarnings("unchecked") public void enterInvalidValue(@NotNull String value, @NotNull String expectedError) { enterValue(value, expectedError); } private void enterValue(@NotNull final String value, @Nullable String expectedError) { RadPropertyTable table = getTable(); TableCell cell = findTableCell(true); assertNotNull(cell); final ComponentDriver componentDriver = new ComponentDriver(myRobot); JTableDriver tableDriver = new JTableDriver(myRobot); // Can't use startCellEditing; doesn't support the subclasses in the designer property sheet //tableDriver.startCellEditing(table, cell); tableDriver.click(table, cell, MouseButton.LEFT_BUTTON, 1); final JTextComponent field = waitUntilFound(myRobot, table, JTextComponentMatcher.any()); componentDriver.focusAndWaitForFocusGain(field); GuiActionRunner.execute(new GuiTask() { @Override protected void executeInEDT() throws Throwable { field.selectAll(); // workaround: when mouse clicking the focus listener doesn't kick in on some Linux window managers } }); myRobot.waitForIdle(); myRobot.enterText(value); componentDriver.pressAndReleaseKeys(field, KeyEvent.VK_ENTER); if (expectedError == null) { // Ensure that after entering the text, the property is committed and exists text editing waitUntilGone(myRobot, table, JTextComponentMatcher.any()); } else { MessageDialogFixture dialog = MessageDialogFixture.findByTitle(myRobot, "Invalid Input"); String message = dialog.getMessage(); assertTrue("Message should contain " + expectedError + " but was " + message, message.contains(expectedError)); dialog.clickOk(); componentDriver.pressAndReleaseKeys(field, KeyEvent.VK_ESCAPE); } } }