1 /*
2  * PlanComponentTest.java 31 mai 2006
3  *
4  * Copyright (c) 2006 Emmanuel PUYBARET / eTeks <info@eteks.com>. All Rights
5  * Reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option) any later
10  * version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19  * Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 package com.eteks.sweethome3d.junit;
22 
23 import java.awt.BorderLayout;
24 import java.awt.Point;
25 import java.awt.event.ActionEvent;
26 import java.awt.event.ActionListener;
27 import java.awt.event.InputEvent;
28 import java.awt.event.KeyEvent;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.List;
32 import java.util.Locale;
33 
34 import javax.swing.ImageIcon;
35 import javax.swing.JButton;
36 import javax.swing.JComponent;
37 import javax.swing.JFrame;
38 import javax.swing.JScrollPane;
39 import javax.swing.JToggleButton;
40 import javax.swing.JToolBar;
41 import javax.swing.undo.UndoManager;
42 import javax.swing.undo.UndoableEditSupport;
43 
44 import junit.extensions.abbot.ComponentTestFixture;
45 import abbot.tester.ComponentLocation;
46 import abbot.tester.JComponentTester;
47 
48 import com.eteks.sweethome3d.io.DefaultUserPreferences;
49 import com.eteks.sweethome3d.model.CollectionEvent;
50 import com.eteks.sweethome3d.model.CollectionListener;
51 import com.eteks.sweethome3d.model.DimensionLine;
52 import com.eteks.sweethome3d.model.Home;
53 import com.eteks.sweethome3d.model.Selectable;
54 import com.eteks.sweethome3d.model.UserPreferences;
55 import com.eteks.sweethome3d.model.Wall;
56 import com.eteks.sweethome3d.swing.PlanComponent;
57 import com.eteks.sweethome3d.swing.SwingViewFactory;
58 import com.eteks.sweethome3d.viewcontroller.PlanController;
59 import com.eteks.sweethome3d.viewcontroller.PlanView;
60 import com.eteks.sweethome3d.viewcontroller.ViewFactory;
61 
62 /**
63  * Tests {@link com.eteks.sweethome3d.swing.PlanComponent plan} component and
64  * its {@link com.eteks.sweethome3d.viewcontroller.PlanController controller}.
65  * @author Emmanuel Puybaret
66  */
67 public class PlanComponentTest extends ComponentTestFixture {
testPlanComponentWithMouse()68   public void testPlanComponentWithMouse() {
69     // 1. Create a frame that displays a PlanComponent instance of
70     // a new home at 540 pixels by 400 preferred size, and a tool bar
71     // with a mode toggle button, an undo button and a redo button
72     final PlanTestFrame frame = new PlanTestFrame();
73     // Show home plan frame
74     showWindow(frame);
75     PlanComponent planComponent = (PlanComponent)frame.planController.getView();
76     assertEquals("Wrong preferred width", 540, planComponent.getWidth());
77 
78     // Build an ordered list of walls added to home
79     final ArrayList<Wall> orderedWalls = new ArrayList<Wall>();
80     frame.home.addWallsListener(new CollectionListener<Wall>() {
81       public void collectionChanged(CollectionEvent<Wall> ev) {
82         if (ev.getType() == CollectionEvent.Type.ADD) {
83           orderedWalls.add(ev.getItem());
84         }
85       }
86     });
87 
88     // 2. Use WALL_CREATION mode
89     JComponentTester tester = new JComponentTester();
90     tester.actionClick(frame.modeButton);
91     assertEquals("Current mode isn't " + PlanController.Mode.WALL_CREATION,
92         PlanController.Mode.WALL_CREATION, frame.planController.getMode());
93     // Click at (30, 30), (270, 31), (269, 170), then double click at (30, 171)
94     tester.actionClick(planComponent, 30, 30);
95     tester.actionClick(planComponent, 270, 31);
96     tester.actionClick(planComponent, 269, 170);
97     tester.actionClick(planComponent, 30, 171, InputEvent.BUTTON1_MASK, 2);
98     // Check 3 walls were created at (20, 20), (500, 20), (500, 300) and (20, 300) coordinates
99     Wall wall1 = orderedWalls.get(0);
100     assertCoordinatesEqualWallPoints(20, 20, 500, 20, wall1);
101     Wall wall2 = orderedWalls.get(1);
102     assertCoordinatesEqualWallPoints(500, 20, 500, 300, wall2);
103     Wall wall3 = orderedWalls.get(2);
104     assertCoordinatesEqualWallPoints(500, 300, 20, 300, wall3);
105     // Check the thickness and the height of first wall
106     assertEquals("Wrong wall tickness", frame.preferences.getNewWallThickness(), wall1.getThickness());
107     assertEquals("Wrong wall height", frame.preferences.getNewWallHeight(), wall1.getHeight());
108     assertEquals("Wrong wall height at end", null, wall1.getHeightAtEnd());
109     // Check they are joined to each other end point
110     assertWallsAreJoined(null, wall1, wall2);
111     assertWallsAreJoined(wall1, wall2, wall3);
112     assertWallsAreJoined(wall2, wall3, null);
113     // Check they are selected
114     assertSelectionContains(frame.home, wall1, wall2, wall3);
115 
116     // 3. Click at (30, 170), then double click at (50, 50) without magnetism
117     tester.actionClick(planComponent, 30, 170);
118     tester.actionKeyPress(TestUtilities.getMagnetismToggleKey());
119     tester.actionClick(planComponent, 50, 50, InputEvent.BUTTON1_MASK, 2);
120     tester.actionKeyRelease(TestUtilities.getMagnetismToggleKey());
121     // Check a forth wall was created at (20, 300), (60, 60) coordinates
122     Wall wall4 = orderedWalls.get(orderedWalls.size() - 1);
123     assertCoordinatesEqualWallPoints(20, 300, 60, 60, wall4);
124     assertSelectionContains(frame.home, wall4);
125     assertWallsAreJoined(wall3, wall4, null);
126 
127     // 4. Use SELECTION mode
128     tester.actionClick(frame.modeButton);
129     // Check current mode is SELECTION
130     assertEquals("Current mode isn't " + PlanController.Mode.SELECTION,
131         PlanController.Mode.SELECTION, frame.planController.getMode());
132     // Give focus to plan component
133     tester.actionFocus(planComponent);
134     // Press the delete key
135     tester.actionKeyStroke(KeyEvent.VK_DELETE);
136     // Check plan contains only the first three walls
137     assertHomeContains(frame.home, wall1, wall2, wall3);
138 
139     // 5. Use WALL_CREATION mode
140     tester.actionClick(frame.modeButton);
141     //  Click at (31, 29), then double click at (30, 170)
142     tester.actionClick(planComponent, 31, 29);
143     tester.actionClick(planComponent, 30, 170, InputEvent.BUTTON1_MASK, 2);
144     // Check a new forth wall was created at (20, 20), (20, 300) coordinates
145     wall4 = orderedWalls.get(orderedWalls.size() - 1);
146     assertCoordinatesEqualWallPoints(20, 20, 20, 300, wall4);
147     // Check its end points are joined to the first and third wall
148     assertWallsAreJoined(wall1, wall4, wall3);
149 
150     // 6. Use SELECTION mode
151     tester.actionClick(frame.modeButton);
152     // Drag and drop cursor from (200, 100) to (300, 180)
153     tester.actionMousePress(planComponent,
154         new ComponentLocation(new Point(200, 100)));
155     tester.actionMouseMove(planComponent,
156         new ComponentLocation(new Point(300, 180)));
157     tester.actionMouseRelease();
158     // Check the selected walls are the second and third ones
159     assertSelectionContains(frame.home, wall2, wall3);
160 
161     // 7. Press twice right arrow key
162     tester.actionKeyStroke(KeyEvent.VK_RIGHT);
163     tester.actionKeyStroke(KeyEvent.VK_RIGHT);
164     // Check the 4 walls coordinates are (20, 20), (504, 20), (504, 300), (24, 300)
165     assertCoordinatesEqualWallPoints(20, 20, 504, 20, wall1);
166     assertCoordinatesEqualWallPoints(504, 20, 504, 300, wall2);
167     assertCoordinatesEqualWallPoints(504, 300, 24, 300, wall3);
168     assertCoordinatesEqualWallPoints(20, 20, 24, 300, wall4);
169 
170     // 8. Click at (272, 40) with Shift key depressed
171     tester.actionKeyPress(KeyEvent.VK_SHIFT);
172     tester.actionClick(planComponent, 272, 40);
173     tester.actionKeyRelease(KeyEvent.VK_SHIFT);
174     // Check the second wall was removed from selection
175     assertSelectionContains(frame.home, wall3);
176 
177      // 9. Drag cursor from (50, 30) to (50, 50)
178     tester.actionMousePress(planComponent,
179         new ComponentLocation(new Point(50, 30)));
180     tester.actionMouseMove(planComponent,
181         new ComponentLocation(new Point(50, 50)));
182     // Check first wall is selected and that it moved
183     assertSelectionContains(frame.home, wall1);
184     assertCoordinatesEqualWallPoints(20, 60, 504, 60, wall1);
185     // Lose focus
186     tester.actionKeyStroke(KeyEvent.VK_TAB);
187     // Check the wall didn't move at end
188     assertCoordinatesEqualWallPoints(20, 20, 504, 20, wall1);
189 
190     // 10. Click 6 times on undo button
191     for (int i = 0; i < 6; i++) {
192       tester.invokeAndWait(new Runnable() {
193           public void run() {
194             frame.undoButton.doClick();
195           }
196         });
197     }
198     // Check home doesn't contain any wall
199     assertHomeContains(frame.home);
200 
201     // 11. Click 6 times on redo button
202     for (int i = 0; i < 6; i++) {
203       tester.invokeAndWait(new Runnable() {
204           public void run() {
205             frame.redoButton.doClick();
206           }
207         });
208     }
209     // Check plan contains the four wall
210     assertHomeContains(frame.home, wall1, wall2, wall3, wall4);
211     //  Check they are joined to each other end point
212     assertWallsAreJoined(wall4, wall1, wall2);
213     assertWallsAreJoined(wall1, wall2, wall3);
214     assertWallsAreJoined(wall2, wall3, wall4);
215     assertWallsAreJoined(wall1, wall4, wall3);
216     // Check the second and the third wall are selected
217     assertSelectionContains(frame.home, wall2, wall3);
218 
219     // 12. Reverse directions of selected walls
220     float xStartWall2 = wall2.getXStart();
221     float yStartWall2 = wall2.getYStart();
222     float xStartWall3 = wall3.getXStart();
223     float yStartWall3 = wall3.getYStart();
224     float xEndWall3 = wall3.getXEnd();
225     float yEndWall3 = wall3.getYEnd();
226     tester.invokeAndWait(new Runnable() {
227         public void run() {
228           frame.reverseDirectionButton.doClick();
229         }
230       });
231     // Check the second and the third wall are still selected
232     assertSelectionContains(frame.home, wall2, wall3);
233     // Check wall2 and wall3 were reserved
234     assertCoordinatesEqualWallPoints(xStartWall3, yStartWall3, xStartWall2, yStartWall2, wall2);
235     assertCoordinatesEqualWallPoints(xEndWall3, yEndWall3, xStartWall3, yStartWall3, wall3);
236     assertWallsAreJoined(wall3, wall2, wall1);
237     assertWallsAreJoined(wall4, wall3, wall2);
238 
239     // 13. Select first wall
240     tester.actionClick(planComponent, 100, 100); // Give focus first
241     tester.actionClick(planComponent, 40, 30);
242     // Drag cursor from (30, 30) to (50, 50) without magnetism
243     tester.actionMousePress(planComponent,
244         new ComponentLocation(new Point(30, 30)));
245     tester.actionMouseMove(planComponent,
246         new ComponentLocation(new Point(50, 50)));
247     tester.actionKeyPress(TestUtilities.getMagnetismToggleKey());
248     tester.waitForIdle();
249     tester.actionMouseRelease();
250     tester.actionKeyRelease(TestUtilities.getMagnetismToggleKey());
251     // Check wall start point moved to (60, 60)
252     assertCoordinatesEqualWallPoints(60, 60, 504, 20, wall1);
253     assertCoordinatesEqualWallPoints(60, 60, 24, 300, wall4);
254 
255     // 14. Select first wall
256     tester.actionClick(planComponent, 60, 50);
257     assertSelectionContains(frame.home, wall1);
258     // Split first wall in two walls
259     tester.actionClick(frame.splitButton);
260     Wall wall5 = orderedWalls.get(orderedWalls.size() - 2);
261     Wall wall6 = orderedWalls.get(orderedWalls.size() - 1);
262     assertSelectionContains(frame.home, wall5);
263     assertCoordinatesEqualWallPoints(60, 60, 282, 40, wall5);
264     assertCoordinatesEqualWallPoints(282, 40, 504, 20, wall6);
265     assertWallsAreJoined(wall4, wall5, wall6);
266     assertWallsAreJoined(wall5, wall6, wall2);
267     assertFalse("Split wall still present in home", frame.home.getWalls().contains(wall1));
268     // Check walls have a new id
269     assertFalse("Walls have same id", wall1.getId().equals(wall5.getId()));
270     assertFalse("Walls have same id", wall1.getId().equals(wall6.getId()));
271     assertFalse("Walls have same id", wall5.getId().equals(wall6.getId()));
272     // Undo operation and check undone state
273     tester.actionClick(frame.undoButton);
274     assertSelectionContains(frame.home, wall1);
275     assertCoordinatesEqualWallPoints(60, 60, 504, 20, wall1);
276     assertWallsAreJoined(wall4, wall1, wall2);
277     assertTrue("Split wall not present in home", frame.home.getWalls().contains(wall1));
278     assertFalse("Wall still present in home", frame.home.getWalls().contains(wall5));
279     assertFalse("Wall still present in home", frame.home.getWalls().contains(wall6));
280   }
281 
testPlanComponentWithKeyboard()282   public void testPlanComponentWithKeyboard() throws InterruptedException {
283     // 1. Create a frame that displays a PlanComponent instance
284     PlanTestFrame frame = new PlanTestFrame();
285     // Show home plan frame
286     showWindow(frame);
287     PlanComponent planComponent = (PlanComponent)frame.planController.getView();
288 
289     // Build an ordered list of walls added to home
290     final ArrayList<Wall> orderedWalls = new ArrayList<Wall>();
291     frame.home.addWallsListener(new CollectionListener<Wall>() {
292       public void collectionChanged(CollectionEvent<Wall> ev) {
293         if (ev.getType() == CollectionEvent.Type.ADD) {
294           orderedWalls.add(ev.getItem());
295         }
296       }
297     });
298 
299     // 2. Create walls with keyboard
300     frame.planController.setMode(PlanController.Mode.WALL_CREATION);
301     assertEquals("Current mode isn't " + PlanController.Mode.WALL_CREATION,
302         PlanController.Mode.WALL_CREATION, frame.planController.getMode());
303     planComponent.requestFocus();
304     JComponentTester tester = new JComponentTester();
305     tester.waitForIdle();
306     assertTrue("Plan component doesn't have focus", planComponent.hasFocus());
307     tester.actionKeyStroke(KeyEvent.VK_ENTER);
308     // Enter the coordinates of the start point
309     tester.actionKeyString("10");
310     tester.actionKeyStroke(KeyEvent.VK_TAB);
311     tester.actionKeyString("21");
312     tester.actionKeyStroke(KeyEvent.VK_ENTER);
313     // Enter the length of the wall
314     tester.actionKeyString("200");
315     tester.actionKeyStroke(KeyEvent.VK_ENTER);
316     // Create a wall with same length
317     Thread.sleep(500);
318     tester.actionKeyStroke(KeyEvent.VK_ENTER);
319     // Create a wall with same length, an angle at 270� and a thickness of 7,55 cm
320     tester.actionKeyStroke(KeyEvent.VK_DOWN);
321     tester.actionKeyStroke(KeyEvent.VK_HOME);
322     tester.actionKeyString("27");
323     tester.actionKeyStroke(KeyEvent.VK_DELETE); // Remove the 9 digit
324     tester.actionKeyStroke(KeyEvent.VK_UP);
325     tester.actionKeyStroke(KeyEvent.VK_UP);
326     tester.actionKeyStroke(KeyEvent.VK_END);
327     tester.actionKeyString("5 ");
328     tester.actionKeyStroke(KeyEvent.VK_ENTER);
329     tester.actionKeyStroke(KeyEvent.VK_ESCAPE);
330     // Check created walls
331     assertEquals("Wrong walls count", 3, frame.home.getWalls().size());
332     Wall wall1 = orderedWalls.get(0);
333     assertCoordinatesEqualWallPoints(10, 21, 210, 21, wall1);
334     Wall wall2 = orderedWalls.get(1);
335     assertCoordinatesEqualWallPoints(210, 21, 210, 221, wall2);
336     assertEquals("Wrong wall thickness", wall1.getThickness(), wall2.getThickness());
337     Wall wall3 = orderedWalls.get(2);
338     assertCoordinatesEqualWallPoints(210, 221, 410, 221, wall3);
339     assertEquals("Wrong wall thickness",
340         Float.parseFloat(String.valueOf(wall1.getThickness()) + "5"), wall3.getThickness());
341     assertWallsAreJoined(wall1, wall2, wall3);
342     assertSelectionContains(frame.home, wall1, wall2, wall3);
343 
344     // 3. Mix mouse and keyboard to create other walls
345     tester.actionClick(planComponent, 300, 200);
346     tester.actionMouseMove(planComponent,
347         new ComponentLocation(new Point(310, 200)));
348     tester.actionKeyStroke(KeyEvent.VK_ENTER);
349     // Enter the length and the angle of the wall
350     tester.actionKeyString("100");
351     tester.actionKeyStroke(KeyEvent.VK_TAB);
352     tester.actionKeyString("315");
353     tester.actionKeyStroke(KeyEvent.VK_ENTER);
354     // Create 3 walls with same length
355     Thread.sleep(500);
356     tester.actionKeyStroke(KeyEvent.VK_ENTER);
357     Thread.sleep(500);
358     tester.actionKeyStroke(KeyEvent.VK_ENTER);
359     // Take control with mouse
360     tester.actionMouseMove(planComponent,
361         new ComponentLocation(new Point(200, 200)));
362     tester.actionKeyPress(TestUtilities.getMagnetismToggleKey());
363     Wall wall7 = orderedWalls.get(7);
364     assertCoordinatesEqualWallPoints(wall7.getXStart(), wall7.getYStart(),
365         planComponent.convertXPixelToModel(200),
366         planComponent.convertYPixelToModel(200), wall7);
367     tester.waitForIdle();
368     tester.actionKeyRelease(TestUtilities.getMagnetismToggleKey());
369     // Take control again with keyboard and close the walls square
370     tester.actionKeyStroke(KeyEvent.VK_ENTER);
371     tester.actionKeyString("100");
372     tester.actionKeyStroke(KeyEvent.VK_TAB);
373     tester.actionKeyString("90");
374     tester.actionKeyStroke(KeyEvent.VK_ENTER);
375     // Check created walls
376     assertEquals("Wrong walls count", 7, frame.home.getWalls().size());
377     Wall wall4 = orderedWalls.get(4);
378     Wall wall5 = orderedWalls.get(5);
379     Wall wall6 = orderedWalls.get(6);
380     assertSelectionContains(frame.home, wall4, wall5, wall6, wall7);
381     assertWallsAreJoined(wall6, wall7, wall4);
382 
383     // 4. Create a dimension line with keyboard
384     frame.planController.setMode(PlanController.Mode.DIMENSION_LINE_CREATION);
385     assertEquals("Current mode isn't " + PlanController.Mode.DIMENSION_LINE_CREATION,
386         PlanController.Mode.DIMENSION_LINE_CREATION, frame.planController.getMode());
387     tester.actionClick(planComponent, 200, 300);
388     tester.actionKeyStroke(KeyEvent.VK_ENTER);
389     tester.actionKeyString("250"); // x start
390     tester.actionKeyStroke(KeyEvent.VK_ENTER);
391     tester.actionKeyString("200"); // length
392     tester.actionKeyStroke(KeyEvent.VK_TAB);
393     tester.actionKeyString("45"); // angle
394     tester.actionKeyStroke(KeyEvent.VK_ENTER);
395     tester.actionKeyString("50"); // offset
396     tester.actionKeyStroke(KeyEvent.VK_ENTER);
397 
398 
399     Collection<DimensionLine> dimensionLines = frame.home.getDimensionLines();
400     assertEquals("Incorrect dimension lines count", 1, dimensionLines.size());
401     DimensionLine dimensionLine = dimensionLines.iterator().next();
402     assertTrue("Incorrect X start " + 250 + " " + dimensionLine.getXStart(),
403         Math.abs(250 - dimensionLine.getXStart()) < 1E-10);
404     assertTrue("Incorrect Y start " + 560 + " " + dimensionLine.getYStart(),
405         Math.abs(560 - dimensionLine.getYStart()) < 1E-10);
406     assertTrue("Incorrect X end " + 391.421 + " " + dimensionLine.getXEnd(),
407         Math.abs(391.421 - dimensionLine.getXEnd()) < 1E-3);
408     assertTrue("Incorrect Y end " + 418.579 + " " + dimensionLine.getYEnd(),
409         Math.abs(418.579 - dimensionLine.getYEnd()) < 1E-3);
410     assertTrue("Incorrect offset " + 50 + " " + dimensionLine.getYEnd(),
411         Math.abs(50 - dimensionLine.getOffset()) < 1E-10);
412   }
413 
414   /**
415    * Asserts the start point and the end point of
416    * <code>wall</code> are at (<code>xStart</code>, <code>yStart</code>), (<code>xEnd</code>, <code>yEnd</code>).
417    */
assertCoordinatesEqualWallPoints(float xStart, float yStart, float xEnd, float yEnd, Wall wall)418   private void assertCoordinatesEqualWallPoints(float xStart, float yStart, float xEnd, float yEnd, Wall wall) {
419     assertTrue("Incorrect X start " + xStart + " " + wall.getXStart(),
420         Math.abs(xStart - wall.getXStart()) < 1E-4);
421     assertTrue("Incorrect Y start " + yStart + " " + wall.getYStart(),
422         Math.abs(yStart - wall.getYStart()) < 1E-4);
423     assertTrue("Incorrect X end " + xEnd + " " + wall.getXEnd(),
424         Math.abs(xEnd - wall.getXEnd()) < 1E-4);
425     assertTrue("Incorrect Y end " + yEnd + " " + wall.getYEnd(),
426         Math.abs(yEnd - wall.getYEnd()) < 1E-4);
427   }
428 
429   /**
430    * Asserts <code>wall</code> is joined to <code>wallAtStart</code>
431    * and <code>wallAtEnd</code>.
432    */
assertWallsAreJoined(Wall wallAtStart, Wall wall, Wall wallAtEnd)433   private void assertWallsAreJoined(Wall wallAtStart, Wall wall, Wall wallAtEnd) {
434     assertSame("Incorrect wall at start", wallAtStart, wall.getWallAtStart());
435     assertSame("Incorrect wall at end", wallAtEnd, wall.getWallAtEnd());
436   }
437 
438   /**
439    * Asserts <code>home</code> contains <code>walls</code>.
440    */
assertHomeContains(Home home, Wall ... walls)441   private void assertHomeContains(Home home, Wall ... walls) {
442     Collection<Wall> planWalls = home.getWalls();
443     assertEquals("Home walls incorrect count",
444         walls.length, planWalls.size());
445     for (Wall wall : walls) {
446       assertTrue("Wall doesn't belong to plan", planWalls.contains(wall));
447     }
448   }
449 
450   /**
451    * Asserts <code>walls</code> are the current selected ones in <code>home</code>.
452    */
assertSelectionContains(Home home, Wall ... walls)453   private void assertSelectionContains(Home home,
454                                        Wall ... walls) {
455     List<Selectable> selectedItems = home.getSelectedItems();
456     assertEquals(walls.length, selectedItems.size());
457     for (Wall wall : walls) {
458       assertTrue("Wall not selected", selectedItems.contains(wall));
459     }
460   }
461 
main(String [] args)462   public static void main(String [] args) {
463     JFrame frame = new PlanTestFrame();
464     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
465     frame.setVisible(true);
466   }
467 
468   private static class PlanTestFrame extends JFrame {
469     private final UserPreferences preferences;
470     private final Home            home;
471     private final PlanController  planController;
472     private final JToggleButton   modeButton;
473     private final JButton         undoButton;
474     private final JButton         redoButton;
475     private final JButton         reverseDirectionButton;
476     private final JButton         splitButton;
477 
PlanTestFrame()478     public PlanTestFrame() {
479       super("Plan Component Test");
480       // Create model objects
481       this.home = new Home();
482       this.home.getCompass().setVisible(false);
483       Locale.setDefault(Locale.FRANCE);
484       this.preferences = new DefaultUserPreferences();
485       ViewFactory viewFactory = new SwingViewFactory() {
486           @Override
487           public PlanView createPlanView(Home home, UserPreferences preferences, PlanController controller) {
488             return new PlanComponent(home, preferences, controller);
489           }
490         };
491       UndoableEditSupport undoSupport = new UndoableEditSupport();
492       final UndoManager undoManager = new UndoManager();
493       undoSupport.addUndoableEditListener(undoManager);
494       this.planController = new PlanController(this.home, this.preferences, viewFactory, null, undoSupport);
495       // Add plan component to frame at its preferred size
496       add(new JScrollPane((JComponent)this.planController.getView()));
497       // Create a toggle button for plan component mode
498       this.modeButton = new JToggleButton(new ImageIcon(
499           getClass().getResource("resources/Add16.gif")));
500       // Add listeners to modeButton that manages plan planController mode
501       this.modeButton.addActionListener(new ActionListener() {
502         public void actionPerformed(ActionEvent ev) {
503           if (modeButton.isSelected()) {
504             planController.setMode(PlanController.Mode.WALL_CREATION);
505           } else {
506             planController.setMode(PlanController.Mode.SELECTION);
507           }
508         }
509       });
510       // Create an undo button
511       this.undoButton = new JButton(new ImageIcon(
512           getClass().getResource("resources/Undo16.gif")));
513       this.undoButton.addActionListener(new ActionListener() {
514         public void actionPerformed(ActionEvent ev) {
515           undoManager.undo();
516         }
517       });
518       // Create a redo button
519       this.redoButton = new JButton(new ImageIcon(
520           getClass().getResource("resources/Redo16.gif")));
521       this.redoButton.addActionListener(new ActionListener() {
522         public void actionPerformed(ActionEvent ev) {
523           undoManager.redo();
524         }
525       });
526       this.reverseDirectionButton = new JButton("Reverse");
527       this.reverseDirectionButton.addActionListener(new ActionListener() {
528           public void actionPerformed(ActionEvent ev) {
529             planController.reverseSelectedWallsDirection();
530           }
531         });
532       this.splitButton = new JButton("Split");
533       this.splitButton.addActionListener(new ActionListener() {
534           public void actionPerformed(ActionEvent ev) {
535             planController.splitSelectedWall();
536           }
537         });
538       // Add a tool bar to the frame with mode toggle button,
539       // undo and redo buttons
540       JToolBar toolBar = new JToolBar();
541       toolBar.add(this.modeButton);
542       toolBar.add(this.undoButton);
543       toolBar.add(this.redoButton);
544       toolBar.add(this.reverseDirectionButton);
545       toolBar.add(this.splitButton);
546       // Add the tool bar at top of the window
547       add(toolBar, BorderLayout.NORTH);
548       // Pack frame to ensure home plan component is at its preferred size
549       pack();
550     }
551   }
552 }
553