1 /* 2 * FurnitureController.java 15 mai 2006 3 * 4 * Sweet Home 3D, Copyright (c) 2006 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.Line2D; 23 import java.beans.PropertyChangeEvent; 24 import java.beans.PropertyChangeListener; 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.Collections; 28 import java.util.Comparator; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.TreeMap; 33 34 import javax.swing.undo.CannotRedoException; 35 import javax.swing.undo.CannotUndoException; 36 import javax.swing.undo.UndoableEditSupport; 37 38 import com.eteks.sweethome3d.model.CollectionEvent; 39 import com.eteks.sweethome3d.model.CollectionListener; 40 import com.eteks.sweethome3d.model.DoorOrWindow; 41 import com.eteks.sweethome3d.model.Home; 42 import com.eteks.sweethome3d.model.HomeDoorOrWindow; 43 import com.eteks.sweethome3d.model.HomeFurnitureGroup; 44 import com.eteks.sweethome3d.model.HomeLight; 45 import com.eteks.sweethome3d.model.HomePieceOfFurniture; 46 import com.eteks.sweethome3d.model.HomePieceOfFurniture.SortableProperty; 47 import com.eteks.sweethome3d.model.Level; 48 import com.eteks.sweethome3d.model.Light; 49 import com.eteks.sweethome3d.model.PieceOfFurniture; 50 import com.eteks.sweethome3d.model.Selectable; 51 import com.eteks.sweethome3d.model.SelectionEvent; 52 import com.eteks.sweethome3d.model.SelectionListener; 53 import com.eteks.sweethome3d.model.UserPreferences; 54 55 /** 56 * A MVC controller for the home furniture table. 57 * @author Emmanuel Puybaret 58 */ 59 public class FurnitureController implements Controller { 60 private final Home home; 61 private final UserPreferences preferences; 62 private final ViewFactory viewFactory; 63 private final ContentManager contentManager; 64 private final UndoableEditSupport undoSupport; 65 private View furnitureView; 66 private HomePieceOfFurniture leadSelectedPieceOfFurniture; 67 68 /** 69 * Creates the controller of home furniture view. 70 * @param home the home edited by this controller and its view 71 * @param preferences the preferences of the application 72 * @param viewFactory a factory able to create the furniture view managed by this controller 73 */ FurnitureController(Home home, UserPreferences preferences, ViewFactory viewFactory)74 public FurnitureController(Home home, 75 UserPreferences preferences, 76 ViewFactory viewFactory) { 77 this(home, preferences, viewFactory, null, null); 78 } 79 80 /** 81 * Creates the controller of home furniture view with undo support. 82 */ FurnitureController(final Home home, UserPreferences preferences, ViewFactory viewFactory, ContentManager contentManager, UndoableEditSupport undoSupport)83 public FurnitureController(final Home home, 84 UserPreferences preferences, 85 ViewFactory viewFactory, 86 ContentManager contentManager, 87 UndoableEditSupport undoSupport) { 88 this.home = home; 89 this.preferences = preferences; 90 this.viewFactory = viewFactory; 91 this.undoSupport = undoSupport; 92 this.contentManager = contentManager; 93 94 addModelListeners(); 95 } 96 97 /** 98 * Returns the view associated with this controller. 99 */ getView()100 public View getView() { 101 // Create view lazily only once it's needed 102 if (this.furnitureView == null) { 103 this.furnitureView = this.viewFactory.createFurnitureView(this.home, this.preferences, this); 104 } 105 return this.furnitureView; 106 } 107 addModelListeners()108 private void addModelListeners() { 109 // Add a selection listener that gets the lead selected piece in home 110 this.home.addSelectionListener(new SelectionListener() { 111 public void selectionChanged(SelectionEvent ev) { 112 List<HomePieceOfFurniture> selectedFurniture = 113 Home.getFurnitureSubList(home.getSelectedItems()); 114 if (selectedFurniture.isEmpty()) { 115 leadSelectedPieceOfFurniture = null; 116 } else if (leadSelectedPieceOfFurniture == null 117 || selectedFurniture.size() == 1 118 || selectedFurniture.indexOf(leadSelectedPieceOfFurniture) == -1) { 119 leadSelectedPieceOfFurniture = selectedFurniture.get(0); 120 } 121 } 122 }); 123 124 // Add listener to update base plan lock when furniture movability changes 125 final PropertyChangeListener furnitureChangeListener = new PropertyChangeListener() { 126 public void propertyChange(PropertyChangeEvent ev) { 127 if (HomePieceOfFurniture.Property.MOVABLE.name().equals(ev.getPropertyName())) { 128 // Remove non movable pieces from selection when base plan is locked 129 HomePieceOfFurniture piece = (HomePieceOfFurniture)ev.getSource(); 130 if (home.isBasePlanLocked() 131 && isPieceOfFurniturePartOfBasePlan(piece)) { 132 List<Selectable> selectedItems = home.getSelectedItems(); 133 if (selectedItems.contains(piece)) { 134 selectedItems = new ArrayList<Selectable>(selectedItems); 135 selectedItems.remove(piece); 136 home.setSelectedItems(selectedItems); 137 } 138 } 139 } 140 } 141 }; 142 for (HomePieceOfFurniture piece : home.getFurniture()) { 143 piece.addPropertyChangeListener(furnitureChangeListener); 144 if (piece instanceof HomeFurnitureGroup) { 145 for (HomePieceOfFurniture childPiece : ((HomeFurnitureGroup)piece).getAllFurniture()) { 146 childPiece.addPropertyChangeListener(furnitureChangeListener); 147 } 148 } 149 } 150 this.home.addFurnitureListener(new CollectionListener<HomePieceOfFurniture> () { 151 public void collectionChanged(CollectionEvent<HomePieceOfFurniture> ev) { 152 HomePieceOfFurniture piece = ev.getItem(); 153 if (ev.getType() == CollectionEvent.Type.ADD) { 154 piece.addPropertyChangeListener(furnitureChangeListener); 155 if (piece instanceof HomeFurnitureGroup) { 156 for (HomePieceOfFurniture childPiece : ((HomeFurnitureGroup)piece).getAllFurniture()) { 157 childPiece.addPropertyChangeListener(furnitureChangeListener); 158 } 159 } 160 } else if (ev.getType() == CollectionEvent.Type.DELETE) { 161 piece.removePropertyChangeListener(furnitureChangeListener); 162 if (piece instanceof HomeFurnitureGroup) { 163 for (HomePieceOfFurniture childPiece : ((HomeFurnitureGroup)piece).getAllFurniture()) { 164 childPiece.removePropertyChangeListener(furnitureChangeListener); 165 } 166 } 167 } 168 } 169 }); 170 } 171 172 /** 173 * Controls new furniture added to home. 174 * Once added the furniture will be selected in view 175 * and undo support will receive a new undoable edit. 176 * @param furniture the furniture to add. 177 */ addFurniture(List<HomePieceOfFurniture> furniture)178 public void addFurniture(List<HomePieceOfFurniture> furniture) { 179 addFurniture(furniture, null, null, null); 180 } 181 182 /** 183 * Controls new furniture added to home. 184 * Once added the furniture will be selected in view 185 * and undo support will receive a new undoable edit. 186 * @param furniture the furniture to add. 187 * @param beforePiece the piece before which the furniture will be added 188 * @since 6.3 189 */ addFurniture(List<HomePieceOfFurniture> furniture, HomePieceOfFurniture beforePiece)190 public void addFurniture(List<HomePieceOfFurniture> furniture, HomePieceOfFurniture beforePiece) { 191 addFurniture(furniture, null, null, beforePiece); 192 } 193 194 /** 195 * Controls new furniture added to the given group. 196 * Once added the furniture will be selected in view 197 * and undo support will receive a new undoable edit. 198 * @param furniture the furniture to add. 199 * @param group the group to which furniture will be added. 200 */ addFurnitureToGroup(List<HomePieceOfFurniture> furniture, HomeFurnitureGroup group)201 public void addFurnitureToGroup(List<HomePieceOfFurniture> furniture, HomeFurnitureGroup group) { 202 if (group == null) { 203 throw new IllegalArgumentException("Group shouldn't be null"); 204 } 205 addFurniture(furniture, null, group, null); 206 } 207 addFurniture(List<HomePieceOfFurniture> furniture, Level [] furnitureLevels, HomeFurnitureGroup group, HomePieceOfFurniture beforePiece)208 private void addFurniture(List<HomePieceOfFurniture> furniture, Level [] furnitureLevels, 209 HomeFurnitureGroup group, HomePieceOfFurniture beforePiece) { 210 final boolean oldBasePlanLocked = this.home.isBasePlanLocked(); 211 final boolean allLevelsSelection = this.home.isAllLevelsSelection(); 212 final List<Selectable> oldSelection = this.home.getSelectedItems(); 213 final HomePieceOfFurniture [] newFurniture = 214 furniture.toArray(new HomePieceOfFurniture [furniture.size()]); 215 // Get indices of added furniture 216 final int [] newFurnitureIndex = new int [furniture.size()]; 217 int insertIndex = group == null 218 ? this.home.getFurniture().size() 219 : group.getFurniture().size(); 220 if (beforePiece != null) { 221 List<HomePieceOfFurniture> parentFurniture = this.home.getFurniture(); 222 group = getPieceOfFurnitureGroup(beforePiece, null, parentFurniture); 223 if (group != null) { 224 parentFurniture = group.getFurniture(); 225 } 226 insertIndex = parentFurniture.indexOf(beforePiece); 227 } 228 final HomeFurnitureGroup [] newFurnitureGroups = group != null 229 ? new HomeFurnitureGroup [furniture.size()] 230 : null; 231 boolean basePlanLocked = oldBasePlanLocked; 232 boolean levelUpdated = group != null || furnitureLevels == null; 233 for (int i = 0; i < newFurnitureIndex.length; i++) { 234 newFurnitureIndex [i] = insertIndex++; 235 // Unlock base plan if the piece is a part of it 236 basePlanLocked &= !isPieceOfFurniturePartOfBasePlan(newFurniture [i]); 237 if (furnitureLevels != null) { 238 levelUpdated |= furnitureLevels [i] == null; 239 } 240 if (newFurnitureGroups != null) { 241 newFurnitureGroups [i] = group; 242 } 243 } 244 final Level [] newFurnitureLevels = levelUpdated ? null : furnitureLevels; 245 final boolean newBasePlanLocked = basePlanLocked; 246 final Level furnitureLevel = group != null 247 ? group.getLevel() 248 : this.home.getSelectedLevel(); 249 250 doAddFurniture(this.home, newFurniture, newFurnitureGroups, newFurnitureIndex, furnitureLevel, newFurnitureLevels, newBasePlanLocked, false); 251 if (this.undoSupport != null) { 252 this.undoSupport.postEdit(new FurnitureAdditionUndoableEdit(this.home, this.preferences, 253 oldSelection.toArray(new Selectable [oldSelection.size()]), oldBasePlanLocked, allLevelsSelection, newFurniture, 254 newFurnitureIndex, newFurnitureGroups, newFurnitureLevels, furnitureLevel, newBasePlanLocked)); 255 } 256 } 257 258 /** 259 * Undoable edit for furniture added to home. 260 */ 261 private static class FurnitureAdditionUndoableEdit extends LocalizedUndoableEdit { 262 private final Home home; 263 private final boolean allLevelsSelection; 264 private final Selectable [] oldSelection; 265 private final boolean oldBasePlanLocked; 266 private final HomePieceOfFurniture [] newFurniture; 267 private final int [] newFurnitureIndex; 268 private final HomeFurnitureGroup [] newFurnitureGroups; 269 private final Level [] newFurnitureLevels; 270 private final Level furnitureLevel; 271 private final boolean newBasePlanLocked; 272 FurnitureAdditionUndoableEdit(Home home, UserPreferences preferences, Selectable[] oldSelection, boolean oldBasePlanLocked, boolean allLevelsSelection, HomePieceOfFurniture [] newFurniture, int [] newFurnitureIndex, HomeFurnitureGroup [] newFurnitureGroups, Level [] newFurnitureLevels, Level furnitureLevel, boolean newBasePlanLocked)273 public FurnitureAdditionUndoableEdit(Home home, UserPreferences preferences, Selectable[] oldSelection, 274 boolean oldBasePlanLocked, boolean allLevelsSelection, 275 HomePieceOfFurniture [] newFurniture, int [] newFurnitureIndex, 276 HomeFurnitureGroup [] newFurnitureGroups, Level [] newFurnitureLevels, 277 Level furnitureLevel, boolean newBasePlanLocked) { 278 super(preferences, FurnitureController.class, "undoAddFurnitureName"); 279 this.home = home; 280 this.oldSelection = oldSelection; 281 this.oldBasePlanLocked = oldBasePlanLocked; 282 this.allLevelsSelection = allLevelsSelection; 283 this.newFurniture = newFurniture; 284 this.newFurnitureIndex = newFurnitureIndex; 285 this.newFurnitureGroups = newFurnitureGroups; 286 this.newFurnitureLevels = newFurnitureLevels; 287 this.furnitureLevel = furnitureLevel; 288 this.newBasePlanLocked = newBasePlanLocked; 289 } 290 291 @Override undo()292 public void undo() throws CannotUndoException { 293 super.undo(); 294 doDeleteFurniture(this.home, this.newFurniture, this.oldBasePlanLocked, this.allLevelsSelection); 295 this.home.setSelectedItems(Arrays.asList(this.oldSelection)); 296 } 297 298 @Override redo()299 public void redo() throws CannotRedoException { 300 super.redo(); 301 doAddFurniture(this.home, this.newFurniture, this.newFurnitureGroups, this.newFurnitureIndex, this.furnitureLevel, 302 this.newFurnitureLevels, this.newBasePlanLocked, false); 303 } 304 } 305 doAddFurniture(Home home, HomePieceOfFurniture [] furniture, HomeFurnitureGroup [] furnitureGroups, int [] furnitureIndex, Level furnitureLevel, Level [] furnitureLevels, boolean basePlanLocked, boolean allLevelsSelection)306 private static void doAddFurniture(Home home, 307 HomePieceOfFurniture [] furniture, 308 HomeFurnitureGroup [] furnitureGroups, 309 int [] furnitureIndex, 310 Level furnitureLevel, 311 Level [] furnitureLevels, 312 boolean basePlanLocked, 313 boolean allLevelsSelection) { 314 for (int i = 0; i < furnitureIndex.length; i++) { 315 if (furnitureGroups != null && furnitureGroups [i] != null) { 316 home.addPieceOfFurnitureToGroup(furniture [i], furnitureGroups [i], furnitureIndex [i]); 317 furniture [i].setVisible(furnitureGroups [i].isVisible()); 318 } else { 319 home.addPieceOfFurniture(furniture [i], furnitureIndex [i]); 320 } 321 furniture [i].setLevel(furnitureLevels != null ? furnitureLevels [i] : furnitureLevel); 322 } 323 home.setBasePlanLocked(basePlanLocked); 324 home.setSelectedItems(Arrays.asList(furniture)); 325 home.setAllLevelsSelection(allLevelsSelection); 326 } 327 328 /** 329 * Controls the deletion of the current selected furniture in home. 330 * Once the selected furniture is deleted, undo support will receive a new undoable edit. 331 */ deleteSelection()332 public void deleteSelection() { 333 deleteFurniture(Home.getFurnitureSubList(this.home.getSelectedItems())); 334 } 335 336 /** 337 * Deletes the furniture of <code>deletedFurniture</code> from home. 338 * Once the selected furniture is deleted, undo support will receive a new undoable edit. 339 */ deleteFurniture(List<HomePieceOfFurniture> deletedFurniture)340 public void deleteFurniture(List<HomePieceOfFurniture> deletedFurniture) { 341 final boolean basePlanLocked = this.home.isBasePlanLocked(); 342 final boolean allLevelsSelection = this.home.isAllLevelsSelection(); 343 final List<Selectable> oldSelection = this.home.getSelectedItems(); 344 List<HomePieceOfFurniture> homeFurniture = this.home.getFurniture(); 345 346 // Replace pieces by their group when they have to be all deleted 347 deletedFurniture = new ArrayList<HomePieceOfFurniture>(deletedFurniture); 348 List<HomeFurnitureGroup> homeGroups = new ArrayList<HomeFurnitureGroup>(); 349 searchGroups(homeFurniture, homeGroups); 350 boolean updated; 351 do { 352 updated = false; 353 for (HomeFurnitureGroup group : homeGroups) { 354 List<HomePieceOfFurniture> groupFurniture = group.getFurniture(); 355 if (deletedFurniture.containsAll(groupFurniture)) { 356 deletedFurniture.removeAll(groupFurniture); 357 deletedFurniture.add(group); 358 updated = true; 359 } 360 } 361 } while (updated); 362 363 // Sort the deletable furniture in the ascending order of their index in home or their group 364 Map<HomeFurnitureGroup, TreeMap<Integer, HomePieceOfFurniture>> deletedFurnitureMap = 365 new HashMap<HomeFurnitureGroup, TreeMap<Integer, HomePieceOfFurniture>>(); 366 int deletedFurnitureCount = 0; 367 for (HomePieceOfFurniture piece : deletedFurniture) { 368 // Check piece is deletable and doesn't belong to a group 369 if (isPieceOfFurnitureDeletable(piece)) { 370 HomeFurnitureGroup group = getPieceOfFurnitureGroup(piece, null, homeFurniture); 371 TreeMap<Integer, HomePieceOfFurniture> sortedMap = deletedFurnitureMap.get(group); 372 if (sortedMap == null) { 373 sortedMap = new TreeMap<Integer, HomePieceOfFurniture>(); 374 deletedFurnitureMap.put(group, sortedMap); 375 } 376 if (group == null) { 377 sortedMap.put(homeFurniture.indexOf(piece), piece); 378 } else { 379 sortedMap.put(group.getFurniture().indexOf(piece), piece); 380 } 381 deletedFurnitureCount++; 382 } 383 } 384 final HomePieceOfFurniture [] furniture = new HomePieceOfFurniture [deletedFurnitureCount]; 385 final int [] furnitureIndex = new int [furniture.length]; 386 final Level [] furnitureLevels = new Level [furniture.length]; 387 final HomeFurnitureGroup [] furnitureGroups = new HomeFurnitureGroup [furniture.length]; 388 int i = 0; 389 for (Map.Entry<HomeFurnitureGroup, TreeMap<Integer, HomePieceOfFurniture>> sortedMapEntry : deletedFurnitureMap.entrySet()) { 390 for (Map.Entry<Integer, HomePieceOfFurniture> pieceEntry : sortedMapEntry.getValue().entrySet()) { 391 furniture [i] = pieceEntry.getValue(); 392 furnitureIndex [i] = pieceEntry.getKey(); 393 furnitureLevels [i] = furniture [i].getLevel(); 394 furnitureGroups [i++] = sortedMapEntry.getKey(); 395 } 396 } 397 doDeleteFurniture(this.home, furniture, basePlanLocked, false); 398 if (this.undoSupport != null) { 399 this.undoSupport.postEdit(new FurnitureDeletionUndoableEdit(this.home, this.preferences, 400 oldSelection.toArray(new Selectable [oldSelection.size()]), basePlanLocked, allLevelsSelection, 401 furniture, furnitureIndex, furnitureGroups, furnitureLevels)); 402 } 403 } 404 405 /** 406 * Undoable edit for furniture deleted from home. 407 */ 408 private static class FurnitureDeletionUndoableEdit extends LocalizedUndoableEdit { 409 private final Home home; 410 private final Selectable [] oldSelection; 411 private final boolean basePlanLocked; 412 private final boolean allLevelsSelection; 413 private final HomePieceOfFurniture [] furniture; 414 private final int [] furnitureIndex; 415 private final HomeFurnitureGroup [] furnitureGroups; 416 private final Level [] furnitureLevels; 417 FurnitureDeletionUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, boolean basePlanLocked, boolean allLevelsSelection, HomePieceOfFurniture [] furniture, int [] furnitureIndex, HomeFurnitureGroup [] furnitureGroups, Level [] furnitureLevels)418 public FurnitureDeletionUndoableEdit(Home home, UserPreferences preferences, 419 Selectable [] oldSelection, boolean basePlanLocked, 420 boolean allLevelsSelection, HomePieceOfFurniture [] furniture, 421 int [] furnitureIndex, HomeFurnitureGroup [] furnitureGroups, 422 Level [] furnitureLevels) { 423 super(preferences, FurnitureController.class, "undoDeleteSelectionName"); 424 this.home = home; 425 this.oldSelection = oldSelection; 426 this.basePlanLocked = basePlanLocked; 427 this.allLevelsSelection = allLevelsSelection; 428 this.furniture = furniture; 429 this.furnitureIndex = furnitureIndex; 430 this.furnitureGroups = furnitureGroups; 431 this.furnitureLevels = furnitureLevels; 432 } 433 434 @Override undo()435 public void undo() throws CannotUndoException { 436 super.undo(); 437 doAddFurniture(this.home, this.furniture, this.furnitureGroups, this.furnitureIndex, null, 438 this.furnitureLevels, this.basePlanLocked, this.allLevelsSelection); 439 this.home.setSelectedItems(Arrays.asList(this.oldSelection)); 440 } 441 442 @Override redo()443 public void redo() throws CannotRedoException { 444 super.redo(); 445 this.home.setSelectedItems(Arrays.asList(this.furniture)); 446 doDeleteFurniture(this.home, this.furniture, this.basePlanLocked, false); 447 } 448 } 449 doDeleteFurniture(Home home, HomePieceOfFurniture [] furniture, boolean basePlanLocked, boolean allLevelsSelection)450 private static void doDeleteFurniture(Home home, 451 HomePieceOfFurniture [] furniture, 452 boolean basePlanLocked, 453 boolean allLevelsSelection) { 454 for (HomePieceOfFurniture piece : furniture) { 455 home.deletePieceOfFurniture(piece); 456 } 457 home.setBasePlanLocked(basePlanLocked); 458 home.setAllLevelsSelection(allLevelsSelection); 459 } 460 461 /** 462 * Searches all the groups among furniture and its children. 463 */ searchGroups(List<HomePieceOfFurniture> furniture, List<HomeFurnitureGroup> groups)464 private static void searchGroups(List<HomePieceOfFurniture> furniture, 465 List<HomeFurnitureGroup> groups) { 466 for (HomePieceOfFurniture piece : furniture) { 467 if (piece instanceof HomeFurnitureGroup) { 468 groups.add((HomeFurnitureGroup)piece); 469 searchGroups(((HomeFurnitureGroup)piece).getFurniture(), groups); 470 } 471 } 472 } 473 474 /** 475 * Returns the furniture group that contains the given <code>piece</code> or <code>null</code> if it can't be found. 476 */ getPieceOfFurnitureGroup(HomePieceOfFurniture piece, HomeFurnitureGroup furnitureGroup, List<HomePieceOfFurniture> furniture)477 private static HomeFurnitureGroup getPieceOfFurnitureGroup(HomePieceOfFurniture piece, 478 HomeFurnitureGroup furnitureGroup, 479 List<HomePieceOfFurniture> furniture) { 480 for (HomePieceOfFurniture homePiece : furniture) { 481 if (homePiece.equals(piece)) { 482 return furnitureGroup; 483 } else if (homePiece instanceof HomeFurnitureGroup) { 484 HomeFurnitureGroup group = getPieceOfFurnitureGroup(piece, 485 (HomeFurnitureGroup)homePiece, ((HomeFurnitureGroup)homePiece).getFurniture()); 486 if (group != null) { 487 return group; 488 } 489 } 490 } 491 return null; 492 } 493 494 /** 495 * Reorders the selected furniture in home to place it before the given piece. 496 * @since 6.3 497 */ moveSelectedFurnitureBefore(HomePieceOfFurniture beforePiece)498 public void moveSelectedFurnitureBefore(HomePieceOfFurniture beforePiece) { 499 List<HomePieceOfFurniture> movedFurniture = Home.getFurnitureSubList(this.home.getSelectedItems()); 500 if (!movedFurniture.isEmpty()) { 501 // Store current level of the furniture 502 final Level [] furnitureLevels = new Level [movedFurniture.size()]; 503 for (int i = 0; i < furnitureLevels.length; i++) { 504 furnitureLevels [i] = movedFurniture.get(i).getLevel(); 505 } 506 this.undoSupport.beginUpdate(); 507 deleteFurniture(movedFurniture); 508 addFurniture(movedFurniture, furnitureLevels, null, beforePiece); 509 undoSupport.postEdit(new LocalizedUndoableEdit(this.preferences, FurnitureController.class, "undoReorderName")); 510 // End compound edit 511 undoSupport.endUpdate(); 512 } 513 } 514 515 /** 516 * Updates the selected furniture in home. 517 */ setSelectedFurniture(List<HomePieceOfFurniture> selectedFurniture)518 public void setSelectedFurniture(List<HomePieceOfFurniture> selectedFurniture) { 519 setSelectedFurniture(selectedFurniture, true); 520 } 521 522 /** 523 * Updates the selected furniture in home, unselecting all other kinds of selected objects 524 * when <code>resetSelection</code> is <code>true</code>. 525 * @since 6.1 526 */ setSelectedFurniture(List<HomePieceOfFurniture> selectedFurniture, boolean resetSelection)527 public void setSelectedFurniture(List<HomePieceOfFurniture> selectedFurniture, boolean resetSelection) { 528 if (this.home.isBasePlanLocked()) { 529 selectedFurniture = getFurnitureNotPartOfBasePlan(selectedFurniture); 530 } 531 if (resetSelection) { 532 this.home.setSelectedItems(selectedFurniture); 533 this.home.setAllLevelsSelection(false); 534 } else { 535 List<Selectable> selectedItems = new ArrayList<Selectable>(this.home.getSelectedItems()); 536 selectedFurniture = new ArrayList<HomePieceOfFurniture>(selectedFurniture); 537 for (int i = selectedItems.size() - 1; i >= 0; i--) { 538 Selectable item = selectedItems.get(i); 539 if (item instanceof HomePieceOfFurniture) { 540 int index = selectedFurniture.indexOf((HomePieceOfFurniture)item); 541 if (index >= 0) { 542 selectedFurniture.remove(index); 543 } else { 544 selectedItems.remove(i); 545 } 546 } 547 } 548 selectedItems.addAll(selectedFurniture); 549 this.home.setSelectedItems(selectedItems); 550 } 551 } 552 553 /** 554 * Selects all furniture in home. 555 */ selectAll()556 public void selectAll() { 557 setSelectedFurniture(this.home.getFurniture()); 558 } 559 560 /** 561 * Returns <code>true</code> if the given <code>piece</code> isn't movable. 562 */ isPieceOfFurniturePartOfBasePlan(HomePieceOfFurniture piece)563 protected boolean isPieceOfFurniturePartOfBasePlan(HomePieceOfFurniture piece) { 564 return !piece.isMovable() || piece.isDoorOrWindow(); 565 } 566 567 /** 568 * Returns <code>true</code> if the given <code>piece</code> may be moved. 569 * Default implementation always returns <code>true</code>. 570 */ isPieceOfFurnitureMovable(HomePieceOfFurniture piece)571 protected boolean isPieceOfFurnitureMovable(HomePieceOfFurniture piece) { 572 return true; 573 } 574 575 /** 576 * Returns <code>true</code> if the given <code>piece</code> may be deleted. 577 * Default implementation always returns <code>true</code>. 578 */ isPieceOfFurnitureDeletable(HomePieceOfFurniture piece)579 protected boolean isPieceOfFurnitureDeletable(HomePieceOfFurniture piece) { 580 return true; 581 } 582 583 /** 584 * Returns a new home piece of furniture created from an other given <code>piece</code> of furniture. 585 */ createHomePieceOfFurniture(PieceOfFurniture piece)586 public HomePieceOfFurniture createHomePieceOfFurniture(PieceOfFurniture piece) { 587 if (piece instanceof DoorOrWindow) { 588 return new HomeDoorOrWindow((DoorOrWindow)piece); 589 } else if (piece instanceof Light) { 590 return new HomeLight((Light)piece); 591 } else { 592 return new HomePieceOfFurniture(piece); 593 } 594 } 595 596 /** 597 * Returns the furniture among the given list that are not part of the base plan. 598 */ getFurnitureNotPartOfBasePlan(List<HomePieceOfFurniture> furniture)599 private List<HomePieceOfFurniture> getFurnitureNotPartOfBasePlan(List<HomePieceOfFurniture> furniture) { 600 List<HomePieceOfFurniture> furnitureNotPartOfBasePlan = new ArrayList<HomePieceOfFurniture>(); 601 for (HomePieceOfFurniture piece : furniture) { 602 if (!isPieceOfFurniturePartOfBasePlan(piece)) { 603 furnitureNotPartOfBasePlan.add(piece); 604 } 605 } 606 return furnitureNotPartOfBasePlan; 607 } 608 609 /** 610 * Uses <code>furnitureProperty</code> to sort home furniture 611 * or cancels home furniture sort if home is already sorted on <code>furnitureProperty</code> 612 * @param furnitureProperty a property of {@link HomePieceOfFurniture HomePieceOfFurniture} class. 613 */ toggleFurnitureSort(HomePieceOfFurniture.SortableProperty furnitureProperty)614 public void toggleFurnitureSort(HomePieceOfFurniture.SortableProperty furnitureProperty) { 615 if (furnitureProperty.equals(this.home.getFurnitureSortedProperty())) { 616 this.home.setFurnitureSortedProperty(null); 617 } else { 618 this.home.setFurnitureSortedProperty(furnitureProperty); 619 } 620 } 621 622 /** 623 * Toggles home furniture sort order. 624 */ toggleFurnitureSortOrder()625 public void toggleFurnitureSortOrder() { 626 this.home.setFurnitureDescendingSorted(!this.home.isFurnitureDescendingSorted()); 627 } 628 629 /** 630 * Controls the sort of the furniture in home. If home furniture isn't sorted 631 * or is sorted on an other property, it will be sorted on the given 632 * <code>furnitureProperty</code> in ascending order. If home furniture is already 633 * sorted on the given <code>furnitureProperty</code>, it will be sorted in descending 634 * order, if the sort is in ascending order, otherwise it won't be sorted at all 635 * and home furniture will be listed in insertion order. 636 * @param furnitureProperty the furniture property on which the view wants 637 * to sort the furniture it displays. 638 */ sortFurniture(HomePieceOfFurniture.SortableProperty furnitureProperty)639 public void sortFurniture(HomePieceOfFurniture.SortableProperty furnitureProperty) { 640 // Compute sort algorithm described in javadoc 641 final HomePieceOfFurniture.SortableProperty oldProperty = 642 this.home.getFurnitureSortedProperty(); 643 final boolean oldDescending = this.home.isFurnitureDescendingSorted(); 644 boolean descending = false; 645 if (furnitureProperty.equals(oldProperty)) { 646 if (oldDescending) { 647 furnitureProperty = null; 648 } else { 649 descending = true; 650 } 651 } 652 this.home.setFurnitureSortedProperty(furnitureProperty); 653 this.home.setFurnitureDescendingSorted(descending); 654 } 655 656 /** 657 * Updates the furniture visible properties in home. 658 */ setFurnitureVisibleProperties(List<HomePieceOfFurniture.SortableProperty> furnitureVisibleProperties)659 public void setFurnitureVisibleProperties(List<HomePieceOfFurniture.SortableProperty> furnitureVisibleProperties) { 660 this.home.setFurnitureVisibleProperties(furnitureVisibleProperties); 661 } 662 663 /** 664 * Toggles furniture property visibility in home. 665 */ toggleFurnitureVisibleProperty(HomePieceOfFurniture.SortableProperty furnitureProperty)666 public void toggleFurnitureVisibleProperty(HomePieceOfFurniture.SortableProperty furnitureProperty) { 667 List<SortableProperty> furnitureVisibleProperties = 668 new ArrayList<SortableProperty>(this.home.getFurnitureVisibleProperties()); 669 if (furnitureVisibleProperties.contains(furnitureProperty)) { 670 furnitureVisibleProperties.remove(furnitureProperty); 671 // Ensure at least one column is visible 672 if (furnitureVisibleProperties.isEmpty()) { 673 furnitureVisibleProperties.add(HomePieceOfFurniture.SortableProperty.NAME); 674 } 675 } else { 676 // Add furniture property after the visible property that has the previous index in 677 // the following list 678 List<HomePieceOfFurniture.SortableProperty> propertiesOrder = 679 Arrays.asList(new HomePieceOfFurniture.SortableProperty [] { 680 HomePieceOfFurniture.SortableProperty.CATALOG_ID, 681 HomePieceOfFurniture.SortableProperty.NAME, 682 HomePieceOfFurniture.SortableProperty.CREATOR, 683 HomePieceOfFurniture.SortableProperty.WIDTH, 684 HomePieceOfFurniture.SortableProperty.DEPTH, 685 HomePieceOfFurniture.SortableProperty.HEIGHT, 686 HomePieceOfFurniture.SortableProperty.X, 687 HomePieceOfFurniture.SortableProperty.Y, 688 HomePieceOfFurniture.SortableProperty.ELEVATION, 689 HomePieceOfFurniture.SortableProperty.ANGLE, 690 HomePieceOfFurniture.SortableProperty.LEVEL, 691 HomePieceOfFurniture.SortableProperty.MODEL_SIZE, 692 HomePieceOfFurniture.SortableProperty.COLOR, 693 HomePieceOfFurniture.SortableProperty.TEXTURE, 694 HomePieceOfFurniture.SortableProperty.MOVABLE, 695 HomePieceOfFurniture.SortableProperty.DOOR_OR_WINDOW, 696 HomePieceOfFurniture.SortableProperty.VISIBLE, 697 HomePieceOfFurniture.SortableProperty.PRICE, 698 HomePieceOfFurniture.SortableProperty.VALUE_ADDED_TAX_PERCENTAGE, 699 HomePieceOfFurniture.SortableProperty.VALUE_ADDED_TAX, 700 HomePieceOfFurniture.SortableProperty.PRICE_VALUE_ADDED_TAX_INCLUDED}); 701 int propertyIndex = propertiesOrder.indexOf(furnitureProperty) - 1; 702 if (propertyIndex > 0) { 703 while (propertyIndex > 0) { 704 int visiblePropertyIndex = furnitureVisibleProperties.indexOf(propertiesOrder.get(propertyIndex)); 705 if (visiblePropertyIndex >= 0) { 706 propertyIndex = visiblePropertyIndex + 1; 707 break; 708 } else { 709 propertyIndex--; 710 } 711 } 712 } 713 if (propertyIndex < 0) { 714 propertyIndex = 0; 715 } 716 furnitureVisibleProperties.add(propertyIndex, furnitureProperty); 717 } 718 this.home.setFurnitureVisibleProperties(furnitureVisibleProperties); 719 } 720 721 /** 722 * Controls the modification of selected furniture. 723 */ modifySelectedFurniture()724 public void modifySelectedFurniture() { 725 if (!Home.getFurnitureSubList(this.home.getSelectedItems()).isEmpty()) { 726 new HomeFurnitureController(this.home, this.preferences, 727 this.viewFactory, this.contentManager, this.undoSupport).displayView(getView()); 728 } 729 } 730 731 /** 732 * Controls the modification of the visibility of the selected piece of furniture. 733 */ toggleSelectedFurnitureVisibility()734 public void toggleSelectedFurnitureVisibility() { 735 if (Home.getFurnitureSubList(this.home.getSelectedItems()).size() == 1) { 736 HomeFurnitureController controller = new HomeFurnitureController(this.home, this.preferences, 737 this.viewFactory, this.contentManager, this.undoSupport); 738 controller.setVisible(!controller.getVisible()); 739 controller.modifyFurniture(); 740 } 741 } 742 743 /** 744 * Groups the selected furniture as one piece of furniture. 745 */ groupSelectedFurniture()746 public void groupSelectedFurniture() { 747 HomePieceOfFurniture [] selectedFurniture = getMovableSelectedFurniture(); 748 if (selectedFurniture.length > 0) { 749 final boolean basePlanLocked = this.home.isBasePlanLocked(); 750 final boolean allLevelsSelection = this.home.isAllLevelsSelection(); 751 final List<Selectable> oldSelection = this.home.getSelectedItems(); 752 List<HomePieceOfFurniture> homeFurniture = this.home.getFurniture(); 753 // Sort the grouped furniture in the ascending order of their index in home or their group 754 Map<HomeFurnitureGroup, TreeMap<Integer, HomePieceOfFurniture>> groupedFurnitureMap = 755 new HashMap<HomeFurnitureGroup, TreeMap<Integer, HomePieceOfFurniture>>(); 756 int groupedFurnitureCount = 0; 757 for (HomePieceOfFurniture piece : selectedFurniture) { 758 HomeFurnitureGroup group = getPieceOfFurnitureGroup(piece, null, homeFurniture); 759 TreeMap<Integer, HomePieceOfFurniture> sortedMap = groupedFurnitureMap.get(group); 760 if (sortedMap == null) { 761 sortedMap = new TreeMap<Integer, HomePieceOfFurniture>(); 762 groupedFurnitureMap.put(group, sortedMap); 763 } 764 if (group == null) { 765 sortedMap.put(homeFurniture.indexOf(piece), piece); 766 } else { 767 sortedMap.put(group.getFurniture().indexOf(piece), piece); 768 } 769 groupedFurnitureCount++; 770 } 771 final HomePieceOfFurniture [] groupedPieces = new HomePieceOfFurniture [groupedFurnitureCount]; 772 final int [] groupedPiecesIndex = new int [groupedPieces.length]; 773 final Level [] groupedPiecesLevel = new Level [groupedPieces.length]; 774 final float [] groupedPiecesElevation = new float [groupedPieces.length]; 775 final boolean [] groupedPiecesVisible = new boolean [groupedPieces.length]; 776 final HomeFurnitureGroup [] groupedPiecesGroups = new HomeFurnitureGroup [groupedPieces.length]; 777 Level minLevel = this.home.getSelectedLevel(); 778 int i = 0; 779 for (Map.Entry<HomeFurnitureGroup, TreeMap<Integer, HomePieceOfFurniture>> sortedMapEntry : groupedFurnitureMap.entrySet()) { 780 for (Map.Entry<Integer, HomePieceOfFurniture> pieceEntry : sortedMapEntry.getValue().entrySet()) { 781 HomePieceOfFurniture piece = pieceEntry.getValue(); 782 groupedPieces [i] = piece; 783 groupedPiecesIndex [i] = pieceEntry.getKey(); 784 groupedPiecesLevel [i] = piece.getLevel(); 785 groupedPiecesElevation [i] = piece.getElevation(); 786 groupedPiecesVisible [i] = piece.isVisible(); 787 groupedPiecesGroups [i] = sortedMapEntry.getKey(); 788 if (groupedPiecesLevel [i] != null) { 789 if (minLevel == null 790 || groupedPiecesLevel [i].getElevation() < minLevel.getElevation()) { 791 minLevel = groupedPiecesLevel [i]; 792 } 793 } 794 i++; 795 } 796 } 797 final HomeFurnitureGroup newGroup; 798 List<HomePieceOfFurniture> groupedFurniture = Arrays.asList(groupedPieces); 799 if (groupedFurniture.indexOf(this.leadSelectedPieceOfFurniture) > 0) { 800 newGroup = createHomeFurnitureGroup(groupedFurniture, this.leadSelectedPieceOfFurniture); 801 } else { 802 newGroup = createHomeFurnitureGroup(groupedFurniture); 803 } 804 // Store piece elevation that could have been updated during grouping 805 final float [] groupPiecesNewElevation = new float [groupedPieces.length]; 806 i = 0; 807 for (HomePieceOfFurniture piece : groupedPieces) { 808 groupPiecesNewElevation [i++] = piece.getElevation(); 809 } 810 TreeMap<Integer, HomePieceOfFurniture> homeSortedMap = groupedFurnitureMap.get(null); 811 final int groupIndex = homeSortedMap != null 812 ? homeSortedMap.lastKey() + 1 - groupedPieces.length 813 : homeFurniture.size(); 814 final boolean movable = newGroup.isMovable(); 815 final Level groupLevel = minLevel; 816 817 doGroupFurniture(this.home, groupedPieces, new HomeFurnitureGroup [] {newGroup}, 818 null, new int [] {groupIndex}, new Level [] {groupLevel}, basePlanLocked, false); 819 if (this.undoSupport != null) { 820 this.undoSupport.postEdit(new FurnitureGroupingUndoableEdit(this.home, this.preferences, 821 oldSelection.toArray(new Selectable [oldSelection.size()]), basePlanLocked, allLevelsSelection, 822 groupedPieces, groupedPiecesIndex, groupedPiecesGroups, groupedPiecesLevel, groupedPiecesElevation, groupedPiecesVisible, 823 newGroup, groupIndex, groupLevel, groupPiecesNewElevation, movable)); 824 } 825 } 826 } 827 828 /** 829 * Undoable edit for furniture grouping. 830 */ 831 private static class FurnitureGroupingUndoableEdit extends LocalizedUndoableEdit { 832 private final Home home; 833 private final Selectable [] oldSelection; 834 private final boolean basePlanLocked; 835 private final boolean allLevelsSelection; 836 private final HomePieceOfFurniture [] groupedPieces; 837 private final int [] groupedPiecesIndex; 838 private final HomeFurnitureGroup [] groupedPiecesGroups; 839 private final Level [] groupedPiecesLevel; 840 private final float [] groupedPiecesElevation; 841 private final boolean [] groupedPiecesVisible; 842 private final HomeFurnitureGroup newGroup; 843 private final int groupIndex; 844 private final Level groupLevel; 845 private final float [] groupPiecesNewElevation; 846 private final boolean movable; 847 FurnitureGroupingUndoableEdit(Home home, UserPreferences preferences, Selectable[] oldSelection, boolean basePlanLocked, boolean allLevelsSelection, HomePieceOfFurniture [] groupedPieces, int [] groupedPiecesIndex, HomeFurnitureGroup [] groupedPiecesGroups, Level [] groupedPiecesLevel, float [] groupedPiecesElevation, boolean [] groupedPiecesVisible, HomeFurnitureGroup newGroup, int groupIndex, Level groupLevel, float [] groupPiecesNewElevation, boolean movable)848 public FurnitureGroupingUndoableEdit(Home home, UserPreferences preferences, 849 Selectable[] oldSelection, boolean basePlanLocked, boolean allLevelsSelection, 850 HomePieceOfFurniture [] groupedPieces, int [] groupedPiecesIndex, 851 HomeFurnitureGroup [] groupedPiecesGroups, Level [] groupedPiecesLevel, 852 float [] groupedPiecesElevation, boolean [] groupedPiecesVisible, 853 HomeFurnitureGroup newGroup, int groupIndex, 854 Level groupLevel, float [] groupPiecesNewElevation, boolean movable) { 855 super(preferences, FurnitureController.class, "undoGroupName"); 856 this.home = home; 857 this.basePlanLocked = basePlanLocked; 858 this.oldSelection = oldSelection; 859 this.allLevelsSelection = allLevelsSelection; 860 this.groupedPieces = groupedPieces; 861 this.groupedPiecesIndex = groupedPiecesIndex; 862 this.groupedPiecesGroups = groupedPiecesGroups; 863 this.groupedPiecesLevel = groupedPiecesLevel; 864 this.groupedPiecesElevation = groupedPiecesElevation; 865 this.groupedPiecesVisible = groupedPiecesVisible; 866 this.newGroup = newGroup; 867 this.groupIndex = groupIndex; 868 this.groupLevel = groupLevel; 869 this.groupPiecesNewElevation = groupPiecesNewElevation; 870 this.movable = movable; 871 } 872 873 @Override undo()874 public void undo() throws CannotUndoException { 875 super.undo(); 876 doUngroupFurniture(this.home, new HomeFurnitureGroup [] {this.newGroup}, this.groupedPieces, 877 this.groupedPiecesGroups, this.groupedPiecesIndex, this.groupedPiecesLevel, this.basePlanLocked, this.allLevelsSelection); 878 for (int i = 0; i < this.groupedPieces.length; i++) { 879 this.groupedPieces [i].setElevation(this.groupedPiecesElevation [i]); 880 this.groupedPieces [i].setVisible(this.groupedPiecesVisible [i]); 881 } 882 this.home.setSelectedItems(Arrays.asList(this.oldSelection)); 883 } 884 885 @Override redo()886 public void redo() throws CannotRedoException { 887 super.redo(); 888 for (int i = 0; i < this.groupedPieces.length; i++) { 889 this.groupedPieces [i].setElevation(this.groupPiecesNewElevation [i]); 890 this.groupedPieces [i].setLevel(null); 891 } 892 this.newGroup.setMovable(this.movable); 893 this.newGroup.setVisible(true); 894 doGroupFurniture(this.home, this.groupedPieces, new HomeFurnitureGroup [] {this.newGroup}, 895 null, new int [] {this.groupIndex}, new Level [] {this.groupLevel}, this.basePlanLocked, false); 896 } 897 } 898 899 /** 900 * Returns a new furniture group for the given furniture list. 901 */ createHomeFurnitureGroup(List<HomePieceOfFurniture> furniture)902 protected HomeFurnitureGroup createHomeFurnitureGroup(List<HomePieceOfFurniture> furniture) { 903 return createHomeFurnitureGroup(furniture, furniture.get(0)); 904 } 905 906 /** 907 * Returns a new furniture group for the given furniture list. 908 * @since 4.5 909 */ createHomeFurnitureGroup(List<HomePieceOfFurniture> furniture, HomePieceOfFurniture leadingPiece)910 protected HomeFurnitureGroup createHomeFurnitureGroup(List<HomePieceOfFurniture> furniture, HomePieceOfFurniture leadingPiece) { 911 String furnitureGroupName = this.preferences.getLocalizedString( 912 FurnitureController.class, "groupName", getFurnitureGroupCount(this.home.getFurniture()) + 1); 913 final HomeFurnitureGroup furnitureGroup = new HomeFurnitureGroup(furniture, leadingPiece, furnitureGroupName); 914 return furnitureGroup; 915 } 916 917 /** 918 * Returns the count of furniture groups among the given list. 919 */ getFurnitureGroupCount(List<HomePieceOfFurniture> furniture)920 private static int getFurnitureGroupCount(List<HomePieceOfFurniture> furniture) { 921 int i = 0; 922 for (HomePieceOfFurniture piece : furniture) { 923 if (piece instanceof HomeFurnitureGroup) { 924 i += 1 + getFurnitureGroupCount(((HomeFurnitureGroup)piece).getFurniture()); 925 } 926 } 927 return i; 928 } 929 doGroupFurniture(Home home, HomePieceOfFurniture [] groupedPieces, HomeFurnitureGroup [] groups, HomeFurnitureGroup [] groupsGroups, int [] groupsIndex, Level [] groupsLevels, boolean basePlanLocked, boolean allLevelsSelection)930 private static void doGroupFurniture(Home home, 931 HomePieceOfFurniture [] groupedPieces, 932 HomeFurnitureGroup [] groups, 933 HomeFurnitureGroup [] groupsGroups, 934 int [] groupsIndex, 935 Level [] groupsLevels, 936 boolean basePlanLocked, 937 boolean allLevelsSelection) { 938 doDeleteFurniture(home, groupedPieces, basePlanLocked, allLevelsSelection); 939 doAddFurniture(home, groups, groupsGroups, groupsIndex, null, groupsLevels, basePlanLocked, allLevelsSelection); 940 } 941 doUngroupFurniture(Home home, HomeFurnitureGroup [] groups, HomePieceOfFurniture [] ungroupedPieces, HomeFurnitureGroup [] ungroupedPiecesGroups, int [] ungroupedPiecesIndex, Level [] ungroupedPiecesLevels, boolean basePlanLocked, boolean allLevelsSelection)942 private static void doUngroupFurniture(Home home, 943 HomeFurnitureGroup [] groups, 944 HomePieceOfFurniture [] ungroupedPieces, 945 HomeFurnitureGroup [] ungroupedPiecesGroups, 946 int [] ungroupedPiecesIndex, 947 Level [] ungroupedPiecesLevels, 948 boolean basePlanLocked, 949 boolean allLevelsSelection) { 950 doDeleteFurniture(home, groups, basePlanLocked, allLevelsSelection); 951 doAddFurniture(home, ungroupedPieces, ungroupedPiecesGroups, ungroupedPiecesIndex, null, ungroupedPiecesLevels, basePlanLocked, allLevelsSelection); 952 } 953 954 /** 955 * Ungroups the selected groups of furniture. 956 */ ungroupSelectedFurniture()957 public void ungroupSelectedFurniture() { 958 List<HomeFurnitureGroup> movableSelectedFurnitureGroups = new ArrayList<HomeFurnitureGroup>(); 959 for (Selectable item : this.home.getSelectedItems()) { 960 if (item instanceof HomeFurnitureGroup) { 961 HomeFurnitureGroup group = (HomeFurnitureGroup)item; 962 if (isPieceOfFurnitureMovable(group)) { 963 movableSelectedFurnitureGroups.add(group); 964 } 965 } 966 } 967 if (!movableSelectedFurnitureGroups.isEmpty()) { 968 List<HomePieceOfFurniture> homeFurniture = this.home.getFurniture(); 969 final boolean oldBasePlanLocked = this.home.isBasePlanLocked(); 970 final boolean allLevelsSelection = this.home.isAllLevelsSelection(); 971 final List<Selectable> oldSelection = this.home.getSelectedItems(); 972 // Sort the groups in the ascending order of their index in home or their group 973 Map<HomeFurnitureGroup, TreeMap<Integer, HomeFurnitureGroup>> groupsMap = 974 new HashMap<HomeFurnitureGroup, TreeMap<Integer, HomeFurnitureGroup>>(); 975 int groupsCount = 0; 976 for (HomeFurnitureGroup piece : movableSelectedFurnitureGroups) { 977 HomeFurnitureGroup groupGroup = getPieceOfFurnitureGroup(piece, null, homeFurniture); 978 TreeMap<Integer, HomeFurnitureGroup> sortedMap = groupsMap.get(groupGroup); 979 if (sortedMap == null) { 980 sortedMap = new TreeMap<Integer, HomeFurnitureGroup>(); 981 groupsMap.put(groupGroup, sortedMap); 982 } 983 if (groupGroup == null) { 984 sortedMap.put(homeFurniture.indexOf(piece), piece); 985 } else { 986 sortedMap.put(groupGroup.getFurniture().indexOf(piece), piece); 987 } 988 groupsCount++; 989 } 990 final HomeFurnitureGroup [] groups = new HomeFurnitureGroup [groupsCount]; 991 final HomeFurnitureGroup [] groupsGroups = new HomeFurnitureGroup [groups.length]; 992 final int [] groupsIndex = new int [groups.length]; 993 final Level [] groupsLevels = new Level [groups.length]; 994 int i = 0; 995 List<HomePieceOfFurniture> ungroupedPiecesList = new ArrayList<HomePieceOfFurniture>(); 996 List<Integer> ungroupedPiecesIndexList = new ArrayList<Integer>(); 997 List<HomeFurnitureGroup> ungroupedPiecesGroupsList = new ArrayList<HomeFurnitureGroup>(); 998 for (Map.Entry<HomeFurnitureGroup, TreeMap<Integer, HomeFurnitureGroup>> sortedMapEntry : groupsMap.entrySet()) { 999 TreeMap<Integer, HomeFurnitureGroup> sortedMap = sortedMapEntry.getValue(); 1000 int endIndex = sortedMap.lastKey() + 1 - sortedMap.size(); 1001 for (Map.Entry<Integer, HomeFurnitureGroup> groupEntry : sortedMap.entrySet()) { 1002 HomeFurnitureGroup group = groupEntry.getValue(); 1003 groups [i] = group; 1004 groupsGroups [i] = sortedMapEntry.getKey(); 1005 groupsIndex [i] = groupEntry.getKey(); 1006 groupsLevels [i++] = group.getLevel(); 1007 for (HomePieceOfFurniture groupPiece : group.getFurniture()) { 1008 ungroupedPiecesList.add(groupPiece); 1009 ungroupedPiecesGroupsList.add(sortedMapEntry.getKey()); 1010 ungroupedPiecesIndexList.add(endIndex++); 1011 } 1012 } 1013 } 1014 final HomePieceOfFurniture [] ungroupedPieces = 1015 ungroupedPiecesList.toArray(new HomePieceOfFurniture [ungroupedPiecesList.size()]); 1016 final HomeFurnitureGroup [] ungroupedPiecesGroups = 1017 ungroupedPiecesGroupsList.toArray(new HomeFurnitureGroup [ungroupedPiecesGroupsList.size()]); 1018 final int [] ungroupedPiecesIndex = new int [ungroupedPieces.length]; 1019 final Level [] ungroupedPiecesLevels = new Level [ungroupedPieces.length]; 1020 boolean basePlanLocked = oldBasePlanLocked; 1021 for (i = 0; i < ungroupedPieces.length; i++) { 1022 ungroupedPiecesIndex [i] = ungroupedPiecesIndexList.get(i); 1023 ungroupedPiecesLevels [i] = ungroupedPieces [i].getLevel(); 1024 // Unlock base plan if the piece is a part of it 1025 basePlanLocked &= !isPieceOfFurniturePartOfBasePlan(ungroupedPieces [i]); 1026 } 1027 final boolean newBasePlanLocked = basePlanLocked; 1028 1029 doUngroupFurniture(this.home, groups, ungroupedPieces, ungroupedPiecesGroups, 1030 ungroupedPiecesIndex, ungroupedPiecesLevels, newBasePlanLocked, false); 1031 if (this.undoSupport != null) { 1032 this.undoSupport.postEdit(new FurnitureUngroupingUndoableEdit(this.home, this.preferences, 1033 oldSelection.toArray(new Selectable [oldSelection.size()]), oldBasePlanLocked, allLevelsSelection, 1034 groups, groupsIndex, groupsGroups, groupsLevels, ungroupedPieces, ungroupedPiecesIndex, 1035 ungroupedPiecesGroups, ungroupedPiecesLevels, newBasePlanLocked)); 1036 } 1037 } 1038 } 1039 1040 /** 1041 * Undoable edit for furniture ungrouping. 1042 */ 1043 private static class FurnitureUngroupingUndoableEdit extends LocalizedUndoableEdit { 1044 private final Home home; 1045 private final boolean oldBasePlanLocked; 1046 private final Selectable [] oldSelection; 1047 private final boolean allLevelsSelection; 1048 private final HomeFurnitureGroup [] groups; 1049 private final int [] groupsIndex; 1050 private final HomeFurnitureGroup [] groupsGroups; 1051 private final Level [] groupsLevels; 1052 private final HomePieceOfFurniture [] ungroupedPieces; 1053 private final int [] ungroupedPiecesIndex; 1054 private final HomeFurnitureGroup [] ungroupedPiecesGroups; 1055 private final Level [] ungroupedPiecesLevels; 1056 private final boolean newBasePlanLocked; 1057 FurnitureUngroupingUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, boolean oldBasePlanLocked, boolean allLevelsSelection, HomeFurnitureGroup [] groups, int [] groupsIndex, HomeFurnitureGroup [] groupsGroups, Level [] groupsLevels, HomePieceOfFurniture [] ungroupedPieces, int [] ungroupedPiecesIndex, HomeFurnitureGroup [] ungroupedPiecesGroups, Level [] ungroupedPiecesLevels, boolean newBasePlanLocked)1058 public FurnitureUngroupingUndoableEdit(Home home, UserPreferences preferences, 1059 Selectable [] oldSelection, boolean oldBasePlanLocked, boolean allLevelsSelection, 1060 HomeFurnitureGroup [] groups, int [] groupsIndex, 1061 HomeFurnitureGroup [] groupsGroups, Level [] groupsLevels, 1062 HomePieceOfFurniture [] ungroupedPieces, int [] ungroupedPiecesIndex, 1063 HomeFurnitureGroup [] ungroupedPiecesGroups, 1064 Level [] ungroupedPiecesLevels, boolean newBasePlanLocked) { 1065 super(preferences, FurnitureController.class, "undoUngroupName"); 1066 this.home = home; 1067 this.oldSelection = oldSelection; 1068 this.oldBasePlanLocked = oldBasePlanLocked; 1069 this.allLevelsSelection = allLevelsSelection; 1070 this.groups = groups; 1071 this.groupsIndex = groupsIndex; 1072 this.groupsGroups = groupsGroups; 1073 this.groupsLevels = groupsLevels; 1074 this.ungroupedPieces = ungroupedPieces; 1075 this.ungroupedPiecesIndex = ungroupedPiecesIndex; 1076 this.ungroupedPiecesGroups = ungroupedPiecesGroups; 1077 this.ungroupedPiecesLevels = ungroupedPiecesLevels; 1078 this.newBasePlanLocked = newBasePlanLocked; 1079 } 1080 1081 @Override undo()1082 public void undo() throws CannotUndoException { 1083 super.undo(); 1084 doGroupFurniture(this.home, this.ungroupedPieces, this.groups, this.groupsGroups, this.groupsIndex, this.groupsLevels, 1085 this.oldBasePlanLocked, this.allLevelsSelection); 1086 this.home.setSelectedItems(Arrays.asList(this.oldSelection)); 1087 } 1088 1089 @Override redo()1090 public void redo() throws CannotRedoException { 1091 super.redo(); 1092 doUngroupFurniture(this.home, this.groups, this.ungroupedPieces, this.ungroupedPiecesGroups, this.ungroupedPiecesIndex, 1093 this.ungroupedPiecesLevels, this.newBasePlanLocked, false); 1094 } 1095 } 1096 1097 /** 1098 * Displays the wizard that helps to import furniture to home. 1099 */ importFurniture()1100 public void importFurniture() { 1101 new ImportedFurnitureWizardController(this.home, this.preferences, this, this.viewFactory, 1102 this.contentManager, this.undoSupport).displayView(getView()); 1103 } 1104 1105 /** 1106 * Displays the wizard that helps to import furniture to home with a 1107 * given model name. 1108 */ importFurniture(String modelName)1109 public void importFurniture(String modelName) { 1110 new ImportedFurnitureWizardController(this.home, modelName, this.preferences, this, 1111 this.viewFactory, this.contentManager, this.undoSupport).displayView(getView()); 1112 } 1113 1114 /** 1115 * Controls the alignment of selected furniture on top of the first selected piece. 1116 */ alignSelectedFurnitureOnTop()1117 public void alignSelectedFurnitureOnTop() { 1118 List<Selectable> oldSelection = this.home.getSelectedItems(); 1119 alignSelectedFurniture(new FurnitureTopAlignmentUndoableEdit(this.home, this.preferences, 1120 oldSelection.toArray(new Selectable [oldSelection.size()]), 1121 getMovableSelectedFurniture(), this.leadSelectedPieceOfFurniture)); 1122 } 1123 1124 private static class FurnitureTopAlignmentUndoableEdit extends FurnitureAlignmentUndoableEdit { FurnitureTopAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1125 public FurnitureTopAlignmentUndoableEdit(Home home, UserPreferences preferences, 1126 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1127 HomePieceOfFurniture leadPiece) { 1128 super(home, preferences, oldSelection, selectedFurniture, leadPiece); 1129 } 1130 1131 @Override alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1132 void alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece) { 1133 float minYLeadPiece = getMinY(leadPiece); 1134 for (HomePieceOfFurniture piece : alignedFurniture) { 1135 float minY = getMinY(piece); 1136 piece.setY(piece.getY() + minYLeadPiece - minY); 1137 } 1138 } 1139 } 1140 1141 /** 1142 * Controls the alignment of selected furniture on bottom of the first selected piece. 1143 */ alignSelectedFurnitureOnBottom()1144 public void alignSelectedFurnitureOnBottom() { 1145 List<Selectable> oldSelection = this.home.getSelectedItems(); 1146 alignSelectedFurniture(new FurnitureBottomAlignmentUndoableEdit(this.home, this.preferences, 1147 oldSelection.toArray(new Selectable [oldSelection.size()]), 1148 getMovableSelectedFurniture(), this.leadSelectedPieceOfFurniture)); 1149 } 1150 1151 private static class FurnitureBottomAlignmentUndoableEdit extends FurnitureAlignmentUndoableEdit { FurnitureBottomAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1152 public FurnitureBottomAlignmentUndoableEdit(Home home, UserPreferences preferences, 1153 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1154 HomePieceOfFurniture leadPiece) { 1155 super(home, preferences, oldSelection, selectedFurniture, leadPiece); 1156 } 1157 1158 @Override alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1159 void alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece) { 1160 float maxYLeadPiece = getMaxY(leadPiece); 1161 for (HomePieceOfFurniture piece : alignedFurniture) { 1162 float maxY = getMaxY(piece); 1163 piece.setY(piece.getY() + maxYLeadPiece - maxY); 1164 } 1165 } 1166 } 1167 1168 /** 1169 * Controls the alignment of selected furniture on left of the first selected piece. 1170 */ alignSelectedFurnitureOnLeft()1171 public void alignSelectedFurnitureOnLeft() { 1172 List<Selectable> oldSelection = this.home.getSelectedItems(); 1173 alignSelectedFurniture(new FurnitureLeftAlignmentUndoableEdit(this.home, this.preferences, 1174 oldSelection.toArray(new Selectable [oldSelection.size()]), 1175 getMovableSelectedFurniture(), this.leadSelectedPieceOfFurniture)); 1176 } 1177 1178 private static class FurnitureLeftAlignmentUndoableEdit extends FurnitureAlignmentUndoableEdit { FurnitureLeftAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1179 public FurnitureLeftAlignmentUndoableEdit(Home home, UserPreferences preferences, 1180 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1181 HomePieceOfFurniture leadPiece) { 1182 super(home, preferences, oldSelection, selectedFurniture, leadPiece); 1183 } 1184 1185 @Override alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1186 void alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece) { 1187 float minXLeadPiece = getMinX(leadPiece); 1188 for (HomePieceOfFurniture piece : alignedFurniture) { 1189 float minX = getMinX(piece); 1190 piece.setX(piece.getX() + minXLeadPiece - minX); 1191 } 1192 } 1193 } 1194 1195 /** 1196 * Controls the alignment of selected furniture on right of the first selected piece. 1197 */ alignSelectedFurnitureOnRight()1198 public void alignSelectedFurnitureOnRight() { 1199 List<Selectable> oldSelection = this.home.getSelectedItems(); 1200 alignSelectedFurniture(new FurnitureRightAlignmentUndoableEdit(this.home, this.preferences, 1201 oldSelection.toArray(new Selectable [oldSelection.size()]), 1202 getMovableSelectedFurniture(), this.leadSelectedPieceOfFurniture)); 1203 } 1204 1205 private static class FurnitureRightAlignmentUndoableEdit extends FurnitureAlignmentUndoableEdit { FurnitureRightAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1206 public FurnitureRightAlignmentUndoableEdit(Home home, UserPreferences preferences, 1207 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1208 HomePieceOfFurniture leadPiece) { 1209 super(home, preferences, oldSelection, selectedFurniture, leadPiece); 1210 } 1211 1212 @Override alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1213 void alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece) { 1214 float maxXLeadPiece = getMaxX(leadPiece); 1215 for (HomePieceOfFurniture piece : alignedFurniture) { 1216 float maxX = getMaxX(piece); 1217 piece.setX(piece.getX() + maxXLeadPiece - maxX); 1218 } 1219 } 1220 } 1221 1222 /** 1223 * Controls the alignment of selected furniture on the front side of the first selected piece. 1224 */ alignSelectedFurnitureOnFrontSide()1225 public void alignSelectedFurnitureOnFrontSide() { 1226 List<Selectable> oldSelection = this.home.getSelectedItems(); 1227 alignSelectedFurniture(new FurnitureFrontSideAlignmentUndoableEdit(this.home, this.preferences, 1228 oldSelection.toArray(new Selectable [oldSelection.size()]), 1229 getMovableSelectedFurniture(), this.leadSelectedPieceOfFurniture)); 1230 } 1231 1232 private static class FurnitureFrontSideAlignmentUndoableEdit extends FurnitureAlignmentUndoableEdit { FurnitureFrontSideAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1233 public FurnitureFrontSideAlignmentUndoableEdit(Home home, UserPreferences preferences, 1234 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1235 HomePieceOfFurniture leadPiece) { 1236 super(home, preferences, oldSelection, selectedFurniture, leadPiece); 1237 } 1238 1239 @Override alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1240 void alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece) { 1241 float [][] points = leadPiece.getPoints(); 1242 Line2D frontLine = new Line2D.Float(points [2][0], points [2][1], points [3][0], points [3][1]); 1243 for (HomePieceOfFurniture piece : alignedFurniture) { 1244 alignPieceOfFurnitureAlongSides(piece, leadPiece, frontLine, true, null, 0); 1245 } 1246 } 1247 } 1248 1249 /** 1250 * Controls the alignment of selected furniture on the back side of the first selected piece. 1251 */ alignSelectedFurnitureOnBackSide()1252 public void alignSelectedFurnitureOnBackSide() { 1253 List<Selectable> oldSelection = this.home.getSelectedItems(); 1254 alignSelectedFurniture(new FurnitureBackSideAlignmentUndoableEdit(this.home, this.preferences, 1255 oldSelection.toArray(new Selectable [oldSelection.size()]), 1256 getMovableSelectedFurniture(), this.leadSelectedPieceOfFurniture)); 1257 } 1258 1259 private static class FurnitureBackSideAlignmentUndoableEdit extends FurnitureAlignmentUndoableEdit { FurnitureBackSideAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1260 public FurnitureBackSideAlignmentUndoableEdit(Home home, UserPreferences preferences, 1261 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1262 HomePieceOfFurniture leadPiece) { 1263 super(home, preferences, oldSelection, selectedFurniture, leadPiece); 1264 } 1265 1266 @Override alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1267 void alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece) { 1268 float [][] points = leadPiece.getPoints(); 1269 Line2D backLine = new Line2D.Float(points [0][0], points [0][1], points [1][0], points [1][1]); 1270 for (HomePieceOfFurniture piece : alignedFurniture) { 1271 alignPieceOfFurnitureAlongSides(piece, leadPiece, backLine, false, null, 0); 1272 } 1273 } 1274 } 1275 1276 /** 1277 * Controls the alignment of selected furniture on the left side of the first selected piece. 1278 */ alignSelectedFurnitureOnLeftSide()1279 public void alignSelectedFurnitureOnLeftSide() { 1280 List<Selectable> oldSelection = this.home.getSelectedItems(); 1281 alignSelectedFurniture(new FurnitureLeftSideAlignmentUndoableEdit(this.home, this.preferences, 1282 oldSelection.toArray(new Selectable [oldSelection.size()]), 1283 getMovableSelectedFurniture(), this.leadSelectedPieceOfFurniture)); 1284 } 1285 1286 private static class FurnitureLeftSideAlignmentUndoableEdit extends FurnitureAlignmentUndoableEdit { FurnitureLeftSideAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1287 public FurnitureLeftSideAlignmentUndoableEdit(Home home, UserPreferences preferences, 1288 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1289 HomePieceOfFurniture leadPiece) { 1290 super(home, preferences, oldSelection, selectedFurniture, leadPiece); 1291 } 1292 1293 @Override alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1294 void alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece) { 1295 float [][] points = leadPiece.getPoints(); 1296 Line2D leftLine = new Line2D.Float(points [3][0], points [3][1], points [0][0], points [0][1]); 1297 for (HomePieceOfFurniture piece : alignedFurniture) { 1298 alignPieceOfFurnitureAlongLeftOrRightSides(piece, leadPiece, leftLine, false); 1299 } 1300 } 1301 } 1302 1303 /** 1304 * Controls the alignment of selected furniture on the right side of the first selected piece. 1305 */ alignSelectedFurnitureOnRightSide()1306 public void alignSelectedFurnitureOnRightSide() { 1307 List<Selectable> oldSelection = this.home.getSelectedItems(); 1308 alignSelectedFurniture(new FurnitureRightSideAlignmentUndoableEdit(this.home, this.preferences, 1309 oldSelection.toArray(new Selectable [oldSelection.size()]), 1310 getMovableSelectedFurniture(), this.leadSelectedPieceOfFurniture)); 1311 } 1312 1313 private static class FurnitureRightSideAlignmentUndoableEdit extends FurnitureAlignmentUndoableEdit { FurnitureRightSideAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1314 public FurnitureRightSideAlignmentUndoableEdit(Home home, UserPreferences preferences, 1315 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1316 HomePieceOfFurniture leadPiece) { 1317 super(home, preferences, oldSelection, selectedFurniture, leadPiece); 1318 } 1319 1320 @Override alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1321 void alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece) { 1322 float [][] points = leadPiece.getPoints(); 1323 Line2D rightLine = new Line2D.Float(points [1][0], points [1][1], points [2][0], points [2][1]); 1324 for (HomePieceOfFurniture alignedPiece : alignedFurniture) { 1325 alignPieceOfFurnitureAlongLeftOrRightSides(alignedPiece, leadPiece, rightLine, true); 1326 } 1327 } 1328 } 1329 1330 /** 1331 * Controls the alignment of selected furniture on the sides of the first selected piece. 1332 */ alignSelectedFurnitureSideBySide()1333 public void alignSelectedFurnitureSideBySide() { 1334 List<Selectable> oldSelection = this.home.getSelectedItems(); 1335 alignSelectedFurniture(new FurnitureSideBySideAlignmentUndoableEdit(this.home, this.preferences, 1336 oldSelection.toArray(new Selectable [oldSelection.size()]), 1337 getMovableSelectedFurniture(), this.leadSelectedPieceOfFurniture)); 1338 } 1339 1340 private static class FurnitureSideBySideAlignmentUndoableEdit extends FurnitureAlignmentUndoableEdit { FurnitureSideBySideAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1341 public FurnitureSideBySideAlignmentUndoableEdit(Home home, UserPreferences preferences, 1342 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1343 HomePieceOfFurniture leadPiece) { 1344 super(home, preferences, oldSelection, selectedFurniture, leadPiece); 1345 } 1346 1347 @Override alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1348 void alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece) { 1349 float [][] points = leadPiece.getPoints(); 1350 final Line2D centerLine = new Line2D.Float(leadPiece.getX(), leadPiece.getY(), 1351 (points [0][0] + points [1][0]) / 2, (points [0][1] + points [1][1]) / 2); 1352 List<HomePieceOfFurniture> furnitureSortedAlongBackLine = sortFurniture(alignedFurniture, leadPiece, centerLine); 1353 1354 int leadPieceIndex = furnitureSortedAlongBackLine.indexOf(leadPiece); 1355 Line2D backLine = new Line2D.Float(points [0][0], points [0][1], points [1][0], points [1][1]); 1356 float sideDistance = leadPiece.getWidthInPlan() / 2; 1357 for (int i = leadPieceIndex + 1; i < furnitureSortedAlongBackLine.size(); i++) { 1358 sideDistance += alignPieceOfFurnitureAlongSides(furnitureSortedAlongBackLine.get(i), 1359 leadPiece, backLine, false, centerLine, sideDistance); 1360 } 1361 sideDistance = -leadPiece.getWidthInPlan() / 2; 1362 for (int i = leadPieceIndex - 1; i >= 0; i--) { 1363 sideDistance -= alignPieceOfFurnitureAlongSides(furnitureSortedAlongBackLine.get(i), 1364 leadPiece, backLine, false, centerLine, sideDistance); 1365 } 1366 } 1367 } 1368 1369 /** 1370 * Returns a list containing aligned furniture and lead piece sorted in the order of their distribution along 1371 * a line orthogonal to the given axis. 1372 */ sortFurniture(HomePieceOfFurniture [] furniture, HomePieceOfFurniture leadPiece, final Line2D orthogonalAxis)1373 private static List<HomePieceOfFurniture> sortFurniture(HomePieceOfFurniture [] furniture, 1374 HomePieceOfFurniture leadPiece, 1375 final Line2D orthogonalAxis) { 1376 List<HomePieceOfFurniture> sortedFurniture = new ArrayList<HomePieceOfFurniture>(furniture.length + 1); 1377 if (leadPiece != null) { 1378 sortedFurniture.add(leadPiece); 1379 } 1380 sortedFurniture.addAll(Arrays.asList(furniture)); 1381 Collections.sort(sortedFurniture, new Comparator<HomePieceOfFurniture>() { 1382 public int compare(HomePieceOfFurniture p1, HomePieceOfFurniture p2) { 1383 return Double.compare(orthogonalAxis.ptLineDistSq(p2.getX(), p2.getY()) * orthogonalAxis.relativeCCW(p2.getX(), p2.getY()), 1384 orthogonalAxis.ptLineDistSq(p1.getX(), p1.getY()) * orthogonalAxis.relativeCCW(p1.getX(), p1.getY())); 1385 } 1386 }); 1387 return sortedFurniture; 1388 } 1389 1390 /** 1391 * Aligns the given <code>piece</code> along the front or back side of the lead piece and its left or right side 1392 * at a distance equal to <code>sideDistance</code>, and returns the width of the bounding box of 1393 * the <code>piece</code> along the back side axis. 1394 */ alignPieceOfFurnitureAlongSides(HomePieceOfFurniture piece, HomePieceOfFurniture leadPiece, Line2D frontOrBackLine, boolean frontLine, Line2D centerLine, float sideDistance)1395 private static double alignPieceOfFurnitureAlongSides(HomePieceOfFurniture piece, HomePieceOfFurniture leadPiece, 1396 Line2D frontOrBackLine, boolean frontLine, 1397 Line2D centerLine, float sideDistance) { 1398 // Search the distance required to align piece on the front or back side 1399 double distance = frontOrBackLine.relativeCCW(piece.getX(), piece.getY()) * frontOrBackLine.ptLineDist(piece.getX(), piece.getY()) 1400 + getPieceBoundingRectangleHeight(piece, -leadPiece.getAngle()) / 2; 1401 if (frontLine) { 1402 distance = -distance; 1403 } 1404 double sinLeadPieceAngle = Math.sin(leadPiece.getAngle()); 1405 double cosLeadPieceAngle = Math.cos(leadPiece.getAngle()); 1406 float deltaX = (float)(-distance * sinLeadPieceAngle); 1407 float deltaY = (float)(distance * cosLeadPieceAngle); 1408 1409 double rotatedBoundingBoxWidth = getPieceBoundingRectangleWidth(piece, -leadPiece.getAngle()); 1410 if (centerLine != null) { 1411 // Search the distance required to align piece on the side of the previous piece 1412 int location = centerLine.relativeCCW(piece.getX(), piece.getY()); 1413 if (location == 0) { 1414 location = frontLine ? 1 : -1; 1415 } 1416 distance = sideDistance + location 1417 * (centerLine.ptLineDist(piece.getX(), piece.getY()) - rotatedBoundingBoxWidth / 2); 1418 deltaX += (float)(distance * cosLeadPieceAngle); 1419 deltaY += (float)(distance * sinLeadPieceAngle); 1420 } 1421 1422 piece.move(deltaX, deltaY); 1423 return rotatedBoundingBoxWidth; 1424 } 1425 1426 /** 1427 * Aligns the given <code>piece</code> along the left or right side of the lead piece. 1428 */ alignPieceOfFurnitureAlongLeftOrRightSides(HomePieceOfFurniture piece, HomePieceOfFurniture leadPiece, Line2D leftOrRightLine, boolean rightLine)1429 private static void alignPieceOfFurnitureAlongLeftOrRightSides(HomePieceOfFurniture piece, HomePieceOfFurniture leadPiece, 1430 Line2D leftOrRightLine, boolean rightLine) { 1431 // Search the distance required to align piece on the side of the lead piece 1432 double distance = leftOrRightLine.relativeCCW(piece.getX(), piece.getY()) * leftOrRightLine.ptLineDist(piece.getX(), piece.getY()) 1433 + getPieceBoundingRectangleWidth(piece, -leadPiece.getAngle()) / 2; 1434 if (rightLine) { 1435 distance = -distance; 1436 } 1437 piece.move((float)(distance * Math.cos(leadPiece.getAngle())), (float)(distance * Math.sin(leadPiece.getAngle()))); 1438 } 1439 1440 /** 1441 * Returns the bounding box width of the given piece when it's rotated of an additional angle. 1442 */ getPieceBoundingRectangleWidth(HomePieceOfFurniture piece, float additionalAngle)1443 private static double getPieceBoundingRectangleWidth(HomePieceOfFurniture piece, float additionalAngle) { 1444 return Math.abs(piece.getWidthInPlan() * Math.cos(additionalAngle + piece.getAngle())) 1445 + Math.abs(piece.getDepthInPlan() * Math.sin(additionalAngle + piece.getAngle())); 1446 } 1447 1448 /** 1449 * Returns the bounding box height of the given piece when it's rotated of an additional angle. 1450 */ getPieceBoundingRectangleHeight(HomePieceOfFurniture piece, float additionalAngle)1451 private static double getPieceBoundingRectangleHeight(HomePieceOfFurniture piece, float additionalAngle) { 1452 return Math.abs(piece.getWidthInPlan() * Math.sin(additionalAngle + piece.getAngle())) 1453 + Math.abs(piece.getDepthInPlan() * Math.cos(additionalAngle + piece.getAngle())); 1454 } 1455 1456 /** 1457 * Controls the alignment of selected furniture. 1458 */ alignSelectedFurniture(final FurnitureAlignmentUndoableEdit alignmentEdit)1459 private void alignSelectedFurniture(final FurnitureAlignmentUndoableEdit alignmentEdit) { 1460 HomePieceOfFurniture [] selectedFurniture = getMovableSelectedFurniture(); 1461 if (selectedFurniture.length >= 2) { 1462 this.home.setSelectedItems(Arrays.asList(selectedFurniture)); 1463 alignmentEdit.alignFurniture(); 1464 if (this.undoSupport != null) { 1465 this.undoSupport.postEdit(alignmentEdit); 1466 } 1467 } 1468 } 1469 1470 /** 1471 * Undoable edit for furniture alignment. 1472 */ 1473 private static abstract class FurnitureAlignmentUndoableEdit extends LocalizedUndoableEdit { 1474 private final Home home; 1475 private final Selectable [] oldSelection; 1476 private final HomePieceOfFurniture [] selectedFurniture; 1477 private final HomePieceOfFurniture leadPiece; 1478 private final HomePieceOfFurniture [] alignedFurniture; 1479 private final float [] oldX; 1480 private final float [] oldY; 1481 FurnitureAlignmentUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, HomePieceOfFurniture leadPiece)1482 public FurnitureAlignmentUndoableEdit(Home home, UserPreferences preferences, 1483 Selectable [] oldSelection, HomePieceOfFurniture [] selectedFurniture, 1484 HomePieceOfFurniture leadPiece) { 1485 super(preferences, FurnitureController.class, "undoAlignName"); 1486 this.home = home; 1487 this.oldSelection = oldSelection; 1488 this.selectedFurniture = selectedFurniture; 1489 this.leadPiece = leadPiece; 1490 this.alignedFurniture = new HomePieceOfFurniture[leadPiece == null ? selectedFurniture.length : selectedFurniture.length - 1]; 1491 this.oldX = new float [this.alignedFurniture.length]; 1492 this.oldY = new float [this.alignedFurniture.length]; 1493 int i = 0; 1494 for (HomePieceOfFurniture piece : selectedFurniture) { 1495 if (piece != leadPiece) { 1496 this.alignedFurniture [i] = piece; 1497 this.oldX [i] = piece.getX(); 1498 this.oldY [i] = piece.getY(); 1499 i++; 1500 } 1501 } 1502 } 1503 1504 @Override undo()1505 public void undo() throws CannotUndoException { 1506 super.undo(); 1507 undoAlignFurniture(this.alignedFurniture, this.oldX, this.oldY); 1508 this.home.setSelectedItems(Arrays.asList(this.oldSelection)); 1509 } 1510 1511 @Override redo()1512 public void redo() throws CannotRedoException { 1513 super.redo(); 1514 this.home.setSelectedItems(Arrays.asList(this.selectedFurniture)); 1515 alignFurniture(); 1516 } 1517 alignFurniture()1518 public void alignFurniture() { 1519 alignFurniture(this.alignedFurniture, this.leadPiece); 1520 } 1521 alignFurniture(HomePieceOfFurniture [] alignedFurniture, HomePieceOfFurniture leadPiece)1522 abstract void alignFurniture(HomePieceOfFurniture [] alignedFurniture, 1523 HomePieceOfFurniture leadPiece); 1524 } 1525 getMovableSelectedFurniture()1526 private HomePieceOfFurniture [] getMovableSelectedFurniture() { 1527 List<HomePieceOfFurniture> movableSelectedFurniture = new ArrayList<HomePieceOfFurniture>(); 1528 for (Selectable item : this.home.getSelectedItems()) { 1529 if (item instanceof HomePieceOfFurniture) { 1530 HomePieceOfFurniture piece = (HomePieceOfFurniture)item; 1531 if (isPieceOfFurnitureMovable(piece)) { 1532 movableSelectedFurniture.add(piece); 1533 } 1534 } 1535 } 1536 return movableSelectedFurniture.toArray(new HomePieceOfFurniture [movableSelectedFurniture.size()]); 1537 } 1538 undoAlignFurniture(HomePieceOfFurniture [] alignedFurniture, float [] x, float [] y)1539 private static void undoAlignFurniture(HomePieceOfFurniture [] alignedFurniture, float [] x, float [] y) { 1540 for (int i = 0; i < alignedFurniture.length; i++) { 1541 HomePieceOfFurniture piece = alignedFurniture [i]; 1542 piece.setX(x [i]); 1543 piece.setY(y [i]); 1544 } 1545 } 1546 1547 /** 1548 * Returns the minimum abscissa of the vertices of <code>piece</code>. 1549 */ getMinX(HomePieceOfFurniture piece)1550 private static float getMinX(HomePieceOfFurniture piece) { 1551 float [][] points = piece.getPoints(); 1552 float minX = Float.POSITIVE_INFINITY; 1553 for (float [] point : points) { 1554 minX = Math.min(minX, point [0]); 1555 } 1556 return minX; 1557 } 1558 1559 /** 1560 * Returns the maximum abscissa of the vertices of <code>piece</code>. 1561 */ getMaxX(HomePieceOfFurniture piece)1562 private static float getMaxX(HomePieceOfFurniture piece) { 1563 float [][] points = piece.getPoints(); 1564 float maxX = Float.NEGATIVE_INFINITY; 1565 for (float [] point : points) { 1566 maxX = Math.max(maxX, point [0]); 1567 } 1568 return maxX; 1569 } 1570 1571 /** 1572 * Returns the minimum ordinate of the vertices of <code>piece</code>. 1573 */ getMinY(HomePieceOfFurniture piece)1574 private static float getMinY(HomePieceOfFurniture piece) { 1575 float [][] points = piece.getPoints(); 1576 float minY = Float.POSITIVE_INFINITY; 1577 for (float [] point : points) { 1578 minY = Math.min(minY, point [1]); 1579 } 1580 return minY; 1581 } 1582 1583 /** 1584 * Returns the maximum ordinate of the vertices of <code>piece</code>. 1585 */ getMaxY(HomePieceOfFurniture piece)1586 private static float getMaxY(HomePieceOfFurniture piece) { 1587 float [][] points = piece.getPoints(); 1588 float maxY = Float.NEGATIVE_INFINITY; 1589 for (float [] point : points) { 1590 maxY = Math.max(maxY, point [1]); 1591 } 1592 return maxY; 1593 } 1594 1595 /** 1596 * Controls the distribution of the selected furniture along horizontal axis. 1597 */ distributeSelectedFurnitureHorizontally()1598 public void distributeSelectedFurnitureHorizontally() { 1599 distributeSelectedFurniture(true); 1600 } 1601 1602 /** 1603 * Controls the distribution of the selected furniture along vertical axis. 1604 */ distributeSelectedFurnitureVertically()1605 public void distributeSelectedFurnitureVertically() { 1606 distributeSelectedFurniture(false); 1607 } 1608 1609 /** 1610 * Controls the distribution of the selected furniture along the axis orthogonal to the given one. 1611 */ distributeSelectedFurniture(final boolean horizontal)1612 public void distributeSelectedFurniture(final boolean horizontal) { 1613 final HomePieceOfFurniture [] alignedFurniture = getMovableSelectedFurniture(); 1614 if (alignedFurniture.length >= 3) { 1615 final List<Selectable> oldSelection = this.home.getSelectedItems(); 1616 final float [] oldX = new float [alignedFurniture.length]; 1617 final float [] oldY = new float [alignedFurniture.length]; 1618 for (int i = 0; i < alignedFurniture.length; i++) { 1619 oldX [i] = alignedFurniture [i].getX(); 1620 oldY [i] = alignedFurniture [i].getY(); 1621 } 1622 this.home.setSelectedItems(Arrays.asList(alignedFurniture)); 1623 doDistributeFurnitureAlongAxis(alignedFurniture, horizontal); 1624 if (this.undoSupport != null) { 1625 this.undoSupport.postEdit(new FurnitureDistributionUndoableEdit(this.home, this.preferences, 1626 oldSelection.toArray(new Selectable [oldSelection.size()]), oldX, oldY, alignedFurniture, horizontal)); 1627 } 1628 } 1629 } 1630 1631 /** 1632 * Undoable edit for furniture distribution. 1633 */ 1634 private static class FurnitureDistributionUndoableEdit extends LocalizedUndoableEdit { 1635 private final Home home; 1636 private final Selectable [] oldSelection; 1637 private float [] oldX; 1638 private float [] oldY; 1639 private final HomePieceOfFurniture [] alignedFurniture; 1640 private final boolean horizontal; 1641 FurnitureDistributionUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, float [] oldX, float[] oldY, HomePieceOfFurniture [] alignedFurniture, boolean horizontal)1642 public FurnitureDistributionUndoableEdit(Home home, 1643 UserPreferences preferences, 1644 Selectable [] oldSelection, float [] oldX, float[] oldY, 1645 HomePieceOfFurniture [] alignedFurniture, boolean horizontal) { 1646 super(preferences, FurnitureController.class, "undoDistributeName"); 1647 this.home = home; 1648 this.oldSelection = oldSelection; 1649 this.oldX = oldX; 1650 this.oldY = oldY; 1651 this.alignedFurniture = alignedFurniture; 1652 this.horizontal = horizontal; 1653 } 1654 1655 @Override undo()1656 public void undo() throws CannotUndoException { 1657 super.undo(); 1658 undoAlignFurniture(this.alignedFurniture, this.oldX, this.oldY); 1659 this.home.setSelectedItems(Arrays.asList(this.oldSelection)); 1660 } 1661 1662 @Override redo()1663 public void redo() throws CannotRedoException { 1664 super.redo(); 1665 this.home.setSelectedItems(Arrays.asList(this.alignedFurniture)); 1666 doDistributeFurnitureAlongAxis(this.alignedFurniture, this.horizontal); 1667 } 1668 } 1669 doDistributeFurnitureAlongAxis(HomePieceOfFurniture [] alignedFurniture, boolean horizontal)1670 private static void doDistributeFurnitureAlongAxis(HomePieceOfFurniture [] alignedFurniture, 1671 boolean horizontal) { 1672 Line2D orthogonalAxis = horizontal ? new Line2D.Float(0, 0, 0, -1) : new Line2D.Float(0, 0, 1, 0); 1673 List<HomePieceOfFurniture> furnitureHorizontallySorted = sortFurniture(alignedFurniture, null, orthogonalAxis); 1674 float axisAngle = (float)(horizontal ? 0 : Math.PI / 2); 1675 HomePieceOfFurniture firstPiece = furnitureHorizontallySorted.get(0); 1676 double firstPieceBoundingRectangleHalfWidth = getPieceBoundingRectangleWidth(firstPiece, axisAngle) / 2; 1677 HomePieceOfFurniture lastPiece = furnitureHorizontallySorted.get(furnitureHorizontallySorted.size() - 1); 1678 double lastPieceBoundingRectangleHalfWidth = getPieceBoundingRectangleWidth(lastPiece, axisAngle) / 2; 1679 double gap = Math.abs( 1680 orthogonalAxis.ptLineDist(lastPiece.getX(), lastPiece.getY()) 1681 * orthogonalAxis.relativeCCW(lastPiece.getX(), lastPiece.getY()) 1682 - orthogonalAxis.ptLineDist(firstPiece.getX(), firstPiece.getY()) 1683 * orthogonalAxis.relativeCCW(firstPiece.getX(), firstPiece.getY())) 1684 - lastPieceBoundingRectangleHalfWidth 1685 - firstPieceBoundingRectangleHalfWidth; 1686 double [] furnitureWidthsAlongAxis = new double [furnitureHorizontallySorted.size() - 2]; 1687 for (int i = 1; i < furnitureHorizontallySorted.size() - 1; i++) { 1688 HomePieceOfFurniture piece = furnitureHorizontallySorted.get(i); 1689 furnitureWidthsAlongAxis [i - 1] = getPieceBoundingRectangleWidth(piece, axisAngle); 1690 gap -= furnitureWidthsAlongAxis [i - 1]; 1691 } 1692 gap /= furnitureHorizontallySorted.size() - 1; 1693 float xOrY = (horizontal ? firstPiece.getX() : firstPiece.getY()) 1694 + (float)(firstPieceBoundingRectangleHalfWidth + gap); 1695 for (int i = 1; i < furnitureHorizontallySorted.size() - 1; i++) { 1696 HomePieceOfFurniture piece = furnitureHorizontallySorted.get(i); 1697 if (horizontal) { 1698 piece.setX((float)(xOrY + furnitureWidthsAlongAxis [i - 1] / 2)); 1699 } else { 1700 piece.setY((float)(xOrY + furnitureWidthsAlongAxis [i - 1] / 2)); 1701 } 1702 xOrY += gap + furnitureWidthsAlongAxis [i - 1]; 1703 } 1704 } 1705 1706 /** 1707 * Resets the elevation of the selected furniture to its default elevation. 1708 * @since 4.4 1709 */ resetFurnitureElevation()1710 public void resetFurnitureElevation() { 1711 final HomePieceOfFurniture [] selectedFurniture = getMovableSelectedFurniture(); 1712 if (selectedFurniture.length >= 1) { 1713 final List<Selectable> oldSelection = this.home.getSelectedItems(); 1714 final float [] furnitureOldElevation = new float [selectedFurniture.length]; 1715 final float [] furnitureNewElevation = new float [selectedFurniture.length]; 1716 for (int i = 0; i < selectedFurniture.length; i++) { 1717 HomePieceOfFurniture piece = selectedFurniture [i]; 1718 furnitureOldElevation [i] = piece.getElevation(); 1719 HomePieceOfFurniture highestSurroundingPiece = getHighestSurroundingPieceOfFurniture(piece, Arrays.asList(selectedFurniture)); 1720 if (highestSurroundingPiece != null) { 1721 float elevation = highestSurroundingPiece.getElevation() 1722 + highestSurroundingPiece.getHeightInPlan() * highestSurroundingPiece.getDropOnTopElevation(); 1723 if (highestSurroundingPiece.getLevel() != null) { 1724 elevation += highestSurroundingPiece.getLevel().getElevation() - piece.getLevel().getElevation(); 1725 } 1726 furnitureNewElevation [i] = Math.max(0, elevation); 1727 } else { 1728 furnitureNewElevation [i] = 0; 1729 } 1730 } 1731 this.home.setSelectedItems(Arrays.asList(selectedFurniture)); 1732 doSetFurnitureElevation(selectedFurniture, furnitureNewElevation); 1733 if (this.undoSupport != null) { 1734 this.undoSupport.postEdit(new FurnitureElevationResetUndoableEdit(this.home, this.preferences, 1735 oldSelection.toArray(new Selectable [oldSelection.size()]), furnitureOldElevation, selectedFurniture, furnitureNewElevation)); 1736 } 1737 } 1738 } 1739 1740 /** 1741 * Undoable edit for furniture elevation reset. 1742 */ 1743 private static class FurnitureElevationResetUndoableEdit extends LocalizedUndoableEdit { 1744 private final Home home; 1745 private final Selectable [] oldSelection; 1746 private final float [] furnitureOldElevation; 1747 private final HomePieceOfFurniture [] selectedFurniture; 1748 private float [] furnitureNewElevation; 1749 FurnitureElevationResetUndoableEdit(Home home, UserPreferences preferences, Selectable [] oldSelection, float [] furnitureOldElevation, HomePieceOfFurniture [] selectedFurniture, float [] furnitureNewElevation)1750 public FurnitureElevationResetUndoableEdit(Home home, UserPreferences preferences, 1751 Selectable [] oldSelection, float [] furnitureOldElevation, 1752 HomePieceOfFurniture [] selectedFurniture, float [] furnitureNewElevation) { 1753 super(preferences, FurnitureController.class, "undoResetElevation"); 1754 this.home = home; 1755 this.oldSelection = oldSelection; 1756 this.furnitureOldElevation = furnitureOldElevation; 1757 this.selectedFurniture = selectedFurniture; 1758 this.furnitureNewElevation = furnitureNewElevation; 1759 } 1760 1761 @Override undo()1762 public void undo() throws CannotUndoException { 1763 super.undo(); 1764 doSetFurnitureElevation(this.selectedFurniture, this.furnitureOldElevation); 1765 this.home.setSelectedItems(Arrays.asList(this.oldSelection)); 1766 } 1767 1768 @Override redo()1769 public void redo() throws CannotRedoException { 1770 super.redo(); 1771 this.home.setSelectedItems(Arrays.asList(this.selectedFurniture)); 1772 doSetFurnitureElevation(this.selectedFurniture, this.furnitureNewElevation); 1773 } 1774 } 1775 doSetFurnitureElevation(HomePieceOfFurniture [] selectedFurniture, float [] furnitureNewElevation)1776 private static void doSetFurnitureElevation(HomePieceOfFurniture [] selectedFurniture, float [] furnitureNewElevation) { 1777 for (int i = 0; i < selectedFurniture.length; i++) { 1778 selectedFurniture [i].setElevation(furnitureNewElevation [i]); 1779 } 1780 } 1781 1782 /** 1783 * Returns the highest piece of furniture that includes the given <code>piece</code> 1784 * with a margin error of 5% of the smallest side length. 1785 * @since 4.4 1786 */ getHighestSurroundingPieceOfFurniture(HomePieceOfFurniture piece)1787 protected HomePieceOfFurniture getHighestSurroundingPieceOfFurniture(HomePieceOfFurniture piece) { 1788 List<HomePieceOfFurniture> ignoredFurniture = Collections.emptyList(); 1789 return getHighestSurroundingPieceOfFurniture(piece, ignoredFurniture); 1790 } 1791 getHighestSurroundingPieceOfFurniture(HomePieceOfFurniture piece, List<HomePieceOfFurniture> ignoredFurniture)1792 private HomePieceOfFurniture getHighestSurroundingPieceOfFurniture(HomePieceOfFurniture piece, 1793 List<HomePieceOfFurniture> ignoredFurniture) { 1794 float [][] piecePoints = piece.getPoints(); 1795 float margin = Math.min(piece.getWidthInPlan(), piece.getDepthInPlan()) * 0.05f; 1796 HomePieceOfFurniture highestSurroundingPiece = null; 1797 float highestElevation = Float.MIN_VALUE; 1798 for (HomePieceOfFurniture homePiece : getFurnitureInSameGroup(piece)) { 1799 if (homePiece != piece 1800 && !ignoredFurniture.contains(homePiece) 1801 && isPieceOfFurnitureVisibleAtSelectedLevel(homePiece) 1802 && homePiece.getDropOnTopElevation() >= 0) { 1803 boolean surroundingPieceContainsPiece = true; 1804 for (float [] point : piecePoints) { 1805 if (!homePiece.containsPoint(point [0], point [1], margin)) { 1806 surroundingPieceContainsPiece = false; 1807 break; 1808 } 1809 } 1810 if (surroundingPieceContainsPiece) { 1811 float elevation = homePiece.getElevation() 1812 + homePiece.getHeightInPlan() * homePiece.getDropOnTopElevation(); 1813 if (elevation > highestElevation) { 1814 highestElevation = elevation; 1815 highestSurroundingPiece = homePiece; 1816 } 1817 } 1818 } 1819 } 1820 return highestSurroundingPiece; 1821 } 1822 1823 /** 1824 * Returns the furniture list of the given <code>piece</code> which belongs to same group 1825 * or home furniture if it doesn't belong to home furniture. 1826 * @since 5.0 1827 */ getFurnitureInSameGroup(HomePieceOfFurniture piece)1828 protected List<HomePieceOfFurniture> getFurnitureInSameGroup(HomePieceOfFurniture piece) { 1829 List<HomePieceOfFurniture> homeFurniture = this.home.getFurniture(); 1830 List<HomePieceOfFurniture> furnitureInSameGroup = getFurnitureInSameGroup(piece, homeFurniture); 1831 if (furnitureInSameGroup != null) { 1832 return furnitureInSameGroup; 1833 } else { 1834 return homeFurniture; 1835 } 1836 } 1837 getFurnitureInSameGroup(HomePieceOfFurniture piece, List<HomePieceOfFurniture> furniture)1838 private static List<HomePieceOfFurniture> getFurnitureInSameGroup(HomePieceOfFurniture piece, List<HomePieceOfFurniture> furniture) { 1839 for (HomePieceOfFurniture piece2 : furniture) { 1840 if (piece2 == piece) { 1841 return furniture; 1842 } else if (piece2 instanceof HomeFurnitureGroup) { 1843 List<HomePieceOfFurniture> siblingFurniture = getFurnitureInSameGroup(piece, ((HomeFurnitureGroup)piece2).getFurniture()); 1844 if (siblingFurniture != null) { 1845 return siblingFurniture; 1846 } 1847 } 1848 } 1849 return null; 1850 } 1851 1852 /** 1853 * Returns <code>true</code> if the given piece is viewable and 1854 * its height and elevation make it viewable at the selected level in home. 1855 * @since 4.4 1856 */ isPieceOfFurnitureVisibleAtSelectedLevel(HomePieceOfFurniture piece)1857 protected boolean isPieceOfFurnitureVisibleAtSelectedLevel(HomePieceOfFurniture piece) { 1858 Level selectedLevel = this.home.getSelectedLevel(); 1859 return piece.isVisible() 1860 && (piece.getLevel() == null 1861 || piece.getLevel().isViewable()) 1862 && (piece.getLevel() == selectedLevel 1863 || piece.isAtLevel(selectedLevel)); 1864 } 1865 1866 /** 1867 * Controls the change of value of a visual property in home. 1868 * @deprecated {@link #setVisualProperty(String, Object) setVisualProperty} should be replaced by a call to 1869 * {@link #setHomeProperty(String, String)} to ensure the property can be easily saved and read. 1870 * @since 5.0 1871 */ setVisualProperty(String propertyName, Object propertyValue)1872 public void setVisualProperty(String propertyName, 1873 Object propertyValue) { 1874 this.home.setVisualProperty(propertyName, propertyValue); 1875 } 1876 1877 /** 1878 * Controls the change of value of a property in home. 1879 * @since 5.2 1880 */ setHomeProperty(String propertyName, String propertyValue)1881 public void setHomeProperty(String propertyName, 1882 String propertyValue) { 1883 this.home.setProperty(propertyName, propertyValue); 1884 } 1885 } 1886