/* * ImportedTextureWizardTest.java 07 Oct. 2008 * * Copyright (c) 2008 Emmanuel PUYBARET / eTeks <info@eteks.com>. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ package com.eteks.sweethome3d.junit; import java.awt.Component; import java.awt.Container; import java.awt.KeyboardFocusManager; import java.awt.event.InputEvent; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.util.Arrays; import java.util.Iterator; import java.util.Locale; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JSpinner; import javax.swing.JTextField; import junit.extensions.abbot.ComponentTestFixture; import abbot.finder.AWTHierarchy; import abbot.finder.BasicFinder; import abbot.finder.ComponentSearchException; import abbot.finder.Matcher; import abbot.finder.matchers.ClassMatcher; import abbot.finder.matchers.WindowMatcher; import abbot.tester.JComponentTester; import com.eteks.sweethome3d.io.FileUserPreferences; import com.eteks.sweethome3d.model.CatalogTexture; import com.eteks.sweethome3d.model.Content; import com.eteks.sweethome3d.model.Home; import com.eteks.sweethome3d.model.LengthUnit; import com.eteks.sweethome3d.model.RecorderException; import com.eteks.sweethome3d.model.TexturesCategory; import com.eteks.sweethome3d.model.UserPreferences; import com.eteks.sweethome3d.model.Wall; import com.eteks.sweethome3d.swing.HomePane; import com.eteks.sweethome3d.swing.ImportedTextureWizardStepsPanel; import com.eteks.sweethome3d.swing.PlanComponent; import com.eteks.sweethome3d.swing.SwingViewFactory; import com.eteks.sweethome3d.swing.TextureChoiceComponent; import com.eteks.sweethome3d.swing.WallPanel; import com.eteks.sweethome3d.swing.WizardPane; import com.eteks.sweethome3d.tools.URLContent; import com.eteks.sweethome3d.viewcontroller.ContentManager; import com.eteks.sweethome3d.viewcontroller.HomeController; import com.eteks.sweethome3d.viewcontroller.ImportedTextureWizardController; import com.eteks.sweethome3d.viewcontroller.View; import com.eteks.sweethome3d.viewcontroller.ViewFactory; import com.eteks.sweethome3d.viewcontroller.WallController; /** * Tests imported texture wizard. * @author Emmanuel Puybaret */ public class ImportedTextureWizardTest extends ComponentTestFixture { public void testImportedTextureWizard() throws ComponentSearchException, InterruptedException, NoSuchFieldException, IllegalAccessException, InvocationTargetException { String language = Locale.getDefault().getLanguage(); final UserPreferences preferences = new FileUserPreferences() { @Override public boolean isActionTipIgnored(String actionKey) { return true; } }; // Ensure we use default language and centimeter unit preferences.setLanguage(language); preferences.setUnit(LengthUnit.CENTIMETER); ViewFactory viewFactory = new SwingViewFactory(); // Create a dummy content manager final URL testedImageName = BackgroundImageWizardTest.class.getResource("resources/test.png"); final ContentManager contentManager = new ContentManager() { public Content getContent(String contentName) throws RecorderException { try { // Let's consider contentName is a URL return new URLContent(new URL(contentName)); } catch (IOException ex) { fail(); return null; } } public String getPresentationName(String contentName, ContentType contentType) { return "test"; } public boolean isAcceptable(String contentName, ContentType contentType) { return true; } public String showOpenDialog(View parentView, String dialogTitle, ContentType contentType) { // Return tested model name URL return testedImageName.toString(); } public String showSaveDialog(View parentView, String dialogTitle, ContentType contentType, String name) { return null; } }; Home home = new Home(); final HomeController controller = new HomeController(home, preferences, viewFactory, contentManager); JComponent homeView = (JComponent)controller.getView(); PlanComponent planComponent = (PlanComponent)TestUtilities.findComponent( homeView, PlanComponent.class); // 1. Create a frame that displays a home view JFrame frame = new JFrame("Imported Texture Wizard Test"); frame.add(homeView); frame.pack(); // Show home plan frame showWindow(frame); JComponentTester tester = new JComponentTester(); tester.waitForIdle(); // Transfer focus to plan view planComponent.requestFocusInWindow(); tester.waitForIdle(); // Check plan view has focus assertTrue("Plan component doesn't have the focus", planComponent.isFocusOwner()); // 2. Create two wall between points (50, 50), (150, 50) and (150, 150) runAction(controller, HomePane.ActionType.CREATE_WALLS); tester.actionClick(planComponent, 50, 50); tester.actionClick(planComponent, 150, 50); tester.actionClick(planComponent, 150, 150, InputEvent.BUTTON1_MASK, 2); runAction(controller, HomePane.ActionType.SELECT); // Check two walls were created and selected assertEquals("Wrong wall count in home", 2, home.getWalls().size()); assertEquals("Wrong selected items count in home", 2, home.getSelectedItems().size()); Iterator<Wall> iterator = home.getWalls().iterator(); Wall wall1 = iterator.next(); Wall wall2 = iterator.next(); // Check walls don't use texture yet assertNull("Wrong texture on wall 1 left side", wall1.getLeftSideTexture()); assertNull("Wrong texture on wall 2 left side", wall2.getLeftSideTexture()); assertNull("Wrong texture on wall 1 right side", wall1.getRightSideTexture()); assertNull("Wrong texture on wall 2 right side", wall2.getRightSideTexture()); // 3. Edit walls JDialog attributesDialog = showWallPanel(preferences, controller, frame, tester); // Retrieve WallPanel components WallPanel wallPanel = (WallPanel)TestUtilities.findComponent( attributesDialog, WallPanel.class); JSpinner xStartSpinner = (JSpinner)TestUtilities.getField(wallPanel, "xStartSpinner"); JSpinner xEndSpinner = (JSpinner)TestUtilities.getField(wallPanel, "xEndSpinner"); TextureChoiceComponent rightSideTextureComponent = (TextureChoiceComponent)TestUtilities.getField(wallPanel, "rightSideTextureComponent"); // Check xStartSpinner and xEndSpinner panels aren't visible assertFalse("X start spinner panel is visible", xStartSpinner.getParent().isVisible()); assertFalse("X end spinner panel is visible", xEndSpinner.getParent().isVisible()); // Edit right side texture JDialog textureDialog = showTexturePanel(preferences, rightSideTextureComponent, false, attributesDialog, tester); JList availableTexturesList = (JList)new BasicFinder().find(textureDialog, new ClassMatcher(JList.class, true)); int textureCount = availableTexturesList.getModel().getSize(); CatalogTexture defaultTexture = (CatalogTexture)availableTexturesList.getSelectedValue(); // Import texture JDialog textureWizardDialog = showImportTextureWizard(preferences, frame, tester, false); // Retrieve ImportedFurnitureWizardStepsPanel components ImportedTextureWizardStepsPanel panel = (ImportedTextureWizardStepsPanel)TestUtilities.findComponent( textureWizardDialog, ImportedTextureWizardStepsPanel.class); final JButton imageChoiceOrChangeButton = (JButton)TestUtilities.getField(panel, "imageChoiceOrChangeButton"); final JTextField nameTextField = (JTextField)TestUtilities.getField(panel, "nameTextField"); JComboBox categoryComboBox = (JComboBox)TestUtilities.getField(panel, "categoryComboBox"); JSpinner widthSpinner = (JSpinner)TestUtilities.getField(panel, "widthSpinner"); JSpinner heightSpinner = (JSpinner)TestUtilities.getField(panel, "heightSpinner"); // Check current step is image tester.waitForIdle(); assertStepShowing(panel, true, false); WizardPane view = (WizardPane)TestUtilities.findComponent(textureWizardDialog, WizardPane.class); // Check wizard view next button is disabled final JButton nextFinishOptionButton = (JButton)TestUtilities.getField(view, "nextFinishOptionButton"); assertFalse("Next button is enabled", nextFinishOptionButton.isEnabled()); // 4. Choose tested image String imageChoiceOrChangeButtonText = imageChoiceOrChangeButton.getText(); tester.invokeAndWait(new Runnable() { public void run() { imageChoiceOrChangeButton.doClick(); } }); // Wait 200 ms to let time to Java to load the image Thread.sleep(200); // Check choice button text changed assertFalse("Choice button text didn't change", imageChoiceOrChangeButtonText.equals(imageChoiceOrChangeButton.getText())); // Click on next button tester.invokeAndWait(new Runnable() { public void run() { nextFinishOptionButton.doClick(); } }); // Check current step is attributes assertStepShowing(panel, false, true); // 5. Check default furniture name is the presentation name proposed by content manager assertEquals("Wrong default name", contentManager.getPresentationName(testedImageName.toString(), ContentManager.ContentType.IMAGE), nameTextField.getText()); // Check name text field has focus assertSame("Name text field doesn't have focus", nameTextField, KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner()); // Check default category is user category String userCategoryName = preferences.getLocalizedString( ImportedTextureWizardStepsPanel.class, "userCategory"); assertEquals("Wrong default category", userCategoryName, ((TexturesCategory)categoryComboBox.getSelectedItem()).getName()); // Rename texture final String textureTestName = "#@" + System.currentTimeMillis() + "@#"; tester.invokeAndWait(new Runnable() { public void run() { nameTextField.setText(textureTestName); } }); // Check next button is enabled again assertTrue("Next button isn't enabled", nextFinishOptionButton.isEnabled()); // 6. Change width with a value 5 times greater float width = (Float)widthSpinner.getValue(); float height = (Float)heightSpinner.getValue(); widthSpinner.setValue(width * 5); // Check height is 5 times greater float newWidth = (Float)widthSpinner.getValue(); float newHeight = (Float)heightSpinner.getValue(); assertEquals("width", 5 * width, newWidth); assertEquals("height", 5 * height, newHeight); tester.invokeAndWait(new Runnable() { public void run() { // Click on Finish to hide dialog box in Event Dispatch Thread nextFinishOptionButton.doClick(); } }); assertFalse("Import texture wizard still showing", textureWizardDialog.isShowing()); // Check the list of available textures has one more selected modifiable texture assertEquals("Wrong texture count in list", textureCount + 1, availableTexturesList.getModel().getSize()); assertEquals("No selected texture in list", 1, availableTexturesList.getSelectedValues().length); CatalogTexture importedTexture = (CatalogTexture)availableTexturesList.getSelectedValue(); assertNotSame("Wrong selected texture in list", defaultTexture, importedTexture); // Check the attributes of the new texture assertEquals("Wrong name", textureTestName, importedTexture.getName()); assertEquals("Wrong category", userCategoryName, importedTexture.getCategory().getName()); assertEquals("Wrong width", newWidth, importedTexture.getWidth()); assertEquals("Wrong height", newHeight, importedTexture.getHeight()); assertTrue("New texture isn't modifiable", importedTexture.isModifiable()); // 7. Click on OK in texture dialog box doClickOnOkInDialog(textureDialog, tester); // Click on OK in wall dialog box doClickOnOkInDialog(attributesDialog, tester); // Check wall attributes are modified accordingly assertNull("Wrong texture on wall 1 left side", wall1.getLeftSideTexture()); assertNull("Wrong texture on wall 2 left side", wall2.getLeftSideTexture()); assertEquals("Wrong texture on wall 1 right side", textureTestName, wall1.getRightSideTexture().getName()); assertEquals("Wrong texture on wall 2 right side", textureTestName, wall2.getRightSideTexture().getName()); // 8. Edit left side texture of first wall home.setSelectedItems(Arrays.asList(wall1)); assertEquals("Wrong selected items count in home", 1, home.getSelectedItems().size()); attributesDialog = showWallPanel(preferences, controller, frame, tester); // Retrieve WallPanel components wallPanel = (WallPanel)TestUtilities.findComponent(attributesDialog, WallPanel.class); xStartSpinner = (JSpinner)TestUtilities.getField(wallPanel, "xStartSpinner"); xEndSpinner = (JSpinner)TestUtilities.getField(wallPanel, "xEndSpinner"); TextureChoiceComponent leftSideTextureComponent = (TextureChoiceComponent)TestUtilities.getField(wallPanel, "leftSideTextureComponent"); // Check xStartSpinner and xEndSpinner panels are visible assertTrue("X start spinner panel isn't visible", xStartSpinner.getParent().isVisible()); assertTrue("X end spinner panel isn't visible", xEndSpinner.getParent().isVisible()); // Edit left side texture textureDialog = showTexturePanel(preferences, leftSideTextureComponent, true, attributesDialog, tester); availableTexturesList = (JList)new BasicFinder().find(textureDialog, new ClassMatcher(JList.class, true)); textureCount = availableTexturesList.getModel().getSize(); // Select imported texture availableTexturesList.setSelectedValue(importedTexture, true); // Modify texture textureWizardDialog = showImportTextureWizard(preferences, frame, tester, true); // Retrieve ImportedFurnitureWizardStepsPanel components panel = (ImportedTextureWizardStepsPanel)TestUtilities.findComponent( textureWizardDialog, ImportedTextureWizardStepsPanel.class); widthSpinner = (JSpinner)TestUtilities.getField(panel, "widthSpinner"); final JButton nextFinishOptionButton2 = (JButton)TestUtilities.getField( TestUtilities.findComponent(textureWizardDialog, WizardPane.class), "nextFinishOptionButton"); tester.invokeAndWait(new Runnable() { public void run() { nextFinishOptionButton2.doClick(); } }); // Change width widthSpinner.setValue((Float)widthSpinner.getValue() * 2); newWidth = (Float)widthSpinner.getValue(); tester.invokeAndWait(new Runnable() { public void run() { // Click on Finish to hide dialog box in Event Dispatch Thread nextFinishOptionButton2.doClick(); } }); tester.waitForIdle(); assertFalse("Import texture wizard still showing", textureWizardDialog.isShowing()); // Check the list of available textures has the same texture count // and a new selected texture assertEquals("Wrong texture count in list", textureCount, availableTexturesList.getModel().getSize()); assertEquals("No selected texture in list", 1, availableTexturesList.getSelectedValues().length); CatalogTexture modifiedTexture = (CatalogTexture)availableTexturesList.getSelectedValue(); assertNotSame("Wrong selected texture in list", importedTexture, modifiedTexture); // Check the attributes of the new texture assertEquals("Wrong name", textureTestName, modifiedTexture.getName()); assertEquals("Wrong category", userCategoryName, modifiedTexture.getCategory().getName()); assertEquals("Wrong width", newWidth, modifiedTexture.getWidth()); assertTrue("New texture isn't modifiable", modifiedTexture.isModifiable()); // 9. Click on OK in texture dialog box doClickOnOkInDialog(textureDialog, tester); // Click on OK in wall dialog box doClickOnOkInDialog(attributesDialog, tester); // Check wall attributes are modified accordingly assertEquals("Wrong texture on wall 1 left side", newWidth, wall1.getLeftSideTexture().getWidth()); assertNull("Wrong texture on wall 2 left side", wall2.getLeftSideTexture()); assertEquals("Wrong texture on wall 1 right side", newWidth / 2, wall1.getRightSideTexture().getWidth()); assertEquals("Wrong texture on wall 2 right side", newWidth / 2, wall2.getRightSideTexture().getWidth()); // 10. Open wall dialog a last time to delete the modified texture attributesDialog = showWallPanel(preferences, controller, frame, tester); // Retrieve WallPanel components wallPanel = (WallPanel)TestUtilities.findComponent(attributesDialog, WallPanel.class); leftSideTextureComponent = (TextureChoiceComponent)TestUtilities.getField(wallPanel, "leftSideTextureComponent"); // Edit left side texture textureDialog = showTexturePanel(preferences, leftSideTextureComponent, true, attributesDialog, tester); availableTexturesList = (JList)new BasicFinder().find(textureDialog, new ClassMatcher(JList.class, true)); textureCount = availableTexturesList.getModel().getSize(); // Select modified texture availableTexturesList.setSelectedValue(modifiedTexture, true); final JButton deleteButton = (JButton)new BasicFinder().find(textureDialog, new Matcher() { public boolean matches(Component c) { return c instanceof JButton && ((JButton)c).getText().equals(preferences.getLocalizedString( TextureChoiceComponent.class, "deleteTextureButton.text")); } }); tester.invokeAndWait(new Runnable() { public void run() { // Display confirm dialog box later in Event Dispatch Thread to avoid blocking test thread deleteButton.doClick(); } }); tester.waitForIdle(); // Wait for confirm dialog to be shown final String confirmDeleteSelectedCatalogTextureDialogTitle = preferences.getLocalizedString( TextureChoiceComponent.class, "confirmDeleteSelectedCatalogTexture.title"); tester.waitForFrameShowing(new AWTHierarchy(), confirmDeleteSelectedCatalogTextureDialogTitle); // Check dialog box is displayed JDialog confirmDialog = (JDialog)new BasicFinder().find(textureDialog, new Matcher() { public boolean matches(Component c) { return c instanceof JDialog && ((JDialog)c).getTitle().equals( confirmDeleteSelectedCatalogTextureDialogTitle); } }); assertTrue("Confirm dialog not showing", confirmDialog.isShowing()); doClickOnOkInDialog(confirmDialog, tester); tester.waitForIdle(); // Check the list of available textures has one less texture and no selected texture assertEquals("Wrong texture count in list", textureCount - 1, availableTexturesList.getModel().getSize()); assertEquals("No selected texture in list", 0, availableTexturesList.getSelectedValues().length); // Check delete button is disabled assertFalse("Delete button isn't disabled", deleteButton.isEnabled()); // Click on OK in texture dialog box doClickOnOkInDialog(textureDialog, tester); // Click on OK in wall dialog box doClickOnOkInDialog(attributesDialog, tester); // Check wall attributes didn't change assertNotNull("Wrong texture on wall 1 left side", wall1.getLeftSideTexture()); assertNull("Wrong texture on wall 2 left side", wall2.getLeftSideTexture()); assertNotNull("Wrong texture on wall 1 right side", wall1.getRightSideTexture()); assertNotNull("Wrong texture on wall 2 right side", wall2.getRightSideTexture()); } /** * Returns the dialog that displays wall attributes. */ private JDialog showWallPanel(UserPreferences preferences, final HomeController controller, JFrame parent, JComponentTester tester) throws ComponentSearchException { tester.invokeLater(new Runnable() { public void run() { // Display dialog box later in Event Dispatch Thread to avoid blocking test thread runAction(controller, HomePane.ActionType.MODIFY_WALL); } }); // Wait for wall view to be shown tester.waitForFrameShowing(new AWTHierarchy(), preferences.getLocalizedString( WallPanel.class, "wall.title")); // Check dialog box is displayed JDialog attributesDialog = (JDialog)new BasicFinder().find(parent, new ClassMatcher (JDialog.class, true)); assertTrue("Wall dialog not showing", attributesDialog.isShowing()); return attributesDialog; } /** * Returns the dialog that displays texture panel. */ private JDialog showTexturePanel(UserPreferences preferences, final TextureChoiceComponent textureComponent, boolean leftSide, Container parent, JComponentTester tester) throws ComponentSearchException { tester.invokeLater(new Runnable() { public void run() { // Display dialog box later in Event Dispatch Thread to avoid blocking test thread textureComponent.doClick(); } }); // Wait for texture panel to be shown String textureTitle = preferences.getLocalizedString( WallController.class, leftSide ? "leftSideTextureTitle" : "rightSideTextureTitle"); tester.waitForFrameShowing(new AWTHierarchy(), textureTitle); // Check texture dialog box is displayed JDialog textureDialog = (JDialog)new BasicFinder().find(parent, new WindowMatcher(textureTitle)); assertTrue("Texture dialog not showing", textureDialog.isShowing()); return textureDialog; } /** * Returns the dialog that displays texture import wizard. */ private JDialog showImportTextureWizard(final UserPreferences preferences, Container parent, JComponentTester tester, final boolean modify) throws ComponentSearchException { final JButton button = (JButton)new BasicFinder().find(parent, new Matcher() { public boolean matches(Component c) { return c instanceof JButton && ((JButton)c).getText() != null && ((JButton)c).getText().equals(preferences.getLocalizedString( TextureChoiceComponent.class, modify ? "modifyTextureButton.text" : "importTextureButton.text")); } }); tester.invokeLater(new Runnable() { public void run() { // Display dialog box later in Event Dispatch Thread to avoid blocking test thread button.doClick(); } }); // Wait for texture wizard to be shown String textureWizardTitle = preferences.getLocalizedString( ImportedTextureWizardController.class, modify ? "modifyTextureWizard.title" : "importTextureWizard.title"); tester.waitForFrameShowing(new AWTHierarchy(), textureWizardTitle); // Check texture dialog box is displayed JDialog textureDialog = (JDialog)new BasicFinder().find(parent, new WindowMatcher(textureWizardTitle)); assertTrue("Texture wizard not showing", textureDialog.isShowing()); return textureDialog; } /** * Clicks on OK in dialog to close it. */ private void doClickOnOkInDialog(JDialog dialog, JComponentTester tester) throws ComponentSearchException { final JOptionPane attributesOptionPane = (JOptionPane)TestUtilities.findComponent( dialog, JOptionPane.class); tester.invokeAndWait(new Runnable() { public void run() { // Select Ok option to hide dialog box in Event Dispatch Thread if (attributesOptionPane.getOptions() != null) { attributesOptionPane.setValue(attributesOptionPane.getOptions() [0]); } else { attributesOptionPane.setValue(JOptionPane.OK_OPTION); } } }); assertFalse("Dialog still showing", dialog.isShowing()); } /** * Runs <code>actionPerformed</code> method matching <code>actionType</code> * in <code>HomePane</code>. */ private void runAction(HomeController controller, HomePane.ActionType actionType) { ((JComponent)controller.getView()).getActionMap().get(actionType).actionPerformed(null); } /** * Asserts if each <code>panel</code> step preview component is showing or not. */ private void assertStepShowing(ImportedTextureWizardStepsPanel panel, boolean imageStepShwing, boolean attributesStepShowing) throws NoSuchFieldException, IllegalAccessException { assertEquals("Wrong image step visibility", imageStepShwing, ((JComponent)TestUtilities.getField(panel, "imageChoicePreviewComponent")).isShowing()); assertEquals("Wrong attributes step visibility", attributesStepShowing, ((JComponent)TestUtilities.getField(panel, "attributesPreviewComponent")).isShowing()); } }