/*
* RoomTest.java 25 nov. 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.event.InputEvent;
import java.util.Arrays;
import java.util.Locale;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JRootPane;
import javax.swing.JTextField;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEditSupport;
import junit.extensions.abbot.ComponentTestFixture;
import abbot.finder.AWTHierarchy;
import abbot.finder.BasicFinder;
import abbot.finder.ComponentSearchException;
import abbot.finder.matchers.ClassMatcher;
import abbot.tester.JComponentTester;
import com.eteks.sweethome3d.io.DefaultUserPreferences;
import com.eteks.sweethome3d.model.Home;
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.FileContentManager;
import com.eteks.sweethome3d.swing.HomePane;
import com.eteks.sweethome3d.swing.NullableCheckBox;
import com.eteks.sweethome3d.swing.PlanComponent;
import com.eteks.sweethome3d.swing.RoomPanel;
import com.eteks.sweethome3d.swing.SwingViewFactory;
import com.eteks.sweethome3d.viewcontroller.HomeController;
import com.eteks.sweethome3d.viewcontroller.HomeView;
import com.eteks.sweethome3d.viewcontroller.PlanController;
import com.eteks.sweethome3d.viewcontroller.PlanView;
import com.eteks.sweethome3d.viewcontroller.RoomController;
import com.eteks.sweethome3d.viewcontroller.ViewFactory;
/**
* Tests rooms in {@link com.eteks.sweethome3d.swing.PlanComponent plan} component and
* their management in {@link com.eteks.sweethome3d.viewcontroller.PlanController controller}.
* @author Emmanuel Puybaret
*/
public class RoomTest extends ComponentTestFixture {
public void testRoomCreation() throws ComponentSearchException,
NoSuchFieldException, IllegalAccessException {
// 1. Create a frame that displays a home view
RoomTestFrame frame = new RoomTestFrame();
// Show home plan frame
showWindow(frame);
// 2. Change default wall thickness and height
frame.preferences.setNewWallThickness(10);
frame.preferences.setNewWallHeight(100);
// Create a home with 5 walls
PlanController planController = frame.homeController.getPlanController();
PlanComponent planComponent = (PlanComponent)planController.getView();
planController.setMode(PlanController.Mode.WALL_CREATION);
// Click at (50, 50), (200, 50), (250, 100), (250, 150), (50, 150) then double click at (50, 50)
JComponentTester tester = new JComponentTester();
tester.actionClick(planComponent, 50, 50);
tester.actionClick(planComponent, 200, 50);
tester.actionClick(planComponent, 250, 100);
tester.actionClick(planComponent, 250, 150);
tester.actionClick(planComponent, 50, 150);
tester.actionClick(planComponent, 50, 50, InputEvent.BUTTON1_MASK, 2);
assertEquals("Wrong wall count in home", 5, frame.home.getWalls().size());
// 3. Use ROOM_CREATION mode
planController.setMode(PlanController.Mode.ROOM_CREATION);
// Double click outside of walls
tester.actionClick(planComponent, 40, 40, InputEvent.BUTTON1_MASK, 2);
// Check no room was created
assertEquals("Wrong room count in home", 0, frame.home.getRooms().size());
// Double click inside walls
tester.actionClick(planComponent, 100, 100, InputEvent.BUTTON1_MASK, 2);
// Check a room was created
assertEquals("Wrong room count in home", 1, frame.home.getRooms().size());
// Check room point count and area
Room room = frame.home.getRooms().get(0);
assertEquals("Wrong point count", 5, room.getPoints().length);
assertEquals("Wrong room area", 69244.76f, room.getArea());
// 4. Edit created room
JDialog attributesDialog = showRoomPanel(frame.preferences, frame.homeController, frame, tester);
// Retrieve RoomPanel components
RoomPanel wallPanel = (RoomPanel)TestUtilities.findComponent(
attributesDialog, RoomPanel.class);
JTextField nameTextField =
(JTextField)TestUtilities.getField(wallPanel, "nameTextField");
NullableCheckBox areaVisibleCheckBox =
(NullableCheckBox)TestUtilities.getField(wallPanel, "areaVisibleCheckBox");
NullableCheckBox floorVisibleCheckBox =
(NullableCheckBox)TestUtilities.getField(wallPanel, "floorVisibleCheckBox");
NullableCheckBox ceilingVisibleCheckBox =
(NullableCheckBox)TestUtilities.getField(wallPanel, "ceilingVisibleCheckBox");
// Check name is empty and check boxes are selected
assertTrue("Name not empty", nameTextField.getText().length() == 0);
assertTrue("Area check box isn't checked", areaVisibleCheckBox.getValue());
assertTrue("Floor check box isn't checked", floorVisibleCheckBox.getValue());
assertTrue("Ceiling check box isn't checked", ceilingVisibleCheckBox.getValue());
// Enter a name and unchecked boxes
nameTextField.setText("Test");
tester.click(areaVisibleCheckBox);
tester.click(floorVisibleCheckBox);
tester.click(ceilingVisibleCheckBox);
final JOptionPane attributesOptionPane = (JOptionPane)TestUtilities.findComponent(
attributesDialog, JOptionPane.class);
tester.invokeAndWait(new Runnable() {
public void run() {
// Select Ok option to hide dialog box in Event Dispatch Thread
attributesOptionPane.setValue(JOptionPane.OK_OPTION);
}
});
assertFalse("Dialog still showing", attributesDialog.isShowing());
// Assert room was modified accordingly
assertEquals("Name is incorrect", "Test", room.getName());
assertFalse("Area is visible", room.isAreaVisible());
assertFalse("Floor is visible", room.isFloorVisible());
assertFalse("Ceiling is visible", room.isCeilingVisible());
// 5. Increase font size of room name text
assertNull("Text style exists", room.getNameStyle());
runAction(frame.homeController, HomeView.ActionType.INCREASE_TEXT_SIZE, tester);
// Check text style
assertEquals("Wrong text size", 26.f, room.getNameStyle().getFontSize());
// Decrease font size of room name text
runAction(frame.homeController, HomeView.ActionType.DECREASE_TEXT_SIZE, tester);
runAction(frame.homeController, HomeView.ActionType.DECREASE_TEXT_SIZE, tester);
assertEquals("Wrong text size", 22.f, room.getNameStyle().getFontSize());
// Change style to italic
runAction(frame.homeController, HomeView.ActionType.TOGGLE_ITALIC_STYLE, tester);
assertTrue("Text isn't italic", room.getNameStyle().isItalic());
assertFalse("Text is bold", room.getNameStyle().isBold());
// Change style to bold
runAction(frame.homeController, HomeView.ActionType.TOGGLE_BOLD_STYLE, tester);
assertTrue("Text isn't italic", room.getNameStyle().isItalic());
assertTrue("Text isn't bold", room.getNameStyle().isBold());
// 6. Undo style change
runAction(frame.homeController, HomeView.ActionType.UNDO, tester);
runAction(frame.homeController, HomeView.ActionType.UNDO, tester);
// Check style
assertFalse("Text is italic", room.getNameStyle().isItalic());
assertFalse("Text is bold", room.getNameStyle().isBold());
// Undo text size change
runAction(frame.homeController, HomeView.ActionType.UNDO, tester);
runAction(frame.homeController, HomeView.ActionType.UNDO, tester);
runAction(frame.homeController, HomeView.ActionType.UNDO, tester);
assertEquals("Wrong text size", 24.f, room.getNameStyle().getFontSize());
// Undo room modification
runAction(frame.homeController, HomeView.ActionType.UNDO, tester);
assertNull("Name isn't empty", room.getName());
assertTrue("Area isn't visible", room.isAreaVisible());
assertTrue("Floor isn't visible", room.isFloorVisible());
assertTrue("Ceiling isn't visible", room.isCeilingVisible());
// Undo room creation
runAction(frame.homeController, HomeView.ActionType.UNDO, tester);
assertEquals("Wrong room count in home", 0, frame.home.getRooms().size());
// 7. Redo everything
for (int i = 0; i < 7; i++) {
runAction(frame.homeController, HomeView.ActionType.REDO, tester);
}
// Check room is back
assertEquals("Wrong room count in home", 1, frame.home.getRooms().size());
room = frame.home.getRooms().get(0);
assertEquals("Name is incorrect", "Test", room.getName());
assertFalse("Area is visible", room.isAreaVisible());
assertFalse("Floor is visible", room.isFloorVisible());
assertFalse("Ceiling is visible", room.isCeilingVisible());
assertEquals("Wrong text size", 22.f, room.getNameStyle().getFontSize());
assertTrue("Text isn't italic", room.getNameStyle().isItalic());
assertTrue("Text isn't bold", room.getNameStyle().isBold());
}
/**
* Runs <code>actionPerformed</code> method matching <code>actionType</code>
* in <code>HomePane</code>.
*/
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);
}
});
}
/**
* Returns the dialog that displays room attributes.
*/
private JDialog showRoomPanel(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
((JComponent)controller.getView()).getActionMap().get(HomeView.ActionType.MODIFY_ROOM).actionPerformed(null);
}
});
// Wait for wall view to be shown
tester.waitForFrameShowing(new AWTHierarchy(), preferences.getLocalizedString(
RoomPanel.class, "room.title"));
// Check dialog box is displayed
JDialog attributesDialog = (JDialog)new BasicFinder().find(parent,
new ClassMatcher (JDialog.class, true));
assertTrue("Room dialog not showing", attributesDialog.isShowing());
return attributesDialog;
}
/**
* Tests automatic split of walls surrounding rooms.
*/
public void testRoomWallsSplit() {
Home home = new Home();
UserPreferences preferences = new DefaultUserPreferences();
UndoableEditSupport undoSupport = new UndoableEditSupport();
UndoManager undoManager = new UndoManager();
undoSupport.addUndoableEditListener(undoManager);
// 1. Create a home drawing walls as follows
// --------------------
// | | |
// | 0 | 1 |
// |--------| |
// | | |
// | | |
// | | /
// -----------------/
Wall [] walls = {new Wall(0, 0, 1000, 0, 20, 250),
new Wall(1000, 0, 1000, 800, 20, 250),
new Wall(1000, 800, 800, 1000, 20, 250),
new Wall(800, 1000, 0, 1000, 20, 250),
new Wall(0, 1000, 0, 0, 20, 250),
new Wall(500, 0, 500, 1000, 10, 250),
new Wall(0, 400, 500, 400, 10, 250)};
// Join the first 4 walls
for (int i = 0; i < 4; i++) {
walls [i].setWallAtStart(walls [(i + 3) % 4]);
walls [i].setWallAtEnd(walls [(i + 1) % 4]);
}
for (Wall wall : walls) {
home.addWall(wall);
}
// 2. Create automatically 2 rooms by simulating double clicks
PlanController planController = new PlanController(home, preferences, new SwingViewFactory(), null, undoSupport);
planController.setMode(PlanController.Mode.ROOM_CREATION);
planController.pressMouse(50, 50, 1, false, false);
planController.pressMouse(50, 50, 2, false, false);
assertEquals("Room wasn't created", 1, home.getRooms().size());
assertRoomCoordinates(home.getRooms().get(0),
new float [][] {{495.0f, 10.0f}, {495.0f, 395.0f}, {10.0f, 395.0f}, {10.0f, 10.0f}});
planController.pressMouse(700, 700, 1, false, false);
planController.pressMouse(700, 700, 2, false, false);
Room room = home.getRooms().get(1);
assertRoomCoordinates(room,
new float [][] {{990.0f, 10.0f}, {990.0f, 795.8579f}, {795.8579f, 990.0f}, {505.0f, 990.0f}, {505.0f, 10.0f}});
assertTrue("Second room isn't selected", home.getSelectedItems().contains(room));
// 3. Split walls automatically
RoomController roomController = new RoomController(home, preferences, new SwingViewFactory(), null, undoSupport);
assertTrue("Walls around second room have to be splitted", roomController.isSplitSurroundingWallsNeeded());
roomController.setSplitSurroundingWalls(true);
roomController.modifyRooms();
// Check two walls were split
assertEquals("No wall was split", walls.length + 2, home.getWalls().size());
undoManager.undo();
assertEquals("Incorrect wall count", walls.length, home.getWalls().size());
home.setSelectedItems(Arrays.asList(new Selectable [] {home.getRooms().get(0), walls [0]}));
roomController = new RoomController(home, preferences, new SwingViewFactory(), null, undoSupport);
roomController.setSplitSurroundingWalls(true);
roomController.modifyRooms();
// Check 3 walls were split
assertEquals("No wall was split", walls.length + 3, home.getWalls().size());
// Check selection contains 1 more item
assertEquals("Selection doesn't contain split walls", 3, home.getSelectedItems().size());
undoManager.undo();
assertEquals("Selection wasn't restored", 2, home.getSelectedItems().size());
undoManager.redo();
assertEquals("No wall was split", walls.length + 3, home.getWalls().size());
assertEquals("Selection doesn't contain split walls", 3, home.getSelectedItems().size());
roomController = new RoomController(home, preferences, new SwingViewFactory(), null, undoSupport);
assertFalse("Walls around first room don't need to be splitted", roomController.isSplitSurroundingWallsNeeded());
}
/**
* Asserts the points of the given <code>room</code> are the same as in <code>points</code>.
*/
private void assertRoomCoordinates(Room room, float [][] points) {
float [][] roomPoints = room.getPoints();
assertEquals("Not same points count", points.length, roomPoints.length);
for (int i = 0; i < roomPoints.length; i++) {
assertEquals("Not same abscissa", points [i][0], roomPoints [i][0]);
assertEquals("Not same ordinate", points [i][1], roomPoints [i][1]);
}
}
public static void main(String [] args) {
JFrame frame = new RoomTestFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static class RoomTestFrame extends JFrame {
private final UserPreferences preferences;
private final Home home;
private final HomeController homeController;
public RoomTestFrame() {
super("Room Test");
// Create model objects
this.home = new Home();
Locale.setDefault(Locale.FRANCE);
this.preferences = new DefaultUserPreferences() {
@Override
public void write() throws RecorderException {
}
};
ViewFactory viewFactory = new SwingViewFactory() {
@Override
public PlanView createPlanView(Home home, UserPreferences preferences, PlanController controller) {
return new PlanComponent(home, preferences, controller);
}
};
FileContentManager contentManager = new FileContentManager(this.preferences);
this.homeController = new HomeController(this.home, this.preferences, viewFactory, contentManager);
setRootPane((JRootPane)this.homeController.getView());
pack();
}
}
}