/* * UserPreferences.java 20 nov. 2010 * * Copyright (c) 2011 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.Point; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.io.File; import java.net.URISyntaxException; import java.util.Collection; import java.util.List; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JSpinner; import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; import junit.extensions.abbot.ComponentTestFixture; import abbot.finder.AWTHierarchy; import abbot.finder.BasicFinder; import abbot.finder.ComponentNotFoundException; import abbot.finder.ComponentSearchException; import abbot.finder.MultipleComponentsFoundException; import abbot.finder.matchers.ClassMatcher; import abbot.tester.ComponentLocation; import abbot.tester.JComponentTester; import abbot.tester.JSpinnerTester; import abbot.tester.JSplitPaneTester; import abbot.tester.JTabbedPaneLocation; import abbot.tester.JTabbedPaneTester; import com.eteks.sweethome3d.io.DefaultUserPreferences; import com.eteks.sweethome3d.io.HomeFileRecorder; import com.eteks.sweethome3d.model.DimensionLine; import com.eteks.sweethome3d.model.Home; import com.eteks.sweethome3d.model.HomePieceOfFurniture; import com.eteks.sweethome3d.model.Label; import com.eteks.sweethome3d.model.Level; import com.eteks.sweethome3d.model.RecorderException; import com.eteks.sweethome3d.model.Room; import com.eteks.sweethome3d.model.Selectable; import com.eteks.sweethome3d.model.UserPreferences; import com.eteks.sweethome3d.model.Wall; import com.eteks.sweethome3d.swing.HomePane; import com.eteks.sweethome3d.swing.LevelPanel; import com.eteks.sweethome3d.swing.SwingViewFactory; import com.eteks.sweethome3d.swing.WallPanel; import com.eteks.sweethome3d.viewcontroller.HomeController; import com.eteks.sweethome3d.viewcontroller.HomeView; import com.eteks.sweethome3d.viewcontroller.PlanView; /** * Tests levels. * @author Emmanuel Puybaret */ public class LevelTest extends ComponentTestFixture { public void testLevels() throws RecorderException, NoSuchFieldException, IllegalAccessException, InterruptedException, ComponentSearchException, URISyntaxException { UserPreferences preferences = new DefaultUserPreferences() { @Override public void write() throws RecorderException { } }; SwingViewFactory viewFactory = new SwingViewFactory(); String testFile = new File(LevelTest.class.getResource("resources/home1.sh3d").toURI()).getAbsolutePath(); Home home = new HomeFileRecorder().readHome(testFile); assertHomeItemsAtLevel(home, null); HomeController homeController = new HomeController(home, preferences, viewFactory); final JComponent view = (JComponent)homeController.getView(); // Create a frame that displays a home view JFrame frame = new JFrame("Levels Test"); frame.add(view); showWindow(frame); JComponentTester tester = new JComponentTester(); tester.waitForIdle(); // Enlarge plan view size PlanView planView = homeController.getPlanController().getView(); JComponent planViewComponent = (JComponent)planView; new JSplitPaneTester().actionMoveDivider(planViewComponent.getParent(), 0.75f); // Give focus to plan view tester.actionClick(planViewComponent, 50, 50); assertTrue("Plan view doesn't have focus", TestUtilities.getField(homeController, "focusedView") == planViewComponent); Collection<Wall> walls = home.getWalls(); List<HomePieceOfFurniture> furniture = home.getFurniture(); List<Room> rooms = home.getRooms(); // Select all in plan to ensure walls at top left are visible runAction(homeController, HomeView.ActionType.SELECT_ALL, tester); assertEquals("All walls are not selected", walls.size(), Home.getWallsSubList(home.getSelectedItems()).size()); assertEquals("All pieces are not selected", furniture.size(), Home.getFurnitureSubList(home.getSelectedItems()).size()); assertEquals("All rooms are not selected", rooms.size(), Home.getRoomsSubList(home.getSelectedItems()).size()); // Select wall at left Point p = new Point(planView.convertXModelToScreen(0), planView.convertYModelToScreen(50)); SwingUtilities.convertPointFromScreen(p, planViewComponent); tester.actionClick(planViewComponent, new ComponentLocation(p)); List<Selectable> selectedItems = home.getSelectedItems(); assertEquals("No wall selected", 1, selectedItems.size()); assertTrue("No wall selected", selectedItems.get(0) instanceof Wall); Wall firstWall = (Wall)selectedItems.get(0); float oldHeight = firstWall.getHeight(); // Modify wall runAction(homeController, HomeView.ActionType.MODIFY_WALL, tester); // Wait for wall view to be shown tester.waitForFrameShowing(new AWTHierarchy(), preferences.getLocalizedString( WallPanel.class, "wall.title")); // Check dialog box is displayed JDialog wallModificationDialog = (JDialog)new BasicFinder().find(frame, new ClassMatcher (JDialog.class, true)); assertTrue("Wall modification dialog not showing", wallModificationDialog.isShowing()); WallPanel wallPanel = (WallPanel)TestUtilities.findComponent(wallModificationDialog, WallPanel.class); JSpinner heightSpinner = (JSpinner)TestUtilities.getField(wallPanel, "rectangularWallHeightSpinner"); // Increase its height JSpinnerTester spinnerTester = new JSpinnerTester(); for (int i = 0; i < 25; i++) { spinnerTester.actionIncrement(heightSpinner); } float newHeight = ((Number)heightSpinner.getValue()).floatValue(); // Click on Ok in dialog box final JOptionPane optionPane = (JOptionPane)TestUtilities.findComponent( wallModificationDialog, JOptionPane.class); tester.invokeAndWait(new Runnable() { public void run() { // Select Ok option to hide dialog box in Event Dispatch Thread optionPane.setValue(JOptionPane.OK_OPTION); } }); assertFalse("Wall modification dialog still showing", wallModificationDialog.isShowing()); assertEquals("Wall height unchanged", newHeight, firstWall.getHeight()); // Create a new level runAction(homeController, HomeView.ActionType.ADD_LEVEL, tester); List<Level> levels = home.getLevels(); assertEquals("No new level", 2, levels.size()); assertSame("New level isn't selected", levels.get(levels.size() - 1), home.getSelectedLevel()); // Check all home items moved to level 0 assertHomeItemsAtLevel(home, levels.get(0)); // Check visibility of modified wall and other walls for (Wall wall : walls) { if (wall == firstWall) { assertTrue("High wall not visible", wall.isAtLevel(home.getSelectedLevel())); } else { assertFalse("High wall visible", wall.isAtLevel(home.getSelectedLevel())); } } // Test undo runAction(homeController, HomeView.ActionType.UNDO, tester); // Check all home items moved back to no level assertHomeItemsAtLevel(home, null); runAction(homeController, HomeView.ActionType.UNDO, tester); assertEquals("Wall height not restored", oldHeight, firstWall.getHeight()); assertEquals("Incorrect level count", 0, home.getLevels().size()); runAction(homeController, HomeView.ActionType.ADD_LEVEL, tester); runAction(homeController, HomeView.ActionType.DELETE_LEVEL, tester); assertEquals("Incorrect level count", 1, home.getLevels().size()); runAction(homeController, HomeView.ActionType.UNDO, tester); // Check visibility of walls for (Wall wall : walls) { assertFalse("High wall visible", wall.isAtLevel(home.getSelectedLevel())); } // Change elevation of second level decreaseLevelElevation(home, homeController, preferences, frame, tester); // Check visibility of walls for (Wall wall : walls) { assertTrue("Wall invisible", wall.isAtLevel(home.getSelectedLevel())); } // Select first level JTabbedPane tabbedPane = (JTabbedPane)new BasicFinder().find(planViewComponent, new ClassMatcher (JTabbedPane.class, true)); JTabbedPaneTester tabbedPaneTester = new JTabbedPaneTester(); tabbedPaneTester.actionSelectTab(tabbedPane, new JTabbedPaneLocation(0)); assertEquals("First level not selected", home.getSelectedLevel(), home.getLevels().get(0)); // Change elevation of first level decreaseLevelElevation(home, homeController, preferences, frame, tester); // Select second level tabbedPaneTester.actionSelectTab(tabbedPane, new JTabbedPaneLocation(1)); assertEquals("Second level not selected", home.getSelectedLevel(), home.getLevels().get(1)); // Create a wall checking magnetism with 1st level works runAction(homeController, HomeView.ActionType.CREATE_WALLS, tester); p = new Point(planView.convertXModelToScreen(firstWall.getXStart()) + 2, planView.convertYModelToScreen(firstWall.getYStart()) - 1); SwingUtilities.convertPointFromScreen(p, planViewComponent); tester.actionClick(planViewComponent, new ComponentLocation(p)); p = new Point(planView.convertXModelToScreen(firstWall.getXEnd()) - 1, planView.convertYModelToScreen(firstWall.getYEnd()) + 2); SwingUtilities.convertPointFromScreen(p, planViewComponent); tester.actionClick(planViewComponent, new ComponentLocation(p), MouseEvent.BUTTON1, 2); assertEquals("No new wall", walls.size() + 1, home.getWalls().size()); Wall newWall = (Wall)home.getWalls().toArray() [walls.size()]; assertTrue("Incorrect X start " + firstWall.getXStart() + " " + newWall.getXStart(), Math.abs(firstWall.getXStart() - newWall.getXStart()) < 1E-4); assertTrue("Incorrect Y start " + firstWall.getYStart() + " " + newWall.getYStart(), Math.abs(firstWall.getYStart() - newWall.getYStart()) < 1E-4); assertTrue("Incorrect X end " + firstWall.getXEnd() + " " + newWall.getXEnd(), Math.abs(firstWall.getXEnd() - newWall.getXEnd()) < 1E-4); assertTrue("Incorrect Y end " + firstWall.getYEnd() + " " + newWall.getYEnd(), Math.abs(firstWall.getYEnd() - newWall.getYEnd()) < 1E-4); // Create a room checking magnetism works runAction(homeController, HomeView.ActionType.CREATE_ROOMS, tester); Room firstRoom = rooms.get(0); float [][] firstRoomPoints = firstRoom.getPoints(); firstRoomPoints = new float [][] {firstRoomPoints [0], firstRoomPoints [1], firstRoomPoints [2], firstRoomPoints [firstRoomPoints.length - 1]}; for (float [] point : firstRoomPoints) { p = new Point(planView.convertXModelToScreen(point [0]) + 1, planView.convertYModelToScreen(point [1]) + 1); SwingUtilities.convertPointFromScreen(p, planViewComponent); tester.actionClick(planViewComponent, new ComponentLocation(p)); } tester.actionMouseMove(planViewComponent, new ComponentLocation(new Point(0, 0))); tester.actionKeyStroke(KeyEvent.VK_ESCAPE); assertEquals("No new room", rooms.size() + 1, home.getRooms().size()); Room newRoom = home.getRooms().get(rooms.size()); assertEquals("Wrong point count", firstRoomPoints.length, newRoom.getPointCount()); float [][] points = newRoom.getPoints(); for (int i = 0; i < firstRoomPoints.length; i++) { assertTrue("Incorrect X [" + i + "] " + firstRoomPoints [i][0] + " " + points [i][0], Math.abs(firstRoomPoints [i][0] - points [i][0]) < 1E-4); assertTrue("Incorrect Y [" + i + "] " + firstRoomPoints [i][1] + " " + points [i][1], Math.abs(firstRoomPoints [i][1] - points [i][1]) < 1E-4); } } private void assertHomeItemsAtLevel(Home home, Level level) { for (HomePieceOfFurniture piece : home.getFurniture()) { assertSame("Piece not at expected level", level, piece.getLevel()); } for (Wall wall : home.getWalls()) { assertSame("Piece not at expected level", level, wall.getLevel()); } for (DimensionLine line : home.getDimensionLines()) { assertSame("Piece not at expected level", level, line.getLevel()); } for (Label label : home.getLabels()) { assertSame("Label not at expected level", level, label.getLevel()); } } private void decreaseLevelElevation(Home home, HomeController homeController, UserPreferences preferences, JFrame frame, JComponentTester tester) throws ComponentNotFoundException, MultipleComponentsFoundException, ComponentSearchException, NoSuchFieldException, IllegalAccessException { JSpinnerTester spinnerTester; runAction(homeController, HomeView.ActionType.MODIFY_LEVEL, tester); // Wait for level view to be shown tester.waitForFrameShowing(new AWTHierarchy(), preferences.getLocalizedString( LevelPanel.class, "level.title")); // Check dialog box is displayed final JDialog levelModificationDialog = (JDialog)new BasicFinder().find(frame, new ClassMatcher (JDialog.class, true)); assertTrue(" Level modification dialog not showing", levelModificationDialog.isShowing()); LevelPanel levelPanel = ( LevelPanel)TestUtilities.findComponent(levelModificationDialog, LevelPanel.class); JSpinner elevationSpinner = (JSpinner)TestUtilities.getField(levelPanel, "elevationSpinner"); // Reduce its elevation at a level where walls of 1st level will be visible spinnerTester = new JSpinnerTester(); for (int i = 0; i < 25; i++) { spinnerTester.actionDecrement(elevationSpinner); } float newElevation = ((Number)elevationSpinner.getValue()).floatValue(); // Click on Ok in dialog box final JOptionPane levelOptionPane = (JOptionPane)TestUtilities.findComponent( levelModificationDialog, JOptionPane.class); tester.invokeAndWait(new Runnable() { public void run() { // Select Ok option to hide dialog box in Event Dispatch Thread levelOptionPane.setValue(JOptionPane.OK_OPTION); } }); assertFalse("Level modification dialog still showing", levelModificationDialog.isShowing()); assertEquals("Level elevation unchanged", newElevation, home.getSelectedLevel().getElevation()); } /** * Runs <code>actionPerformed</code> method matching <code>actionType</code> * in <code>controller</code> view. */ private void runAction(final HomeController controller, final HomePane.ActionType actionType, JComponentTester tester) { tester.invokeAndWait(new Runnable() { public void run() { ((JComponent)controller.getView()).getActionMap().get(actionType).actionPerformed(null); } }); } }