1 /* 2 * RoomController.java 20 nov. 2008 3 * 4 * Sweet Home 3D, Copyright (c) 2008 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.Area; 23 import java.awt.geom.GeneralPath; 24 import java.awt.geom.Line2D; 25 import java.awt.geom.PathIterator; 26 import java.awt.geom.Point2D; 27 import java.beans.PropertyChangeEvent; 28 import java.beans.PropertyChangeListener; 29 import java.beans.PropertyChangeSupport; 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.HashMap; 33 import java.util.List; 34 import java.util.Map; 35 36 import javax.swing.undo.CannotRedoException; 37 import javax.swing.undo.CannotUndoException; 38 import javax.swing.undo.UndoableEditSupport; 39 40 import com.eteks.sweethome3d.model.Baseboard; 41 import com.eteks.sweethome3d.model.Home; 42 import com.eteks.sweethome3d.model.HomeTexture; 43 import com.eteks.sweethome3d.model.Level; 44 import com.eteks.sweethome3d.model.Room; 45 import com.eteks.sweethome3d.model.Selectable; 46 import com.eteks.sweethome3d.model.UserPreferences; 47 import com.eteks.sweethome3d.model.Wall; 48 49 /** 50 * A MVC controller for room view. 51 * @author Emmanuel Puybaret 52 */ 53 public class RoomController implements Controller { 54 /** 55 * The properties that may be edited by the view associated to this controller. 56 */ 57 public enum Property {NAME, AREA_VISIBLE, FLOOR_VISIBLE, FLOOR_COLOR, FLOOR_PAINT, FLOOR_SHININESS, 58 CEILING_VISIBLE, CEILING_COLOR, CEILING_PAINT, CEILING_SHININESS, 59 SPLIT_SURROUNDING_WALLS, WALL_SIDES_COLOR, WALL_SIDES_PAINT, WALL_SIDES_SHININESS, WALL_SIDES_BASEBOARD} 60 61 /** 62 * The possible values for {@linkplain #getFloorPaint() room paint type}. 63 */ 64 public enum RoomPaint {DEFAULT, COLORED, TEXTURED} 65 66 private final Home home; 67 private final UserPreferences preferences; 68 private final ViewFactory viewFactory; 69 private final ContentManager contentManager; 70 private final UndoableEditSupport undoSupport; 71 private TextureChoiceController floorTextureController; 72 private TextureChoiceController ceilingTextureController; 73 private TextureChoiceController wallSidesTextureController; 74 private BaseboardChoiceController wallSidesBaseboardController; 75 private final PropertyChangeSupport propertyChangeSupport; 76 private DialogView roomView; 77 78 private String name; 79 private Boolean areaVisible; 80 private Boolean floorVisible; 81 private Integer floorColor; 82 private RoomPaint floorPaint; 83 private Float floorShininess; 84 private Boolean ceilingVisible; 85 private Integer ceilingColor; 86 private RoomPaint ceilingPaint; 87 private Float ceilingShininess; 88 private boolean wallSidesEditable; 89 private boolean splitSurroundingWalls; 90 private boolean splitSurroundingWallsNeeded; 91 private Integer wallSidesColor; 92 private RoomPaint wallSidesPaint; 93 private Float wallSidesShininess; 94 95 /** 96 * Creates the controller of room view with undo support. 97 */ RoomController(final Home home, UserPreferences preferences, ViewFactory viewFactory, ContentManager contentManager, UndoableEditSupport undoSupport)98 public RoomController(final Home home, 99 UserPreferences preferences, 100 ViewFactory viewFactory, 101 ContentManager contentManager, 102 UndoableEditSupport undoSupport) { 103 this.home = home; 104 this.preferences = preferences; 105 this.viewFactory = viewFactory; 106 this.contentManager = contentManager; 107 this.undoSupport = undoSupport; 108 this.propertyChangeSupport = new PropertyChangeSupport(this); 109 110 updateProperties(); 111 } 112 113 /** 114 * Returns the texture controller of the room floor. 115 */ getFloorTextureController()116 public TextureChoiceController getFloorTextureController() { 117 // Create sub controller lazily only once it's needed 118 if (this.floorTextureController == null) { 119 this.floorTextureController = new TextureChoiceController( 120 this.preferences.getLocalizedString(RoomController.class, "floorTextureTitle"), 121 this.preferences, this.viewFactory, this.contentManager); 122 this.floorTextureController.addPropertyChangeListener(TextureChoiceController.Property.TEXTURE, 123 new PropertyChangeListener() { 124 public void propertyChange(PropertyChangeEvent ev) { 125 setFloorPaint(RoomPaint.TEXTURED); 126 } 127 }); 128 } 129 return this.floorTextureController; 130 } 131 132 /** 133 * Returns the texture controller of the room ceiling. 134 */ getCeilingTextureController()135 public TextureChoiceController getCeilingTextureController() { 136 // Create sub controller lazily only once it's needed 137 if (this.ceilingTextureController == null) { 138 this.ceilingTextureController = new TextureChoiceController( 139 this.preferences.getLocalizedString(RoomController.class, "ceilingTextureTitle"), 140 this.preferences, this.viewFactory, this.contentManager); 141 this.ceilingTextureController.addPropertyChangeListener(TextureChoiceController.Property.TEXTURE, 142 new PropertyChangeListener() { 143 public void propertyChange(PropertyChangeEvent ev) { 144 setCeilingPaint(RoomPaint.TEXTURED); 145 } 146 }); 147 } 148 return this.ceilingTextureController; 149 } 150 151 /** 152 * Returns the texture controller of the room wall sides. 153 */ getWallSidesTextureController()154 public TextureChoiceController getWallSidesTextureController() { 155 // Create sub controller lazily only once it's needed 156 if (this.wallSidesTextureController == null) { 157 this.wallSidesTextureController = new TextureChoiceController( 158 this.preferences.getLocalizedString(RoomController.class, "wallSidesTextureTitle"), 159 this.preferences, this.viewFactory, this.contentManager); 160 this.wallSidesTextureController.addPropertyChangeListener(TextureChoiceController.Property.TEXTURE, 161 new PropertyChangeListener() { 162 public void propertyChange(PropertyChangeEvent ev) { 163 setWallSidesPaint(RoomPaint.TEXTURED); 164 } 165 }); 166 } 167 return this.wallSidesTextureController; 168 } 169 170 /** 171 * Returns the controller of the wall sides baseboard. 172 * @since 5.0 173 */ getWallSidesBaseboardController()174 public BaseboardChoiceController getWallSidesBaseboardController() { 175 // Create sub controller lazily only once it's needed 176 if (this.wallSidesBaseboardController == null) { 177 this.wallSidesBaseboardController = new BaseboardChoiceController( 178 this.preferences, this.viewFactory, this.contentManager); 179 } 180 return this.wallSidesBaseboardController; 181 } 182 183 /** 184 * Returns the view associated with this controller. 185 */ getView()186 public DialogView getView() { 187 // Create view lazily only once it's needed 188 if (this.roomView == null) { 189 this.roomView = this.viewFactory.createRoomView(this.preferences, this); 190 } 191 return this.roomView; 192 } 193 194 /** 195 * Displays the view controlled by this controller. 196 */ displayView(View parentView)197 public void displayView(View parentView) { 198 getView().displayView(parentView); 199 } 200 201 /** 202 * Adds the property change <code>listener</code> in parameter to this controller. 203 */ addPropertyChangeListener(Property property, PropertyChangeListener listener)204 public void addPropertyChangeListener(Property property, PropertyChangeListener listener) { 205 this.propertyChangeSupport.addPropertyChangeListener(property.name(), listener); 206 } 207 208 /** 209 * Removes the property change <code>listener</code> in parameter from this controller. 210 */ removePropertyChangeListener(Property property, PropertyChangeListener listener)211 public void removePropertyChangeListener(Property property, PropertyChangeListener listener) { 212 this.propertyChangeSupport.removePropertyChangeListener(property.name(), listener); 213 } 214 215 /** 216 * Returns <code>true</code> if the given <code>property</code> is editable. 217 * Depending on whether a property is editable or not, the view associated to this controller 218 * may render it differently. 219 * The implementation of this method always returns <code>true</code> except for <code>WALL</code> properties. 220 */ isPropertyEditable(Property property)221 public boolean isPropertyEditable(Property property) { 222 switch (property) { 223 case SPLIT_SURROUNDING_WALLS : 224 case WALL_SIDES_COLOR : 225 case WALL_SIDES_PAINT : 226 case WALL_SIDES_SHININESS : 227 case WALL_SIDES_BASEBOARD : 228 return this.wallSidesEditable; 229 default : 230 return true; 231 } 232 } 233 234 /** 235 * Updates edited properties from selected rooms in the home edited by this controller. 236 */ updateProperties()237 protected void updateProperties() { 238 List<Room> selectedRooms = Home.getRoomsSubList(this.home.getSelectedItems()); 239 if (selectedRooms.isEmpty()) { 240 setAreaVisible(null); // Nothing to edit 241 setFloorColor(null); 242 getFloorTextureController().setTexture(null); 243 setFloorPaint(null); 244 setFloorShininess(null); 245 setCeilingColor(null); 246 getCeilingTextureController().setTexture(null); 247 setCeilingPaint(null); 248 setCeilingShininess(null); 249 } else { 250 // Search the common properties among selected rooms 251 Room firstRoom = selectedRooms.get(0); 252 253 String name = firstRoom.getName(); 254 if (name != null) { 255 for (int i = 1; i < selectedRooms.size(); i++) { 256 if (!name.equals(selectedRooms.get(i).getName())) { 257 name = null; 258 break; 259 } 260 } 261 } 262 setName(name); 263 264 // Search the common areaVisible value among rooms 265 Boolean areaVisible = firstRoom.isAreaVisible(); 266 for (int i = 1; i < selectedRooms.size(); i++) { 267 if (areaVisible != selectedRooms.get(i).isAreaVisible()) { 268 areaVisible = null; 269 break; 270 } 271 } 272 setAreaVisible(areaVisible); 273 274 // Search the common floorVisible value among rooms 275 Boolean floorVisible = firstRoom.isFloorVisible(); 276 for (int i = 1; i < selectedRooms.size(); i++) { 277 if (floorVisible != selectedRooms.get(i).isFloorVisible()) { 278 floorVisible = null; 279 break; 280 } 281 } 282 setFloorVisible(floorVisible); 283 284 // Search the common floor color among rooms 285 Integer floorColor = firstRoom.getFloorColor(); 286 if (floorColor != null) { 287 for (int i = 1; i < selectedRooms.size(); i++) { 288 if (!floorColor.equals(selectedRooms.get(i).getFloorColor())) { 289 floorColor = null; 290 break; 291 } 292 } 293 } 294 setFloorColor(floorColor); 295 296 // Search the common floor texture among rooms 297 HomeTexture floorTexture = firstRoom.getFloorTexture(); 298 if (floorTexture != null) { 299 for (int i = 1; i < selectedRooms.size(); i++) { 300 if (!floorTexture.equals(selectedRooms.get(i).getFloorTexture())) { 301 floorTexture = null; 302 break; 303 } 304 } 305 } 306 getFloorTextureController().setTexture(floorTexture); 307 308 boolean defaultColorsAndTextures = true; 309 for (int i = 0; i < selectedRooms.size(); i++) { 310 Room room = selectedRooms.get(i); 311 if (room.getFloorColor() != null 312 || room.getFloorTexture() != null) { 313 defaultColorsAndTextures = false; 314 break; 315 } 316 } 317 318 if (floorColor != null) { 319 setFloorPaint(RoomPaint.COLORED); 320 } else if (floorTexture != null) { 321 setFloorPaint(RoomPaint.TEXTURED); 322 } else if (defaultColorsAndTextures) { 323 setFloorPaint(RoomPaint.DEFAULT); 324 } else { 325 setFloorPaint(null); 326 } 327 328 // Search the common floor shininess among rooms 329 Float floorShininess = firstRoom.getFloorShininess(); 330 for (int i = 1; i < selectedRooms.size(); i++) { 331 if (!floorShininess.equals(selectedRooms.get(i).getFloorShininess())) { 332 floorShininess = null; 333 break; 334 } 335 } 336 setFloorShininess(floorShininess); 337 338 // Search the common ceilingVisible value among rooms 339 Boolean ceilingVisible = firstRoom.isCeilingVisible(); 340 for (int i = 1; i < selectedRooms.size(); i++) { 341 if (ceilingVisible != selectedRooms.get(i).isCeilingVisible()) { 342 ceilingVisible = null; 343 break; 344 } 345 } 346 setCeilingVisible(ceilingVisible); 347 348 // Search the common ceiling color among rooms 349 Integer ceilingColor = firstRoom.getCeilingColor(); 350 if (ceilingColor != null) { 351 for (int i = 1; i < selectedRooms.size(); i++) { 352 if (!ceilingColor.equals(selectedRooms.get(i).getCeilingColor())) { 353 ceilingColor = null; 354 break; 355 } 356 } 357 } 358 setCeilingColor(ceilingColor); 359 360 // Search the common ceiling texture among rooms 361 HomeTexture ceilingTexture = firstRoom.getCeilingTexture(); 362 if (ceilingTexture != null) { 363 for (int i = 1; i < selectedRooms.size(); i++) { 364 if (!ceilingTexture.equals(selectedRooms.get(i).getCeilingTexture())) { 365 ceilingTexture = null; 366 break; 367 } 368 } 369 } 370 getCeilingTextureController().setTexture(ceilingTexture); 371 372 defaultColorsAndTextures = true; 373 for (int i = 0; i < selectedRooms.size(); i++) { 374 Room room = selectedRooms.get(i); 375 if (room.getCeilingColor() != null 376 || room.getCeilingTexture() != null) { 377 defaultColorsAndTextures = false; 378 break; 379 } 380 } 381 382 if (ceilingColor != null) { 383 setCeilingPaint(RoomPaint.COLORED); 384 } else if (ceilingTexture != null) { 385 setCeilingPaint(RoomPaint.TEXTURED); 386 } else if (defaultColorsAndTextures) { 387 setCeilingPaint(RoomPaint.DEFAULT); 388 } else { 389 setCeilingPaint(null); 390 } 391 392 // Search the common ceiling shininess among rooms 393 Float ceilingShininess = firstRoom.getCeilingShininess(); 394 for (int i = 1; i < selectedRooms.size(); i++) { 395 if (!ceilingShininess.equals(selectedRooms.get(i).getCeilingShininess())) { 396 ceilingShininess = null; 397 break; 398 } 399 } 400 setCeilingShininess(ceilingShininess); 401 } 402 403 List<WallSide> wallSides = getRoomsWallSides(selectedRooms, null); 404 if (wallSides.isEmpty()) { 405 this.wallSidesEditable = 406 this.splitSurroundingWallsNeeded = 407 this.splitSurroundingWalls = false; 408 setWallSidesColor(null); 409 setWallSidesPaint(null); 410 setWallSidesShininess(null); 411 getWallSidesBaseboardController().setVisible(null); 412 getWallSidesBaseboardController().setThickness(null); 413 getWallSidesBaseboardController().setHeight(null); 414 getWallSidesBaseboardController().setColor(null); 415 getWallSidesBaseboardController().getTextureController().setTexture(null); 416 getWallSidesBaseboardController().setPaint(null); 417 } else { 418 this.wallSidesEditable = true; 419 this.splitSurroundingWallsNeeded = splitWalls(wallSides, null, null, null); 420 this.splitSurroundingWalls = false; 421 WallSide firstWallSide = wallSides.get(0); 422 423 // Search the common wall color among wall sides 424 Integer wallSidesColor = firstWallSide.getSide() == WallSide.LEFT_SIDE 425 ? firstWallSide.getWall().getLeftSideColor() 426 : firstWallSide.getWall().getRightSideColor(); 427 if (wallSidesColor != null) { 428 for (int i = 1; i < wallSides.size(); i++) { 429 WallSide wallSide = wallSides.get(i); 430 if (!wallSidesColor.equals(wallSide.getSide() == WallSide.LEFT_SIDE 431 ? wallSide.getWall().getLeftSideColor() 432 : wallSide.getWall().getRightSideColor())) { 433 wallSidesColor = null; 434 break; 435 } 436 } 437 } 438 setWallSidesColor(wallSidesColor); 439 440 // Search the common wall texture among wall sides 441 HomeTexture wallSidesTexture = firstWallSide.getSide() == WallSide.LEFT_SIDE 442 ? firstWallSide.getWall().getLeftSideTexture() 443 : firstWallSide.getWall().getRightSideTexture(); 444 if (wallSidesTexture != null) { 445 for (int i = 1; i < wallSides.size(); i++) { 446 WallSide wallSide = wallSides.get(i); 447 if (!wallSidesTexture.equals(wallSide.getSide() == WallSide.LEFT_SIDE 448 ? wallSide.getWall().getLeftSideTexture() 449 : wallSide.getWall().getRightSideTexture())) { 450 wallSidesTexture = null; 451 break; 452 } 453 } 454 } 455 getWallSidesTextureController().setTexture(wallSidesTexture); 456 457 boolean defaultColorsAndTextures = true; 458 for (int i = 0; i < wallSides.size(); i++) { 459 WallSide wallSide = wallSides.get(i); 460 if ((wallSide.getSide() == WallSide.LEFT_SIDE 461 ? wallSide.getWall().getLeftSideColor() 462 : wallSide.getWall().getRightSideColor()) != null 463 || (wallSide.getSide() == WallSide.LEFT_SIDE 464 ? wallSide.getWall().getLeftSideTexture() 465 : wallSide.getWall().getRightSideTexture()) != null) { 466 defaultColorsAndTextures = false; 467 break; 468 } 469 } 470 471 if (wallSidesColor != null) { 472 setWallSidesPaint(RoomPaint.COLORED); 473 } else if (wallSidesTexture != null) { 474 setWallSidesPaint(RoomPaint.TEXTURED); 475 } else if (defaultColorsAndTextures) { 476 setWallSidesPaint(RoomPaint.DEFAULT); 477 } else { 478 setWallSidesPaint(null); 479 } 480 481 // Search the common floor shininess among rooms 482 Float wallSidesShininess = firstWallSide.getSide() == WallSide.LEFT_SIDE 483 ? firstWallSide.getWall().getLeftSideShininess() 484 : firstWallSide.getWall().getRightSideShininess(); 485 if (wallSidesShininess != null) { 486 for (int i = 1; i < wallSides.size(); i++) { 487 WallSide wallSide = wallSides.get(i); 488 if (!wallSidesShininess.equals(wallSide.getSide() == WallSide.LEFT_SIDE 489 ? wallSide.getWall().getLeftSideShininess() 490 : wallSide.getWall().getRightSideShininess())) { 491 wallSidesShininess = null; 492 break; 493 } 494 } 495 } 496 setWallSidesShininess(wallSidesShininess); 497 498 Baseboard firstWallSideBaseboard = firstWallSide.getSide() == WallSide.LEFT_SIDE 499 ? firstWallSide.getWall().getLeftSideBaseboard() 500 : firstWallSide.getWall().getRightSideBaseboard(); 501 Boolean wallSidesBaseboardVisible = firstWallSideBaseboard != null; 502 for (int i = 1; i < wallSides.size(); i++) { 503 WallSide wallSide = wallSides.get(i); 504 if (wallSidesBaseboardVisible 505 != (wallSide.getSide() == WallSide.LEFT_SIDE 506 ? wallSide.getWall().getLeftSideBaseboard() != null 507 : wallSide.getWall().getRightSideBaseboard() != null)) { 508 wallSidesBaseboardVisible = null; 509 break; 510 } 511 } 512 getWallSidesBaseboardController().setVisible(wallSidesBaseboardVisible); 513 514 // Search the common baseboard thickness among walls 515 Float wallSidesBaseboardThickness = firstWallSideBaseboard != null 516 ? firstWallSideBaseboard.getThickness() 517 : this.preferences.getNewWallBaseboardThickness(); 518 for (int i = 1; i < wallSides.size(); i++) { 519 WallSide wallSide = wallSides.get(i); 520 Baseboard baseboard = wallSide.getSide() == WallSide.LEFT_SIDE 521 ? wallSide.getWall().getLeftSideBaseboard() 522 : wallSide.getWall().getRightSideBaseboard(); 523 if (!wallSidesBaseboardThickness.equals(baseboard != null 524 ? baseboard.getThickness() 525 : this.preferences.getNewWallBaseboardThickness())) { 526 wallSidesBaseboardThickness = null; 527 break; 528 } 529 } 530 getWallSidesBaseboardController().setThickness(wallSidesBaseboardThickness); 531 532 // Search the common baseboard height among walls 533 Float wallSidesBaseboardHeight = firstWallSideBaseboard != null 534 ? firstWallSideBaseboard.getHeight() 535 : this.preferences.getNewWallBaseboardHeight(); 536 for (int i = 1; i < wallSides.size(); i++) { 537 WallSide wallSide = wallSides.get(i); 538 Baseboard baseboard = wallSide.getSide() == WallSide.LEFT_SIDE 539 ? wallSide.getWall().getLeftSideBaseboard() 540 : wallSide.getWall().getRightSideBaseboard(); 541 if (!wallSidesBaseboardHeight.equals(baseboard != null 542 ? baseboard.getHeight() 543 : this.preferences.getNewWallBaseboardHeight())) { 544 wallSidesBaseboardHeight = null; 545 break; 546 } 547 } 548 getWallSidesBaseboardController().setHeight(wallSidesBaseboardHeight); 549 550 // Search the maximum height among walls 551 float maxBaseboardHeight = firstWallSide.getWall().isTrapezoidal() 552 ? Math.max(firstWallSide.getWall().getHeight(), firstWallSide.getWall().getHeightAtEnd()) 553 : firstWallSide.getWall().getHeight(); 554 for (int i = 1; i < wallSides.size(); i++) { 555 Wall wall = wallSides.get(i).getWall(); 556 maxBaseboardHeight = Math.max(maxBaseboardHeight, 557 wall.isTrapezoidal() 558 ? Math.max(wall.getHeight(), wall.getHeightAtEnd()) 559 : wall.getHeight()); 560 } 561 getWallSidesBaseboardController().setMaxHeight(maxBaseboardHeight); 562 563 // Search the common baseboard color among walls 564 Integer wallSidesBaseboardColor = firstWallSideBaseboard != null 565 ? firstWallSideBaseboard.getColor() 566 : null; 567 if (wallSidesBaseboardColor != null) { 568 for (int i = 1; i < wallSides.size(); i++) { 569 WallSide wallSide = wallSides.get(i); 570 Baseboard baseboard = wallSide.getSide() == WallSide.LEFT_SIDE 571 ? wallSide.getWall().getLeftSideBaseboard() 572 : wallSide.getWall().getRightSideBaseboard(); 573 if (baseboard == null 574 || !wallSidesBaseboardColor.equals(baseboard.getColor())) { 575 wallSidesBaseboardColor = null; 576 break; 577 } 578 } 579 } 580 getWallSidesBaseboardController().setColor(wallSidesBaseboardColor); 581 582 // Search the common right baseboard texture among walls 583 HomeTexture wallSidesBaseboardTexture = firstWallSideBaseboard != null 584 ? firstWallSideBaseboard.getTexture() 585 : null; 586 if (wallSidesBaseboardTexture != null) { 587 for (int i = 1; i < wallSides.size(); i++) { 588 WallSide wallSide = wallSides.get(i); 589 Baseboard baseboard = wallSide.getSide() == WallSide.LEFT_SIDE 590 ? wallSide.getWall().getLeftSideBaseboard() 591 : wallSide.getWall().getRightSideBaseboard(); 592 if (baseboard == null 593 || !wallSidesBaseboardTexture.equals(baseboard.getTexture())) { 594 wallSidesBaseboardTexture = null; 595 break; 596 } 597 } 598 } 599 getWallSidesBaseboardController().getTextureController().setTexture(wallSidesBaseboardTexture); 600 601 defaultColorsAndTextures = true; 602 for (int i = 0; i < wallSides.size(); i++) { 603 WallSide wallSide = wallSides.get(i); 604 Baseboard baseboard = wallSide.getSide() == WallSide.LEFT_SIDE 605 ? wallSide.getWall().getLeftSideBaseboard() 606 : wallSide.getWall().getRightSideBaseboard(); 607 if (baseboard != null 608 && (baseboard.getColor() != null 609 || baseboard.getTexture() != null)) { 610 defaultColorsAndTextures = false; 611 break; 612 } 613 } 614 615 if (wallSidesBaseboardColor != null) { 616 getWallSidesBaseboardController().setPaint(BaseboardChoiceController.BaseboardPaint.COLORED); 617 } else if (wallSidesBaseboardTexture != null) { 618 getWallSidesBaseboardController().setPaint(BaseboardChoiceController.BaseboardPaint.TEXTURED); 619 } else if (defaultColorsAndTextures) { 620 getWallSidesBaseboardController().setPaint(BaseboardChoiceController.BaseboardPaint.DEFAULT); 621 } else { 622 getWallSidesBaseboardController().setPaint(null); 623 } 624 } 625 } 626 627 /** 628 * Returns the wall sides close to each room of <code>rooms</code>. 629 */ getRoomsWallSides(List<Room> rooms, List<WallSide> defaultWallSides)630 private List<WallSide> getRoomsWallSides(List<Room> rooms, List<WallSide> defaultWallSides) { 631 List<WallSide> wallSides = new ArrayList<WallSide>(); 632 for (Room room : rooms) { 633 Area roomArea = new Area(getPath(room.getPoints(), true)); 634 if (defaultWallSides != null) { 635 for (WallSide wallSide : defaultWallSides) { 636 if (isRoomItersectingWallSide(wallSide.getWall().getPoints(), wallSide.getSide(), roomArea)) { 637 wallSides.add(wallSide); 638 } 639 } 640 } else { 641 for (Wall wall : this.home.getWalls()) { 642 if ((wall.getLevel() == null || wall.getLevel().isViewable()) 643 && wall.isAtLevel(this.home.getSelectedLevel())) { 644 float [][] wallPoints = wall.getPoints(); 645 if (isRoomItersectingWallSide(wallPoints, WallSide.LEFT_SIDE, roomArea)) { 646 wallSides.add(new WallSide(wall, WallSide.LEFT_SIDE)); 647 } 648 if (isRoomItersectingWallSide(wallPoints, WallSide.RIGHT_SIDE, roomArea)) { 649 wallSides.add(new WallSide(wall, WallSide.RIGHT_SIDE)); 650 } 651 } 652 } 653 } 654 } 655 return wallSides; 656 } 657 658 /** 659 * Returns <code>true</code> if the wall points on the given <code>wallSide</code> 660 * intersects room area. 661 */ isRoomItersectingWallSide(float [][] wallPoints, int wallSide, Area roomArea)662 private boolean isRoomItersectingWallSide(float [][] wallPoints, int wallSide, Area roomArea) { 663 Area wallSideTestArea = getWallSideArea(wallPoints, wallSide); 664 float wallSideTestAreaSurface = getSurface(wallSideTestArea); 665 wallSideTestArea.intersect(roomArea); 666 if (!wallSideTestArea.isEmpty()) { 667 float wallSideIntersectionSurface = getSurface(wallSideTestArea); 668 // Take into account only walls that shares a minimum surface with the room 669 if (wallSideIntersectionSurface > wallSideTestAreaSurface * 0.02f) { 670 return true; 671 } 672 } 673 return false; 674 } 675 676 /** 677 * Returns the area of the side of the given <code>wall</code>. 678 */ getWallSideArea(float [][] wallPoints, int wallSide)679 private Area getWallSideArea(float [][] wallPoints, int wallSide) { 680 final float thickness = 2f; 681 // Build an area of the given thickness using walls instances 682 if (wallPoints.length == 4) { 683 if (wallSide == WallSide.LEFT_SIDE) { 684 return new Area(getPath(new Wall( 685 wallPoints [0][0], wallPoints [0][1], wallPoints [1][0], wallPoints [1][1], thickness, 0).getPoints(), true)); 686 } else { 687 return new Area(getPath(new Wall( 688 wallPoints [2][0], wallPoints [2][1], wallPoints [3][0], wallPoints [3][1], thickness, 0).getPoints(), true)); 689 } 690 } else { 691 float [][] wallSidePoints = new float [wallPoints.length / 2][]; 692 System.arraycopy(wallPoints, wallSide == WallSide.LEFT_SIDE ? 0 : wallSidePoints.length, 693 wallSidePoints, 0, wallSidePoints.length); 694 Wall [] wallSideWalls = new Wall [wallSidePoints.length - 1]; 695 for (int i = 0; i < wallSideWalls.length; i++) { 696 wallSideWalls [i] = new Wall(wallSidePoints [i][0], wallSidePoints [i][1], wallSidePoints [i + 1][0], wallSidePoints [i + 1][1], thickness, 0); 697 if (i > 0) { 698 wallSideWalls [i].setWallAtStart(wallSideWalls [i - 1]); 699 wallSideWalls [i - 1].setWallAtEnd(wallSideWalls [i]); 700 } 701 } 702 wallSidePoints = new float [wallPoints.length][]; 703 float [][] wallSideWallPoints = null; 704 for (int i = 0; i < wallSideWalls.length; i++) { 705 wallSideWallPoints = wallSideWalls [i].getPoints(); 706 wallSidePoints [i] = wallSideWallPoints [0]; 707 wallSidePoints [wallSidePoints.length - i - 1] = wallSideWallPoints [3]; 708 } 709 wallSidePoints [wallSidePoints.length / 2 - 1] = wallSideWallPoints [1]; 710 wallSidePoints [wallSidePoints.length / 2] = wallSideWallPoints [2]; 711 return new Area(getPath(wallSidePoints, true)); 712 } 713 } 714 715 /** 716 * Returns the shape matching the coordinates in <code>points</code> array. 717 */ getPath(float [][] points, boolean closedPath)718 private GeneralPath getPath(float [][] points, boolean closedPath) { 719 GeneralPath path = new GeneralPath(); 720 path.moveTo(points [0][0], points [0][1]); 721 for (int i = 1; i < points.length; i++) { 722 path.lineTo(points [i][0], points [i][1]); 723 } 724 if (closedPath) { 725 path.closePath(); 726 } 727 return path; 728 } 729 730 /** 731 * Returns the surface of the given <code>area</code>. 732 */ getSurface(Area area)733 private float getSurface(Area area) { 734 // Add the surface of the different polygons of this room 735 float surface = 0; 736 List<float []> currentPathPoints = new ArrayList<float[]>(); 737 for (PathIterator it = area.getPathIterator(null); !it.isDone(); ) { 738 float [] roomPoint = new float[2]; 739 switch (it.currentSegment(roomPoint)) { 740 case PathIterator.SEG_MOVETO : 741 currentPathPoints.add(roomPoint); 742 break; 743 case PathIterator.SEG_LINETO : 744 currentPathPoints.add(roomPoint); 745 break; 746 case PathIterator.SEG_CLOSE : 747 float [][] pathPoints = 748 currentPathPoints.toArray(new float [currentPathPoints.size()][]); 749 surface += Math.abs(getSignedSurface(pathPoints)); 750 currentPathPoints.clear(); 751 break; 752 } 753 it.next(); 754 } 755 return surface; 756 } 757 getSignedSurface(float areaPoints [][])758 private float getSignedSurface(float areaPoints [][]) { 759 // From "Area of a General Polygon" algorithm described in 760 // http://www.davidchandler.com/AreaOfAGeneralPolygon.pdf 761 float area = 0; 762 for (int i = 1; i < areaPoints.length; i++) { 763 area += areaPoints [i][0] * areaPoints [i - 1][1]; 764 area -= areaPoints [i][1] * areaPoints [i - 1][0]; 765 } 766 area += areaPoints [0][0] * areaPoints [areaPoints.length - 1][1]; 767 area -= areaPoints [0][1] * areaPoints [areaPoints.length - 1][0]; 768 return area / 2; 769 } 770 771 /** 772 * Sets the edited name. 773 */ setName(String name)774 public void setName(String name) { 775 if (name != this.name) { 776 String oldName = this.name; 777 this.name = name; 778 this.propertyChangeSupport.firePropertyChange(Property.NAME.name(), oldName, name); 779 } 780 } 781 782 /** 783 * Returns the edited name. 784 */ getName()785 public String getName() { 786 return this.name; 787 } 788 789 /** 790 * Sets whether room area is visible or not. 791 */ setAreaVisible(Boolean areaVisible)792 public void setAreaVisible(Boolean areaVisible) { 793 if (areaVisible != this.areaVisible) { 794 Boolean oldAreaVisible = this.areaVisible; 795 this.areaVisible = areaVisible; 796 this.propertyChangeSupport.firePropertyChange(Property.AREA_VISIBLE.name(), oldAreaVisible, areaVisible); 797 } 798 } 799 800 /** 801 * Returns whether room area is visible or not. 802 */ getAreaVisible()803 public Boolean getAreaVisible() { 804 return this.areaVisible; 805 } 806 807 /** 808 * Sets whether room floor is visible or not. 809 */ setFloorVisible(Boolean floorVisible)810 public void setFloorVisible(Boolean floorVisible) { 811 if (floorVisible != this.floorVisible) { 812 Boolean oldFloorVisible = this.floorVisible; 813 this.floorVisible = floorVisible; 814 this.propertyChangeSupport.firePropertyChange(Property.FLOOR_VISIBLE.name(), oldFloorVisible, floorVisible); 815 } 816 } 817 818 /** 819 * Returns whether room floor is visible or not. 820 */ getFloorVisible()821 public Boolean getFloorVisible() { 822 return this.floorVisible; 823 } 824 825 /** 826 * Sets the edited color of the floor. 827 */ setFloorColor(Integer floorColor)828 public void setFloorColor(Integer floorColor) { 829 if (floorColor != this.floorColor) { 830 Integer oldFloorColor = this.floorColor; 831 this.floorColor = floorColor; 832 this.propertyChangeSupport.firePropertyChange(Property.FLOOR_COLOR.name(), oldFloorColor, floorColor); 833 834 setFloorPaint(RoomPaint.COLORED); 835 } 836 } 837 838 /** 839 * Returns the edited color of the floor. 840 */ getFloorColor()841 public Integer getFloorColor() { 842 return this.floorColor; 843 } 844 845 /** 846 * Sets whether the floor is colored, textured or unknown painted. 847 */ setFloorPaint(RoomPaint floorPaint)848 public void setFloorPaint(RoomPaint floorPaint) { 849 if (floorPaint != this.floorPaint) { 850 RoomPaint oldFloorPaint = this.floorPaint; 851 this.floorPaint = floorPaint; 852 this.propertyChangeSupport.firePropertyChange(Property.FLOOR_PAINT.name(), oldFloorPaint, floorPaint); 853 } 854 } 855 856 /** 857 * Returns whether the floor is colored, textured or unknown painted. 858 */ getFloorPaint()859 public RoomPaint getFloorPaint() { 860 return this.floorPaint; 861 } 862 863 /** 864 * Sets the edited shininess of the floor. 865 */ setFloorShininess(Float floorShininess)866 public void setFloorShininess(Float floorShininess) { 867 if (floorShininess != this.floorShininess) { 868 Float oldFloorShininess = this.floorShininess; 869 this.floorShininess = floorShininess; 870 this.propertyChangeSupport.firePropertyChange(Property.FLOOR_SHININESS.name(), oldFloorShininess, floorShininess); 871 } 872 } 873 874 /** 875 * Returns the edited shininess of the floor. 876 */ getFloorShininess()877 public Float getFloorShininess() { 878 return this.floorShininess; 879 } 880 881 /** 882 * Sets whether room ceiling is visible or not. 883 */ setCeilingVisible(Boolean ceilingCeilingVisible)884 public void setCeilingVisible(Boolean ceilingCeilingVisible) { 885 if (ceilingCeilingVisible != this.ceilingVisible) { 886 Boolean oldCeilingVisible = this.ceilingVisible; 887 this.ceilingVisible = ceilingCeilingVisible; 888 this.propertyChangeSupport.firePropertyChange(Property.CEILING_VISIBLE.name(), oldCeilingVisible, ceilingCeilingVisible); 889 } 890 } 891 892 /** 893 * Returns whether room ceiling is ceilingCeilingVisible or not. 894 */ getCeilingVisible()895 public Boolean getCeilingVisible() { 896 return this.ceilingVisible; 897 } 898 899 /** 900 * Sets the edited color of the ceiling. 901 */ setCeilingColor(Integer ceilingColor)902 public void setCeilingColor(Integer ceilingColor) { 903 if (ceilingColor != this.ceilingColor) { 904 Integer oldCeilingColor = this.ceilingColor; 905 this.ceilingColor = ceilingColor; 906 this.propertyChangeSupport.firePropertyChange(Property.CEILING_COLOR.name(), oldCeilingColor, ceilingColor); 907 908 setCeilingPaint(RoomPaint.COLORED); 909 } 910 } 911 912 /** 913 * Returns the edited color of the ceiling. 914 */ getCeilingColor()915 public Integer getCeilingColor() { 916 return this.ceilingColor; 917 } 918 919 /** 920 * Sets whether the ceiling is colored, textured or unknown painted. 921 */ setCeilingPaint(RoomPaint ceilingPaint)922 public void setCeilingPaint(RoomPaint ceilingPaint) { 923 if (ceilingPaint != this.ceilingPaint) { 924 RoomPaint oldCeilingPaint = this.ceilingPaint; 925 this.ceilingPaint = ceilingPaint; 926 this.propertyChangeSupport.firePropertyChange(Property.CEILING_PAINT.name(), oldCeilingPaint, ceilingPaint); 927 } 928 } 929 930 /** 931 * Returns whether the ceiling is colored, textured or unknown painted. 932 */ getCeilingPaint()933 public RoomPaint getCeilingPaint() { 934 return this.ceilingPaint; 935 } 936 937 /** 938 * Sets the edited shininess of the ceiling. 939 */ setCeilingShininess(Float ceilingShininess)940 public void setCeilingShininess(Float ceilingShininess) { 941 if (ceilingShininess != this.ceilingShininess) { 942 Float oldCeilingShininess = this.ceilingShininess; 943 this.ceilingShininess = ceilingShininess; 944 this.propertyChangeSupport.firePropertyChange(Property.CEILING_SHININESS.name(), oldCeilingShininess, ceilingShininess); 945 } 946 } 947 948 /** 949 * Returns the edited shininess of the ceiling. 950 */ getCeilingShininess()951 public Float getCeilingShininess() { 952 return this.ceilingShininess; 953 } 954 955 /** 956 * Returns <code>true</code> if walls around the edited rooms should be split. 957 * @since 4.0 958 */ isSplitSurroundingWalls()959 public boolean isSplitSurroundingWalls() { 960 return this.splitSurroundingWalls; 961 } 962 963 /** 964 * Sets whether walls around the edited rooms should be split or not. 965 * @since 4.0 966 */ setSplitSurroundingWalls(boolean splitSurroundingWalls)967 public void setSplitSurroundingWalls(boolean splitSurroundingWalls) { 968 if (splitSurroundingWalls != this.splitSurroundingWalls) { 969 this.splitSurroundingWalls = splitSurroundingWalls; 970 this.propertyChangeSupport.firePropertyChange(Property.SPLIT_SURROUNDING_WALLS.name(), !splitSurroundingWalls, splitSurroundingWalls); 971 } 972 } 973 974 /** 975 * Returns <code>true</code> if walls around the edited rooms need to be split 976 * to avoid changing the color of wall sides that belong to neighborhood rooms. 977 * @since 4.0 978 */ isSplitSurroundingWallsNeeded()979 public boolean isSplitSurroundingWallsNeeded() { 980 return this.splitSurroundingWallsNeeded; 981 } 982 983 /** 984 * Sets the edited color of the wall sides. 985 * @since 4.0 986 */ setWallSidesColor(Integer wallSidesColor)987 public void setWallSidesColor(Integer wallSidesColor) { 988 if (wallSidesColor != this.wallSidesColor) { 989 Integer oldWallSidesColor = this.wallSidesColor; 990 this.wallSidesColor = wallSidesColor; 991 this.propertyChangeSupport.firePropertyChange(Property.WALL_SIDES_COLOR.name(), oldWallSidesColor, wallSidesColor); 992 993 setWallSidesPaint(RoomPaint.COLORED); 994 } 995 } 996 997 /** 998 * Returns the edited color of the wall sides. 999 * @since 4.0 1000 */ getWallSidesColor()1001 public Integer getWallSidesColor() { 1002 return this.wallSidesColor; 1003 } 1004 1005 /** 1006 * Sets whether the wall sides are colored, textured or unknown painted. 1007 * @since 4.0 1008 */ setWallSidesPaint(RoomPaint wallSidesPaint)1009 public void setWallSidesPaint(RoomPaint wallSidesPaint) { 1010 if (wallSidesPaint != this.wallSidesPaint) { 1011 RoomPaint oldWallSidesPaint = this.wallSidesPaint; 1012 this.wallSidesPaint = wallSidesPaint; 1013 this.propertyChangeSupport.firePropertyChange(Property.WALL_SIDES_PAINT.name(), oldWallSidesPaint, wallSidesPaint); 1014 } 1015 } 1016 1017 /** 1018 * Returns whether the wall sides are colored, textured or unknown painted. 1019 * @since 4.0 1020 */ getWallSidesPaint()1021 public RoomPaint getWallSidesPaint() { 1022 return this.wallSidesPaint; 1023 } 1024 1025 /** 1026 * Sets the edited shininess of the wall sides. 1027 * @since 4.0 1028 */ setWallSidesShininess(Float wallSidesShininess)1029 public void setWallSidesShininess(Float wallSidesShininess) { 1030 if (wallSidesShininess != this.wallSidesShininess) { 1031 Float oldWallSidesShininess = this.wallSidesShininess; 1032 this.wallSidesShininess = wallSidesShininess; 1033 this.propertyChangeSupport.firePropertyChange(Property.WALL_SIDES_SHININESS.name(), oldWallSidesShininess, wallSidesShininess); 1034 } 1035 } 1036 1037 /** 1038 * Returns the edited shininess of the wall sides. 1039 * @since 4.0 1040 */ getWallSidesShininess()1041 public Float getWallSidesShininess() { 1042 return this.wallSidesShininess; 1043 } 1044 1045 /** 1046 * Controls the modification of selected rooms in edited home. 1047 */ modifyRooms()1048 public void modifyRooms() { 1049 List<Selectable> oldSelection = this.home.getSelectedItems(); 1050 List<Room> selectedRooms = Home.getRoomsSubList(oldSelection); 1051 if (!selectedRooms.isEmpty()) { 1052 String name = getName(); 1053 Boolean areaVisible = getAreaVisible(); 1054 Boolean floorVisible = getFloorVisible(); 1055 RoomPaint floorPaint = getFloorPaint(); 1056 Integer floorColor = floorPaint == RoomPaint.COLORED 1057 ? getFloorColor() : null; 1058 HomeTexture floorTexture = floorPaint == RoomPaint.TEXTURED 1059 ? getFloorTextureController().getTexture() : null; 1060 Float floorShininess = getFloorShininess(); 1061 Boolean ceilingVisible = getCeilingVisible(); 1062 RoomPaint ceilingPaint = getCeilingPaint(); 1063 Integer ceilingColor = ceilingPaint == RoomPaint.COLORED 1064 ? getCeilingColor() : null; 1065 HomeTexture ceilingTexture = ceilingPaint == RoomPaint.TEXTURED 1066 ? getCeilingTextureController().getTexture() : null; 1067 Float ceilingShininess = getCeilingShininess(); 1068 RoomPaint wallSidesPaint = getWallSidesPaint(); 1069 Integer wallSidesColor = wallSidesPaint == RoomPaint.COLORED 1070 ? getWallSidesColor() : null; 1071 HomeTexture wallSidesTexture = wallSidesPaint == RoomPaint.TEXTURED 1072 ? getWallSidesTextureController().getTexture() : null; 1073 Float wallSidesShininess = getWallSidesShininess(); 1074 Boolean wallSidesBaseboardVisible = getWallSidesBaseboardController().getVisible(); 1075 Float wallSidesBaseboardThickness = getWallSidesBaseboardController().getThickness(); 1076 Float wallSidesBaseboardHeight = getWallSidesBaseboardController().getHeight(); 1077 BaseboardChoiceController.BaseboardPaint wallSidesBaseboardPaint = getWallSidesBaseboardController().getPaint(); 1078 Integer wallSidesBaseboardColor = wallSidesBaseboardPaint == BaseboardChoiceController.BaseboardPaint.COLORED 1079 ? getWallSidesBaseboardController().getColor() : null; 1080 HomeTexture wallSidesBaseboardTexture = wallSidesBaseboardPaint == BaseboardChoiceController.BaseboardPaint.TEXTURED 1081 ? getWallSidesBaseboardController().getTextureController().getTexture() 1082 : null; 1083 List<WallSide> selectedRoomsWallSides = getRoomsWallSides(selectedRooms, null); 1084 1085 // Create an array of modified rooms with their current properties values 1086 ModifiedRoom [] modifiedRooms = new ModifiedRoom [selectedRooms.size()]; 1087 for (int i = 0; i < modifiedRooms.length; i++) { 1088 modifiedRooms [i] = new ModifiedRoom(selectedRooms.get(i)); 1089 } 1090 1091 // Apply modification 1092 List<ModifiedWall> deletedWalls = new ArrayList<ModifiedWall>(); 1093 List<ModifiedWall> addedWalls = new ArrayList<ModifiedWall>(); 1094 List<Selectable> newSelection = new ArrayList<Selectable>(oldSelection); 1095 if (this.splitSurroundingWalls) { 1096 if (splitWalls(selectedRoomsWallSides, deletedWalls, addedWalls, newSelection)) { 1097 this.home.setSelectedItems(newSelection); 1098 // Update wall sides 1099 selectedRoomsWallSides = getRoomsWallSides(selectedRooms, selectedRoomsWallSides); 1100 } 1101 } 1102 1103 // Create an array of modified wall sides with their current properties values 1104 ModifiedWallSide [] modifiedWallSides = new ModifiedWallSide [selectedRoomsWallSides.size()]; 1105 for (int i = 0; i < modifiedWallSides.length; i++) { 1106 modifiedWallSides [i] = new ModifiedWallSide(selectedRoomsWallSides.get(i)); 1107 } 1108 doModifyRoomsAndWallSides(home, modifiedRooms, name, areaVisible, 1109 floorVisible, floorPaint, floorColor, floorTexture, floorShininess, 1110 ceilingVisible, ceilingPaint, ceilingColor, ceilingTexture, ceilingShininess, 1111 modifiedWallSides, this.preferences.getNewWallBaseboardThickness(), this.preferences.getNewWallBaseboardHeight(), 1112 wallSidesPaint, wallSidesColor, wallSidesTexture, wallSidesShininess, 1113 wallSidesBaseboardVisible, wallSidesBaseboardThickness, wallSidesBaseboardHeight, 1114 wallSidesBaseboardPaint, wallSidesBaseboardColor, wallSidesBaseboardTexture, null, null); 1115 if (this.undoSupport != null) { 1116 this.undoSupport.postEdit(new RoomsAndWallSidesModificationUndoableEdit(this.home, this.preferences, 1117 oldSelection.toArray(new Selectable [oldSelection.size()]), newSelection.toArray(new Selectable [newSelection.size()]), 1118 modifiedRooms, name, areaVisible, 1119 floorVisible, floorPaint, floorColor, floorTexture, floorShininess, 1120 ceilingVisible, ceilingPaint, ceilingColor, ceilingTexture, ceilingShininess, 1121 modifiedWallSides, this.preferences.getNewWallBaseboardThickness(), this.preferences.getNewWallBaseboardHeight(), 1122 wallSidesPaint, wallSidesColor, wallSidesTexture, wallSidesShininess, 1123 wallSidesBaseboardVisible, wallSidesBaseboardThickness, wallSidesBaseboardHeight, 1124 wallSidesBaseboardPaint, wallSidesBaseboardColor, wallSidesBaseboardTexture, 1125 deletedWalls.toArray(new ModifiedWall [deletedWalls.size()]), 1126 addedWalls.toArray(new ModifiedWall [addedWalls.size()]))); 1127 } 1128 if (name != null) { 1129 this.preferences.addAutoCompletionString("RoomName", name); 1130 } 1131 } 1132 } 1133 1134 /** 1135 * Splits walls that overfill on other rooms if needed and returns <code>false</code> if the operation wasn't needed. 1136 */ splitWalls(List<WallSide> wallSides, List<ModifiedWall> deletedWalls, List<ModifiedWall> addedWalls, List<Selectable> selectedItems)1137 private boolean splitWalls(List<WallSide> wallSides, 1138 List<ModifiedWall> deletedWalls, 1139 List<ModifiedWall> addedWalls, 1140 List<Selectable> selectedItems) { 1141 Map<Wall, ModifiedWall> existingWalls = null; 1142 List<Wall> newWalls = new ArrayList<Wall>(); 1143 WallSide splitWallSide; 1144 do { 1145 splitWallSide = null; 1146 Wall firstWall = null; 1147 Wall secondWall = null; 1148 ModifiedWall deletedWall = null; 1149 for (int i = 0; i < wallSides.size() && splitWallSide == null; i++) { 1150 WallSide wallSide = wallSides.get(i); 1151 Wall wall = wallSide.getWall(); 1152 Float arcExtent = wall.getArcExtent(); 1153 if (arcExtent == null || arcExtent.floatValue() == 0) { // Ignore round walls 1154 Area wallArea = new Area(getPath(wall.getPoints(), true)); 1155 for (WallSide intersectedWallSide : wallSides) { 1156 Wall intersectedWall = intersectedWallSide.getWall(); 1157 if (wall != intersectedWall) { 1158 Area intersectedWallArea = new Area(getPath(intersectedWall.getPoints(), true)); 1159 intersectedWallArea.intersect(wallArea); 1160 if (!intersectedWallArea.isEmpty() 1161 && intersectedWallArea.isSingular()) { 1162 float [] intersection = computeIntersection( 1163 wall.getXStart(), wall.getYStart(), wall.getXEnd(), wall.getYEnd(), 1164 intersectedWall.getXStart(), intersectedWall.getYStart(), intersectedWall.getXEnd(), intersectedWall.getYEnd()); 1165 if (intersection != null) { 1166 // Duplicate new walls to copy their characteristics 1167 firstWall = (Wall)wall.duplicate(); 1168 secondWall = (Wall)wall.duplicate(); 1169 // Store wall level to add new walls at the same level as the split wall 1170 firstWall.setLevel(wall.getLevel()); 1171 secondWall.setLevel(wall.getLevel()); 1172 1173 // Change split walls end and start point 1174 firstWall.setXEnd(intersection [0]); 1175 firstWall.setYEnd(intersection [1]); 1176 secondWall.setXStart(intersection [0]); 1177 secondWall.setYStart(intersection [1]); 1178 1179 if (firstWall.getLength() > intersectedWall.getThickness() / 2 1180 && secondWall.getLength() > intersectedWall.getThickness() / 2) { 1181 // If method is called for test purpose 1182 if (deletedWalls == null) { 1183 return true; 1184 } 1185 1186 if (existingWalls == null) { 1187 // Store all walls at start and end in case there would be more than one change on a wall 1188 existingWalls = new HashMap<Wall, ModifiedWall>(wallSides.size()); 1189 for (WallSide side : wallSides) { 1190 if (!existingWalls.containsKey(side.getWall())) { 1191 existingWalls.put(side.getWall(), new ModifiedWall(side.getWall())); 1192 } 1193 } 1194 } 1195 1196 deletedWall = existingWalls.get(wall); 1197 Wall wallAtStart = wall.getWallAtStart(); 1198 if (wallAtStart != null) { 1199 firstWall.setWallAtStart(wallAtStart); 1200 if (wallAtStart.getWallAtEnd() == wall) { 1201 wallAtStart.setWallAtEnd(firstWall); 1202 } else { 1203 wallAtStart.setWallAtStart(firstWall); 1204 } 1205 } 1206 1207 Wall wallAtEnd = wall.getWallAtEnd(); 1208 if (wallAtEnd != null) { 1209 secondWall.setWallAtEnd(wallAtEnd); 1210 if (wallAtEnd.getWallAtEnd() == wall) { 1211 wallAtEnd.setWallAtEnd(secondWall); 1212 } else { 1213 wallAtEnd.setWallAtStart(secondWall); 1214 } 1215 } 1216 1217 firstWall.setWallAtEnd(secondWall); 1218 secondWall.setWallAtStart(firstWall); 1219 1220 if (wall.getHeightAtEnd() != null) { 1221 Float heightAtIntersecion = wall.getHeight() 1222 + (wall.getHeightAtEnd() - wall.getHeight()) 1223 * (float)Point2D.distance(wall.getXStart(), wall.getYStart(), intersection [0], intersection [1]) 1224 / wall.getLength(); 1225 firstWall.setHeightAtEnd(heightAtIntersecion); 1226 secondWall.setHeight(heightAtIntersecion); 1227 } 1228 1229 splitWallSide = wallSide; 1230 break; 1231 } 1232 } 1233 } 1234 } 1235 } 1236 } 1237 } 1238 1239 if (splitWallSide != null) { 1240 newWalls.add(firstWall); 1241 newWalls.add(secondWall); 1242 Wall splitWall = splitWallSide.getWall(); 1243 if (this.home.getWalls().contains(splitWall)) { 1244 deletedWalls.add(deletedWall); 1245 } else { 1246 // Remove from newWalls in case it was a wall split twice 1247 for (int i = newWalls.size() - 1; i >= 0; i--) { 1248 if (newWalls.get(i) == splitWall) { 1249 newWalls.remove(i); 1250 break; 1251 } 1252 } 1253 } 1254 // Update selected items 1255 if (selectedItems.remove(splitWall)) { 1256 selectedItems.add(firstWall); 1257 selectedItems.add(secondWall); 1258 } 1259 1260 wallSides.remove(splitWallSide); 1261 wallSides.add(new WallSide(firstWall, splitWallSide.getSide())); 1262 wallSides.add(new WallSide(secondWall, splitWallSide.getSide())); 1263 // Update any wall side that reference the same wall 1264 List<WallSide> sameWallSides = new ArrayList<WallSide>(); 1265 for (int i = wallSides.size() - 1; i >= 0; i--) { 1266 WallSide wallSide = wallSides.get(i); 1267 if (wallSide.getWall() == splitWall) { 1268 wallSides.remove(i); 1269 sameWallSides.add(new WallSide(firstWall, wallSide.getSide())); 1270 sameWallSides.add(new WallSide(secondWall, wallSide.getSide())); 1271 } 1272 } 1273 wallSides.addAll(sameWallSides); 1274 } 1275 } while (splitWallSide != null); 1276 1277 // If method is called for test purpose 1278 if (deletedWalls == null) { 1279 return false; 1280 } else { 1281 for (Wall newWall : newWalls) { 1282 ModifiedWall addedWall = new ModifiedWall(newWall); 1283 addedWalls.add(addedWall); 1284 this.home.addWall(newWall); 1285 newWall.setLevel(addedWall.getLevel()); 1286 } 1287 for (ModifiedWall deletedWall : deletedWalls) { 1288 this.home.deleteWall(deletedWall.getWall()); 1289 } 1290 return !deletedWalls.isEmpty(); 1291 } 1292 } 1293 1294 /** 1295 * Returns the intersection between a line segment and a second line. 1296 */ computeIntersection(float xPoint1, float yPoint1, float xPoint2, float yPoint2, float xPoint3, float yPoint3, float xPoint4, float yPoint4)1297 private float [] computeIntersection(float xPoint1, float yPoint1, float xPoint2, float yPoint2, 1298 float xPoint3, float yPoint3, float xPoint4, float yPoint4) { 1299 float [] point = PlanController.computeIntersection(xPoint1, yPoint1, xPoint2, yPoint2, 1300 xPoint3, yPoint3, xPoint4, yPoint4); 1301 if (Line2D.ptSegDistSq(xPoint1, yPoint1, xPoint2, yPoint2, point [0], point [1]) < 1E-7 1302 && (Math.abs(xPoint1 - point [0]) > 1E-4 1303 || Math.abs(yPoint1 - point [1]) > 1E-4) 1304 && (Math.abs(xPoint2 - point [0]) > 1E-4 1305 || Math.abs(yPoint2 - point [1]) > 1E-4)) { 1306 return point; 1307 } else { 1308 return null; 1309 } 1310 } 1311 1312 /** 1313 * Undoable edit for rooms modification. This class isn't anonymous to avoid 1314 * being bound to controller and its view. 1315 */ 1316 private static class RoomsAndWallSidesModificationUndoableEdit extends LocalizedUndoableEdit { 1317 private final Home home; 1318 private final Selectable [] oldSelection; 1319 private final Selectable [] newSelection; 1320 private final ModifiedRoom [] modifiedRooms; 1321 private final String name; 1322 private final Boolean areaVisible; 1323 private final Boolean floorVisible; 1324 private final RoomPaint floorPaint; 1325 private final Integer floorColor; 1326 private final HomeTexture floorTexture; 1327 private final Float floorShininess; 1328 private final Boolean ceilingVisible; 1329 private final RoomPaint ceilingPaint; 1330 private final Integer ceilingColor; 1331 private final HomeTexture ceilingTexture; 1332 private final Float ceilingShininess; 1333 private final ModifiedWallSide [] modifiedWallSides; 1334 private final float newWallBaseboardHeight; 1335 private final float newWallBaseboardThickness; 1336 private final RoomPaint wallSidesPaint; 1337 private final Integer wallSidesColor; 1338 private final HomeTexture wallSidesTexture; 1339 private final Float wallSidesShininess; 1340 private final Boolean wallSidesBaseboardVisible; 1341 private final Float wallSidesBaseboardThickness; 1342 private final Float wallSidesBaseboardHeight; 1343 private final BaseboardChoiceController.BaseboardPaint wallSidesBaseboardPaint; 1344 private final Integer wallSidesBaseboardColor; 1345 private final HomeTexture wallSidesBaseboardTexture; 1346 private final ModifiedWall [] deletedWalls; 1347 private final ModifiedWall [] addedWalls; 1348 RoomsAndWallSidesModificationUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, Selectable [] newSelection, ModifiedRoom [] modifiedRooms, String name, Boolean areaVisible, Boolean floorVisible, RoomPaint floorPaint, Integer floorColor, HomeTexture floorTexture, Float floorShininess, Boolean ceilingVisible, RoomPaint ceilingPaint, Integer ceilingColor, HomeTexture ceilingTexture, Float ceilingShininess, ModifiedWallSide [] modifiedWallSides, float newWallBaseboardThickness, float newWallBaseboardHeight, RoomPaint wallSidesPaint, Integer wallSidesColor, HomeTexture wallSidesTexture, Float wallSidesShininess, Boolean wallSidesBaseboardVisible, Float wallSidesBaseboardThickness, Float wallSidesBaseboardHeight, BaseboardChoiceController.BaseboardPaint wallSidesBaseboardPaint, Integer wallSidesBaseboardColor, HomeTexture wallSidesBaseboardTexture, ModifiedWall [] deletedWalls, ModifiedWall [] addedWalls)1349 private RoomsAndWallSidesModificationUndoableEdit(Home home, 1350 UserPreferences preferences, 1351 Selectable [] oldSelection, 1352 Selectable [] newSelection, 1353 ModifiedRoom [] modifiedRooms, 1354 String name, 1355 Boolean areaVisible, 1356 Boolean floorVisible, 1357 RoomPaint floorPaint, 1358 Integer floorColor, 1359 HomeTexture floorTexture, 1360 Float floorShininess, 1361 Boolean ceilingVisible, 1362 RoomPaint ceilingPaint, 1363 Integer ceilingColor, 1364 HomeTexture ceilingTexture, 1365 Float ceilingShininess, 1366 ModifiedWallSide [] modifiedWallSides, 1367 float newWallBaseboardThickness, 1368 float newWallBaseboardHeight, 1369 RoomPaint wallSidesPaint, 1370 Integer wallSidesColor, 1371 HomeTexture wallSidesTexture, 1372 Float wallSidesShininess, 1373 Boolean wallSidesBaseboardVisible, 1374 Float wallSidesBaseboardThickness, 1375 Float wallSidesBaseboardHeight, 1376 BaseboardChoiceController.BaseboardPaint wallSidesBaseboardPaint, 1377 Integer wallSidesBaseboardColor, 1378 HomeTexture wallSidesBaseboardTexture, 1379 ModifiedWall [] deletedWalls, 1380 ModifiedWall [] addedWalls) { 1381 super(preferences, RoomController.class, "undoModifyRoomsName"); 1382 this.home = home; 1383 this.oldSelection = oldSelection; 1384 this.newSelection = newSelection; 1385 this.modifiedRooms = modifiedRooms; 1386 this.name = name; 1387 this.areaVisible = areaVisible; 1388 this.floorVisible = floorVisible; 1389 this.floorPaint = floorPaint; 1390 this.floorColor = floorColor; 1391 this.floorTexture = floorTexture; 1392 this.floorShininess = floorShininess; 1393 this.ceilingVisible = ceilingVisible; 1394 this.ceilingPaint = ceilingPaint; 1395 this.ceilingColor = ceilingColor; 1396 this.ceilingTexture = ceilingTexture; 1397 this.ceilingShininess = ceilingShininess; 1398 this.modifiedWallSides = modifiedWallSides; 1399 this.newWallBaseboardThickness = newWallBaseboardThickness; 1400 this.newWallBaseboardHeight = newWallBaseboardHeight; 1401 this.wallSidesPaint = wallSidesPaint; 1402 this.wallSidesColor = wallSidesColor; 1403 this.wallSidesTexture = wallSidesTexture; 1404 this.wallSidesShininess = wallSidesShininess; 1405 this.wallSidesBaseboardVisible = wallSidesBaseboardVisible; 1406 this.wallSidesBaseboardThickness = wallSidesBaseboardThickness; 1407 this.wallSidesBaseboardHeight = wallSidesBaseboardHeight; 1408 this.wallSidesBaseboardPaint = wallSidesBaseboardPaint; 1409 this.wallSidesBaseboardColor = wallSidesBaseboardColor; 1410 this.wallSidesBaseboardTexture = wallSidesBaseboardTexture; 1411 this.deletedWalls = deletedWalls; 1412 this.addedWalls = addedWalls; 1413 } 1414 1415 @Override undo()1416 public void undo() throws CannotUndoException { 1417 super.undo(); 1418 undoModifyRoomsAndWallSides(this.home, this.modifiedRooms, this.modifiedWallSides, this.deletedWalls, this.addedWalls); 1419 this.home.setSelectedItems(Arrays.asList(this.oldSelection)); 1420 } 1421 1422 @Override redo()1423 public void redo() throws CannotRedoException { 1424 super.redo(); 1425 doModifyRoomsAndWallSides(this.home, 1426 this.modifiedRooms, this.name, this.areaVisible, 1427 this.floorVisible, this.floorPaint, this.floorColor, this.floorTexture, this.floorShininess, 1428 this.ceilingVisible, this.ceilingPaint, this.ceilingColor, this.ceilingTexture, this.ceilingShininess, 1429 this.modifiedWallSides, newWallBaseboardThickness, this.newWallBaseboardHeight, 1430 this.wallSidesPaint, this.wallSidesColor, this.wallSidesTexture, this.wallSidesShininess, 1431 this.wallSidesBaseboardVisible, this.wallSidesBaseboardThickness, this.wallSidesBaseboardHeight, 1432 this.wallSidesBaseboardPaint, this.wallSidesBaseboardColor, this.wallSidesBaseboardTexture, 1433 this.deletedWalls, this.addedWalls); 1434 this.home.setSelectedItems(Arrays.asList(this.newSelection)); 1435 } 1436 } 1437 1438 /** 1439 * Modifies rooms and walls properties with the values in parameter. 1440 */ doModifyRoomsAndWallSides(Home home, ModifiedRoom [] modifiedRooms, String name, Boolean areaVisible, Boolean floorVisible, RoomPaint floorPaint, Integer floorColor, HomeTexture floorTexture, Float floorShininess, Boolean ceilingVisible, RoomPaint ceilingPaint, Integer ceilingColor, HomeTexture ceilingTexture, Float ceilingShininess, ModifiedWallSide [] modifiedWallSides, float newWallBaseboardThickness, float newWallBaseboardHeight, RoomPaint wallSidesPaint, Integer wallSidesColor, HomeTexture wallSidesTexture, Float wallSidesShininess, Boolean wallSidesBaseboardVisible, Float wallSidesBaseboardThickness, Float wallSidesBaseboardHeight, BaseboardChoiceController.BaseboardPaint wallSidesBaseboardPaint, Integer wallSidesBaseboardColor, HomeTexture wallSidesBaseboardTexture, ModifiedWall [] deletedWalls, ModifiedWall [] addedWalls)1441 private static void doModifyRoomsAndWallSides(Home home, ModifiedRoom [] modifiedRooms, 1442 String name, Boolean areaVisible, 1443 Boolean floorVisible, RoomPaint floorPaint, Integer floorColor, HomeTexture floorTexture, Float floorShininess, 1444 Boolean ceilingVisible, RoomPaint ceilingPaint, Integer ceilingColor, HomeTexture ceilingTexture, Float ceilingShininess, 1445 ModifiedWallSide [] modifiedWallSides, 1446 float newWallBaseboardThickness, float newWallBaseboardHeight, 1447 RoomPaint wallSidesPaint, Integer wallSidesColor, HomeTexture wallSidesTexture, Float wallSidesShininess, 1448 Boolean wallSidesBaseboardVisible, Float wallSidesBaseboardThickness, Float wallSidesBaseboardHeight, 1449 BaseboardChoiceController.BaseboardPaint wallSidesBaseboardPaint, Integer wallSidesBaseboardColor, HomeTexture wallSidesBaseboardTexture, 1450 ModifiedWall [] deletedWalls, 1451 ModifiedWall [] addedWalls) { 1452 if (deletedWalls != null) { 1453 for (ModifiedWall newWall : addedWalls) { 1454 newWall.resetJoinedWalls(); 1455 home.addWall(newWall.getWall()); 1456 newWall.getWall().setLevel(newWall.getLevel()); 1457 } 1458 for (ModifiedWall deletedWall : deletedWalls) { 1459 home.deleteWall(deletedWall.getWall()); 1460 } 1461 } 1462 for (ModifiedRoom modifiedRoom : modifiedRooms) { 1463 Room room = modifiedRoom.getRoom(); 1464 if (name != null) { 1465 room.setName(name); 1466 } 1467 if (areaVisible != null) { 1468 room.setAreaVisible(areaVisible); 1469 } 1470 if (floorVisible != null) { 1471 room.setFloorVisible(floorVisible); 1472 } 1473 if (floorPaint != null) { 1474 switch (floorPaint) { 1475 case DEFAULT : 1476 room.setFloorColor(null); 1477 room.setFloorTexture(null); 1478 break; 1479 case COLORED : 1480 room.setFloorColor(floorColor); 1481 room.setFloorTexture(null); 1482 break; 1483 case TEXTURED : 1484 room.setFloorColor(null); 1485 room.setFloorTexture(floorTexture); 1486 break; 1487 } 1488 } 1489 if (floorShininess != null) { 1490 room.setFloorShininess(floorShininess); 1491 } 1492 if (ceilingVisible != null) { 1493 room.setCeilingVisible(ceilingVisible); 1494 } 1495 if (ceilingPaint != null) { 1496 switch (ceilingPaint) { 1497 case DEFAULT : 1498 room.setCeilingColor(null); 1499 room.setCeilingTexture(null); 1500 break; 1501 case COLORED : 1502 room.setCeilingColor(ceilingColor); 1503 room.setCeilingTexture(null); 1504 break; 1505 case TEXTURED : 1506 room.setCeilingColor(null); 1507 room.setCeilingTexture(ceilingTexture); 1508 break; 1509 } 1510 } 1511 if (ceilingShininess != null) { 1512 room.setCeilingShininess(ceilingShininess); 1513 } 1514 } 1515 for (ModifiedWallSide modifiedWallSide : modifiedWallSides) { 1516 WallSide wallSide = modifiedWallSide.getWallSide(); 1517 Wall wall = wallSide.getWall(); 1518 if (wallSide.getSide() == WallSide.LEFT_SIDE) { 1519 if (wallSidesPaint != null) { 1520 switch (wallSidesPaint) { 1521 case DEFAULT : 1522 wall.setLeftSideColor(null); 1523 wall.setLeftSideTexture(null); 1524 break; 1525 case COLORED : 1526 wall.setLeftSideColor(wallSidesColor); 1527 wall.setLeftSideTexture(null); 1528 break; 1529 case TEXTURED : 1530 wall.setLeftSideColor(null); 1531 wall.setLeftSideTexture(wallSidesTexture); 1532 break; 1533 } 1534 } 1535 if (wallSidesShininess != null) { 1536 wall.setLeftSideShininess(wallSidesShininess); 1537 } 1538 } else { 1539 if (wallSidesPaint != null) { 1540 switch (wallSidesPaint) { 1541 case DEFAULT : 1542 wall.setRightSideColor(null); 1543 wall.setRightSideTexture(null); 1544 break; 1545 case COLORED : 1546 wall.setRightSideColor(wallSidesColor); 1547 wall.setRightSideTexture(null); 1548 break; 1549 case TEXTURED : 1550 wall.setRightSideColor(null); 1551 wall.setRightSideTexture(wallSidesTexture); 1552 break; 1553 } 1554 } 1555 if (wallSidesShininess != null) { 1556 wall.setRightSideShininess(wallSidesShininess); 1557 } 1558 } 1559 1560 if (wallSidesBaseboardVisible == Boolean.FALSE) { 1561 if (wallSide.getSide() == WallSide.LEFT_SIDE) { 1562 wall.setLeftSideBaseboard(null); 1563 } else { 1564 wall.setRightSideBaseboard(null); 1565 } 1566 } else { 1567 Baseboard baseboard = wallSide.getSide() == WallSide.LEFT_SIDE 1568 ? wall.getLeftSideBaseboard() 1569 : wall.getRightSideBaseboard(); 1570 if (wallSidesBaseboardVisible == Boolean.TRUE 1571 || baseboard != null) { 1572 float baseboardThickness = baseboard != null 1573 ? baseboard.getThickness() 1574 : newWallBaseboardThickness; 1575 float baseboardHeight = baseboard != null 1576 ? baseboard.getHeight() 1577 : newWallBaseboardHeight; 1578 Integer baseboardColor = baseboard != null 1579 ? baseboard.getColor() 1580 : null; 1581 HomeTexture baseboardTexture = baseboard != null 1582 ? baseboard.getTexture() 1583 : null; 1584 if (wallSidesBaseboardPaint != null) { 1585 switch (wallSidesBaseboardPaint) { 1586 case DEFAULT : 1587 baseboardColor = null; 1588 baseboardTexture = null; 1589 break; 1590 case COLORED : 1591 if (wallSidesBaseboardColor != null) { 1592 baseboardColor = wallSidesBaseboardColor; 1593 } 1594 baseboardTexture = null; 1595 break; 1596 case TEXTURED : 1597 baseboardColor = null; 1598 if (wallSidesBaseboardTexture != null) { 1599 baseboardTexture = wallSidesBaseboardTexture; 1600 } 1601 break; 1602 } 1603 } 1604 baseboard = Baseboard.getInstance( 1605 wallSidesBaseboardThickness != null 1606 ? wallSidesBaseboardThickness 1607 : baseboardThickness, 1608 wallSidesBaseboardHeight != null 1609 ? wallSidesBaseboardHeight 1610 : baseboardHeight, 1611 baseboardColor, baseboardTexture); 1612 if (wallSide.getSide() == WallSide.LEFT_SIDE) { 1613 wall.setLeftSideBaseboard(baseboard); 1614 } else { 1615 wall.setRightSideBaseboard(baseboard); 1616 } 1617 } 1618 } 1619 } 1620 } 1621 1622 /** 1623 * Restores room properties from the values stored in <code>modifiedRooms</code> and <code>modifiedWallSides</code>. 1624 */ undoModifyRoomsAndWallSides(Home home, ModifiedRoom [] modifiedRooms, ModifiedWallSide [] modifiedWallSides, ModifiedWall [] deletedWalls, ModifiedWall [] addedWalls)1625 private static void undoModifyRoomsAndWallSides(Home home, 1626 ModifiedRoom [] modifiedRooms, 1627 ModifiedWallSide [] modifiedWallSides, 1628 ModifiedWall [] deletedWalls, 1629 ModifiedWall [] addedWalls) { 1630 for (ModifiedRoom modifiedRoom : modifiedRooms) { 1631 modifiedRoom.reset(); 1632 } 1633 for (ModifiedWallSide modifiedWallSide : modifiedWallSides) { 1634 modifiedWallSide.reset(); 1635 } 1636 for (ModifiedWall newWall : addedWalls) { 1637 home.deleteWall(newWall.getWall()); 1638 } 1639 for (ModifiedWall deletedWall : deletedWalls) { 1640 deletedWall.resetJoinedWalls(); 1641 home.addWall(deletedWall.getWall()); 1642 deletedWall.getWall().setLevel(deletedWall.getLevel()); 1643 } 1644 } 1645 1646 /** 1647 * Stores the current properties values of a modified room. 1648 */ 1649 private static final class ModifiedRoom { 1650 private final Room room; 1651 private final String name; 1652 private final boolean areaVisible; 1653 private final boolean floorVisible; 1654 private final Integer floorColor; 1655 private final HomeTexture floorTexture; 1656 private final float floorShininess; 1657 private final boolean ceilingVisible; 1658 private final Integer ceilingColor; 1659 private final HomeTexture ceilingTexture; 1660 private final float ceilingShininess; 1661 ModifiedRoom(Room room)1662 public ModifiedRoom(Room room) { 1663 this.room = room; 1664 this.name = room.getName(); 1665 this.areaVisible = room.isAreaVisible(); 1666 this.floorVisible = room.isFloorVisible(); 1667 this.floorColor = room.getFloorColor(); 1668 this.floorTexture = room.getFloorTexture(); 1669 this.floorShininess = room.getFloorShininess(); 1670 this.ceilingVisible = room.isCeilingVisible(); 1671 this.ceilingColor = room.getCeilingColor(); 1672 this.ceilingTexture = room.getCeilingTexture(); 1673 this.ceilingShininess = room.getCeilingShininess(); 1674 } 1675 getRoom()1676 public Room getRoom() { 1677 return this.room; 1678 } 1679 reset()1680 public void reset() { 1681 this.room.setName(this.name); 1682 this.room.setAreaVisible(this.areaVisible); 1683 this.room.setFloorVisible(this.floorVisible); 1684 this.room.setFloorColor(this.floorColor); 1685 this.room.setFloorTexture(this.floorTexture); 1686 this.room.setFloorShininess(this.floorShininess); 1687 this.room.setCeilingVisible(this.ceilingVisible); 1688 this.room.setCeilingColor(this.ceilingColor); 1689 this.room.setCeilingTexture(this.ceilingTexture); 1690 this.room.setCeilingShininess(this.ceilingShininess); 1691 } 1692 } 1693 1694 /** 1695 * A wall side. 1696 */ 1697 private static class WallSide { 1698 public static final int LEFT_SIDE = 0; 1699 public static final int RIGHT_SIDE = 1; 1700 1701 private Wall wall; 1702 private int side; 1703 private final Wall wallAtStart; 1704 private final Wall wallAtEnd; 1705 private final boolean joinedAtEndOfWallAtStart; 1706 private final boolean joinedAtStartOfWallAtEnd; 1707 WallSide(Wall wall, int side)1708 public WallSide(Wall wall, int side) { 1709 this.wall = wall; 1710 this.side = side; 1711 this.wallAtStart = wall.getWallAtStart(); 1712 this.joinedAtEndOfWallAtStart = 1713 this.wallAtStart != null 1714 && this.wallAtStart.getWallAtEnd() == wall; 1715 this.wallAtEnd = wall.getWallAtEnd(); 1716 this.joinedAtStartOfWallAtEnd = 1717 this.wallAtEnd != null 1718 && wallAtEnd.getWallAtStart() == wall; 1719 } 1720 getWall()1721 public Wall getWall() { 1722 return this.wall; 1723 } 1724 getSide()1725 public int getSide() { 1726 return this.side; 1727 } 1728 getWallAtStart()1729 public Wall getWallAtStart() { 1730 return this.wallAtStart; 1731 } 1732 getWallAtEnd()1733 public Wall getWallAtEnd() { 1734 return this.wallAtEnd; 1735 } 1736 isJoinedAtEndOfWallAtStart()1737 public boolean isJoinedAtEndOfWallAtStart() { 1738 return this.joinedAtEndOfWallAtStart; 1739 } 1740 isJoinedAtStartOfWallAtEnd()1741 public boolean isJoinedAtStartOfWallAtEnd() { 1742 return this.joinedAtStartOfWallAtEnd; 1743 } 1744 } 1745 1746 /** 1747 * A modified wall. 1748 */ 1749 private static class ModifiedWall { 1750 private Wall wall; 1751 private final Level level; 1752 private final Wall wallAtStart; 1753 private final Wall wallAtEnd; 1754 private final boolean joinedAtEndOfWallAtStart; 1755 private final boolean joinedAtStartOfWallAtEnd; 1756 ModifiedWall(Wall wall)1757 public ModifiedWall(Wall wall) { 1758 this.wall = wall; 1759 this.level = wall.getLevel(); 1760 this.wallAtStart = wall.getWallAtStart(); 1761 this.joinedAtEndOfWallAtStart = 1762 this.wallAtStart != null 1763 && this.wallAtStart.getWallAtEnd() == wall; 1764 this.wallAtEnd = wall.getWallAtEnd(); 1765 this.joinedAtStartOfWallAtEnd = 1766 this.wallAtEnd != null 1767 && wallAtEnd.getWallAtStart() == wall; 1768 } 1769 getWall()1770 public Wall getWall() { 1771 return this.wall; 1772 } 1773 getLevel()1774 public Level getLevel() { 1775 return this.level; 1776 } 1777 resetJoinedWalls()1778 public void resetJoinedWalls() { 1779 if (this.wallAtStart != null) { 1780 this.wall.setWallAtStart(this.wallAtStart); 1781 if (this.joinedAtEndOfWallAtStart) { 1782 this.wallAtStart.setWallAtEnd(this.wall); 1783 } else { 1784 this.wallAtStart.setWallAtStart(this.wall); 1785 } 1786 } 1787 if (this.wallAtEnd != null) { 1788 this.wall.setWallAtEnd(wallAtEnd); 1789 if (this.joinedAtStartOfWallAtEnd) { 1790 this.wallAtEnd.setWallAtStart(this.wall); 1791 } else { 1792 this.wallAtEnd.setWallAtEnd(this.wall); 1793 } 1794 } 1795 } 1796 } 1797 1798 /** 1799 * Stores the current properties values of a modified wall side. 1800 */ 1801 private static final class ModifiedWallSide { 1802 private final WallSide wallSide; 1803 private final Integer wallColor; 1804 private final HomeTexture wallTexture; 1805 private final Float wallShininess; 1806 private final Baseboard wallBaseboard; 1807 ModifiedWallSide(WallSide wallSide)1808 public ModifiedWallSide(WallSide wallSide) { 1809 this.wallSide = wallSide; 1810 Wall wall = wallSide.getWall(); 1811 if (wallSide.getSide() == WallSide.LEFT_SIDE) { 1812 this.wallColor = wall.getLeftSideColor(); 1813 this.wallTexture = wall.getLeftSideTexture(); 1814 this.wallShininess = wall.getLeftSideShininess(); 1815 this.wallBaseboard = wall.getLeftSideBaseboard(); 1816 } else { 1817 this.wallColor = wall.getRightSideColor(); 1818 this.wallTexture = wall.getRightSideTexture(); 1819 this.wallShininess = wall.getRightSideShininess(); 1820 this.wallBaseboard = wall.getRightSideBaseboard(); 1821 } 1822 } 1823 getWallSide()1824 public WallSide getWallSide() { 1825 return this.wallSide; 1826 } 1827 reset()1828 public void reset() { 1829 Wall wall = this.wallSide.getWall(); 1830 if (this.wallSide.getSide() == WallSide.LEFT_SIDE) { 1831 wall.setLeftSideColor(this.wallColor); 1832 wall.setLeftSideTexture(this.wallTexture); 1833 wall.setLeftSideShininess(this.wallShininess); 1834 wall.setLeftSideBaseboard(this.wallBaseboard); 1835 } else { 1836 wall.setRightSideColor(this.wallColor); 1837 wall.setRightSideTexture(this.wallTexture); 1838 wall.setRightSideShininess(this.wallShininess); 1839 wall.setRightSideBaseboard(this.wallBaseboard); 1840 } 1841 Wall wallAtStart = wallSide.getWallAtStart(); 1842 if (wallAtStart != null) { 1843 wall.setWallAtStart(wallAtStart); 1844 if (wallSide.isJoinedAtEndOfWallAtStart()) { 1845 wallAtStart.setWallAtEnd(wall); 1846 } else { 1847 wallAtStart.setWallAtStart(wall); 1848 } 1849 } 1850 Wall wallAtEnd = wallSide.getWallAtEnd(); 1851 if (wallAtEnd != null) { 1852 wall.setWallAtEnd(wallAtEnd); 1853 if (wallSide.isJoinedAtStartOfWallAtEnd()) { 1854 wallAtEnd.setWallAtStart(wall); 1855 } else { 1856 wallAtEnd.setWallAtEnd(wall); 1857 } 1858 } 1859 } 1860 } 1861 } 1862