1 /*
2  * WallController.java 30 mai 07
3  *
4  * Sweet Home 3D, Copyright (c) 2007 Emmanuel PUYBARET / eTeks <info@eteks.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 package com.eteks.sweethome3d.viewcontroller;
21 
22 import java.awt.geom.Point2D;
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
25 import java.beans.PropertyChangeSupport;
26 import java.util.Arrays;
27 import java.util.List;
28 
29 import javax.swing.undo.CannotRedoException;
30 import javax.swing.undo.CannotUndoException;
31 import javax.swing.undo.UndoableEdit;
32 import javax.swing.undo.UndoableEditSupport;
33 
34 import com.eteks.sweethome3d.model.Baseboard;
35 import com.eteks.sweethome3d.model.Home;
36 import com.eteks.sweethome3d.model.HomeTexture;
37 import com.eteks.sweethome3d.model.Selectable;
38 import com.eteks.sweethome3d.model.TextureImage;
39 import com.eteks.sweethome3d.model.UserPreferences;
40 import com.eteks.sweethome3d.model.Wall;
41 
42 /**
43  * A MVC controller for wall view.
44  * @author Emmanuel Puybaret
45  */
46 public class WallController implements Controller {
47   /**
48    * The properties that may be edited by the view associated to this controller.
49    */
50   public enum Property {X_START, Y_START, X_END, Y_END, LENGTH, DISTANCE_TO_END_POINT, EDITABLE_POINTS,
51       LEFT_SIDE_COLOR, LEFT_SIDE_PAINT, LEFT_SIDE_SHININESS,
52       RIGHT_SIDE_COLOR, RIGHT_SIDE_PAINT, RIGHT_SIDE_SHININESS,
53       PATTERN, TOP_COLOR, TOP_PAINT,
54       SHAPE, RECTANGULAR_WALL_HEIGHT, SLOPING_WALL_HEIGHT_AT_START, SLOPING_WALL_HEIGHT_AT_END,
55       THICKNESS, ARC_EXTENT_IN_DEGREES}
56   /**
57    * The possible values for {@linkplain #getShape() wall shape}.
58    */
59   public enum WallShape {RECTANGULAR_WALL, SLOPING_WALL}
60   /**
61    * The possible values for {@linkplain #getLeftSidePaint() wall paint type}.
62    */
63   public enum WallPaint {DEFAULT, COLORED, TEXTURED}
64 
65   private final Home                  home;
66   private final UserPreferences       preferences;
67   private final ViewFactory           viewFactory;
68   private final ContentManager        contentManager;
69   private final UndoableEditSupport   undoSupport;
70   private TextureChoiceController     leftSideTextureController;
71   private BaseboardChoiceController   leftSideBaseboardController;
72   private TextureChoiceController     rightSideTextureController;
73   private BaseboardChoiceController   rightSideBaseboardController;
74   private final PropertyChangeSupport propertyChangeSupport;
75   private DialogView                  wallView;
76 
77   private boolean      editablePoints;
78   private Float        xStart;
79   private Float        yStart;
80   private Float        xEnd;
81   private Float        yEnd;
82   private Float        length;
83   private Float        distanceToEndPoint;
84   private Integer      leftSideColor;
85   private WallPaint    leftSidePaint;
86   private Float        leftSideShininess;
87   private Integer      rightSideColor;
88   private WallPaint    rightSidePaint;
89   private Float        rightSideShininess;
90   private TextureImage pattern;
91   private Integer      topColor;
92   private WallPaint    topPaint;
93   private WallShape    shape;
94   private Float        rectangularWallHeight;
95   private Float        slopingWallHeightAtStart;
96   private Float        sloppingWallHeightAtEnd;
97   private Float        thickness;
98   private Float        arcExtentInDegrees;
99 
100   /**
101    * Creates the controller of wall view with undo support.
102    */
WallController(final Home home, UserPreferences preferences, ViewFactory viewFactory, ContentManager contentManager, UndoableEditSupport undoSupport)103   public WallController(final Home home,
104                         UserPreferences preferences,
105                         ViewFactory viewFactory,
106                         ContentManager contentManager,
107                         UndoableEditSupport undoSupport) {
108     this.home = home;
109     this.preferences = preferences;
110     this.viewFactory = viewFactory;
111     this.contentManager = contentManager;
112     this.undoSupport = undoSupport;
113     this.propertyChangeSupport = new PropertyChangeSupport(this);
114 
115     updateProperties();
116   }
117 
118   /**
119    * Returns the texture controller of the wall left side.
120    */
getLeftSideTextureController()121   public TextureChoiceController getLeftSideTextureController() {
122     // Create sub controller lazily only once it's needed
123     if (this.leftSideTextureController == null) {
124       this.leftSideTextureController = new TextureChoiceController(
125           this.preferences.getLocalizedString(WallController.class, "leftSideTextureTitle"),
126           this.preferences, this.viewFactory, this.contentManager);
127       this.leftSideTextureController.addPropertyChangeListener(TextureChoiceController.Property.TEXTURE,
128           new PropertyChangeListener() {
129             public void propertyChange(PropertyChangeEvent ev) {
130               setLeftSidePaint(WallPaint.TEXTURED);
131             }
132           });
133     }
134     return this.leftSideTextureController;
135   }
136 
137   /**
138    * Returns the controller of the wall left side baseboard.
139    * @since 5.0
140    */
getLeftSideBaseboardController()141   public BaseboardChoiceController getLeftSideBaseboardController() {
142     // Create sub controller lazily only once it's needed
143     if (this.leftSideBaseboardController == null) {
144       this.leftSideBaseboardController = new BaseboardChoiceController(
145           this.preferences, this.viewFactory, this.contentManager);
146     }
147     return this.leftSideBaseboardController;
148   }
149 
150   /**
151    * Returns the texture controller of the wall right side.
152    */
getRightSideTextureController()153   public TextureChoiceController getRightSideTextureController() {
154     // Create sub controller lazily only once it's needed
155     if (this.rightSideTextureController == null) {
156       this.rightSideTextureController = new TextureChoiceController(
157           this.preferences.getLocalizedString(WallController.class, "rightSideTextureTitle"),
158           this.preferences, this.viewFactory, this.contentManager);
159       this.rightSideTextureController.addPropertyChangeListener(TextureChoiceController.Property.TEXTURE,
160           new PropertyChangeListener() {
161             public void propertyChange(PropertyChangeEvent ev) {
162               setRightSidePaint(WallPaint.TEXTURED);
163             }
164           });
165     }
166     return this.rightSideTextureController;
167   }
168 
169   /**
170    * Returns the controller of the wall right side baseboard.
171    * @since 5.0
172    */
getRightSideBaseboardController()173   public BaseboardChoiceController getRightSideBaseboardController() {
174     // Create sub controller lazily only once it's needed
175     if (this.rightSideBaseboardController == null) {
176       this.rightSideBaseboardController = new BaseboardChoiceController(
177           this.preferences, this.viewFactory, this.contentManager);
178     }
179     return this.rightSideBaseboardController;
180   }
181 
182   /**
183    * Returns the view associated with this controller.
184    */
getView()185   public DialogView getView() {
186     // Create view lazily only once it's needed
187     if (this.wallView == null) {
188       this.wallView = this.viewFactory.createWallView(this.preferences, this);
189     }
190     return this.wallView;
191   }
192 
193   /**
194    * Displays the view controlled by this controller.
195    */
displayView(View parentView)196   public void displayView(View parentView) {
197     getView().displayView(parentView);
198   }
199 
200   /**
201    * Adds the property change <code>listener</code> in parameter to this controller.
202    */
addPropertyChangeListener(Property property, PropertyChangeListener listener)203   public void addPropertyChangeListener(Property property, PropertyChangeListener listener) {
204     this.propertyChangeSupport.addPropertyChangeListener(property.name(), listener);
205   }
206 
207   /**
208    * Removes the property change <code>listener</code> in parameter from this controller.
209    */
removePropertyChangeListener(Property property, PropertyChangeListener listener)210   public void removePropertyChangeListener(Property property, PropertyChangeListener listener) {
211     this.propertyChangeSupport.removePropertyChangeListener(property.name(), listener);
212   }
213 
214   /**
215    * Updates edited properties from selected walls in the home edited by this controller.
216    */
updateProperties()217   protected void updateProperties() {
218     List<Wall> selectedWalls = Home.getWallsSubList(this.home.getSelectedItems());
219     if (selectedWalls.isEmpty()) {
220       setXStart(null); // Nothing to edit
221       setYStart(null);
222       setXEnd(null);
223       setYEnd(null);
224       setEditablePoints(false);
225       setLeftSideColor(null);
226       getLeftSideTextureController().setTexture(null);
227       setLeftSidePaint(null);
228       setLeftSideShininess(null);
229       getLeftSideBaseboardController().setVisible(null);
230       getLeftSideBaseboardController().setThickness(null);
231       getLeftSideBaseboardController().setHeight(null);
232       getLeftSideBaseboardController().setColor(null);
233       getLeftSideBaseboardController().getTextureController().setTexture(null);
234       getLeftSideBaseboardController().setPaint(null);
235       setRightSideColor(null);
236       getRightSideTextureController().setTexture(null);
237       setRightSidePaint(null);
238       setRightSideShininess(null);
239       getRightSideBaseboardController().setVisible(null);
240       getRightSideBaseboardController().setThickness(null);
241       getRightSideBaseboardController().setHeight(null);
242       getRightSideBaseboardController().setColor(null);
243       getRightSideBaseboardController().getTextureController().setTexture(null);
244       getRightSideBaseboardController().setPaint(null);
245       setPattern(null);
246       setTopColor(null);
247       setTopPaint(null);
248       setRectangularWallHeight(null);
249       setSlopingWallHeightAtStart(null);
250       setSlopingWallHeightAtEnd(null);
251       setShape(null);
252       setThickness(null);
253       setArcExtentInDegrees(null);
254     } else {
255       // Search the common properties among selected walls
256       Wall firstWall = selectedWalls.get(0);
257       boolean multipleSelection = selectedWalls.size() > 1;
258 
259       setEditablePoints(!multipleSelection);
260 
261       // Search the common xStart value among walls
262       Float xStart = firstWall.getXStart();
263       for (int i = 1; i < selectedWalls.size(); i++) {
264         if (!xStart.equals(selectedWalls.get(i).getXStart())) {
265           xStart = null;
266           break;
267         }
268       }
269       setXStart(xStart);
270 
271       // Search the common yStart value among walls
272       Float yStart = firstWall.getYStart();
273       for (int i = 1; i < selectedWalls.size(); i++) {
274         if (!yStart.equals(selectedWalls.get(i).getYStart())) {
275           yStart = null;
276           break;
277         }
278       }
279       setYStart(yStart);
280 
281       // Search the common xEnd value among walls
282       Float xEnd = firstWall.getXEnd();
283       for (int i = 1; i < selectedWalls.size(); i++) {
284         if (!xEnd.equals(selectedWalls.get(i).getXEnd())) {
285           xEnd = null;
286           break;
287         }
288       }
289       setXEnd(xEnd);
290 
291       // Search the common yEnd value among walls
292       Float yEnd = firstWall.getYEnd();
293       for (int i = 1; i < selectedWalls.size(); i++) {
294         if (!yEnd.equals(selectedWalls.get(i).getYEnd())) {
295           yEnd = null;
296           break;
297         }
298       }
299       setYEnd(yEnd);
300 
301       // Search the common left side color among walls
302       Integer leftSideColor = firstWall.getLeftSideColor();
303       if (leftSideColor != null) {
304         for (int i = 1; i < selectedWalls.size(); i++) {
305           if (!leftSideColor.equals(selectedWalls.get(i).getLeftSideColor())) {
306             leftSideColor = null;
307             break;
308           }
309         }
310       }
311       setLeftSideColor(leftSideColor);
312 
313       // Search the common left side texture among walls
314       HomeTexture leftSideTexture = firstWall.getLeftSideTexture();
315       if (leftSideTexture != null) {
316         for (int i = 1; i < selectedWalls.size(); i++) {
317           if (!leftSideTexture.equals(selectedWalls.get(i).getLeftSideTexture())) {
318             leftSideTexture = null;
319             break;
320           }
321         }
322       }
323       getLeftSideTextureController().setTexture(leftSideTexture);
324 
325       boolean defaultColorsAndTextures = true;
326       for (int i = 0; i < selectedWalls.size(); i++) {
327         Wall wall = selectedWalls.get(i);
328         if (wall.getLeftSideColor() != null
329             || wall.getLeftSideTexture() != null) {
330           defaultColorsAndTextures = false;
331           break;
332         }
333       }
334 
335       if (leftSideColor != null) {
336         setLeftSidePaint(WallPaint.COLORED);
337       } else if (leftSideTexture != null) {
338         setLeftSidePaint(WallPaint.TEXTURED);
339       } else if (defaultColorsAndTextures) {
340         setLeftSidePaint(WallPaint.DEFAULT);
341       } else {
342         setLeftSidePaint(null);
343       }
344 
345       // Search the common left side shininess value among walls
346       Float leftSideShininess = firstWall.getLeftSideShininess();
347       for (int i = 1; i < selectedWalls.size(); i++) {
348         if (!leftSideShininess.equals(selectedWalls.get(i).getLeftSideShininess())) {
349           leftSideShininess = null;
350           break;
351         }
352       }
353       setLeftSideShininess(leftSideShininess);
354 
355       Boolean leftSideBaseboardVisible = firstWall.getLeftSideBaseboard() != null;
356       for (int i = 1; i < selectedWalls.size(); i++) {
357         if (leftSideBaseboardVisible != (selectedWalls.get(i).getLeftSideBaseboard() != null)) {
358           leftSideBaseboardVisible = null;
359           break;
360         }
361       }
362       getLeftSideBaseboardController().setVisible(leftSideBaseboardVisible);
363 
364       // Search the common thickness left baseboard among walls
365       Baseboard firstWallLeftSideBaseboard = firstWall.getLeftSideBaseboard();
366       Float leftSideBaseboardThickness = firstWallLeftSideBaseboard != null
367           ? firstWallLeftSideBaseboard.getThickness()
368           : this.preferences.getNewWallBaseboardThickness();
369       for (int i = 1; i < selectedWalls.size(); i++) {
370         Baseboard baseboard = selectedWalls.get(i).getLeftSideBaseboard();
371         if (!leftSideBaseboardThickness.equals(baseboard != null
372                 ? baseboard.getThickness()
373                 : this.preferences.getNewWallBaseboardThickness())) {
374           leftSideBaseboardThickness = null;
375           break;
376         }
377       }
378       getLeftSideBaseboardController().setThickness(leftSideBaseboardThickness);
379 
380       // Search the common height left baseboard among walls
381       Float leftSideBaseboardHeight = firstWallLeftSideBaseboard != null
382           ? firstWallLeftSideBaseboard.getHeight()
383           : this.preferences.getNewWallBaseboardHeight();
384       for (int i = 1; i < selectedWalls.size(); i++) {
385         Baseboard baseboard = selectedWalls.get(i).getLeftSideBaseboard();
386         if (!leftSideBaseboardHeight.equals(baseboard != null
387                 ? baseboard.getHeight()
388                 : this.preferences.getNewWallBaseboardHeight())) {
389           leftSideBaseboardHeight = null;
390           break;
391         }
392       }
393       getLeftSideBaseboardController().setHeight(leftSideBaseboardHeight);
394 
395       // Search the common left baseboard color among walls
396       Integer leftSideBaseboardColor = firstWallLeftSideBaseboard != null
397           ? firstWallLeftSideBaseboard.getColor()
398           : null;
399       if (leftSideBaseboardColor != null) {
400         for (int i = 1; i < selectedWalls.size(); i++) {
401           Baseboard baseboard = selectedWalls.get(i).getLeftSideBaseboard();
402           if (baseboard == null
403               || !leftSideBaseboardColor.equals(baseboard.getColor())) {
404             leftSideBaseboardColor = null;
405             break;
406           }
407         }
408       }
409       getLeftSideBaseboardController().setColor(leftSideBaseboardColor);
410 
411       // Search the common left baseboard texture among walls
412       HomeTexture leftSideBaseboardTexture = firstWallLeftSideBaseboard != null
413           ? firstWallLeftSideBaseboard.getTexture()
414           : null;
415       if (leftSideBaseboardTexture != null) {
416         for (int i = 1; i < selectedWalls.size(); i++) {
417           Baseboard baseboard = selectedWalls.get(i).getLeftSideBaseboard();
418           if (baseboard == null
419               || !leftSideBaseboardTexture.equals(baseboard.getTexture())) {
420             leftSideBaseboardTexture = null;
421             break;
422           }
423         }
424       }
425       getLeftSideBaseboardController().getTextureController().setTexture(leftSideBaseboardTexture);
426 
427       defaultColorsAndTextures = true;
428       for (int i = 0; i < selectedWalls.size(); i++) {
429         Baseboard baseboard = selectedWalls.get(i).getLeftSideBaseboard();
430         if (baseboard != null
431             && (baseboard.getColor() != null
432                 || baseboard.getTexture() != null)) {
433           defaultColorsAndTextures = false;
434           break;
435         }
436       }
437 
438       if (leftSideBaseboardColor != null) {
439         getLeftSideBaseboardController().setPaint(BaseboardChoiceController.BaseboardPaint.COLORED);
440       } else if (leftSideBaseboardTexture != null) {
441         getLeftSideBaseboardController().setPaint(BaseboardChoiceController.BaseboardPaint.TEXTURED);
442       } else if (defaultColorsAndTextures) {
443         getLeftSideBaseboardController().setPaint(BaseboardChoiceController.BaseboardPaint.DEFAULT);
444       } else {
445         getLeftSideBaseboardController().setPaint(null);
446       }
447 
448       // Search the common right side color among walls
449       Integer rightSideColor = firstWall.getRightSideColor();
450       if (rightSideColor != null) {
451         for (int i = 1; i < selectedWalls.size(); i++) {
452           if (!rightSideColor.equals(selectedWalls.get(i).getRightSideColor())) {
453             rightSideColor = null;
454             break;
455           }
456         }
457       }
458       setRightSideColor(rightSideColor);
459 
460       // Search the common right side texture among walls
461       HomeTexture rightSideTexture = firstWall.getRightSideTexture();
462       if (rightSideTexture != null) {
463         for (int i = 1; i < selectedWalls.size(); i++) {
464           if (!rightSideTexture.equals(selectedWalls.get(i).getRightSideTexture())) {
465             rightSideTexture = null;
466             break;
467           }
468         }
469       }
470       getRightSideTextureController().setTexture(rightSideTexture);
471 
472       defaultColorsAndTextures = true;
473       for (int i = 0; i < selectedWalls.size(); i++) {
474         Wall wall = selectedWalls.get(i);
475         if (wall.getRightSideColor() != null
476             || wall.getRightSideTexture() != null) {
477           defaultColorsAndTextures = false;
478           break;
479         }
480       }
481 
482       if (rightSideColor != null) {
483         setRightSidePaint(WallPaint.COLORED);
484       } else if (rightSideTexture != null) {
485         setRightSidePaint(WallPaint.TEXTURED);
486       } else if (defaultColorsAndTextures) {
487         setRightSidePaint(WallPaint.DEFAULT);
488       } else {
489         setRightSidePaint(null);
490       }
491 
492       // Search the common right side shininess value among walls
493       Float rightSideShininess = firstWall.getRightSideShininess();
494       for (int i = 1; i < selectedWalls.size(); i++) {
495         if (!rightSideShininess.equals(selectedWalls.get(i).getRightSideShininess())) {
496           rightSideShininess = null;
497           break;
498         }
499       }
500       setRightSideShininess(rightSideShininess);
501 
502       Boolean rightSideBaseboardVisible = firstWall.getRightSideBaseboard() != null;
503       for (int i = 1; i < selectedWalls.size(); i++) {
504         if (rightSideBaseboardVisible != (selectedWalls.get(i).getRightSideBaseboard() != null)) {
505           rightSideBaseboardVisible = null;
506           break;
507         }
508       }
509       getRightSideBaseboardController().setVisible(rightSideBaseboardVisible);
510 
511       // Search the common thickness right baseboard among walls
512       Baseboard firstWallRightSideBaseboard = firstWall.getRightSideBaseboard();
513       Float rightSideBaseboardThickness = firstWallRightSideBaseboard != null
514           ? firstWallRightSideBaseboard.getThickness()
515           : this.preferences.getNewWallBaseboardThickness();
516       for (int i = 1; i < selectedWalls.size(); i++) {
517         Baseboard baseboard = selectedWalls.get(i).getRightSideBaseboard();
518         if (!rightSideBaseboardThickness.equals(baseboard != null
519                 ? baseboard.getThickness()
520                 : this.preferences.getNewWallBaseboardThickness())) {
521           rightSideBaseboardThickness = null;
522           break;
523         }
524       }
525       getRightSideBaseboardController().setThickness(rightSideBaseboardThickness);
526 
527       // Search the common height right baseboard among walls
528       Float rightSideBaseboardHeight = firstWallRightSideBaseboard != null
529           ? firstWallRightSideBaseboard.getHeight()
530           : this.preferences.getNewWallBaseboardHeight();
531       for (int i = 1; i < selectedWalls.size(); i++) {
532         Baseboard baseboard = selectedWalls.get(i).getRightSideBaseboard();
533         if (!rightSideBaseboardHeight.equals(baseboard != null
534                 ? baseboard.getHeight()
535                 : this.preferences.getNewWallBaseboardHeight())) {
536           rightSideBaseboardHeight = null;
537           break;
538         }
539       }
540       getRightSideBaseboardController().setHeight(rightSideBaseboardHeight);
541 
542       // Search the common right baseboard color among walls
543       Integer rightSideBaseboardColor = firstWallRightSideBaseboard != null
544           ? firstWallRightSideBaseboard.getColor()
545           : null;
546       if (rightSideBaseboardColor != null) {
547         for (int i = 1; i < selectedWalls.size(); i++) {
548           Baseboard baseboard = selectedWalls.get(i).getRightSideBaseboard();
549           if (baseboard == null
550               || !rightSideBaseboardColor.equals(baseboard.getColor())) {
551             rightSideBaseboardColor = null;
552             break;
553           }
554         }
555       }
556       getRightSideBaseboardController().setColor(rightSideBaseboardColor);
557 
558       // Search the common right baseboard texture among walls
559       HomeTexture rightSideBaseboardTexture = firstWallRightSideBaseboard != null
560           ? firstWallRightSideBaseboard.getTexture()
561           : null;
562       if (rightSideBaseboardTexture != null) {
563         for (int i = 1; i < selectedWalls.size(); i++) {
564           Baseboard baseboard = selectedWalls.get(i).getRightSideBaseboard();
565           if (baseboard == null
566               || !rightSideBaseboardTexture.equals(baseboard.getTexture())) {
567             rightSideBaseboardTexture = null;
568             break;
569           }
570         }
571       }
572       getRightSideBaseboardController().getTextureController().setTexture(rightSideBaseboardTexture);
573 
574       defaultColorsAndTextures = true;
575       for (int i = 0; i < selectedWalls.size(); i++) {
576         Baseboard baseboard = selectedWalls.get(i).getRightSideBaseboard();
577         if (baseboard != null
578             && (baseboard.getColor() != null
579                 || baseboard.getTexture() != null)) {
580           defaultColorsAndTextures = false;
581           break;
582         }
583       }
584 
585       if (rightSideBaseboardColor != null) {
586         getRightSideBaseboardController().setPaint(BaseboardChoiceController.BaseboardPaint.COLORED);
587       } else if (rightSideBaseboardTexture != null) {
588         getRightSideBaseboardController().setPaint(BaseboardChoiceController.BaseboardPaint.TEXTURED);
589       } else if (defaultColorsAndTextures) {
590         getRightSideBaseboardController().setPaint(BaseboardChoiceController.BaseboardPaint.DEFAULT);
591       } else {
592         getRightSideBaseboardController().setPaint(null);
593       }
594 
595       // Search the common pattern among walls
596       TextureImage pattern = firstWall.getPattern();
597       if (pattern == null) {
598         pattern = this.preferences.getWallPattern();
599       }
600       for (int i = 1; i < selectedWalls.size(); i++) {
601         TextureImage otherPattern = selectedWalls.get(i).getPattern();
602         if (otherPattern == null) {
603           otherPattern = this.preferences.getWallPattern();
604         }
605         if (!pattern.equals(otherPattern)) {
606           pattern = null;
607           break;
608         }
609       }
610       setPattern(pattern);
611 
612       // Search the common top color among walls
613       Integer topColor = firstWall.getTopColor();
614       boolean defaultTopColor;
615       if (topColor != null) {
616         defaultTopColor = false;
617         for (int i = 1; i < selectedWalls.size(); i++) {
618           if (!topColor.equals(selectedWalls.get(i).getTopColor())) {
619             topColor = null;
620             break;
621           }
622         }
623       } else {
624         defaultTopColor = true;
625         for (int i = 1; i < selectedWalls.size(); i++) {
626           if (selectedWalls.get(i).getTopColor() != null) {
627             defaultTopColor = false;
628             break;
629           }
630         }
631       }
632       setTopColor(topColor);
633 
634       if (defaultTopColor) {
635         setTopPaint(WallPaint.DEFAULT);
636       } else if (topColor != null) {
637         setTopPaint(WallPaint.COLORED);
638       } else {
639         setTopPaint(null);
640       }
641 
642       // Search the common height among walls
643       Float height = firstWall.getHeight();
644       // If wall height was never set, use home wall height
645       if (height == null && firstWall.getHeight() == null) {
646         height = this.home.getWallHeight();
647       }
648       for (int i = 1; i < selectedWalls.size(); i++) {
649         Wall wall = selectedWalls.get(i);
650         float wallHeight = wall.getHeight() == null
651             ? this.home.getWallHeight()
652             : wall.getHeight();
653         if (height != wallHeight) {
654           height = null;
655           break;
656         }
657       }
658       setRectangularWallHeight(height);
659       setSlopingWallHeightAtStart(height);
660 
661       // Search the common height at end among walls
662       Float heightAtEnd = firstWall.getHeightAtEnd();
663       if (heightAtEnd != null) {
664         for (int i = 1; i < selectedWalls.size(); i++) {
665           if (!heightAtEnd.equals(selectedWalls.get(i).getHeightAtEnd())) {
666             heightAtEnd = null;
667             break;
668           }
669         }
670       }
671       setSlopingWallHeightAtEnd(heightAtEnd == null && selectedWalls.size() == 1 ? height : heightAtEnd);
672 
673       boolean allWallsRectangular = !firstWall.isTrapezoidal();
674       boolean allWallsTrapezoidal = firstWall.isTrapezoidal();
675       for (int i = 1; i < selectedWalls.size(); i++) {
676         if (!selectedWalls.get(i).isTrapezoidal()) {
677           allWallsTrapezoidal = false;
678         } else {
679           allWallsRectangular = false;
680         }
681       }
682       if (allWallsRectangular) {
683         setShape(WallShape.RECTANGULAR_WALL);
684       } else if (allWallsTrapezoidal) {
685         setShape(WallShape.SLOPING_WALL);
686       } else {
687         setShape(null);
688       }
689 
690       // Search the common thickness among walls
691       Float thickness = firstWall.getThickness();
692       for (int i = 1; i < selectedWalls.size(); i++) {
693         if (thickness != selectedWalls.get(i).getThickness()) {
694           thickness = null;
695           break;
696         }
697       }
698       setThickness(thickness);
699 
700       // Search the common arc extent among walls
701       Float arcExtent = firstWall.getArcExtent();
702       if (arcExtent != null) {
703         for (int i = 1; i < selectedWalls.size(); i++) {
704           if (!arcExtent.equals(selectedWalls.get(i).getArcExtent())) {
705             arcExtent = null;
706             break;
707           }
708         }
709       }
710       if (arcExtent != null) {
711         setArcExtentInDegrees((float)Math.toDegrees(arcExtent));
712       } else {
713         setArcExtentInDegrees(selectedWalls.size() == 1 ? new Float(0) : null);
714       }
715     }
716   }
717 
718   /**
719    * Sets the edited abscissa of the start point.
720    */
setXStart(Float xStart)721   public void setXStart(Float xStart) {
722     if (xStart != this.xStart) {
723       Float oldXStart = this.xStart;
724       this.xStart = xStart;
725       this.propertyChangeSupport.firePropertyChange(Property.X_START.name(), oldXStart, xStart);
726       updateLength();
727       updateDistanceToEndPoint();
728     }
729   }
730 
731   /**
732    * Returns the edited abscissa of the start point.
733    */
getXStart()734   public Float getXStart() {
735     return this.xStart;
736   }
737 
738   /**
739    * Sets the edited ordinate of the start point.
740    */
setYStart(Float yStart)741   public void setYStart(Float yStart) {
742     if (yStart != this.yStart) {
743       Float oldYStart = this.yStart;
744       this.yStart = yStart;
745       this.propertyChangeSupport.firePropertyChange(Property.Y_START.name(), oldYStart, yStart);
746       updateLength();
747       updateDistanceToEndPoint();
748     }
749   }
750 
751   /**
752    * Returns the edited ordinate of the start point.
753    */
getYStart()754   public Float getYStart() {
755     return this.yStart;
756   }
757 
758   /**
759    * Sets the edited abscissa of the end point.
760    */
setXEnd(Float xEnd)761   public void setXEnd(Float xEnd) {
762     if (xEnd != this.xEnd) {
763       Float oldXEnd = this.xEnd;
764       this.xEnd = xEnd;
765       this.propertyChangeSupport.firePropertyChange(Property.X_END.name(), oldXEnd, xEnd);
766       updateLength();
767       updateDistanceToEndPoint();
768     }
769   }
770 
771   /**
772    * Returns the edited abscissa of the end point.
773    */
getXEnd()774   public Float getXEnd() {
775     return this.xEnd;
776   }
777 
778   /**
779    * Sets the edited ordinate of the end point.
780    */
setYEnd(Float yEnd)781   public void setYEnd(Float yEnd) {
782     if (yEnd != this.yEnd) {
783       Float oldYEnd = this.yEnd;
784       this.yEnd = yEnd;
785       this.propertyChangeSupport.firePropertyChange(Property.Y_END.name(), oldYEnd, yEnd);
786       updateLength();
787       updateDistanceToEndPoint();
788     }
789   }
790 
791   /**
792    * Returns the edited ordinate of the end point.
793    */
getYEnd()794   public Float getYEnd() {
795     return this.yEnd;
796   }
797 
798   /**
799    * Updates the edited length after its coordinates change.
800    */
updateLength()801   private void updateLength() {
802     Float xStart = getXStart();
803     Float yStart = getYStart();
804     Float xEnd = getXEnd();
805     Float yEnd = getYEnd();
806     if (xStart != null && yStart != null && xEnd != null && yEnd != null) {
807       Wall wall = new Wall(xStart, yStart, xEnd, yEnd, 0, 0);
808       Float arcExtent = getArcExtentInDegrees();
809       if (arcExtent != null) {
810         wall.setArcExtent((float)Math.toRadians(arcExtent));
811       }
812       setLength(wall.getLength(), false);
813     } else {
814       setLength(null, false);
815     }
816   }
817 
818   /**
819    * Sets the edited length.
820    */
setLength(Float length)821   public void setLength(Float length) {
822     setLength(length, true);
823   }
824 
825   /**
826    * Returns the edited length.
827    */
getLength()828   public Float getLength() {
829     return this.length;
830   }
831 
832   /**
833    * Sets the edited length and updates the coordinates of the end point if
834    * <code>updateEndPoint</code> is <code>true</code>.
835    */
setLength(Float length, boolean updateEndPoint)836   private void setLength(Float length, boolean updateEndPoint) {
837     if (length != this.length) {
838       Float oldLength = this.length;
839       this.length = length;
840       this.propertyChangeSupport.firePropertyChange(Property.LENGTH.name(), oldLength, length);
841 
842       if (updateEndPoint) {
843         Float xStart = getXStart();
844         Float yStart = getYStart();
845         Float xEnd = getXEnd();
846         Float yEnd = getYEnd();
847         if (xStart != null && yStart != null && xEnd != null && yEnd != null && length != null) {
848           if (getArcExtentInDegrees() != null && getArcExtentInDegrees().floatValue() == 0) {
849             double wallAngle = Math.atan2(yStart - yEnd, xEnd - xStart);
850             setXEnd((float)(xStart + length * Math.cos(wallAngle)));
851             setYEnd((float)(yStart - length * Math.sin(wallAngle)));
852           } else {
853             throw new UnsupportedOperationException(
854                 "Computing end point of a round wall from its length not supported");
855           }
856         } else {
857           setXEnd(null);
858           setYEnd(null);
859         }
860       }
861     }
862   }
863 
864   /**
865    * Updates the edited distance to end point after its coordinates change.
866    */
updateDistanceToEndPoint()867   private void updateDistanceToEndPoint() {
868     Float xStart = getXStart();
869     Float yStart = getYStart();
870     Float xEnd = getXEnd();
871     Float yEnd = getYEnd();
872     if (xStart != null && yStart != null && xEnd != null && yEnd != null) {
873       setDistanceToEndPoint((float)Point2D.distance(xStart, yStart, xEnd, yEnd), false);
874     } else {
875       setDistanceToEndPoint(null, false);
876     }
877   }
878 
879   /**
880    * Sets the edited distance to end point.
881    */
setDistanceToEndPoint(Float distanceToEndPoint)882   public void setDistanceToEndPoint(Float distanceToEndPoint) {
883     setDistanceToEndPoint(distanceToEndPoint, true);
884   }
885 
886   /**
887    * Sets the edited distance to end point and updates the coordinates of the end point if
888    * <code>updateEndPoint</code> is <code>true</code>.
889    */
setDistanceToEndPoint(Float distanceToEndPoint, boolean updateEndPoint)890   private void setDistanceToEndPoint(Float distanceToEndPoint, boolean updateEndPoint) {
891     if (distanceToEndPoint != this.distanceToEndPoint) {
892       Float oldDistance = this.distanceToEndPoint;
893       this.distanceToEndPoint = distanceToEndPoint;
894       this.propertyChangeSupport.firePropertyChange(Property.DISTANCE_TO_END_POINT.name(), oldDistance, distanceToEndPoint);
895 
896       if (updateEndPoint) {
897         Float xStart = getXStart();
898         Float yStart = getYStart();
899         Float xEnd = getXEnd();
900         Float yEnd = getYEnd();
901         if (xStart != null && yStart != null && xEnd != null && yEnd != null && distanceToEndPoint != null) {
902           double wallAngle = Math.atan2(yStart - yEnd, xEnd - xStart);
903           setXEnd((float)(xStart + distanceToEndPoint * Math.cos(wallAngle)));
904           setYEnd((float)(yStart - distanceToEndPoint * Math.sin(wallAngle)));
905         } else {
906           setXEnd(null);
907           setYEnd(null);
908         }
909       }
910     }
911   }
912 
913   /**
914    * Returns the edited distance to end point.
915    */
getDistanceToEndPoint()916   public Float getDistanceToEndPoint() {
917     return this.distanceToEndPoint;
918   }
919 
920   /**
921    * Sets whether the point coordinates can be be edited or not.
922    */
setEditablePoints(boolean editablePoints)923   public void setEditablePoints(boolean editablePoints) {
924     if (editablePoints != this.editablePoints) {
925       this.editablePoints = editablePoints;
926       this.propertyChangeSupport.firePropertyChange(Property.EDITABLE_POINTS.name(), !editablePoints, editablePoints);
927     }
928   }
929 
930   /**
931    * Returns whether the point coordinates can be be edited or not.
932    */
isEditablePoints()933   public boolean isEditablePoints() {
934     return this.editablePoints;
935   }
936 
937   /**
938    * Sets the edited color of the left side.
939    */
setLeftSideColor(Integer leftSideColor)940   public void setLeftSideColor(Integer leftSideColor) {
941     if (leftSideColor != this.leftSideColor) {
942       Integer oldLeftSideColor = this.leftSideColor;
943       this.leftSideColor = leftSideColor;
944       this.propertyChangeSupport.firePropertyChange(Property.LEFT_SIDE_COLOR.name(), oldLeftSideColor, leftSideColor);
945 
946       setLeftSidePaint(WallPaint.COLORED);
947     }
948   }
949 
950   /**
951    * Returns the edited color of the left side.
952    */
getLeftSideColor()953   public Integer getLeftSideColor() {
954     return this.leftSideColor;
955   }
956 
957   /**
958    * Sets whether the left side is colored, textured or unknown painted.
959    */
setLeftSidePaint(WallPaint leftSidePaint)960   public void setLeftSidePaint(WallPaint leftSidePaint) {
961     if (leftSidePaint != this.leftSidePaint) {
962       WallPaint oldLeftSidePaint = this.leftSidePaint;
963       this.leftSidePaint = leftSidePaint;
964       this.propertyChangeSupport.firePropertyChange(Property.LEFT_SIDE_PAINT.name(), oldLeftSidePaint, leftSidePaint);
965     }
966   }
967 
968   /**
969    * Returns whether the left side is colored, textured or unknown painted.
970    * @return {@link WallPaint#COLORED}, {@link WallPaint#TEXTURED} or <code>null</code>
971    */
getLeftSidePaint()972   public WallPaint getLeftSidePaint() {
973     return this.leftSidePaint;
974   }
975 
976   /**
977    * Sets the edited left side shininess.
978    */
setLeftSideShininess(Float leftSideShininess)979   public void setLeftSideShininess(Float leftSideShininess) {
980     if (leftSideShininess != this.leftSideShininess) {
981       Float oldLeftSideShininess = this.leftSideShininess;
982       this.leftSideShininess = leftSideShininess;
983       this.propertyChangeSupport.firePropertyChange(Property.LEFT_SIDE_SHININESS.name(), oldLeftSideShininess, leftSideShininess);
984     }
985   }
986 
987   /**
988    * Returns the edited left side shininess.
989    */
getLeftSideShininess()990   public Float getLeftSideShininess() {
991     return this.leftSideShininess;
992   }
993 
994   /**
995    * Sets the edited color of the right side.
996    */
setRightSideColor(Integer rightSideColor)997   public void setRightSideColor(Integer rightSideColor) {
998     if (rightSideColor != this.rightSideColor) {
999       Integer oldRightSideColor = this.rightSideColor;
1000       this.rightSideColor = rightSideColor;
1001       this.propertyChangeSupport.firePropertyChange(Property.RIGHT_SIDE_COLOR.name(), oldRightSideColor, rightSideColor);
1002 
1003       setRightSidePaint(WallPaint.COLORED);
1004     }
1005   }
1006 
1007   /**
1008    * Returns the edited color of the right side.
1009    */
getRightSideColor()1010   public Integer getRightSideColor() {
1011     return this.rightSideColor;
1012   }
1013 
1014   /**
1015    * Sets whether the right side is colored, textured or unknown painted.
1016    */
setRightSidePaint(WallPaint rightSidePaint)1017   public void setRightSidePaint(WallPaint rightSidePaint) {
1018     if (rightSidePaint != this.rightSidePaint) {
1019       WallPaint oldRightSidePaint = this.rightSidePaint;
1020       this.rightSidePaint = rightSidePaint;
1021       this.propertyChangeSupport.firePropertyChange(Property.RIGHT_SIDE_PAINT.name(), oldRightSidePaint, rightSidePaint);
1022     }
1023   }
1024 
1025   /**
1026    * Returns whether the right side is colored, textured or unknown painted.
1027    * @return {@link WallPaint#COLORED}, {@link WallPaint#TEXTURED} or <code>null</code>
1028    */
getRightSidePaint()1029   public WallPaint getRightSidePaint() {
1030     return this.rightSidePaint;
1031   }
1032 
1033   /**
1034    * Sets the edited right side shininess.
1035    */
setRightSideShininess(Float rightSideShininess)1036   public void setRightSideShininess(Float rightSideShininess) {
1037     if (rightSideShininess != this.rightSideShininess) {
1038       Float oldRightSideShininess = this.rightSideShininess;
1039       this.rightSideShininess = rightSideShininess;
1040       this.propertyChangeSupport.firePropertyChange(Property.RIGHT_SIDE_SHININESS.name(), oldRightSideShininess, rightSideShininess);
1041     }
1042   }
1043 
1044   /**
1045    * Returns the edited right side shininess.
1046    */
getRightSideShininess()1047   public Float getRightSideShininess() {
1048     return this.rightSideShininess;
1049   }
1050 
1051   /**
1052    * Sets the pattern of edited wall in plan, and notifies
1053    * listeners of this change.
1054    */
setPattern(TextureImage pattern)1055   public void setPattern(TextureImage pattern) {
1056     if (this.pattern != pattern) {
1057       TextureImage oldPattern = this.pattern;
1058       this.pattern = pattern;
1059       this.propertyChangeSupport.firePropertyChange(Property.PATTERN.name(), oldPattern, pattern);
1060     }
1061   }
1062 
1063   /**
1064    * Returns the pattern of edited wall in plan.
1065    */
getPattern()1066   public TextureImage getPattern() {
1067     return this.pattern;
1068   }
1069 
1070   /**
1071    * Sets the edited top color in the 3D view.
1072    */
setTopColor(Integer topColor)1073   public void setTopColor(Integer topColor) {
1074     if (topColor != this.topColor) {
1075       Integer oldTopColor = this.topColor;
1076       this.topColor = topColor;
1077       this.propertyChangeSupport.firePropertyChange(Property.TOP_COLOR.name(), oldTopColor, topColor);
1078     }
1079   }
1080 
1081   /**
1082    * Returns the edited top color in the 3D view.
1083    */
getTopColor()1084   public Integer getTopColor() {
1085     return this.topColor;
1086   }
1087 
1088   /**
1089    * Sets whether the top of the wall in the 3D view uses default rendering, is colored, or unknown painted.
1090    */
setTopPaint(WallPaint topPaint)1091   public void setTopPaint(WallPaint topPaint) {
1092     if (topPaint != this.topPaint) {
1093       WallPaint oldTopPaint = this.topPaint;
1094       this.topPaint = topPaint;
1095       this.propertyChangeSupport.firePropertyChange(Property.TOP_PAINT.name(), oldTopPaint, topPaint);
1096     }
1097   }
1098 
1099   /**
1100    * Returns whether the top of the wall in the 3D view uses default rendering, is colored, or unknown painted.
1101    * @return {@link WallPaint#DEFAULT}, {@link WallPaint#COLORED} or <code>null</code>
1102    */
getTopPaint()1103   public WallPaint getTopPaint() {
1104     return this.topPaint;
1105   }
1106 
1107   /**
1108    * Sets whether the edited wall is a rectangular wall, a sloping wall or unknown.
1109    */
setShape(WallShape shape)1110   public void setShape(WallShape shape) {
1111     if (shape != this.shape) {
1112       WallShape oldShape = this.shape;
1113       this.shape = shape;
1114       this.propertyChangeSupport.firePropertyChange(Property.SHAPE.name(), oldShape, shape);
1115 
1116       if (shape == WallShape.RECTANGULAR_WALL) {
1117         if (this.rectangularWallHeight != null) {
1118           getLeftSideBaseboardController().setMaxHeight(this.rectangularWallHeight);
1119           getRightSideBaseboardController().setMaxHeight(this.rectangularWallHeight);
1120         }
1121       } else if (shape == WallShape.SLOPING_WALL) {
1122         if (this.slopingWallHeightAtStart != null
1123             && this.sloppingWallHeightAtEnd != null) {
1124           float baseboardMaxHeight = Math.max(this.sloppingWallHeightAtEnd, this.slopingWallHeightAtStart);
1125           getLeftSideBaseboardController().setMaxHeight(baseboardMaxHeight);
1126           getRightSideBaseboardController().setMaxHeight(baseboardMaxHeight);
1127         } else if (this.slopingWallHeightAtStart != null) {
1128           getLeftSideBaseboardController().setMaxHeight(this.slopingWallHeightAtStart);
1129           getRightSideBaseboardController().setMaxHeight(this.slopingWallHeightAtStart);
1130         } else if (this.sloppingWallHeightAtEnd != null) {
1131           getLeftSideBaseboardController().setMaxHeight(this.sloppingWallHeightAtEnd);
1132           getRightSideBaseboardController().setMaxHeight(this.sloppingWallHeightAtEnd);
1133         }
1134       }
1135     }
1136   }
1137 
1138   /**
1139    * Returns whether the edited wall is a rectangular wall, a sloping wall or unknown.
1140    */
getShape()1141   public WallShape getShape() {
1142     return this.shape;
1143   }
1144 
1145   /**
1146    * Sets the edited height of a rectangular wall.
1147    */
setRectangularWallHeight(Float rectangularWallHeight)1148   public void setRectangularWallHeight(Float rectangularWallHeight) {
1149     if (rectangularWallHeight != this.rectangularWallHeight) {
1150       Float oldRectangularWallHeight = this.rectangularWallHeight;
1151       this.rectangularWallHeight = rectangularWallHeight;
1152       this.propertyChangeSupport.firePropertyChange(Property.RECTANGULAR_WALL_HEIGHT.name(),
1153           oldRectangularWallHeight, rectangularWallHeight);
1154 
1155       setShape(WallShape.RECTANGULAR_WALL);
1156       if (rectangularWallHeight != null) {
1157         getLeftSideBaseboardController().setMaxHeight(rectangularWallHeight);
1158         getRightSideBaseboardController().setMaxHeight(rectangularWallHeight);
1159       }
1160     }
1161   }
1162 
1163   /**
1164    * Returns the edited height of a rectangular wall.
1165    */
getRectangularWallHeight()1166   public Float getRectangularWallHeight() {
1167     return this.rectangularWallHeight;
1168   }
1169 
1170   /**
1171    * Sets the edited height at start of a sloping wall.
1172    */
setSlopingWallHeightAtStart(Float slopingWallHeightAtStart)1173   public void setSlopingWallHeightAtStart(Float slopingWallHeightAtStart) {
1174     if (slopingWallHeightAtStart != this.slopingWallHeightAtStart) {
1175       Float oldSlopingHeightHeightAtStart = this.slopingWallHeightAtStart;
1176       this.slopingWallHeightAtStart = slopingWallHeightAtStart;
1177       this.propertyChangeSupport.firePropertyChange(Property.SLOPING_WALL_HEIGHT_AT_START.name(),
1178           oldSlopingHeightHeightAtStart, slopingWallHeightAtStart);
1179 
1180       setShape(WallShape.SLOPING_WALL);
1181       if (slopingWallHeightAtStart != null) {
1182         float baseboardMaxHeight = this.sloppingWallHeightAtEnd != null
1183             ? Math.max(this.sloppingWallHeightAtEnd, slopingWallHeightAtStart)
1184             : slopingWallHeightAtStart;
1185         baseboardMaxHeight = Math.max(baseboardMaxHeight, this.preferences.getLengthUnit().getMinimumLength());
1186         getLeftSideBaseboardController().setMaxHeight(baseboardMaxHeight);
1187         getRightSideBaseboardController().setMaxHeight(baseboardMaxHeight);
1188       }
1189     }
1190   }
1191 
1192   /**
1193    * Returns the edited height at start of a sloping wall.
1194    */
getSlopingWallHeightAtStart()1195   public Float getSlopingWallHeightAtStart() {
1196     return this.slopingWallHeightAtStart;
1197   }
1198 
1199   /**
1200    * Sets the edited height at end of a sloping wall.
1201    */
setSlopingWallHeightAtEnd(Float sloppingWallHeightAtEnd)1202   public void setSlopingWallHeightAtEnd(Float sloppingWallHeightAtEnd) {
1203     if (sloppingWallHeightAtEnd != this.sloppingWallHeightAtEnd) {
1204       Float oldSlopingWallHeightAtEnd = this.sloppingWallHeightAtEnd;
1205       this.sloppingWallHeightAtEnd = sloppingWallHeightAtEnd;
1206       this.propertyChangeSupport.firePropertyChange(Property.SLOPING_WALL_HEIGHT_AT_END.name(),
1207           oldSlopingWallHeightAtEnd, sloppingWallHeightAtEnd);
1208 
1209       setShape(WallShape.SLOPING_WALL);
1210       if (sloppingWallHeightAtEnd != null) {
1211         float baseboardMaxHeight = this.slopingWallHeightAtStart != null
1212             ? Math.max(this.slopingWallHeightAtStart, sloppingWallHeightAtEnd)
1213             : sloppingWallHeightAtEnd;
1214         baseboardMaxHeight = Math.max(baseboardMaxHeight, this.preferences.getLengthUnit().getMinimumLength());
1215         getLeftSideBaseboardController().setMaxHeight(baseboardMaxHeight);
1216         getRightSideBaseboardController().setMaxHeight(baseboardMaxHeight);
1217       }
1218     }
1219   }
1220 
1221   /**
1222    * Returns the edited height at end of a sloping wall.
1223    */
getSlopingWallHeightAtEnd()1224   public Float getSlopingWallHeightAtEnd() {
1225     return this.sloppingWallHeightAtEnd;
1226   }
1227 
1228   /**
1229    * Sets the edited thickness.
1230    */
setThickness(Float thickness)1231   public void setThickness(Float thickness) {
1232     if (thickness != this.thickness) {
1233       Float oldThickness = this.thickness;
1234       this.thickness = thickness;
1235       this.propertyChangeSupport.firePropertyChange(Property.THICKNESS.name(), oldThickness, thickness);
1236     }
1237   }
1238 
1239   /**
1240    * Returns the edited thickness.
1241    */
getThickness()1242   public Float getThickness() {
1243     return this.thickness;
1244   }
1245 
1246   /**
1247    * Sets the edited arc extent.
1248    */
setArcExtentInDegrees(Float arcExtentInDegrees)1249   public void setArcExtentInDegrees(Float arcExtentInDegrees) {
1250     if (arcExtentInDegrees != this.arcExtentInDegrees) {
1251       Float oldArcExtent = this.arcExtentInDegrees;
1252       this.arcExtentInDegrees = arcExtentInDegrees;
1253       this.propertyChangeSupport.firePropertyChange(Property.ARC_EXTENT_IN_DEGREES.name(), oldArcExtent, arcExtentInDegrees);
1254     }
1255   }
1256 
1257   /**
1258    * Returns the edited arc extent.
1259    */
getArcExtentInDegrees()1260   public Float getArcExtentInDegrees() {
1261     return this.arcExtentInDegrees;
1262   }
1263 
1264   /**
1265    * Returns the length of wall after applying the edited arc extent.
1266    * @return the arc length or null if data is missing to compute it
1267    * @since 6.0
1268    */
getArcLength()1269   public Float getArcLength() {
1270     Float xStart = getXStart();
1271     Float yStart = getYStart();
1272     Float xEnd = getXEnd();
1273     Float yEnd = getYEnd();
1274     Float arcExtentInDegrees = getArcExtentInDegrees();
1275     if (xStart != null && yStart != null && xEnd != null && yEnd != null && arcExtentInDegrees != null) {
1276       Wall wall = new Wall(xStart, yStart, xEnd, yEnd, 0.00001f, 0);
1277       wall.setArcExtent((float)Math.toRadians(arcExtentInDegrees));
1278       return wall.getLength();
1279     } else {
1280       return null;
1281     }
1282   }
1283 
1284   /**
1285    * Controls the modification of selected walls in edited home.
1286    */
modifyWalls()1287   public void modifyWalls() {
1288     List<Selectable> oldSelection = this.home.getSelectedItems();
1289     List<Wall> selectedWalls = Home.getWallsSubList(oldSelection);
1290     if (!selectedWalls.isEmpty()) {
1291       Float xStart = getXStart();
1292       Float yStart = getYStart();
1293       Float xEnd = getXEnd();
1294       Float yEnd = getYEnd();
1295       WallPaint leftSidePaint = getLeftSidePaint();
1296       Integer leftSideColor = leftSidePaint == WallPaint.COLORED
1297           ? getLeftSideColor() : null;
1298       HomeTexture leftSideTexture = leftSidePaint == WallPaint.TEXTURED
1299           ? getLeftSideTextureController().getTexture() : null;
1300       Float leftSideShininess = getLeftSideShininess();
1301       Boolean leftSideBaseboardVisible = getLeftSideBaseboardController().getVisible();
1302       Float leftSideBaseboardThickness = getLeftSideBaseboardController().getThickness();
1303       Float leftSideBaseboardHeight = getLeftSideBaseboardController().getHeight();
1304       BaseboardChoiceController.BaseboardPaint leftSideBaseboardPaint = getLeftSideBaseboardController().getPaint();
1305       Integer leftSideBaseboardColor = leftSideBaseboardPaint == BaseboardChoiceController.BaseboardPaint.COLORED
1306           ? getLeftSideBaseboardController().getColor() : null;
1307       HomeTexture leftSideBaseboardTexture = leftSideBaseboardPaint == BaseboardChoiceController.BaseboardPaint.TEXTURED
1308           ? getLeftSideBaseboardController().getTextureController().getTexture()
1309           : null;
1310       WallPaint rightSidePaint = getRightSidePaint();
1311       Integer rightSideColor = rightSidePaint == WallPaint.COLORED
1312           ? getRightSideColor() : null;
1313       HomeTexture rightSideTexture = rightSidePaint == WallPaint.TEXTURED
1314           ? getRightSideTextureController().getTexture() : null;
1315       Float rightSideShininess = getRightSideShininess();
1316       Boolean rightSideBaseboardVisible = getRightSideBaseboardController().getVisible();
1317       Float rightSideBaseboardThickness = getRightSideBaseboardController().getThickness();
1318       Float rightSideBaseboardHeight = getRightSideBaseboardController().getHeight();
1319       BaseboardChoiceController.BaseboardPaint rightSideBaseboardPaint = getRightSideBaseboardController().getPaint();
1320       Integer rightSideBaseboardColor = rightSideBaseboardPaint == BaseboardChoiceController.BaseboardPaint.COLORED
1321           ? getRightSideBaseboardController().getColor() : null;
1322       HomeTexture rightSideBaseboardTexture = rightSideBaseboardPaint == BaseboardChoiceController.BaseboardPaint.TEXTURED
1323           ? getRightSideBaseboardController().getTextureController().getTexture()
1324           : null;
1325       TextureImage pattern = getPattern();
1326       boolean modifiedTopColor = getTopPaint() != null;
1327       Integer topColor = getTopPaint() == WallPaint.COLORED
1328           ? getTopColor() : null;
1329       Float thickness = getThickness();
1330       Float arcExtent = getArcExtentInDegrees();
1331       if (arcExtent != null) {
1332         arcExtent = (float)Math.toRadians(arcExtent);
1333       }
1334       Float height;
1335       if (getShape() == WallShape.SLOPING_WALL) {
1336         height = getSlopingWallHeightAtStart();
1337       } else if (getShape() == WallShape.RECTANGULAR_WALL) {
1338         height = getRectangularWallHeight();
1339       } else {
1340         height = null;
1341       }
1342       Float heightAtEnd;
1343       if (getShape() == WallShape.SLOPING_WALL) {
1344         heightAtEnd = getSlopingWallHeightAtEnd();
1345       } else if (getShape() == WallShape.RECTANGULAR_WALL) {
1346         heightAtEnd = getRectangularWallHeight();
1347       } else {
1348         heightAtEnd = null;
1349       }
1350 
1351       if (height != null && heightAtEnd != null) {
1352         float maxHeight = Math.max(height, heightAtEnd);
1353         if (leftSideBaseboardHeight != null) {
1354           leftSideBaseboardHeight = Math.min(leftSideBaseboardHeight, maxHeight);
1355         }
1356         if (rightSideBaseboardHeight != null) {
1357           rightSideBaseboardHeight = Math.min(rightSideBaseboardHeight, maxHeight);
1358         }
1359       }
1360 
1361       // Create an array of modified walls with their current properties values
1362       ModifiedWall [] modifiedWalls = new ModifiedWall [selectedWalls.size()];
1363       for (int i = 0; i < modifiedWalls.length; i++) {
1364         modifiedWalls [i] = new ModifiedWall(selectedWalls.get(i));
1365       }
1366       // Apply modification
1367       doModifyWalls(modifiedWalls,
1368           this.preferences.getNewWallBaseboardThickness(), this.preferences.getNewWallBaseboardHeight(),
1369           xStart, yStart, xEnd, yEnd,
1370           leftSidePaint, leftSideColor, leftSideTexture, leftSideShininess,
1371           leftSideBaseboardVisible, leftSideBaseboardThickness, leftSideBaseboardHeight,
1372           leftSideBaseboardPaint,  leftSideBaseboardColor, leftSideBaseboardTexture,
1373           rightSidePaint, rightSideColor, rightSideTexture, rightSideShininess,
1374           rightSideBaseboardVisible, rightSideBaseboardThickness, rightSideBaseboardHeight,
1375           rightSideBaseboardPaint, rightSideBaseboardColor, rightSideBaseboardTexture,
1376           pattern, modifiedTopColor, topColor,
1377           height, heightAtEnd, thickness, arcExtent);
1378       if (this.undoSupport != null) {
1379         UndoableEdit undoableEdit = new WallsModificationUndoableEdit(this.home,
1380             this.preferences, oldSelection.toArray(new Selectable [oldSelection.size()]) , modifiedWalls,
1381             this.preferences.getNewWallBaseboardThickness(), this.preferences.getNewWallBaseboardHeight(),
1382             xStart, yStart, xEnd, yEnd,
1383             leftSidePaint, leftSideColor, leftSideTexture, leftSideShininess,
1384             leftSideBaseboardVisible, leftSideBaseboardThickness, leftSideBaseboardHeight,
1385             leftSideBaseboardPaint, leftSideBaseboardColor, leftSideBaseboardTexture,
1386             rightSidePaint, rightSideColor, rightSideTexture, rightSideShininess,
1387             rightSideBaseboardVisible, rightSideBaseboardThickness, rightSideBaseboardHeight,
1388             rightSideBaseboardPaint, rightSideBaseboardColor, rightSideBaseboardTexture,
1389             pattern, modifiedTopColor, topColor,
1390             height, heightAtEnd, thickness, arcExtent);
1391         this.undoSupport.postEdit(undoableEdit);
1392       }
1393     }
1394   }
1395 
1396   /**
1397    * Undoable edit for walls modification. This class isn't anonymous to avoid
1398    * being bound to controller and its view.
1399    */
1400   private static class WallsModificationUndoableEdit extends LocalizedUndoableEdit {
1401     private final Home             home;
1402     private final Selectable []    oldSelection;
1403     private final ModifiedWall []  modifiedWalls;
1404     private final float            newWallBaseboardThickness;
1405     private final float            newWallBaseboardHeight;
1406     private final Float            xStart;
1407     private final Float            yStart;
1408     private final Float            xEnd;
1409     private final Float            yEnd;
1410     private final WallPaint        leftSidePaint;
1411     private final Integer          leftSideColor;
1412     private final HomeTexture      leftSideTexture;
1413     private final Float            leftSideShininess;
1414     private final Boolean          leftSideBaseboardVisible;
1415     private final Float            leftSideBaseboardThickness;
1416     private final Float            leftSideBaseboardHeight;
1417     private final BaseboardChoiceController.BaseboardPaint leftSideBaseboardPaint;
1418     private final Integer          leftSideBaseboardColor;
1419     private final HomeTexture      leftSideBaseboardTexture;
1420     private final WallPaint        rightSidePaint;
1421     private final Integer          rightSideColor;
1422     private final HomeTexture      rightSideTexture;
1423     private final Float            rightSideShininess;
1424     private final Boolean          rightSideBaseboardVisible;
1425     private final Float            rightSideBaseboardThickness;
1426     private final Float            rightSideBaseboardHeight;
1427     private final BaseboardChoiceController.BaseboardPaint rightSideBaseboardPaint;
1428     private final Integer          rightSideBaseboardColor;
1429     private final HomeTexture      rightSideBaseboardTexture;
1430     private final TextureImage     pattern;
1431     private final boolean          modifiedTopColor;
1432     private final Integer          topColor;
1433     private final Float            height;
1434     private final Float            heightAtEnd;
1435     private final Float            thickness;
1436     private final Float            arcExtent;
1437 
WallsModificationUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, ModifiedWall [] modifiedWalls, float newWallBaseboardThickness, float newWallBaseboardHeight, Float xStart, Float yStart, Float xEnd, Float yEnd, WallPaint leftSidePaint, Integer leftSideColor, HomeTexture leftSideTexture, Float leftSideShininess, Boolean leftSideBaseboardVisible, Float leftSideBaseboardThickness, Float leftSideBaseboardHeight, BaseboardChoiceController.BaseboardPaint leftSideBaseboardPaint, Integer leftSideBaseboardColor, HomeTexture leftSideBaseboardTexture, WallPaint rightSidePaint, Integer rightSideColor, HomeTexture rightSideTexture, Float rightSideShininess, Boolean rightSideBaseboardVisible, Float rightSideBaseboardThickness, Float rightSideBaseboardHeight, BaseboardChoiceController.BaseboardPaint rightSideBaseboardPaint, Integer rightSideBaseboardColor, HomeTexture rightSideBaseboardTexture, TextureImage pattern, boolean modifiedTopColor, Integer topColor, Float height, Float heightAtEnd, Float thickness, Float arcExtent)1438     private WallsModificationUndoableEdit(Home home,
1439                                           UserPreferences preferences,
1440                                           Selectable [] oldSelection, ModifiedWall [] modifiedWalls,
1441                                           float newWallBaseboardThickness, float newWallBaseboardHeight,
1442                                           Float xStart, Float yStart, Float xEnd, Float yEnd,
1443                                           WallPaint leftSidePaint, Integer leftSideColor,
1444                                           HomeTexture leftSideTexture, Float leftSideShininess,
1445                                           Boolean leftSideBaseboardVisible, Float leftSideBaseboardThickness, Float leftSideBaseboardHeight,
1446                                           BaseboardChoiceController.BaseboardPaint leftSideBaseboardPaint, Integer leftSideBaseboardColor, HomeTexture leftSideBaseboardTexture,
1447                                           WallPaint rightSidePaint, Integer rightSideColor,
1448                                           HomeTexture rightSideTexture, Float rightSideShininess,
1449                                           Boolean rightSideBaseboardVisible, Float rightSideBaseboardThickness, Float rightSideBaseboardHeight,
1450                                           BaseboardChoiceController.BaseboardPaint rightSideBaseboardPaint, Integer rightSideBaseboardColor, HomeTexture rightSideBaseboardTexture,
1451                                           TextureImage pattern,
1452                                           boolean modifiedTopColor,
1453                                           Integer topColor,
1454                                           Float height,
1455                                           Float heightAtEnd,
1456                                           Float thickness,
1457                                           Float arcExtent) {
1458       super(preferences, WallController.class, "undoModifyWallsName");
1459       this.home = home;
1460       this.oldSelection = oldSelection;
1461       this.modifiedWalls = modifiedWalls;
1462       this.newWallBaseboardThickness = newWallBaseboardThickness;
1463       this.newWallBaseboardHeight = newWallBaseboardHeight;
1464       this.xStart = xStart;
1465       this.yStart = yStart;
1466       this.xEnd = xEnd;
1467       this.yEnd = yEnd;
1468       this.leftSidePaint = leftSidePaint;
1469       this.leftSideColor = leftSideColor;
1470       this.leftSideShininess = leftSideShininess;
1471       this.leftSideBaseboardVisible = leftSideBaseboardVisible;
1472       this.leftSideBaseboardThickness = leftSideBaseboardThickness;
1473       this.leftSideBaseboardHeight = leftSideBaseboardHeight;
1474       this.leftSideBaseboardPaint = leftSideBaseboardPaint;
1475       this.leftSideBaseboardColor = leftSideBaseboardColor;
1476       this.leftSideBaseboardTexture = leftSideBaseboardTexture;
1477       this.rightSidePaint = rightSidePaint;
1478       this.rightSideColor = rightSideColor;
1479       this.rightSideTexture = rightSideTexture;
1480       this.leftSideTexture = leftSideTexture;
1481       this.rightSideShininess = rightSideShininess;
1482       this.rightSideBaseboardVisible = rightSideBaseboardVisible;
1483       this.rightSideBaseboardThickness = rightSideBaseboardThickness;
1484       this.rightSideBaseboardHeight = rightSideBaseboardHeight;
1485       this.rightSideBaseboardPaint = rightSideBaseboardPaint;
1486       this.rightSideBaseboardColor = rightSideBaseboardColor;
1487       this.rightSideBaseboardTexture = rightSideBaseboardTexture;
1488       this.pattern = pattern;
1489       this.modifiedTopColor = modifiedTopColor;
1490       this.topColor = topColor;
1491       this.height = height;
1492       this.heightAtEnd = heightAtEnd;
1493       this.thickness = thickness;
1494       this.arcExtent = arcExtent;
1495     }
1496 
1497     @Override
undo()1498     public void undo() throws CannotUndoException {
1499       super.undo();
1500       undoModifyWalls(this.modifiedWalls);
1501       this.home.setSelectedItems(Arrays.asList(this.oldSelection));
1502     }
1503 
1504     @Override
redo()1505     public void redo() throws CannotRedoException {
1506       super.redo();
1507       doModifyWalls(this.modifiedWalls, this.newWallBaseboardThickness, this.newWallBaseboardHeight,
1508           this.xStart, this.yStart, this.xEnd, this.yEnd,
1509           this.leftSidePaint, this.leftSideColor, this.leftSideTexture, this.leftSideShininess,
1510           this.leftSideBaseboardVisible, this.leftSideBaseboardThickness, this.leftSideBaseboardHeight,
1511           this.leftSideBaseboardPaint, this.leftSideBaseboardColor, this.leftSideBaseboardTexture,
1512           this.rightSidePaint, this.rightSideColor, this.rightSideTexture, this.rightSideShininess,
1513           this.rightSideBaseboardVisible, this.rightSideBaseboardThickness, this.rightSideBaseboardHeight,
1514           this.rightSideBaseboardPaint, this.rightSideBaseboardColor, this.rightSideBaseboardTexture,
1515           this.pattern, this.modifiedTopColor, this.topColor,
1516           this.height, this.heightAtEnd, this.thickness, this.arcExtent);
1517       this.home.setSelectedItems(Arrays.asList(this.oldSelection));
1518     }
1519   }
1520 
1521   /**
1522    * Modifies walls properties with the values in parameter.
1523    */
doModifyWalls(ModifiedWall [] modifiedWalls, float newWallBaseboardThickness, float newWallBaseboardHeight, Float xStart, Float yStart, Float xEnd, Float yEnd, WallPaint leftSidePaint, Integer leftSideColor, HomeTexture leftSideTexture, Float leftSideShininess, Boolean leftSideBaseboardVisible, Float leftSideBaseboardThickness, Float leftSideBaseboardHeight, BaseboardChoiceController.BaseboardPaint leftSideBaseboardPaint, Integer leftSideBaseboardColor, HomeTexture leftSideBaseboardTexture, WallPaint rightSidePaint, Integer rightSideColor, HomeTexture rightSideTexture, Float rightSideShininess, Boolean rightSideBaseboardVisible, Float rightSideBaseboardThickness, Float rightSideBaseboardHeight, BaseboardChoiceController.BaseboardPaint rightSideBaseboardPaint, Integer rightSideBaseboardColor, HomeTexture rightSideBaseboardTexture, TextureImage pattern, boolean modifiedTopColor, Integer topColor, Float height, Float heightAtEnd, Float thickness, Float arcExtent)1524   private static void doModifyWalls(ModifiedWall [] modifiedWalls, float newWallBaseboardThickness, float newWallBaseboardHeight,
1525                                     Float xStart, Float yStart, Float xEnd, Float yEnd,
1526                                     WallPaint leftSidePaint, Integer leftSideColor, HomeTexture leftSideTexture, Float leftSideShininess,
1527                                     Boolean leftSideBaseboardVisible, Float leftSideBaseboardThickness, Float leftSideBaseboardHeight,
1528                                     BaseboardChoiceController.BaseboardPaint leftSideBaseboardPaint, Integer leftSideBaseboardColor, HomeTexture leftSideBaseboardTexture,
1529                                     WallPaint rightSidePaint, Integer rightSideColor, HomeTexture rightSideTexture, Float rightSideShininess,
1530                                     Boolean rightSideBaseboardVisible, Float rightSideBaseboardThickness, Float rightSideBaseboardHeight,
1531                                     BaseboardChoiceController.BaseboardPaint rightSideBaseboardPaint, Integer rightSideBaseboardColor, HomeTexture rightSideBaseboardTexture,
1532                                     TextureImage pattern, boolean modifiedTopColor, Integer topColor,
1533                                     Float height, Float heightAtEnd, Float thickness, Float arcExtent) {
1534     for (ModifiedWall modifiedWall : modifiedWalls) {
1535       Wall wall = modifiedWall.getWall();
1536       moveWallPoints(wall, xStart, yStart, xEnd, yEnd);
1537       if (leftSidePaint != null) {
1538         switch (leftSidePaint) {
1539           case DEFAULT :
1540             wall.setLeftSideColor(null);
1541             wall.setLeftSideTexture(null);
1542             break;
1543           case COLORED :
1544             if (leftSideColor != null) {
1545               wall.setLeftSideColor(leftSideColor);
1546             }
1547             wall.setLeftSideTexture(null);
1548             break;
1549           case TEXTURED :
1550             wall.setLeftSideColor(null);
1551             if (leftSideTexture != null) {
1552               wall.setLeftSideTexture(leftSideTexture);
1553             }
1554             break;
1555         }
1556       }
1557       if (leftSideShininess != null) {
1558         wall.setLeftSideShininess(leftSideShininess);
1559       }
1560       if (leftSideBaseboardVisible == Boolean.FALSE) {
1561         wall.setLeftSideBaseboard(null);
1562       } else {
1563         Baseboard baseboard = wall.getLeftSideBaseboard();
1564         if (leftSideBaseboardVisible == Boolean.TRUE
1565             || baseboard != null) {
1566           float baseboardThickness = baseboard != null
1567               ? baseboard.getThickness()
1568               : newWallBaseboardThickness;
1569           float baseboardHeight = baseboard != null
1570               ? baseboard.getHeight()
1571               : newWallBaseboardHeight;
1572           Integer baseboardColor = baseboard != null
1573               ? baseboard.getColor()
1574               : null;
1575           HomeTexture baseboardTexture = baseboard != null
1576               ? baseboard.getTexture()
1577               : null;
1578           if (leftSideBaseboardPaint != null) {
1579             switch (leftSideBaseboardPaint) {
1580               case DEFAULT :
1581                 baseboardColor = null;
1582                 baseboardTexture = null;
1583                 break;
1584               case COLORED :
1585                 if (leftSideBaseboardColor != null) {
1586                   baseboardColor = leftSideBaseboardColor;
1587                 }
1588                 baseboardTexture = null;
1589                 break;
1590               case TEXTURED :
1591                 baseboardColor = null;
1592                 if (leftSideBaseboardTexture != null) {
1593                   baseboardTexture = leftSideBaseboardTexture;
1594                 }
1595                 break;
1596             }
1597           }
1598           wall.setLeftSideBaseboard(Baseboard.getInstance(
1599               leftSideBaseboardThickness != null
1600                   ? leftSideBaseboardThickness
1601                   : baseboardThickness,
1602               leftSideBaseboardHeight != null
1603                   ? leftSideBaseboardHeight
1604                   : baseboardHeight,
1605               baseboardColor, baseboardTexture));
1606         }
1607       }
1608       if (rightSidePaint != null) {
1609         switch (rightSidePaint) {
1610           case DEFAULT :
1611             wall.setRightSideColor(null);
1612             wall.setRightSideTexture(null);
1613             break;
1614           case COLORED :
1615             if (rightSideColor != null) {
1616               wall.setRightSideColor(rightSideColor);
1617             }
1618             wall.setRightSideTexture(null);
1619             break;
1620           case TEXTURED :
1621             wall.setRightSideColor(null);
1622             if (rightSideTexture != null) {
1623               wall.setRightSideTexture(rightSideTexture);
1624             }
1625             break;
1626         }
1627       }
1628       if (rightSideShininess != null) {
1629         wall.setRightSideShininess(rightSideShininess);
1630       }
1631       if (rightSideBaseboardVisible == Boolean.FALSE) {
1632         wall.setRightSideBaseboard(null);
1633       } else {
1634         Baseboard baseboard = wall.getRightSideBaseboard();
1635         if (rightSideBaseboardVisible == Boolean.TRUE
1636             || baseboard != null) {
1637           float baseboardThickness = baseboard != null
1638               ? baseboard.getThickness()
1639               : newWallBaseboardThickness;
1640           float baseboardHeight = baseboard != null
1641               ? baseboard.getHeight()
1642               : newWallBaseboardHeight;
1643           Integer baseboardColor = baseboard != null
1644               ? baseboard.getColor()
1645               : null;
1646           HomeTexture baseboardTexture = baseboard != null
1647               ? baseboard.getTexture()
1648               : null;
1649           if (rightSideBaseboardPaint != null) {
1650             switch (rightSideBaseboardPaint) {
1651               case DEFAULT :
1652                 baseboardColor = null;
1653                 baseboardTexture = null;
1654                 break;
1655               case COLORED :
1656                 if (rightSideBaseboardColor != null) {
1657                   baseboardColor = rightSideBaseboardColor;
1658                 }
1659                 baseboardTexture = null;
1660                 break;
1661               case TEXTURED :
1662                 baseboardColor = null;
1663                 if (rightSideBaseboardTexture != null) {
1664                   baseboardTexture = rightSideBaseboardTexture;
1665                 }
1666                 break;
1667             }
1668           }
1669           wall.setRightSideBaseboard(Baseboard.getInstance(
1670               rightSideBaseboardThickness != null
1671                   ? rightSideBaseboardThickness
1672                   : baseboardThickness,
1673               rightSideBaseboardHeight != null
1674                   ? rightSideBaseboardHeight
1675                   : baseboardHeight,
1676               baseboardColor, baseboardTexture));
1677         }
1678       }
1679       if (pattern != null) {
1680         wall.setPattern(pattern);
1681       }
1682       if (modifiedTopColor) {
1683         wall.setTopColor(topColor);
1684       }
1685       if (height != null) {
1686         wall.setHeight(height);
1687         if (heightAtEnd != null) {
1688           if (heightAtEnd.equals(height)) {
1689             wall.setHeightAtEnd(null);
1690           } else {
1691             wall.setHeightAtEnd(heightAtEnd);
1692           }
1693         }
1694       }
1695       if (thickness != null) {
1696         wall.setThickness(thickness.floatValue());
1697       }
1698       if (arcExtent != null) {
1699         if (arcExtent.floatValue() == 0) {
1700           wall.setArcExtent(null);
1701         } else {
1702           wall.setArcExtent(arcExtent);
1703         }
1704       }
1705     }
1706   }
1707 
1708   /**
1709    * Restores wall properties from the values stored in <code>modifiedWalls</code>.
1710    */
undoModifyWalls(ModifiedWall [] modifiedWalls)1711   private static void undoModifyWalls(ModifiedWall [] modifiedWalls) {
1712     for (ModifiedWall modifiedWall : modifiedWalls) {
1713       Wall wall = modifiedWall.getWall();
1714       moveWallPoints(wall, modifiedWall.getXStart(), modifiedWall.getYStart(),
1715           modifiedWall.getXEnd(), modifiedWall.getYEnd());
1716       wall.setLeftSideColor(modifiedWall.getLeftSideColor());
1717       wall.setLeftSideTexture(modifiedWall.getLeftSideTexture());
1718       wall.setLeftSideShininess(modifiedWall.getLeftSideShininess());
1719       wall.setLeftSideBaseboard(modifiedWall.getLeftSideBaseboard());
1720       wall.setRightSideColor(modifiedWall.getRightSideColor());
1721       wall.setRightSideTexture(modifiedWall.getRightSideTexture());
1722       wall.setRightSideShininess(modifiedWall.getRightSideShininess());
1723       wall.setRightSideBaseboard(modifiedWall.getRightSideBaseboard());
1724       wall.setPattern(modifiedWall.getPattern());
1725       wall.setTopColor(modifiedWall.getTopColor());
1726       wall.setHeight(modifiedWall.getHeight());
1727       wall.setHeightAtEnd(modifiedWall.getHeightAtEnd());
1728       wall.setThickness(modifiedWall.getThickness());
1729       wall.setArcExtent(modifiedWall.getArcExtent());
1730     }
1731   }
1732 
moveWallPoints(Wall wall, Float xStart, Float yStart, Float xEnd, Float yEnd)1733   private static void moveWallPoints(Wall wall, Float xStart, Float yStart, Float xEnd, Float yEnd) {
1734     Wall wallAtStart = wall.getWallAtStart();
1735     if (xStart != null) {
1736       wall.setXStart(xStart);
1737       // If wall is joined to a wall at its start
1738       if (wallAtStart != null) {
1739         // Move the wall start point or end point
1740         if (wallAtStart.getWallAtStart() == wall) {
1741           wallAtStart.setXStart(xStart);
1742         } else if (wallAtStart.getWallAtEnd() == wall) {
1743           wallAtStart.setXEnd(xStart);
1744         }
1745       }
1746     }
1747     if (yStart != null) {
1748       wall.setYStart(yStart);
1749       // If wall is joined to a wall at its start
1750       if (wallAtStart != null) {
1751         // Move the wall start point or end point
1752         if (wallAtStart.getWallAtStart() == wall) {
1753           wallAtStart.setYStart(yStart);
1754         } else if (wallAtStart.getWallAtEnd() == wall) {
1755           wallAtStart.setYEnd(yStart);
1756         }
1757       }
1758     }
1759     Wall wallAtEnd = wall.getWallAtEnd();
1760     if (xEnd != null) {
1761       wall.setXEnd(xEnd);
1762       // If wall is joined to a wall at its end
1763       if (wallAtEnd != null) {
1764         // Move the wall start point or end point
1765         if (wallAtEnd.getWallAtStart() == wall) {
1766           wallAtEnd.setXStart(xEnd);
1767         } else if (wallAtEnd.getWallAtEnd() == wall) {
1768           wallAtEnd.setXEnd(xEnd);
1769         }
1770       }
1771     }
1772     if (yEnd != null) {
1773       wall.setYEnd(yEnd);
1774       // If wall is joined to a wall at its end
1775       if (wallAtEnd != null) {
1776         // Move the wall start point or end point
1777         if (wallAtEnd.getWallAtStart() == wall) {
1778           wallAtEnd.setYStart(yEnd);
1779         } else if (wallAtEnd.getWallAtEnd() == wall) {
1780           wallAtEnd.setYEnd(yEnd);
1781         }
1782       }
1783     }
1784   }
1785 
1786   /**
1787    * Stores the current properties values of a modified wall.
1788    */
1789   private static final class ModifiedWall {
1790     private final Wall         wall;
1791     private final float        xStart;
1792     private final float        yStart;
1793     private final float        xEnd;
1794     private final float        yEnd;
1795     private final Integer      leftSideColor;
1796     private final HomeTexture  leftSideTexture;
1797     private final float        leftSideShininess;
1798     private final Baseboard    leftSideBaseboard;
1799     private final Integer      rightSideColor;
1800     private final HomeTexture  rightSideTexture;
1801     private final float        rightSideShininess;
1802     private final Baseboard    rightSideBaseboard;
1803     private final TextureImage pattern;
1804     private final Integer      topColor;
1805     private final Float        height;
1806     private final Float        heightAtEnd;
1807     private final float        thickness;
1808     private final Float        arcExtent;
1809 
ModifiedWall(Wall wall)1810     public ModifiedWall(Wall wall) {
1811       this.wall = wall;
1812       this.xStart = wall.getXStart();
1813       this.yStart = wall.getYStart();
1814       this.xEnd = wall.getXEnd();
1815       this.yEnd = wall.getYEnd();
1816       this.leftSideColor = wall.getLeftSideColor();
1817       this.leftSideTexture = wall.getLeftSideTexture();
1818       this.leftSideShininess = wall.getLeftSideShininess();
1819       this.leftSideBaseboard = wall.getLeftSideBaseboard();
1820       this.rightSideColor = wall.getRightSideColor();
1821       this.rightSideTexture = wall.getRightSideTexture();
1822       this.rightSideShininess = wall.getRightSideShininess();
1823       this.rightSideBaseboard = wall.getRightSideBaseboard();
1824       this.pattern = wall.getPattern();
1825       this.topColor = wall.getTopColor();
1826       this.height = wall.getHeight();
1827       this.heightAtEnd = wall.getHeightAtEnd();
1828       this.thickness = wall.getThickness();
1829       this.arcExtent = wall.getArcExtent();
1830     }
1831 
getWall()1832     public Wall getWall() {
1833       return this.wall;
1834     }
1835 
getXStart()1836     public float getXStart() {
1837       return this.xStart;
1838     }
1839 
getXEnd()1840     public float getXEnd() {
1841       return this.xEnd;
1842     }
1843 
getYStart()1844     public float getYStart() {
1845       return this.yStart;
1846     }
1847 
getYEnd()1848     public float getYEnd() {
1849       return this.yEnd;
1850     }
1851 
getHeight()1852     public Float getHeight() {
1853       return this.height;
1854     }
1855 
getHeightAtEnd()1856     public Float getHeightAtEnd() {
1857       return this.heightAtEnd;
1858     }
1859 
getLeftSideColor()1860     public Integer getLeftSideColor() {
1861       return this.leftSideColor;
1862     }
1863 
getLeftSideTexture()1864     public HomeTexture getLeftSideTexture() {
1865       return this.leftSideTexture;
1866     }
1867 
getLeftSideShininess()1868     public float getLeftSideShininess() {
1869       return this.leftSideShininess;
1870     }
1871 
getLeftSideBaseboard()1872     public Baseboard getLeftSideBaseboard() {
1873       return this.leftSideBaseboard;
1874     }
1875 
getRightSideColor()1876     public Integer getRightSideColor() {
1877       return this.rightSideColor;
1878     }
1879 
getRightSideTexture()1880     public HomeTexture getRightSideTexture() {
1881       return this.rightSideTexture;
1882     }
1883 
getRightSideShininess()1884     public float getRightSideShininess() {
1885       return this.rightSideShininess;
1886     }
1887 
getRightSideBaseboard()1888     public Baseboard getRightSideBaseboard() {
1889       return this.rightSideBaseboard;
1890     }
1891 
getPattern()1892     public TextureImage getPattern() {
1893       return this.pattern;
1894     }
1895 
getTopColor()1896     public Integer getTopColor() {
1897       return this.topColor;
1898     }
1899 
getThickness()1900     public float getThickness() {
1901       return this.thickness;
1902     }
1903 
getArcExtent()1904     public Float getArcExtent() {
1905       return this.arcExtent;
1906     }
1907   }
1908 }
1909