1 /*
2  * Home3DAttributesController.java 25 juin 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.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.beans.PropertyChangeSupport;
25 
26 import javax.swing.undo.CannotRedoException;
27 import javax.swing.undo.CannotUndoException;
28 import javax.swing.undo.UndoableEditSupport;
29 
30 import com.eteks.sweethome3d.model.Home;
31 import com.eteks.sweethome3d.model.HomeEnvironment;
32 import com.eteks.sweethome3d.model.HomeTexture;
33 import com.eteks.sweethome3d.model.UserPreferences;
34 
35 /**
36  * A MVC controller for home 3D attributes view.
37  * @author Emmanuel Puybaret
38  */
39 public class Home3DAttributesController implements Controller {
40   /**
41    * The properties that may be edited by the view associated to this controller.
42    */
43   public enum Property {GROUND_COLOR, GROUND_PAINT, BACKGROUND_IMAGE_VISIBLE_ON_GROUND_3D, SKY_COLOR, SKY_PAINT, LIGHT_COLOR, WALLS_ALPHA, WALLS_TOP_COLOR}
44   /**
45    * The possible values for {@linkplain #getGroundPaint() ground paint type}.
46    */
47   public enum EnvironmentPaint {COLORED, TEXTURED}
48 
49   private final Home                  home;
50   private final UserPreferences       preferences;
51   private final ViewFactory           viewFactory;
52   private final ContentManager        contentManager;
53   private final UndoableEditSupport   undoSupport;
54   private TextureChoiceController     groundTextureController;
55   private TextureChoiceController     skyTextureController;
56   private final PropertyChangeSupport propertyChangeSupport;
57   private DialogView                  home3DAttributesView;
58 
59   private int               groundColor;
60   private EnvironmentPaint  groundPaint;
61   private boolean           backgroundImageVisibleOnGround3D;
62   private int               skyColor;
63   private EnvironmentPaint  skyPaint;
64   private int               lightColor;
65   private float             wallsAlpha;
66 
67   /**
68    * Creates the controller of 3D view with undo support.
69    */
Home3DAttributesController(Home home, UserPreferences preferences, ViewFactory viewFactory, ContentManager contentManager, UndoableEditSupport undoSupport)70   public Home3DAttributesController(Home home,
71                                     UserPreferences preferences,
72                                     ViewFactory viewFactory,
73                                     ContentManager contentManager,
74                                     UndoableEditSupport undoSupport) {
75     this.home = home;
76     this.preferences = preferences;
77     this.viewFactory = viewFactory;
78     this.contentManager = contentManager;
79     this.undoSupport = undoSupport;
80     this.propertyChangeSupport = new PropertyChangeSupport(this);
81 
82     updateProperties();
83   }
84 
85   /**
86    * Returns the texture controller of the ground.
87    */
getGroundTextureController()88   public TextureChoiceController getGroundTextureController() {
89     // Create sub controller lazily only once it's needed
90     if (this.groundTextureController == null) {
91       this.groundTextureController = new TextureChoiceController(
92           this.preferences.getLocalizedString(Home3DAttributesController.class, "groundTextureTitle"),
93           this.preferences, this.viewFactory, this.contentManager);
94       this.groundTextureController.addPropertyChangeListener(TextureChoiceController.Property.TEXTURE,
95           new PropertyChangeListener() {
96             public void propertyChange(PropertyChangeEvent ev) {
97               setGroundPaint(EnvironmentPaint.TEXTURED);
98             }
99           });
100     }
101     return this.groundTextureController;
102   }
103 
104   /**
105    * Returns the texture controller of the sky.
106    */
getSkyTextureController()107   public TextureChoiceController getSkyTextureController() {
108     // Create sub controller lazily only once it's needed
109     if (this.skyTextureController == null) {
110       this.skyTextureController = new TextureChoiceController(
111           this.preferences.getLocalizedString(Home3DAttributesController.class, "skyTextureTitle"),
112           false,
113           this.preferences, this.viewFactory, this.contentManager);
114       this.skyTextureController.addPropertyChangeListener(TextureChoiceController.Property.TEXTURE,
115           new PropertyChangeListener() {
116             public void propertyChange(PropertyChangeEvent ev) {
117               setSkyPaint(EnvironmentPaint.TEXTURED);
118             }
119           });
120     }
121     return this.skyTextureController;
122   }
123 
124   /**
125    * Returns the view associated with this controller.
126    */
getView()127   public DialogView getView() {
128     // Create view lazily only once it's needed
129     if (this.home3DAttributesView == null) {
130       this.home3DAttributesView = this.viewFactory.createHome3DAttributesView(
131           this.preferences, this);
132     }
133     return this.home3DAttributesView;
134   }
135 
136   /**
137    * Displays the view controlled by this controller.
138    */
displayView(View parentView)139   public void displayView(View parentView) {
140     getView().displayView(parentView);
141   }
142 
143   /**
144    * Adds the property change <code>listener</code> in parameter to this controller.
145    */
addPropertyChangeListener(Property property, PropertyChangeListener listener)146   public void addPropertyChangeListener(Property property, PropertyChangeListener listener) {
147     this.propertyChangeSupport.addPropertyChangeListener(property.name(), listener);
148   }
149 
150   /**
151    * Removes the property change <code>listener</code> in parameter from this controller.
152    */
removePropertyChangeListener(Property property, PropertyChangeListener listener)153   public void removePropertyChangeListener(Property property, PropertyChangeListener listener) {
154     this.propertyChangeSupport.removePropertyChangeListener(property.name(), listener);
155   }
156 
157   /**
158    * Updates edited properties from the 3D attributes of the home edited by this controller.
159    */
updateProperties()160   protected void updateProperties() {
161     HomeEnvironment homeEnvironment = this.home.getEnvironment();
162     setGroundColor(homeEnvironment.getGroundColor());
163     HomeTexture groundTexture = homeEnvironment.getGroundTexture();
164     getGroundTextureController().setTexture(groundTexture);
165     if (groundTexture != null) {
166       setGroundPaint(EnvironmentPaint.TEXTURED);
167     } else {
168       setGroundPaint(EnvironmentPaint.COLORED);
169     }
170     setBackgroundImageVisibleOnGround3D(homeEnvironment.isBackgroundImageVisibleOnGround3D());
171     setSkyColor(homeEnvironment.getSkyColor());
172     HomeTexture skyTexture = homeEnvironment.getSkyTexture();
173     getSkyTextureController().setTexture(skyTexture);
174     if (skyTexture != null) {
175       setSkyPaint(EnvironmentPaint.TEXTURED);
176     } else {
177       setSkyPaint(EnvironmentPaint.COLORED);
178     }
179     setLightColor(homeEnvironment.getLightColor());
180     setWallsAlpha(homeEnvironment.getWallsAlpha());
181   }
182 
183   /**
184    * Sets the edited ground color.
185    */
setGroundColor(int groundColor)186   public void setGroundColor(int groundColor) {
187     if (groundColor != this.groundColor) {
188       int oldGroundColor = this.groundColor;
189       this.groundColor = groundColor;
190       this.propertyChangeSupport.firePropertyChange(Property.GROUND_COLOR.name(), oldGroundColor, groundColor);
191 
192       setGroundPaint(EnvironmentPaint.COLORED);
193     }
194   }
195 
196   /**
197    * Returns the edited ground color.
198    */
getGroundColor()199   public int getGroundColor() {
200     return this.groundColor;
201   }
202 
203   /**
204    * Sets whether the ground is colored or textured.
205    */
setGroundPaint(EnvironmentPaint groundPaint)206   public void setGroundPaint(EnvironmentPaint groundPaint) {
207     if (groundPaint != this.groundPaint) {
208       EnvironmentPaint oldGroundPaint = this.groundPaint;
209       this.groundPaint = groundPaint;
210       this.propertyChangeSupport.firePropertyChange(Property.GROUND_PAINT.name(), oldGroundPaint, groundPaint);
211     }
212   }
213 
214   /**
215    * Returns whether the ground is colored or textured.
216    */
getGroundPaint()217   public EnvironmentPaint getGroundPaint() {
218     return this.groundPaint;
219   }
220 
221   /**
222    * Returns <code>true</code> if the background image should be displayed on the ground in 3D.
223    * @since 6.0
224    */
isBackgroundImageVisibleOnGround3D()225   public boolean isBackgroundImageVisibleOnGround3D() {
226     return this.backgroundImageVisibleOnGround3D;
227   }
228 
229   /**
230    * Sets whether the background image should be displayed on the ground in 3D.
231    * @since 6.0
232    */
setBackgroundImageVisibleOnGround3D(boolean backgroundImageVisibleOnGround3D)233   public void setBackgroundImageVisibleOnGround3D(boolean backgroundImageVisibleOnGround3D) {
234     if (this.backgroundImageVisibleOnGround3D != backgroundImageVisibleOnGround3D) {
235       this.backgroundImageVisibleOnGround3D = backgroundImageVisibleOnGround3D;
236       this.propertyChangeSupport.firePropertyChange(Property.BACKGROUND_IMAGE_VISIBLE_ON_GROUND_3D.name(),
237           !backgroundImageVisibleOnGround3D, backgroundImageVisibleOnGround3D);
238     }
239   }
240 
241   /**
242    * Sets the edited sky color.
243    */
setSkyColor(int skyColor)244   public void setSkyColor(int skyColor) {
245     if (skyColor != this.skyColor) {
246       int oldSkyColor = this.skyColor;
247       this.skyColor = skyColor;
248       this.propertyChangeSupport.firePropertyChange(Property.SKY_COLOR.name(), oldSkyColor, skyColor);
249     }
250   }
251 
252   /**
253    * Returns the edited sky color.
254    */
getSkyColor()255   public int getSkyColor() {
256     return this.skyColor;
257   }
258 
259   /**
260    * Sets whether the sky is colored or textured.
261    */
setSkyPaint(EnvironmentPaint skyPaint)262   public void setSkyPaint(EnvironmentPaint skyPaint) {
263     if (skyPaint != this.skyPaint) {
264       EnvironmentPaint oldSkyPaint = this.skyPaint;
265       this.skyPaint = skyPaint;
266       this.propertyChangeSupport.firePropertyChange(Property.SKY_PAINT.name(), oldSkyPaint, skyPaint);
267     }
268   }
269 
270   /**
271    * Returns whether the sky is colored or textured.
272    */
getSkyPaint()273   public EnvironmentPaint getSkyPaint() {
274     return this.skyPaint;
275   }
276 
277   /**
278    * Sets the edited light color.
279    */
setLightColor(int lightColor)280   public void setLightColor(int lightColor) {
281     if (lightColor != this.lightColor) {
282       int oldLightColor = this.lightColor;
283       this.lightColor = lightColor;
284       this.propertyChangeSupport.firePropertyChange(Property.LIGHT_COLOR.name(), oldLightColor, lightColor);
285     }
286   }
287 
288   /**
289    * Returns the edited light color.
290    */
getLightColor()291   public int getLightColor() {
292     return this.lightColor;
293   }
294 
295   /**
296    * Sets the edited walls transparency alpha.
297    */
setWallsAlpha(float wallsAlpha)298   public void setWallsAlpha(float wallsAlpha) {
299     if (wallsAlpha != this.wallsAlpha) {
300       float oldWallsAlpha = this.wallsAlpha;
301       this.wallsAlpha = wallsAlpha;
302       this.propertyChangeSupport.firePropertyChange(Property.WALLS_ALPHA.name(), oldWallsAlpha, wallsAlpha);
303     }
304   }
305 
306   /**
307    * Returns the edited walls transparency alpha.
308    */
getWallsAlpha()309   public float getWallsAlpha() {
310     return this.wallsAlpha;
311   }
312 
313   /**
314    * Controls the modification of the 3D attributes of the edited home.
315    */
modify3DAttributes()316   public void modify3DAttributes() {
317     int   groundColor = getGroundColor();
318     HomeTexture groundTexture = getGroundPaint() == EnvironmentPaint.TEXTURED
319         ? getGroundTextureController().getTexture()
320         : null;
321     boolean backgroundImageVisibleOnGround3D = isBackgroundImageVisibleOnGround3D();
322     int   skyColor = getSkyColor();
323     HomeTexture skyTexture = getSkyPaint() == EnvironmentPaint.TEXTURED
324         ? getSkyTextureController().getTexture()
325         : null;
326     int   lightColor  = getLightColor();
327     float wallsAlpha = getWallsAlpha();
328 
329     HomeEnvironment homeEnvironment = this.home.getEnvironment();
330     int   oldGroundColor = homeEnvironment.getGroundColor();
331     boolean oldBackgroundImageVisibleOnGround3D = homeEnvironment.isBackgroundImageVisibleOnGround3D();
332     HomeTexture oldGroundTexture = homeEnvironment.getGroundTexture();
333     int   oldSkyColor = homeEnvironment.getSkyColor();
334     HomeTexture oldSkyTexture = homeEnvironment.getSkyTexture();
335     int   oldLightColor = homeEnvironment.getLightColor();
336     float oldWallsAlpha = homeEnvironment.getWallsAlpha();
337 
338     // Apply modification
339     doModify3DAttributes(home, groundColor, groundTexture, backgroundImageVisibleOnGround3D, skyColor,
340         skyTexture, lightColor, wallsAlpha);
341     if (this.undoSupport != null) {
342       this.undoSupport.postEdit(new Home3DAttributesModificationUndoableEdit(
343           this.home, this.preferences,
344           oldGroundColor, oldGroundTexture,
345           oldBackgroundImageVisibleOnGround3D, oldSkyColor,
346           oldSkyTexture, oldLightColor, oldWallsAlpha,
347           groundColor, groundTexture,
348           backgroundImageVisibleOnGround3D, skyColor,
349           skyTexture, lightColor, wallsAlpha));
350     }
351   }
352 
353   /**
354    * Undoable edit for 3D attributes modification. This class isn't anonymous to avoid
355    * being bound to controller and its view.
356    */
357   private static class Home3DAttributesModificationUndoableEdit extends LocalizedUndoableEdit {
358     private final Home            home;
359     private final int             oldGroundColor;
360     private final HomeTexture     oldGroundTexture;
361     private final boolean         oldBackgroundImageVisibleOnGround3D;
362     private final int             oldSkyColor;
363     private final HomeTexture     oldSkyTexture;
364     private final int             oldLightColor;
365     private final float           oldWallsAlpha;
366     private final int             groundColor;
367     private final HomeTexture     groundTexture;
368     private final boolean         backgroundImageVisibleOnGround3D;
369     private final int             skyColor;
370     private final HomeTexture     skyTexture;
371     private final int             lightColor;
372     private final float           wallsAlpha;
373 
Home3DAttributesModificationUndoableEdit(Home home, UserPreferences preferences, int oldGroundColor, HomeTexture oldGroundTexture, boolean oldBackgroundImageVisibleOnGround3D, int oldSkyColor, HomeTexture oldSkyTexture, int oldLightColor, float oldWallsAlpha, int groundColor, HomeTexture groundTexture, boolean backgroundImageVisibleOnGround3D, int skyColor, HomeTexture skyTexture, int lightColor, float wallsAlpha)374     private Home3DAttributesModificationUndoableEdit(Home home,
375                                                      UserPreferences preferences,
376                                                      int oldGroundColor,
377                                                      HomeTexture oldGroundTexture,
378                                                      boolean oldBackgroundImageVisibleOnGround3D,
379                                                      int oldSkyColor,
380                                                      HomeTexture oldSkyTexture,
381                                                      int oldLightColor,
382                                                      float oldWallsAlpha,
383                                                      int groundColor,
384                                                      HomeTexture groundTexture,
385                                                      boolean backgroundImageVisibleOnGround3D,
386                                                      int skyColor,
387                                                      HomeTexture skyTexture,
388                                                      int lightColor,
389                                                      float wallsAlpha) {
390       super(preferences, Home3DAttributesController.class, "undoModify3DAttributesName");
391       this.home = home;
392       this.oldGroundColor = oldGroundColor;
393       this.oldGroundTexture = oldGroundTexture;
394       this.oldBackgroundImageVisibleOnGround3D = oldBackgroundImageVisibleOnGround3D;
395       this.oldSkyColor = oldSkyColor;
396       this.oldSkyTexture = oldSkyTexture;
397       this.oldLightColor = oldLightColor;
398       this.oldWallsAlpha = oldWallsAlpha;
399       this.groundColor = groundColor;
400       this.groundTexture = groundTexture;
401       this.backgroundImageVisibleOnGround3D = backgroundImageVisibleOnGround3D;
402       this.skyColor = skyColor;
403       this.skyTexture = skyTexture;
404       this.lightColor = lightColor;
405       this.wallsAlpha = wallsAlpha;
406     }
407 
408     @Override
undo()409     public void undo() throws CannotUndoException {
410       super.undo();
411       doModify3DAttributes(this.home, this.oldGroundColor, this.oldGroundTexture, this.oldBackgroundImageVisibleOnGround3D,
412           this.oldSkyColor, this.oldSkyTexture, this.oldLightColor, this.oldWallsAlpha);
413     }
414 
415     @Override
redo()416     public void redo() throws CannotRedoException {
417       super.redo();
418       doModify3DAttributes(this.home, this.groundColor, this.groundTexture, this.backgroundImageVisibleOnGround3D,
419           this.skyColor, this.skyTexture, this.lightColor, this.wallsAlpha);
420     }
421   }
422 
423   /**
424    * Modifies the 3D attributes of the given <code>home</code>.
425    */
doModify3DAttributes(Home home, int groundColor, HomeTexture groundTexture, boolean backgroundImageVisibleOnGround3D, int skyColor, HomeTexture skyTexture, int lightColor, float wallsAlpha)426   private static void doModify3DAttributes(Home home,
427                                            int groundColor, HomeTexture groundTexture,
428                                            boolean backgroundImageVisibleOnGround3D,
429                                            int skyColor, HomeTexture skyTexture,
430                                            int lightColor,
431                                            float wallsAlpha) {
432     HomeEnvironment homeEnvironment = home.getEnvironment();
433     homeEnvironment.setGroundColor(groundColor);
434     homeEnvironment.setGroundTexture(groundTexture);
435     homeEnvironment.setBackgroundImageVisibleOnGround3D(backgroundImageVisibleOnGround3D);
436     homeEnvironment.setSkyColor(skyColor);
437     homeEnvironment.setSkyTexture(skyTexture);
438     homeEnvironment.setLightColor(lightColor);
439     homeEnvironment.setWallsAlpha(wallsAlpha);
440   }
441 }
442