2
* HomeController.java 15 mai 2006
4
* Sweet Home 3D, Copyright (c) 2006 Emmanuel PUYBARET / eTeks <info@eteks.com>
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.
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.
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
20
package com.eteks.sweethome3d.viewcontroller;
22
import java.beans.PropertyChangeEvent;
23
import java.beans.PropertyChangeListener;
24
import java.lang.ref.WeakReference;
25
import java.text.DateFormat;
26
import java.util.ArrayList;
27
import java.util.Arrays;
28
import java.util.Collections;
29
import java.util.Date;
30
import java.util.HashSet;
31
import java.util.Iterator;
32
import java.util.List;
34
import java.util.concurrent.Callable;
36
import javax.swing.event.UndoableEditEvent;
37
import javax.swing.event.UndoableEditListener;
38
import javax.swing.undo.AbstractUndoableEdit;
39
import javax.swing.undo.CannotRedoException;
40
import javax.swing.undo.CannotUndoException;
41
import javax.swing.undo.CompoundEdit;
42
import javax.swing.undo.UndoManager;
43
import javax.swing.undo.UndoableEdit;
44
import javax.swing.undo.UndoableEditSupport;
46
import com.eteks.sweethome3d.model.AspectRatio;
47
import com.eteks.sweethome3d.model.BackgroundImage;
48
import com.eteks.sweethome3d.model.Camera;
49
import com.eteks.sweethome3d.model.CatalogPieceOfFurniture;
50
import com.eteks.sweethome3d.model.CatalogTexture;
51
import com.eteks.sweethome3d.model.CollectionEvent;
52
import com.eteks.sweethome3d.model.CollectionListener;
53
import com.eteks.sweethome3d.model.Compass;
54
import com.eteks.sweethome3d.model.DimensionLine;
55
import com.eteks.sweethome3d.model.Elevatable;
56
import com.eteks.sweethome3d.model.FurnitureCatalog;
57
import com.eteks.sweethome3d.model.Home;
58
import com.eteks.sweethome3d.model.HomeApplication;
59
import com.eteks.sweethome3d.model.HomeDoorOrWindow;
60
import com.eteks.sweethome3d.model.HomeEnvironment;
61
import com.eteks.sweethome3d.model.HomeFurnitureGroup;
62
import com.eteks.sweethome3d.model.HomePieceOfFurniture;
63
import com.eteks.sweethome3d.model.HomeRecorder;
64
import com.eteks.sweethome3d.model.InterruptedRecorderException;
65
import com.eteks.sweethome3d.model.Label;
66
import com.eteks.sweethome3d.model.Level;
67
import com.eteks.sweethome3d.model.RecorderException;
68
import com.eteks.sweethome3d.model.Room;
69
import com.eteks.sweethome3d.model.Selectable;
70
import com.eteks.sweethome3d.model.SelectionEvent;
71
import com.eteks.sweethome3d.model.SelectionListener;
72
import com.eteks.sweethome3d.model.TexturesCatalog;
73
import com.eteks.sweethome3d.model.UserPreferences;
74
import com.eteks.sweethome3d.model.Wall;
75
import com.eteks.sweethome3d.viewcontroller.PlanController.Mode;
78
* A MVC controller for the home view.
79
* @author Emmanuel Puybaret
81
public class HomeController implements Controller {
82
private final Home home;
83
private final UserPreferences preferences;
84
private final HomeApplication application;
85
private final ViewFactory viewFactory;
86
private final ContentManager contentManager;
87
private final UndoableEditSupport undoSupport;
88
private final UndoManager undoManager;
89
private HomeView homeView;
90
private FurnitureCatalogController furnitureCatalogController;
91
private FurnitureController furnitureController;
92
private PlanController planController;
93
private HomeController3D homeController3D;
94
private static HelpController helpController; // Only one help controller
95
private int saveUndoLevel;
96
private boolean notUndoableModifications;
97
private View focusedView;
100
* Creates the controller of home view.
101
* @param home the home edited by this controller and its view.
102
* @param application the instance of current application.
103
* @param viewFactory a factory able to create views.
104
* @param contentManager the content manager of the application.
106
public HomeController(Home home,
107
HomeApplication application,
108
ViewFactory viewFactory,
109
ContentManager contentManager) {
110
this(home, application.getUserPreferences(), viewFactory,
111
contentManager, application);
115
* Creates the controller of home view.
116
* @param home the home edited by this controller and its view.
117
* @param application the instance of current application.
118
* @param viewFactory a factory able to create views.
120
public HomeController(Home home,
121
HomeApplication application,
122
ViewFactory viewFactory) {
123
this(home, application.getUserPreferences(), viewFactory, null, application);
127
* Creates the controller of home view.
128
* @param home the home edited by this controller and its view.
129
* @param preferences the preferences of the application.
130
* @param viewFactory a factory able to create views.
132
public HomeController(Home home,
133
UserPreferences preferences,
134
ViewFactory viewFactory) {
135
this(home, preferences, viewFactory, null, null);
139
* Creates the controller of home view.
140
* @param home the home edited by this controller and its view.
141
* @param preferences the preferences of the application.
142
* @param viewFactory a factory able to create views.
143
* @param contentManager the content manager of the application.
145
public HomeController(Home home,
146
UserPreferences preferences,
147
ViewFactory viewFactory,
148
ContentManager contentManager) {
149
this(home, preferences, viewFactory, contentManager, null);
152
private HomeController(final Home home,
153
final UserPreferences preferences,
154
ViewFactory viewFactory,
155
ContentManager contentManager,
156
HomeApplication application) {
158
this.preferences = preferences;
159
this.viewFactory = viewFactory;
160
this.contentManager = contentManager;
161
this.application = application;
162
this.undoSupport = new UndoableEditSupport() {
164
protected void _postEdit(UndoableEdit edit) {
165
// Ignore not significant compound edit
166
if (!(edit instanceof CompoundEdit)
167
|| edit.isSignificant()) {
168
super._postEdit(edit);
172
this.undoManager = new UndoManager();
173
this.undoSupport.addUndoableEditListener(this.undoManager);
175
// Update recent homes list
176
if (home.getName() != null) {
177
List<String> recentHomes = new ArrayList<String>(this.preferences.getRecentHomes());
178
recentHomes.remove(home.getName());
179
recentHomes.add(0, home.getName());
180
updateUserPreferencesRecentHomes(recentHomes);
182
// If home version is more recent than current version
183
if (home.getVersion() > Home.CURRENT_VERSION) {
184
// Warn the user that view will display a home created with a more recent version
185
getView().invokeLater(new Runnable() {
187
String message = preferences.getLocalizedString(HomeController.class,
188
"moreRecentVersionHome", home.getName());
189
getView().showMessage(message);
197
* Enables actions at controller instantiation.
199
private void enableDefaultActions(HomeView homeView) {
200
boolean applicationExists = this.application != null;
202
homeView.setEnabled(HomeView.ActionType.NEW_HOME, applicationExists);
203
homeView.setEnabled(HomeView.ActionType.OPEN, applicationExists);
204
homeView.setEnabled(HomeView.ActionType.DELETE_RECENT_HOMES,
205
applicationExists && !this.preferences.getRecentHomes().isEmpty());
206
homeView.setEnabled(HomeView.ActionType.CLOSE, applicationExists);
207
homeView.setEnabled(HomeView.ActionType.SAVE, applicationExists);
208
homeView.setEnabled(HomeView.ActionType.SAVE_AS, applicationExists);
209
homeView.setEnabled(HomeView.ActionType.SAVE_AND_COMPRESS, applicationExists);
210
homeView.setEnabled(HomeView.ActionType.PAGE_SETUP, true);
211
homeView.setEnabled(HomeView.ActionType.PRINT_PREVIEW, true);
212
homeView.setEnabled(HomeView.ActionType.PRINT, true);
213
homeView.setEnabled(HomeView.ActionType.PRINT_TO_PDF, true);
214
homeView.setEnabled(HomeView.ActionType.PREFERENCES, true);
215
homeView.setEnabled(HomeView.ActionType.EXIT, applicationExists);
216
homeView.setEnabled(HomeView.ActionType.IMPORT_FURNITURE, true);
217
homeView.setEnabled(HomeView.ActionType.IMPORT_FURNITURE_LIBRARY, true);
218
homeView.setEnabled(HomeView.ActionType.IMPORT_TEXTURES_LIBRARY, true);
219
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_CATALOG_ID, true);
220
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_NAME, true);
221
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_WIDTH, true);
222
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_HEIGHT, true);
223
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_DEPTH, true);
224
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_X, true);
225
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_Y, true);
226
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_ELEVATION, true);
227
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_ANGLE, true);
228
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_LEVEL, true);
229
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_COLOR, true);
230
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_TEXTURE, true);
231
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_MOVABILITY, true);
232
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_TYPE, true);
233
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_VISIBILITY, true);
234
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_PRICE, true);
235
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_VALUE_ADDED_TAX_PERCENTAGE, true);
236
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_VALUE_ADDED_TAX, true);
237
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_PRICE_VALUE_ADDED_TAX_INCLUDED, true);
238
homeView.setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_DESCENDING_ORDER,
239
this.home.getFurnitureSortedProperty() != null);
240
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_CATALOG_ID, true);
241
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_NAME, true);
242
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_WIDTH, true);
243
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_DEPTH, true);
244
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_HEIGHT, true);
245
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_X, true);
246
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_Y, true);
247
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_ELEVATION, true);
248
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_ANGLE, true);
249
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_LEVEL, true);
250
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_COLOR, true);
251
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_TEXTURE, true);
252
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_MOVABLE, true);
253
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_DOOR_OR_WINDOW, true);
254
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_VISIBLE, true);
255
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_PRICE, true);
256
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_VALUE_ADDED_TAX_PERCENTAGE, true);
257
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_VALUE_ADDED_TAX, true);
258
homeView.setEnabled(HomeView.ActionType.DISPLAY_HOME_FURNITURE_PRICE_VALUE_ADDED_TAX_INCLUDED, true);
259
homeView.setEnabled(HomeView.ActionType.SELECT, true);
260
homeView.setEnabled(HomeView.ActionType.PAN, true);
261
homeView.setEnabled(HomeView.ActionType.CREATE_WALLS, true);
262
homeView.setEnabled(HomeView.ActionType.CREATE_ROOMS, true);
263
homeView.setEnabled(HomeView.ActionType.CREATE_DIMENSION_LINES, true);
264
homeView.setEnabled(HomeView.ActionType.CREATE_LABELS, true);
265
homeView.setEnabled(HomeView.ActionType.LOCK_BASE_PLAN, true);
266
homeView.setEnabled(HomeView.ActionType.UNLOCK_BASE_PLAN, true);
267
homeView.setEnabled(HomeView.ActionType.MODIFY_COMPASS, true);
268
Level selectedLevel = this.home.getSelectedLevel();
269
enableBackgroungImageActions(homeView, selectedLevel != null
270
? selectedLevel.getBackgroundImage()
271
: this.home.getBackgroundImage());
272
homeView.setEnabled(HomeView.ActionType.ADD_LEVEL, true);
273
List<Level> levels = this.home.getLevels();
274
boolean homeContainsOneSelectedLevel = levels.size() > 1 && selectedLevel != null;
275
homeView.setEnabled(HomeView.ActionType.MODIFY_LEVEL, homeContainsOneSelectedLevel);
276
homeView.setEnabled(HomeView.ActionType.DELETE_LEVEL, homeContainsOneSelectedLevel);
277
homeView.setEnabled(HomeView.ActionType.ZOOM_IN, true);
278
homeView.setEnabled(HomeView.ActionType.ZOOM_OUT, true);
279
homeView.setEnabled(HomeView.ActionType.EXPORT_TO_SVG, true);
280
homeView.setEnabled(HomeView.ActionType.VIEW_FROM_TOP, true);
281
homeView.setEnabled(HomeView.ActionType.VIEW_FROM_OBSERVER, true);
282
homeView.setEnabled(HomeView.ActionType.MODIFY_OBSERVER, this.home.getCamera() == this.home.getObserverCamera());
283
homeView.setEnabled(HomeView.ActionType.STORE_POINT_OF_VIEW, true);
284
homeView.setEnabled(HomeView.ActionType.DISPLAY_ALL_LEVELS, levels.size() > 1);
285
homeView.setEnabled(HomeView.ActionType.DISPLAY_SELECTED_LEVEL, levels.size() > 1);
286
homeView.setEnabled(HomeView.ActionType.DETACH_3D_VIEW, true);
287
homeView.setEnabled(HomeView.ActionType.ATTACH_3D_VIEW, true);
288
homeView.setEnabled(HomeView.ActionType.VIEW_FROM_OBSERVER, true);
289
homeView.setEnabled(HomeView.ActionType.MODIFY_3D_ATTRIBUTES, true);
290
homeView.setEnabled(HomeView.ActionType.CREATE_PHOTO, true);
291
homeView.setEnabled(HomeView.ActionType.CREATE_VIDEO, true);
292
homeView.setEnabled(HomeView.ActionType.EXPORT_TO_OBJ, true);
293
homeView.setEnabled(HomeView.ActionType.HELP, true);
294
homeView.setEnabled(HomeView.ActionType.ABOUT, true);
295
homeView.setTransferEnabled(true);
299
* Returns the view associated with this controller.
301
public HomeView getView() {
302
if (this.homeView == null) {
303
this.homeView = this.viewFactory.createHomeView(this.home, this.preferences, this);
304
enableDefaultActions(this.homeView);
307
return this.homeView;
311
* Returns the content manager of this controller.
313
public ContentManager getContentManager() {
314
return this.contentManager;
318
* Returns the furniture catalog controller managed by this controller.
320
public FurnitureCatalogController getFurnitureCatalogController() {
321
// Create sub controller lazily only once it's needed
322
if (this.furnitureCatalogController == null) {
323
this.furnitureCatalogController = new FurnitureCatalogController(
324
this.preferences.getFurnitureCatalog(), this.preferences, this.viewFactory, this.contentManager);
326
return this.furnitureCatalogController;
330
* Returns the furniture controller managed by this controller.
332
public FurnitureController getFurnitureController() {
333
// Create sub controller lazily only once it's needed
334
if (this.furnitureController == null) {
335
this.furnitureController = new FurnitureController(
336
this.home, this.preferences, this.viewFactory, this.contentManager, getUndoableEditSupport());
338
return this.furnitureController;
342
* Returns the controller of home plan.
344
public PlanController getPlanController() {
345
// Create sub controller lazily only once it's needed
346
if (this.planController == null) {
347
this.planController = new PlanController(
348
this.home, this.preferences, this.viewFactory, this.contentManager, getUndoableEditSupport());
350
return this.planController;
354
* Returns the controller of home 3D view.
356
public HomeController3D getHomeController3D() {
357
// Create sub controller lazily only once it's needed
358
if (this.homeController3D == null) {
359
this.homeController3D = new HomeController3D(
360
this.home, this.preferences, this.viewFactory, this.contentManager, getUndoableEditSupport());
362
return this.homeController3D;
366
* Returns the undoable edit support managed by this controller.
368
protected final UndoableEditSupport getUndoableEditSupport() {
369
return this.undoSupport;
373
* Adds listeners that updates the enabled / disabled state of actions.
375
private void addListeners() {
376
// Save preferences when they change
377
this.preferences.getFurnitureCatalog().addFurnitureListener(
378
new FurnitureCatalogChangeListener(this));
379
this.preferences.getTexturesCatalog().addTexturesListener(
380
new TexturesCatalogChangeListener(this));
381
UserPreferencesPropertiesChangeListener listener =
382
new UserPreferencesPropertiesChangeListener(this);
383
for (UserPreferences.Property property : UserPreferences.Property.values()) {
384
this.preferences.addPropertyChangeListener(property, listener);
387
addCatalogSelectionListener();
388
addHomeBackgroundImageListener();
389
addNotUndoableModificationListeners();
390
addHomeSelectionListener();
391
addFurnitureSortListener();
392
addUndoSupportListener();
393
addHomeItemsListener();
395
addPlanControllerListeners();
396
addLanguageListener();
400
* Super class of catalog listeners that writes preferences each time a piece of furniture or a texture
401
* is deleted or added in furniture or textures catalog.
403
private abstract static class UserPreferencesChangeListener {
404
// Stores the currently writing preferences
405
private static Set<UserPreferences> writingPreferences = new HashSet<UserPreferences>();
407
public void writePreferences(final HomeController controller) {
408
if (!writingPreferences.contains(controller.preferences)) {
409
writingPreferences.add(controller.preferences);
410
// Write preferences later once all catalog modifications are notified
411
controller.getView().invokeLater(new Runnable() {
414
controller.preferences.write();
415
writingPreferences.remove(controller.preferences);
416
} catch (RecorderException ex) {
417
controller.getView().showError(controller.preferences.getLocalizedString(
418
HomeController.class, "savePreferencesError"));
427
* Furniture catalog listener that writes preferences each time a piece of furniture
428
* is deleted or added in furniture catalog. This listener is bound to this controller
429
* with a weak reference to avoid strong link between catalog and this controller.
431
private static class FurnitureCatalogChangeListener extends UserPreferencesChangeListener
432
implements CollectionListener<CatalogPieceOfFurniture> {
433
private WeakReference<HomeController> homeController;
435
public FurnitureCatalogChangeListener(HomeController homeController) {
436
this.homeController = new WeakReference<HomeController>(homeController);
439
public void collectionChanged(CollectionEvent<CatalogPieceOfFurniture> ev) {
440
// If controller was garbage collected, remove this listener from catalog
441
final HomeController controller = this.homeController.get();
442
if (controller == null) {
443
((FurnitureCatalog)ev.getSource()).removeFurnitureListener(this);
445
writePreferences(controller);
451
* Textures catalog listener that writes preferences each time a texture
452
* is deleted or added in textures catalog. This listener is bound to this controller
453
* with a weak reference to avoid strong link between catalog and this controller.
455
private static class TexturesCatalogChangeListener extends UserPreferencesChangeListener
456
implements CollectionListener<CatalogTexture> {
457
private WeakReference<HomeController> homeController;
459
public TexturesCatalogChangeListener(HomeController homeController) {
460
this.homeController = new WeakReference<HomeController>(homeController);
463
public void collectionChanged(CollectionEvent<CatalogTexture> ev) {
464
// If controller was garbage collected, remove this listener from catalog
465
final HomeController controller = this.homeController.get();
466
if (controller == null) {
467
((TexturesCatalog)ev.getSource()).removeTexturesListener(this);
469
writePreferences(controller);
475
* Properties listener that writes preferences each time the value of one of its properties changes.
476
* This listener is bound to this controller with a weak reference to avoid strong link
477
* between catalog and this controller.
479
private static class UserPreferencesPropertiesChangeListener extends UserPreferencesChangeListener
480
implements PropertyChangeListener {
481
private WeakReference<HomeController> homeController;
483
public UserPreferencesPropertiesChangeListener(HomeController homeController) {
484
this.homeController = new WeakReference<HomeController>(homeController);
487
public void propertyChange(PropertyChangeEvent ev) {
488
// If controller was garbage collected, remove this listener from catalog
489
final HomeController controller = this.homeController.get();
490
if (controller == null) {
491
((UserPreferences)ev.getSource()).removePropertyChangeListener(
492
UserPreferences.Property.valueOf(ev.getPropertyName()), this);
494
writePreferences(controller);
500
* Adds a selection listener to catalog that enables / disables Add Furniture action.
502
private void addCatalogSelectionListener() {
503
getFurnitureCatalogController().addSelectionListener(new SelectionListener() {
504
public void selectionChanged(SelectionEvent ev) {
505
enableActionsBoundToSelection();
511
* Adds a property change listener to <code>preferences</code> to update
512
* undo and redo presentation names when preferred language changes.
514
private void addLanguageListener() {
515
this.preferences.addPropertyChangeListener(UserPreferences.Property.LANGUAGE,
516
new LanguageChangeListener(this));
520
* Preferences property listener bound to this component with a weak reference to avoid
521
* strong link between preferences and this component.
523
private static class LanguageChangeListener implements PropertyChangeListener {
524
private WeakReference<HomeController> homeController;
526
public LanguageChangeListener(HomeController homeController) {
527
this.homeController = new WeakReference<HomeController>(homeController);
530
public void propertyChange(PropertyChangeEvent ev) {
531
// If home pane was garbage collected, remove this listener from preferences
532
HomeController homeController = this.homeController.get();
533
if (homeController == null) {
534
((UserPreferences)ev.getSource()).removePropertyChangeListener(
535
UserPreferences.Property.LANGUAGE, this);
537
// Update undo and redo name
538
homeController.getView().setUndoRedoName(
539
homeController.undoManager.canUndo()
540
? homeController.undoManager.getUndoPresentationName()
542
homeController.undoManager.canRedo()
543
? homeController.undoManager.getRedoPresentationName()
550
* Adds a selection listener to home that enables / disables actions on selection.
552
private void addHomeSelectionListener() {
553
if (this.home != null) {
554
this.home.addSelectionListener(new SelectionListener() {
555
public void selectionChanged(SelectionEvent ev) {
556
enableActionsBoundToSelection();
563
* Adds a property change listener to home that enables / disables sort order action.
565
private void addFurnitureSortListener() {
566
if (this.home != null) {
567
this.home.addPropertyChangeListener(Home.Property.FURNITURE_SORTED_PROPERTY,
568
new PropertyChangeListener() {
569
public void propertyChange(PropertyChangeEvent ev) {
570
getView().setEnabled(HomeView.ActionType.SORT_HOME_FURNITURE_BY_DESCENDING_ORDER,
571
ev.getNewValue() != null);
578
* Adds a property change listener to home that enables / disables background image actions.
580
private void addHomeBackgroundImageListener() {
581
if (this.home != null) {
582
this.home.addPropertyChangeListener(Home.Property.BACKGROUND_IMAGE,
583
new PropertyChangeListener() {
584
public void propertyChange(PropertyChangeEvent ev) {
585
enableBackgroungImageActions(getView(), (BackgroundImage)ev.getNewValue());
592
* Enables background image actions.
594
private void enableBackgroungImageActions(HomeView homeView, BackgroundImage backgroundImage) {
595
boolean homeHasBackgroundImage = backgroundImage != null;
596
getView().setEnabled(HomeView.ActionType.IMPORT_BACKGROUND_IMAGE, !homeHasBackgroundImage);
597
getView().setEnabled(HomeView.ActionType.MODIFY_BACKGROUND_IMAGE, homeHasBackgroundImage);
598
getView().setEnabled(HomeView.ActionType.HIDE_BACKGROUND_IMAGE,
599
homeHasBackgroundImage && backgroundImage.isVisible());
600
getView().setEnabled(HomeView.ActionType.SHOW_BACKGROUND_IMAGE,
601
homeHasBackgroundImage && !backgroundImage.isVisible());
602
getView().setEnabled(HomeView.ActionType.DELETE_BACKGROUND_IMAGE, homeHasBackgroundImage);
606
* Adds listeners to track property changes that are not undoable.
608
private void addNotUndoableModificationListeners() {
609
if (this.home != null) {
610
final PropertyChangeListener notUndoableModificationListener = new PropertyChangeListener() {
611
public void propertyChange(PropertyChangeEvent ev) {
612
notUndoableModifications = true;
613
home.setModified(true);
616
this.home.addPropertyChangeListener(Home.Property.STORED_CAMERAS, notUndoableModificationListener);
617
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.OBSERVER_CAMERA_ELEVATION_ADJUSTED, notUndoableModificationListener);
618
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.VIDEO_WIDTH, notUndoableModificationListener);
619
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.VIDEO_ASPECT_RATIO, notUndoableModificationListener);
620
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.VIDEO_FRAME_RATE, notUndoableModificationListener);
621
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.VIDEO_QUALITY, notUndoableModificationListener);
622
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.VIDEO_CAMERA_PATH, notUndoableModificationListener);
623
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.CEILING_LIGHT_COLOR, notUndoableModificationListener);
624
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.PHOTO_QUALITY, notUndoableModificationListener);
625
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.PHOTO_ASPECT_RATIO, notUndoableModificationListener);
626
PropertyChangeListener photoSizeModificationListener = new PropertyChangeListener() {
627
public void propertyChange(PropertyChangeEvent ev) {
628
if (home.getEnvironment().getPhotoAspectRatio() != AspectRatio.VIEW_3D_RATIO) {
629
// Ignore photo size modification with 3D view aspect ratio since it can change for various reasons
630
notUndoableModificationListener.propertyChange(ev);
634
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.PHOTO_WIDTH, photoSizeModificationListener);
635
this.home.getEnvironment().addPropertyChangeListener(HomeEnvironment.Property.PHOTO_HEIGHT, photoSizeModificationListener);
636
PropertyChangeListener timeOrLensModificationListener = new PropertyChangeListener() {
637
public void propertyChange(PropertyChangeEvent ev) {
638
if (ev.getPropertyName().equals(Camera.Property.TIME.name())
639
|| ev.getPropertyName().equals(Camera.Property.LENS.name())) {
640
notUndoableModificationListener.propertyChange(ev);
644
this.home.getObserverCamera().addPropertyChangeListener(timeOrLensModificationListener);
645
this.home.getTopCamera().addPropertyChangeListener(timeOrLensModificationListener);
650
* Enables or disables action bound to selection.
651
* This method will be called when selection in plan or in catalog changes and when
652
* focused component or modification state in plan changes.
654
protected void enableActionsBoundToSelection() {
655
boolean modificationState = getPlanController().isModificationState();
657
// Search if catalog selection contains at least one piece
658
List<CatalogPieceOfFurniture> catalogSelectedItems =
659
getFurnitureCatalogController().getSelectedFurniture();
660
boolean catalogSelectionContainsFurniture = !catalogSelectedItems.isEmpty();
661
boolean catalogSelectionContainsOneModifiablePiece = catalogSelectedItems.size() == 1
662
&& catalogSelectedItems.get(0).isModifiable();
664
// Search if home selection contains at least one piece, one wall or one dimension line
665
List<Selectable> selectedItems = this.home.getSelectedItems();
666
boolean homeSelectionContainsDeletableItems = false;
667
boolean homeSelectionContainsFurniture = false;
668
boolean homeSelectionContainsDeletableFurniture = false;
669
boolean homeSelectionContainsOneCopiableItemOrMore = false;
670
boolean homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore = false;
671
boolean homeSelectionContainsThreeMovablePiecesOfFurnitureOrMore = false;
672
boolean homeSelectionContainsFurnitureGroup = false;
673
boolean homeSelectionContainsWalls = false;
674
boolean homeSelectionContainsRooms = false;
675
boolean homeSelectionContainsOneWall = false;
676
boolean homeSelectionContainsOneLabel = false;
677
boolean homeSelectionContainsItemsWithText = false;
678
boolean homeSelectionContainsCompass = false;
679
FurnitureController furnitureController = getFurnitureController();
680
if (!modificationState) {
681
for (Selectable item : selectedItems) {
682
if (getPlanController().isItemDeletable(item)) {
683
homeSelectionContainsDeletableItems = true;
687
List<HomePieceOfFurniture> selectedFurniture = Home.getFurnitureSubList(selectedItems);
688
homeSelectionContainsFurniture = !selectedFurniture.isEmpty();
689
for (HomePieceOfFurniture piece : selectedFurniture) {
690
if (furnitureController.isPieceOfFurnitureDeletable(piece)) {
691
homeSelectionContainsDeletableFurniture = true;
695
for (HomePieceOfFurniture piece : selectedFurniture) {
696
if (piece instanceof HomeFurnitureGroup) {
697
homeSelectionContainsFurnitureGroup = true;
701
int movablePiecesOfFurnitureCount = 0;
702
for (HomePieceOfFurniture piece : selectedFurniture) {
703
if (furnitureController.isPieceOfFurnitureMovable(piece)) {
704
movablePiecesOfFurnitureCount++;
705
if (movablePiecesOfFurnitureCount >= 2) {
706
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore = true;
708
if (movablePiecesOfFurnitureCount >= 3) {
709
homeSelectionContainsThreeMovablePiecesOfFurnitureOrMore = true;
714
List<Wall> selectedWalls = Home.getWallsSubList(selectedItems);
715
homeSelectionContainsWalls = !selectedWalls.isEmpty();
716
homeSelectionContainsOneWall = selectedWalls.size() == 1;
717
homeSelectionContainsRooms = !Home.getRoomsSubList(selectedItems).isEmpty();
718
boolean homeSelectionContainsDimensionLines = !Home.getDimensionLinesSubList(selectedItems).isEmpty();
719
final List<Label> selectedLabels = Home.getLabelsSubList(selectedItems);
720
boolean homeSelectionContainsLabels = !selectedLabels.isEmpty();
721
homeSelectionContainsCompass = selectedItems.contains(this.home.getCompass());
722
homeSelectionContainsOneLabel = selectedLabels.size() == 1;
723
homeSelectionContainsOneCopiableItemOrMore =
724
homeSelectionContainsFurniture || homeSelectionContainsWalls
725
|| homeSelectionContainsRooms || homeSelectionContainsDimensionLines
726
|| homeSelectionContainsLabels || homeSelectionContainsCompass;
727
homeSelectionContainsItemsWithText =
728
homeSelectionContainsFurniture || homeSelectionContainsRooms
729
|| homeSelectionContainsDimensionLines || homeSelectionContainsLabels;
732
HomeView view = getView();
733
if (this.focusedView == getFurnitureCatalogController().getView()) {
734
view.setEnabled(HomeView.ActionType.COPY,
735
!modificationState && catalogSelectionContainsFurniture);
736
view.setEnabled(HomeView.ActionType.CUT, false);
737
view.setEnabled(HomeView.ActionType.DELETE, false);
738
for (CatalogPieceOfFurniture piece : catalogSelectedItems) {
739
if (piece.isModifiable()) {
740
// Only modifiable catalog furniture may be deleted
741
view.setEnabled(HomeView.ActionType.DELETE, true);
745
} else if (this.focusedView == furnitureController.getView()) {
746
view.setEnabled(HomeView.ActionType.COPY, homeSelectionContainsFurniture);
747
view.setEnabled(HomeView.ActionType.CUT, homeSelectionContainsDeletableFurniture);
748
view.setEnabled(HomeView.ActionType.DELETE, homeSelectionContainsDeletableFurniture);
749
} else if (this.focusedView == getPlanController().getView()) {
750
view.setEnabled(HomeView.ActionType.COPY, homeSelectionContainsOneCopiableItemOrMore);
751
view.setEnabled(HomeView.ActionType.CUT, homeSelectionContainsDeletableItems);
752
view.setEnabled(HomeView.ActionType.DELETE, homeSelectionContainsDeletableItems);
754
view.setEnabled(HomeView.ActionType.COPY, false);
755
view.setEnabled(HomeView.ActionType.CUT, false);
756
view.setEnabled(HomeView.ActionType.DELETE, false);
759
view.setEnabled(HomeView.ActionType.ADD_HOME_FURNITURE, catalogSelectionContainsFurniture);
760
// In creation mode all actions bound to selection are disabled
761
view.setEnabled(HomeView.ActionType.DELETE_HOME_FURNITURE,
762
homeSelectionContainsDeletableFurniture);
763
view.setEnabled(HomeView.ActionType.DELETE_SELECTION,
764
(catalogSelectionContainsFurniture
765
&& this.focusedView == getFurnitureCatalogController().getView())
766
|| (homeSelectionContainsDeletableItems
767
&& (this.focusedView == furnitureController.getView()
768
|| this.focusedView == getPlanController().getView()
769
|| this.focusedView == getHomeController3D().getView())));
770
view.setEnabled(HomeView.ActionType.MODIFY_FURNITURE,
771
(catalogSelectionContainsOneModifiablePiece
772
&& this.focusedView == getFurnitureCatalogController().getView())
773
|| (homeSelectionContainsFurniture
774
&& (this.focusedView == furnitureController.getView()
775
|| this.focusedView == getPlanController().getView()
776
|| this.focusedView == getHomeController3D().getView())));
777
view.setEnabled(HomeView.ActionType.MODIFY_WALL,
778
homeSelectionContainsWalls);
779
view.setEnabled(HomeView.ActionType.REVERSE_WALL_DIRECTION,
780
homeSelectionContainsWalls);
781
view.setEnabled(HomeView.ActionType.SPLIT_WALL,
782
homeSelectionContainsOneWall);
783
view.setEnabled(HomeView.ActionType.MODIFY_ROOM,
784
homeSelectionContainsRooms);
785
view.setEnabled(HomeView.ActionType.MODIFY_LABEL,
786
homeSelectionContainsOneLabel);
787
view.setEnabled(HomeView.ActionType.TOGGLE_BOLD_STYLE,
788
homeSelectionContainsItemsWithText);
789
view.setEnabled(HomeView.ActionType.TOGGLE_ITALIC_STYLE,
790
homeSelectionContainsItemsWithText);
791
view.setEnabled(HomeView.ActionType.INCREASE_TEXT_SIZE,
792
homeSelectionContainsItemsWithText);
793
view.setEnabled(HomeView.ActionType.DECREASE_TEXT_SIZE,
794
homeSelectionContainsItemsWithText);
795
view.setEnabled(HomeView.ActionType.ALIGN_FURNITURE_ON_TOP,
796
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
797
view.setEnabled(HomeView.ActionType.ALIGN_FURNITURE_ON_BOTTOM,
798
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
799
view.setEnabled(HomeView.ActionType.ALIGN_FURNITURE_ON_LEFT,
800
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
801
view.setEnabled(HomeView.ActionType.ALIGN_FURNITURE_ON_RIGHT,
802
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
803
view.setEnabled(HomeView.ActionType.ALIGN_FURNITURE_ON_FRONT_SIDE,
804
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
805
view.setEnabled(HomeView.ActionType.ALIGN_FURNITURE_ON_BACK_SIDE,
806
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
807
view.setEnabled(HomeView.ActionType.ALIGN_FURNITURE_ON_LEFT_SIDE,
808
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
809
view.setEnabled(HomeView.ActionType.ALIGN_FURNITURE_ON_RIGHT_SIDE,
810
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
811
view.setEnabled(HomeView.ActionType.ALIGN_FURNITURE_SIDE_BY_SIDE,
812
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
813
view.setEnabled(HomeView.ActionType.DISTRIBUTE_FURNITURE_HORIZONTALLY,
814
homeSelectionContainsThreeMovablePiecesOfFurnitureOrMore);
815
view.setEnabled(HomeView.ActionType.DISTRIBUTE_FURNITURE_VERTICALLY,
816
homeSelectionContainsThreeMovablePiecesOfFurnitureOrMore);
817
view.setEnabled(HomeView.ActionType.GROUP_FURNITURE,
818
homeSelectionContainsTwoMovablePiecesOfFurnitureOrMore);
819
view.setEnabled(HomeView.ActionType.UNGROUP_FURNITURE,
820
homeSelectionContainsFurnitureGroup);
824
* Enables clipboard paste action if clipboard isn't empty.
826
public void enablePasteAction() {
827
HomeView view = getView();
828
if (this.focusedView == getFurnitureController().getView()
829
|| this.focusedView == getPlanController().getView()) {
830
view.setEnabled(HomeView.ActionType.PASTE,
831
!getPlanController().isModificationState() && !view.isClipboardEmpty());
833
view.setEnabled(HomeView.ActionType.PASTE, false);
838
* Enables select all action if home isn't empty.
840
protected void enableSelectAllAction() {
841
HomeView view = getView();
842
boolean modificationState = getPlanController().isModificationState();
843
if (this.focusedView == getFurnitureController().getView()) {
844
view.setEnabled(HomeView.ActionType.SELECT_ALL,
846
&& this.home.getFurniture().size() > 0);
847
} else if (this.focusedView == getPlanController().getView()
848
|| this.focusedView == getHomeController3D().getView()) {
849
boolean homeContainsOneSelectableItemOrMore = !this.home.isEmpty()
850
|| this.home.getCompass().isVisible();
851
view.setEnabled(HomeView.ActionType.SELECT_ALL,
852
!modificationState && homeContainsOneSelectableItemOrMore);
854
view.setEnabled(HomeView.ActionType.SELECT_ALL, false);
859
* Enables zoom actions depending on current scale.
861
private void enableZoomActions() {
862
PlanController planController = getPlanController();
863
float scale = planController.getScale();
864
HomeView view = getView();
865
view.setEnabled(HomeView.ActionType.ZOOM_IN, scale < planController.getMaximumScale());
866
view.setEnabled(HomeView.ActionType.ZOOM_OUT, scale > planController.getMinimumScale());
870
* Adds undoable edit listener to undo support that enables Undo action.
872
private void addUndoSupportListener() {
873
getUndoableEditSupport().addUndoableEditListener(
874
new UndoableEditListener () {
875
public void undoableEditHappened(UndoableEditEvent ev) {
876
HomeView view = getView();
877
view.setEnabled(HomeView.ActionType.UNDO,
878
!getPlanController().isModificationState());
879
view.setEnabled(HomeView.ActionType.REDO, false);
880
view.setUndoRedoName(ev.getEdit().getUndoPresentationName(), null);
882
home.setModified(true);
885
home.addPropertyChangeListener(Home.Property.MODIFIED, new PropertyChangeListener() {
886
public void propertyChange(PropertyChangeEvent ev) {
887
if (!home.isModified()) {
888
// Change undo level and modification flag if home is set as unmodified
890
notUndoableModifications = false;
897
* Adds a furniture listener to home that enables / disables actions on furniture list change.
899
@SuppressWarnings("unchecked")
900
private void addHomeItemsListener() {
901
CollectionListener homeItemsListener =
902
new CollectionListener() {
903
public void collectionChanged(CollectionEvent ev) {
904
if (ev.getType() == CollectionEvent.Type.ADD
905
|| ev.getType() == CollectionEvent.Type.DELETE) {
906
enableSelectAllAction();
910
this.home.addFurnitureListener((CollectionListener<HomePieceOfFurniture>)homeItemsListener);
911
this.home.addWallsListener((CollectionListener<Wall>)homeItemsListener);
912
this.home.addRoomsListener((CollectionListener<Room>)homeItemsListener);
913
this.home.addDimensionLinesListener((CollectionListener<DimensionLine>)homeItemsListener);
914
this.home.addLabelsListener((CollectionListener<Label>)homeItemsListener);
915
this.home.getCompass().addPropertyChangeListener(new PropertyChangeListener() {
916
public void propertyChange(PropertyChangeEvent ev) {
917
if (Compass.Property.VISIBLE.equals(ev.getPropertyName())) {
918
enableSelectAllAction();
922
this.home.addPropertyChangeListener(Home.Property.CAMERA, new PropertyChangeListener() {
923
public void propertyChange(PropertyChangeEvent ev) {
924
getView().setEnabled(HomeView.ActionType.MODIFY_OBSERVER, home.getCamera() == home.getObserverCamera());
930
* Adds a property change listener to home to
931
* enable/disable authorized actions according to selected level.
933
private void addLevelListeners() {
934
final PropertyChangeListener selectedLevelListener = new PropertyChangeListener() {
935
public void propertyChange(PropertyChangeEvent ev) {
936
// Keep in selection only items that are at this level
937
List<Selectable> selectedItemsAtLevel = new ArrayList<Selectable>();
938
Level selectedLevel = home.getSelectedLevel();
939
for (Selectable item : home.getSelectedItems()) {
940
if (!(item instanceof Elevatable)
941
|| ((Elevatable)item).isAtLevel(selectedLevel)) {
942
selectedItemsAtLevel.add(item);
945
home.setSelectedItems(selectedItemsAtLevel);
946
enableBackgroungImageActions(getView(), selectedLevel == null
947
? home.getBackgroundImage()
948
: selectedLevel.getBackgroundImage());
949
List<Level> levels = home.getLevels();
950
boolean homeContainsOneSelectedLevel = levels.size() > 1 && selectedLevel != null;
951
getView().setEnabled(HomeView.ActionType.MODIFY_LEVEL, homeContainsOneSelectedLevel);
952
getView().setEnabled(HomeView.ActionType.DELETE_LEVEL, homeContainsOneSelectedLevel);
953
getView().setEnabled(HomeView.ActionType.DISPLAY_ALL_LEVELS, levels.size() > 1);
954
getView().setEnabled(HomeView.ActionType.DISPLAY_SELECTED_LEVEL, levels.size() > 1);
957
this.home.addPropertyChangeListener(Home.Property.SELECTED_LEVEL, selectedLevelListener);
958
final PropertyChangeListener backgroundImageChangeListener = new PropertyChangeListener() {
959
public void propertyChange(PropertyChangeEvent ev) {
960
if (Level.Property.BACKGROUND_IMAGE.name().equals(ev.getPropertyName())) {
961
enableBackgroungImageActions(getView(), (BackgroundImage)ev.getNewValue());
965
for (Level level : home.getLevels()) {
966
level.addPropertyChangeListener(backgroundImageChangeListener);
968
this.home.addLevelsListener(new CollectionListener<Level>() {
969
public void collectionChanged(CollectionEvent<Level> ev) {
970
switch (ev.getType()) {
972
home.setSelectedLevel(ev.getItem());
973
ev.getItem().addPropertyChangeListener(backgroundImageChangeListener);
976
selectedLevelListener.propertyChange(null);
977
ev.getItem().removePropertyChangeListener(backgroundImageChangeListener);
985
* Adds a property change listener to plan controller to
986
* enable/disable authorized actions according to its modification state and the plan scale.
988
private void addPlanControllerListeners() {
989
getPlanController().addPropertyChangeListener(PlanController.Property.MODIFICATION_STATE,
990
new PropertyChangeListener() {
991
public void propertyChange(PropertyChangeEvent ev) {
992
enableActionsBoundToSelection();
993
enableSelectAllAction();
994
HomeView view = getView();
995
if (getPlanController().isModificationState()) {
996
view.setEnabled(HomeView.ActionType.PASTE, false);
997
view.setEnabled(HomeView.ActionType.UNDO, false);
998
view.setEnabled(HomeView.ActionType.REDO, false);
1000
enablePasteAction();
1001
view.setEnabled(HomeView.ActionType.UNDO, undoManager.canUndo());
1002
view.setEnabled(HomeView.ActionType.REDO, undoManager.canRedo());
1006
getPlanController().addPropertyChangeListener(PlanController.Property.SCALE,
1007
new PropertyChangeListener() {
1008
public void propertyChange(PropertyChangeEvent ev) {
1009
enableZoomActions();
1015
* Adds the selected furniture in catalog to home and selects it.
1017
public void addHomeFurniture() {
1018
// Use automatically selection mode
1019
getPlanController().setMode(PlanController.Mode.SELECTION);
1020
List<CatalogPieceOfFurniture> selectedFurniture =
1021
getFurnitureCatalogController().getSelectedFurniture();
1022
if (!selectedFurniture.isEmpty()) {
1023
List<HomePieceOfFurniture> newFurniture =
1024
new ArrayList<HomePieceOfFurniture>();
1025
for (CatalogPieceOfFurniture piece : selectedFurniture) {
1026
HomePieceOfFurniture homePiece = getFurnitureController().createHomePieceOfFurniture(piece);
1027
// If magnetism is enabled, adjust piece size and elevation
1028
if (this.preferences.isMagnetismEnabled()) {
1029
if (homePiece.isResizable()) {
1030
homePiece.setWidth(this.preferences.getLengthUnit().getMagnetizedLength(homePiece.getWidth(), 0.1f));
1031
homePiece.setDepth(this.preferences.getLengthUnit().getMagnetizedLength(homePiece.getDepth(), 0.1f));
1032
homePiece.setHeight(this.preferences.getLengthUnit().getMagnetizedLength(homePiece.getHeight(), 0.1f));
1034
homePiece.setElevation(this.preferences.getLengthUnit().getMagnetizedLength(homePiece.getElevation(), 0.1f));
1036
newFurniture.add(homePiece);
1038
// Add newFurniture to home with furnitureController
1039
getFurnitureController().addFurniture(newFurniture);
1044
* Modifies the selected furniture of the focused view.
1046
public void modifySelectedFurniture() {
1047
if (this.focusedView == getFurnitureCatalogController().getView()) {
1048
getFurnitureCatalogController().modifySelectedFurniture();
1049
} else if (this.focusedView == getFurnitureController().getView()
1050
|| this.focusedView == getPlanController().getView()
1051
|| this.focusedView == getHomeController3D().getView()) {
1052
getFurnitureController().modifySelectedFurniture();
1057
* Imports a language library chosen by the user.
1059
public void importLanguageLibrary() {
1060
getView().invokeLater(new Runnable() {
1062
final String languageLibraryName = getView().showImportLanguageLibraryDialog();
1063
if (languageLibraryName != null) {
1064
importLanguageLibrary(languageLibraryName);
1071
* Imports a given language library.
1073
public void importLanguageLibrary(String languageLibraryName) {
1075
if (!this.preferences.languageLibraryExists(languageLibraryName)
1076
|| getView().confirmReplaceLanguageLibrary(languageLibraryName)) {
1077
this.preferences.addLanguageLibrary(languageLibraryName);
1079
} catch (RecorderException ex) {
1080
String message = this.preferences.getLocalizedString(HomeController.class,
1081
"importLanguageLibraryError", languageLibraryName);
1082
getView().showError(message);
1087
* Imports furniture to the catalog or home depending on the focused view.
1089
public void importFurniture() {
1090
// Always use selection mode after an import furniture operation
1091
getPlanController().setMode(PlanController.Mode.SELECTION);
1092
if (this.focusedView == getFurnitureCatalogController().getView()) {
1093
getFurnitureCatalogController().importFurniture();
1095
getFurnitureController().importFurniture();
1100
* Imports a furniture library chosen by the user.
1102
public void importFurnitureLibrary() {
1103
getView().invokeLater(new Runnable() {
1105
final String furnitureLibraryName = getView().showImportFurnitureLibraryDialog();
1106
if (furnitureLibraryName != null) {
1107
importFurnitureLibrary(furnitureLibraryName);
1114
* Imports a given furniture library.
1116
public void importFurnitureLibrary(String furnitureLibraryName) {
1118
if (!this.preferences.furnitureLibraryExists(furnitureLibraryName)
1119
|| getView().confirmReplaceFurnitureLibrary(furnitureLibraryName)) {
1120
this.preferences.addFurnitureLibrary(furnitureLibraryName);
1122
} catch (RecorderException ex) {
1123
String message = this.preferences.getLocalizedString(HomeController.class,
1124
"importFurnitureLibraryError", furnitureLibraryName);
1125
getView().showError(message);
1130
* Imports a textures library chosen by the user.
1132
public void importTexturesLibrary() {
1133
getView().invokeLater(new Runnable() {
1135
final String texturesLibraryName = getView().showImportTexturesLibraryDialog();
1136
if (texturesLibraryName != null) {
1137
importTexturesLibrary(texturesLibraryName);
1144
* Imports a given textures library.
1146
public void importTexturesLibrary(String texturesLibraryName) {
1148
if (!this.preferences.texturesLibraryExists(texturesLibraryName)
1149
|| getView().confirmReplaceTexturesLibrary(texturesLibraryName)) {
1150
this.preferences.addTexturesLibrary(texturesLibraryName);
1152
} catch (RecorderException ex) {
1153
String message = this.preferences.getLocalizedString(HomeController.class,
1154
"importTexturesLibraryError", texturesLibraryName);
1155
getView().showError(message);
1160
* Undoes last operation.
1162
public void undo() {
1163
this.undoManager.undo();
1164
HomeView view = getView();
1165
boolean moreUndo = this.undoManager.canUndo();
1166
view.setEnabled(HomeView.ActionType.UNDO, moreUndo);
1167
view.setEnabled(HomeView.ActionType.REDO, true);
1169
view.setUndoRedoName(this.undoManager.getUndoPresentationName(),
1170
this.undoManager.getRedoPresentationName());
1172
view.setUndoRedoName(null, this.undoManager.getRedoPresentationName());
1174
this.saveUndoLevel--;
1175
this.home.setModified(this.saveUndoLevel != 0 || this.notUndoableModifications);
1179
* Redoes last undone operation.
1181
public void redo() {
1182
this.undoManager.redo();
1183
HomeView view = getView();
1184
boolean moreRedo = this.undoManager.canRedo();
1185
view.setEnabled(HomeView.ActionType.UNDO, true);
1186
view.setEnabled(HomeView.ActionType.REDO, moreRedo);
1188
view.setUndoRedoName(this.undoManager.getUndoPresentationName(),
1189
this.undoManager.getRedoPresentationName());
1191
view.setUndoRedoName(this.undoManager.getUndoPresentationName(), null);
1193
this.saveUndoLevel++;
1194
this.home.setModified(this.saveUndoLevel != 0 || this.notUndoableModifications);
1198
* Deletes items and post a cut operation to undo support.
1200
public void cut(List<? extends Selectable> items) {
1201
// Start a compound edit that deletes items and changes presentation name
1202
UndoableEditSupport undoSupport = getUndoableEditSupport();
1203
undoSupport.beginUpdate();
1204
getPlanController().deleteItems(items);
1205
// Add a undoable edit to change presentation name
1206
undoSupport.postEdit(new AbstractUndoableEdit() {
1208
public String getPresentationName() {
1209
return preferences.getLocalizedString(HomeController.class, "undoCutName");
1212
// End compound edit
1213
undoSupport.endUpdate();
1217
* Adds items to home and posts a paste operation to undo support.
1219
public void paste(final List<? extends Selectable> items) {
1220
// Check if pasted items and currently selected items overlap
1221
List<Selectable> selectedItems = this.home.getSelectedItems();
1222
float pastedItemsDelta = 0;
1223
if (items.size() == selectedItems.size()) {
1224
// The default delta used to be able to distinguish dropped items from previous selection
1225
pastedItemsDelta = 20;
1226
for (Selectable pastedItem : items) {
1227
// Search which item of selected items it may overlap
1228
float [][] pastedItemPoints = pastedItem.getPoints();
1229
boolean pastedItemOverlapSelectedItem = false;
1230
for (Selectable selectedItem : selectedItems) {
1231
if (Arrays.deepEquals(pastedItemPoints, selectedItem.getPoints())) {
1232
pastedItemOverlapSelectedItem = true;
1236
if (!pastedItemOverlapSelectedItem) {
1237
pastedItemsDelta = 0;
1242
addPastedItems(items, pastedItemsDelta, pastedItemsDelta, false, "undoPasteName");
1246
* Adds items to home, moves them of (dx, dy)
1247
* and posts a drop operation to undo support.
1249
public void drop(final List<? extends Selectable> items, float dx, float dy) {
1250
drop(items, null, dx, dy);
1254
* Adds items to home, moves them of (dx, dy)
1255
* and posts a drop operation to undo support.
1257
public void drop(final List<? extends Selectable> items, View destinationView, float dx, float dy) {
1258
addPastedItems(items, dx, dy, destinationView == getPlanController().getView(), "undoDropName");
1262
* Adds items to home.
1264
private void addPastedItems(final List<? extends Selectable> items,
1265
float dx, float dy, final boolean isDropInPlanView,
1266
final String presentationNameKey) {
1267
if (items.size() > 1
1268
|| (items.size() == 1
1269
&& !(items.get(0) instanceof Compass))) {
1270
// Always use selection mode after a drop or a paste operation
1271
getPlanController().setMode(PlanController.Mode.SELECTION);
1272
// Start a compound edit that adds walls, furniture, rooms, dimension lines and labels to home
1273
UndoableEditSupport undoSupport = getUndoableEditSupport();
1274
undoSupport.beginUpdate();
1275
List<HomePieceOfFurniture> addedFurniture = Home.getFurnitureSubList(items);
1276
// If magnetism is enabled, adjust furniture size and elevation
1277
if (this.preferences.isMagnetismEnabled()) {
1278
for (HomePieceOfFurniture piece : addedFurniture) {
1279
if (piece.isResizable()) {
1280
piece.setWidth(this.preferences.getLengthUnit().getMagnetizedLength(piece.getWidth(), 0.1f));
1281
// Don't adjust depth of doors or windows otherwise they may be misplaced in a wall
1282
if (!(piece instanceof HomeDoorOrWindow) || dx != 0 || dy != 0) {
1283
piece.setDepth(this.preferences.getLengthUnit().getMagnetizedLength(piece.getDepth(), 0.1f));
1285
piece.setHeight(this.preferences.getLengthUnit().getMagnetizedLength(piece.getHeight(), 0.1f));
1287
piece.setElevation(this.preferences.getLengthUnit().getMagnetizedLength(piece.getElevation(), 0.1f));
1290
getPlanController().moveItems(items, dx, dy);
1291
if (isDropInPlanView
1292
&& this.preferences.isMagnetismEnabled()
1293
&& items.size() == 1
1294
&& addedFurniture.size() == 1) {
1295
// Adjust piece when it's dropped in plan view
1296
getPlanController().adjustMagnetizedPieceOfFurniture((HomePieceOfFurniture)items.get(0), dx, dy);
1298
getPlanController().addItems(items);
1299
undoSupport.postEdit(new AbstractUndoableEdit() {
1301
public String getPresentationName() {
1302
return preferences.getLocalizedString(HomeController.class, presentationNameKey);
1306
// End compound edit
1307
undoSupport.endUpdate();
1312
* Adds imported models to home, moves them of (dx, dy)
1313
* and post a drop operation to undo support.
1315
public void dropFiles(final List<String> importableModels, float dx, float dy) {
1316
// Always use selection mode after a drop operation
1317
getPlanController().setMode(PlanController.Mode.SELECTION);
1318
// Add to home a listener to track imported furniture
1319
final List<HomePieceOfFurniture> importedFurniture =
1320
new ArrayList<HomePieceOfFurniture>(importableModels.size());
1321
CollectionListener<HomePieceOfFurniture> addedFurnitureListener =
1322
new CollectionListener<HomePieceOfFurniture>() {
1323
public void collectionChanged(CollectionEvent<HomePieceOfFurniture> ev) {
1324
importedFurniture.add(ev.getItem());
1327
this.home.addFurnitureListener(addedFurnitureListener);
1329
// Start a compound edit that adds furniture to home
1330
UndoableEditSupport undoSupport = getUndoableEditSupport();
1331
undoSupport.beginUpdate();
1333
for (String model : importableModels) {
1334
getFurnitureController().importFurniture(model);
1336
this.home.removeFurnitureListener(addedFurnitureListener);
1338
if (importedFurniture.size() > 0) {
1339
getPlanController().moveItems(importedFurniture, dx, dy);
1340
this.home.setSelectedItems(importedFurniture);
1342
// Add a undoable edit that will select the imported furniture at redo
1343
undoSupport.postEdit(new AbstractUndoableEdit() {
1345
public void redo() throws CannotRedoException {
1347
home.setSelectedItems(importedFurniture);
1351
public String getPresentationName() {
1352
return preferences.getLocalizedString(HomeController.class, "undoDropName");
1357
// End compound edit
1358
undoSupport.endUpdate();
1362
* Deletes the selection in the focused component.
1364
public void delete() {
1365
if (this.focusedView == getFurnitureCatalogController().getView()) {
1366
if (getView().confirmDeleteCatalogSelection()) {
1367
getFurnitureCatalogController().deleteSelection();
1369
} else if (this.focusedView == getFurnitureController().getView()) {
1370
getFurnitureController().deleteSelection();
1371
} else if (this.focusedView == getPlanController().getView()) {
1372
getPlanController().deleteSelection();
1377
* Updates actions when focused view changed.
1379
public void focusedViewChanged(View focusedView) {
1380
this.focusedView = focusedView;
1381
enableActionsBoundToSelection();
1382
enablePasteAction();
1383
enableSelectAllAction();
1387
* Selects everything in the focused component.
1389
public void selectAll() {
1390
if (this.focusedView == getFurnitureController().getView()) {
1391
getFurnitureController().selectAll();
1392
} else if (this.focusedView == getPlanController().getView()
1393
|| this.focusedView == getHomeController3D().getView()) {
1394
getPlanController().selectAll();
1399
* Creates a new home and adds it to application home list.
1401
public void newHome() {
1403
if (this.application != null) {
1404
home = this.application.createHome();
1406
home = new Home(this.preferences.getNewWallHeight());
1408
this.application.addHome(home);
1412
* Opens a home. This method displays an {@link HomeView#showOpenDialog() open dialog}
1413
* in view, reads the home from the chosen name and adds it to application home list.
1415
public void open() {
1416
getView().invokeLater(new Runnable() {
1418
final String homeName = getView().showOpenDialog();
1419
if (homeName != null) {
1427
* Opens a given <code>homeName</code>home.
1429
public void open(final String homeName) {
1430
// Check if requested home isn't already opened
1431
for (Home home : this.application.getHomes()) {
1432
if (homeName.equals(home.getName())) {
1433
String message = this.preferences.getLocalizedString(
1434
HomeController.class, "alreadyOpen", homeName);
1435
getView().showMessage(message);
1440
// Read home in a threaded task
1441
Callable<Void> openTask = new Callable<Void>() {
1442
public Void call() throws RecorderException {
1443
// Read home with application recorder
1444
Home openedHome = application.getHomeRecorder().readHome(homeName);
1445
openedHome.setName(homeName);
1446
addHomeToApplication(openedHome);
1450
ThreadedTaskController.ExceptionHandler exceptionHandler =
1451
new ThreadedTaskController.ExceptionHandler() {
1452
public void handleException(Exception ex) {
1453
if (!(ex instanceof InterruptedRecorderException)) {
1454
if (ex instanceof RecorderException) {
1455
String message = preferences.getLocalizedString(
1456
HomeController.class, "openError", homeName);
1457
getView().showError(message);
1459
ex.printStackTrace();
1464
new ThreadedTaskController(openTask,
1465
this.preferences.getLocalizedString(HomeController.class, "openMessage"), exceptionHandler,
1466
this.preferences, this.viewFactory).executeTask(getView());
1470
* Adds the given home to application.
1472
private void addHomeToApplication(final Home home) {
1473
getView().invokeLater(new Runnable() {
1475
application.addHome(home);
1481
* Updates user preferences <code>recentHomes</code> and write preferences.
1483
private void updateUserPreferencesRecentHomes(List<String> recentHomes) {
1484
if (this.application != null) {
1485
// Check every recent home exists
1486
for (Iterator<String> it = recentHomes.iterator(); it.hasNext(); ) {
1488
if (!this.application.getHomeRecorder().exists(it.next())) {
1491
} catch (RecorderException ex) {
1492
// If homeName can't be checked ignore it
1495
this.preferences.setRecentHomes(recentHomes);
1500
* Returns a list of displayable recent homes.
1502
public List<String> getRecentHomes() {
1503
if (this.application != null) {
1504
List<String> recentHomes = new ArrayList<String>();
1505
for (String homeName : this.preferences.getRecentHomes()) {
1507
if (this.application.getHomeRecorder().exists(homeName)) {
1508
recentHomes.add(homeName);
1509
if (recentHomes.size() == this.preferences.getRecentHomesMaxCount()) {
1513
} catch (RecorderException ex) {
1514
// If homeName can't be checked ignore it
1517
getView().setEnabled(HomeView.ActionType.DELETE_RECENT_HOMES,
1518
!recentHomes.isEmpty());
1519
return Collections.unmodifiableList(recentHomes);
1521
return new ArrayList<String>();
1526
* Returns the version of the application.
1528
public String getVersion() {
1529
if (this.application != null) {
1530
return this.application.getVersion();
1537
* Deletes the list of recent homes in user preferences.
1539
public void deleteRecentHomes() {
1540
updateUserPreferencesRecentHomes(new ArrayList<String>());
1541
getView().setEnabled(HomeView.ActionType.DELETE_RECENT_HOMES, false);
1545
* Manages home close operation. If the home managed by this controller is modified,
1546
* this method will {@link HomeView#confirmSave(String) confirm}
1547
* in view whether home should be saved. Once home is actually saved,
1548
* home is removed from application homes list.
1550
public void close() {
1556
* Manages home close operation. If the home managed by this controller is modified,
1557
* this method will {@link HomeView#confirmSave(String) confirm}
1558
* in view whether home should be saved. Once home is actually saved,
1559
* home is removed from application homes list and postCloseTask is called if
1560
* it's not <code>null</code>.
1562
protected void close(final Runnable postCloseTask) {
1563
// Create a task that deletes home and run postCloseTask
1564
Runnable closeTask = new Runnable() {
1566
home.setRecovered(false);
1567
application.deleteHome(home);
1568
if (postCloseTask != null) {
1569
postCloseTask.run();
1574
if (this.home.isModified() || this.home.isRecovered()) {
1575
switch (getView().confirmSave(this.home.getName())) {
1576
case SAVE : save(HomeRecorder.Type.DEFAULT, closeTask); // Falls through
1577
case CANCEL : return;
1584
* Saves the home managed by this controller. If home name doesn't exist,
1585
* this method will act as {@link #saveAs() saveAs} method.
1587
public void save() {
1588
save(HomeRecorder.Type.DEFAULT, null);
1592
* Saves the home managed by this controller and executes <code>postSaveTask</code>
1593
* if it's not <code>null</code>.
1595
private void save(HomeRecorder.Type recorderType, Runnable postSaveTask) {
1596
if (this.home.getName() == null) {
1597
saveAs(recorderType, postSaveTask);
1599
save(this.home.getName(), recorderType, postSaveTask);
1604
* Saves the home managed by this controller with a different name.
1605
* This method displays a {@link HomeView#showSaveDialog(String) save dialog} in view,
1606
* and saves home with the chosen name if any.
1608
public void saveAs() {
1609
saveAs(HomeRecorder.Type.DEFAULT, null);
1613
* Saves the home managed by this controller with a different name.
1615
private void saveAs(HomeRecorder.Type recorderType, Runnable postSaveTask) {
1616
String newName = getView().showSaveDialog(this.home.getName());
1617
if (newName != null) {
1618
save(newName, recorderType, postSaveTask);
1623
* Saves the home managed by this controller and compresses it. If home name doesn't exist,
1624
* this method will prompt user to choose a home name.
1626
public void saveAndCompress() {
1627
save(HomeRecorder.Type.COMPRESSED, null);
1631
* Actually saves the home managed by this controller and executes <code>postSaveTask</code>
1632
* if it's not <code>null</code>.
1634
private void save(final String homeName,
1635
final HomeRecorder.Type recorderType,
1636
final Runnable postSaveTask) {
1637
// If home version is older than current version
1638
// or if home name is changed
1639
// or if user confirms to save a home created with a newer version
1640
if (this.home.getVersion() <= Home.CURRENT_VERSION
1641
|| !homeName.equals(this.home.getName())
1642
|| getView().confirmSaveNewerHome(homeName)) {
1643
// Save home in a threaded task
1644
Callable<Void> saveTask = new Callable<Void>() {
1645
public Void call() throws RecorderException {
1646
// Write home with application recorder
1647
application.getHomeRecorder(recorderType).writeHome(home, homeName);
1648
updateSavedHome(homeName, postSaveTask);
1652
ThreadedTaskController.ExceptionHandler exceptionHandler =
1653
new ThreadedTaskController.ExceptionHandler() {
1654
public void handleException(Exception ex) {
1655
if (!(ex instanceof InterruptedRecorderException)) {
1656
if (ex instanceof RecorderException) {
1657
String message = preferences.getLocalizedString(
1658
HomeController.class, "saveError", homeName);
1659
getView().showError(message);
1661
ex.printStackTrace();
1666
new ThreadedTaskController(saveTask,
1667
this.preferences.getLocalizedString(HomeController.class, "saveMessage"), exceptionHandler,
1668
this.preferences, this.viewFactory).executeTask(getView());
1673
* Updates the saved home and executes <code>postSaveTask</code>
1674
* if it's not <code>null</code>.
1676
private void updateSavedHome(final String homeName,
1677
final Runnable postSaveTask) {
1678
getView().invokeLater(new Runnable() {
1680
home.setName(homeName);
1681
home.setModified(false);
1682
home.setRecovered(false);
1683
// Update recent homes list
1684
List<String> recentHomes = new ArrayList<String>(preferences.getRecentHomes());
1685
int homeNameIndex = recentHomes.indexOf(homeName);
1686
if (homeNameIndex >= 0) {
1687
recentHomes.remove(homeNameIndex);
1689
recentHomes.add(0, homeName);
1690
updateUserPreferencesRecentHomes(recentHomes);
1692
if (postSaveTask != null) {
1700
* Controls the export of the 3D view of current home to a SVG file.
1702
public void exportToSVG() {
1703
final String svgName = getView().showExportToSVGDialog(this.home.getName());
1704
if (svgName != null) {
1705
// Export 3D view in a threaded task
1706
Callable<Void> exportToSvgTask = new Callable<Void>() {
1707
public Void call() throws RecorderException {
1708
getView().exportToSVG(svgName);
1712
ThreadedTaskController.ExceptionHandler exceptionHandler =
1713
new ThreadedTaskController.ExceptionHandler() {
1714
public void handleException(Exception ex) {
1715
if (!(ex instanceof InterruptedRecorderException)) {
1716
if (ex instanceof RecorderException) {
1717
String message = preferences.getLocalizedString(
1718
HomeController.class, "exportToSVGError", svgName);
1719
getView().showError(message);
1721
ex.printStackTrace();
1726
new ThreadedTaskController(exportToSvgTask,
1727
this.preferences.getLocalizedString(HomeController.class, "exportToSVGMessage"), exceptionHandler,
1728
this.preferences, this.viewFactory).executeTask(getView());
1733
* Controls the export of the 3D view of current home to an OBJ file.
1735
public void exportToOBJ() {
1736
final String objName = getView().showExportToOBJDialog(this.home.getName());
1737
if (objName != null) {
1738
// Export 3D view in a threaded task
1739
Callable<Void> exportToObjTask = new Callable<Void>() {
1740
public Void call() throws RecorderException {
1741
getView().exportToOBJ(objName);
1745
ThreadedTaskController.ExceptionHandler exceptionHandler =
1746
new ThreadedTaskController.ExceptionHandler() {
1747
public void handleException(Exception ex) {
1748
if (!(ex instanceof InterruptedRecorderException)) {
1749
if (ex instanceof RecorderException) {
1750
String message = preferences.getLocalizedString(
1751
HomeController.class, "exportToOBJError", objName);
1752
getView().showError(message);
1754
ex.printStackTrace();
1759
new ThreadedTaskController(exportToObjTask,
1760
this.preferences.getLocalizedString(HomeController.class, "exportToOBJMessage"), exceptionHandler,
1761
this.preferences, this.viewFactory).executeTask(getView());
1766
* Controls the creation of photo-realistic images.
1768
public void createPhoto() {
1769
PhotoController photoController = new PhotoController(this.home, this.preferences,
1770
getHomeController3D().getView(), this.viewFactory, this.contentManager);
1771
photoController.displayView(getView());
1775
* Controls the creation of 3D videos.
1777
public void createVideo() {
1778
getPlanController().setMode(PlanController.Mode.SELECTION);
1779
getHomeController3D().viewFromObserver();
1780
VideoController videoController = new VideoController(this.home, this.preferences,
1781
this.viewFactory, this.contentManager);
1782
videoController.displayView(getView());
1786
* Controls page setup.
1788
public void setupPage() {
1789
new PageSetupController(this.home, this.preferences,
1790
this.viewFactory, getUndoableEditSupport()).displayView(getView());
1794
* Controls the print preview.
1796
public void previewPrint() {
1797
new PrintPreviewController(this.home, this.preferences,
1798
this, this.viewFactory).displayView(getView());
1802
* Controls the print of this home.
1804
public void print() {
1805
final Callable<Void> printTask = getView().showPrintDialog();
1806
if (printTask != null) {
1807
// Print in a threaded task
1808
ThreadedTaskController.ExceptionHandler exceptionHandler =
1809
new ThreadedTaskController.ExceptionHandler() {
1810
public void handleException(Exception ex) {
1811
if (!(ex instanceof InterruptedRecorderException)) {
1812
if (ex instanceof RecorderException) {
1813
String message = preferences.getLocalizedString(
1814
HomeController.class, "printError", home.getName());
1815
getView().showError(message);
1817
ex.printStackTrace();
1822
new ThreadedTaskController(printTask,
1823
this.preferences.getLocalizedString(HomeController.class, "printMessage"), exceptionHandler,
1824
this.preferences, this.viewFactory).executeTask(getView());
1829
* Controls the print of this home in a PDF file.
1831
public void printToPDF() {
1832
final String pdfName = getView().showPrintToPDFDialog(this.home.getName());
1833
if (pdfName != null) {
1834
// Print to PDF in a threaded task
1835
Callable<Void> printToPdfTask = new Callable<Void>() {
1836
public Void call() throws RecorderException {
1837
getView().printToPDF(pdfName);
1841
ThreadedTaskController.ExceptionHandler exceptionHandler =
1842
new ThreadedTaskController.ExceptionHandler() {
1843
public void handleException(Exception ex) {
1844
if (!(ex instanceof InterruptedRecorderException)) {
1845
if (ex instanceof RecorderException) {
1846
String message = preferences.getLocalizedString(
1847
HomeController.class, "printToPDFError", pdfName);
1848
getView().showError(message);
1850
ex.printStackTrace();
1855
new ThreadedTaskController(printToPdfTask,
1856
preferences.getLocalizedString(HomeController.class, "printToPDFMessage"), exceptionHandler,
1857
this.preferences, this.viewFactory).executeTask(getView());
1862
* Controls application exit. If any home in application homes list is modified,
1863
* the user will be {@link HomeView#confirmExit() prompted} in view whether he wants
1864
* to discard his modifications ot not.
1866
public void exit() {
1867
for (Home home : this.application.getHomes()) {
1868
if (home.isModified() || home.isRecovered()) {
1869
if (getView().confirmExit()) {
1876
// Remove all homes from application
1877
for (Home home : this.application.getHomes()) {
1878
home.setRecovered(false);
1879
this.application.deleteHome(home);
1881
// Let application decide what to do when there's no more home
1885
* Edits preferences and changes them if user agrees.
1887
public void editPreferences() {
1888
new UserPreferencesController(this.preferences,
1889
this.viewFactory, this.contentManager, this).displayView(getView());
1893
* Displays a tip message dialog depending on the given mode and
1894
* sets the active mode of the plan controller.
1896
public void setMode(Mode mode) {
1897
if (getPlanController().getMode() != mode) {
1898
final String actionKey;
1899
if (mode == Mode.WALL_CREATION) {
1900
actionKey = HomeView.ActionType.CREATE_WALLS.name();
1901
} else if (mode == Mode.ROOM_CREATION) {
1902
actionKey = HomeView.ActionType.CREATE_ROOMS.name();
1903
} else if (mode == Mode.DIMENSION_LINE_CREATION) {
1904
actionKey = HomeView.ActionType.CREATE_DIMENSION_LINES.name();
1905
} else if (mode == Mode.LABEL_CREATION) {
1906
actionKey = HomeView.ActionType.CREATE_LABELS.name();
1910
// Display the tip message dialog matching mode
1911
if (actionKey != null
1912
&& !this.preferences.isActionTipIgnored(actionKey)) {
1913
getView().invokeLater(new Runnable() {
1915
// Show tip later to let the mode switch finish first
1916
if (getView().showActionTipMessage(actionKey)) {
1917
preferences.setActionTipIgnored(actionKey);
1922
getPlanController().setMode(mode);
1927
* Displays the wizard that helps to import home background image.
1929
public void importBackgroundImage() {
1930
new BackgroundImageWizardController(this.home, this.preferences,
1931
this.viewFactory, this.contentManager, getUndoableEditSupport()).displayView(getView());
1935
* Displays the wizard that helps to change home background image.
1937
public void modifyBackgroundImage() {
1938
importBackgroundImage();
1942
* Hides the home background image.
1944
public void hideBackgroundImage() {
1945
toggleBackgroundImageVisibility("undoHideBackgroundImageName");
1949
* Shows the home background image.
1951
public void showBackgroundImage() {
1952
toggleBackgroundImageVisibility("undoShowBackgroundImageName");
1956
* Toggles visibility of the background image and posts an undoable operation.
1958
private void toggleBackgroundImageVisibility(final String presentationName) {
1959
final Level selectedLevel = this.home.getSelectedLevel();
1960
doToggleBackgroundImageVisibility();
1961
UndoableEdit undoableEdit = new AbstractUndoableEdit() {
1963
public void undo() throws CannotUndoException {
1965
home.setSelectedLevel(selectedLevel);
1966
doToggleBackgroundImageVisibility();
1970
public void redo() throws CannotRedoException {
1972
home.setSelectedLevel(selectedLevel);
1973
doToggleBackgroundImageVisibility();
1977
public String getPresentationName() {
1978
return preferences.getLocalizedString(HomeController.class, presentationName);
1981
getUndoableEditSupport().postEdit(undoableEdit);
1985
* Toggles visibility of the background image.
1987
private void doToggleBackgroundImageVisibility() {
1988
BackgroundImage backgroundImage = this.home.getSelectedLevel() != null
1989
? this.home.getSelectedLevel().getBackgroundImage()
1990
: this.home.getBackgroundImage();
1991
backgroundImage = new BackgroundImage(backgroundImage.getImage(),
1992
backgroundImage.getScaleDistance(),
1993
backgroundImage.getScaleDistanceXStart(), backgroundImage.getScaleDistanceYStart(),
1994
backgroundImage.getScaleDistanceXEnd(), backgroundImage.getScaleDistanceYEnd(),
1995
backgroundImage.getXOrigin(), backgroundImage.getYOrigin(), !backgroundImage.isVisible());
1996
if (this.home.getSelectedLevel() != null) {
1997
this.home.getSelectedLevel().setBackgroundImage(backgroundImage);
1999
this.home.setBackgroundImage(backgroundImage);
2004
* Deletes home background image and posts and posts an undoable operation.
2006
public void deleteBackgroundImage() {
2007
final Level selectedLevel = this.home.getSelectedLevel();
2008
final BackgroundImage oldImage;
2009
if (selectedLevel != null) {
2010
oldImage = selectedLevel.getBackgroundImage();
2011
selectedLevel.setBackgroundImage(null);
2013
oldImage = this.home.getBackgroundImage();
2014
this.home.setBackgroundImage(null);
2016
UndoableEdit undoableEdit = new AbstractUndoableEdit() {
2018
public void undo() throws CannotUndoException {
2020
home.setSelectedLevel(selectedLevel);
2021
if (selectedLevel != null) {
2022
selectedLevel.setBackgroundImage(oldImage);
2024
home.setBackgroundImage(oldImage);
2029
public void redo() throws CannotRedoException {
2031
home.setSelectedLevel(selectedLevel);
2032
if (selectedLevel != null) {
2033
selectedLevel.setBackgroundImage(null);
2035
home.setBackgroundImage(null);
2040
public String getPresentationName() {
2041
return preferences.getLocalizedString(HomeController.class, "undoDeleteBackgroundImageName");
2044
getUndoableEditSupport().postEdit(undoableEdit);
2048
* Zooms out in plan.
2050
public void zoomOut() {
2051
PlanController planController = getPlanController();
2052
float newScale = planController.getScale() / 1.5f;
2053
planController.setScale(newScale);
2059
public void zoomIn() {
2060
PlanController planController = getPlanController();
2061
float newScale = planController.getScale() * 1.5f;
2062
planController.setScale(newScale);
2066
* Prompts a name for the current camera and stores it in home.
2068
public void storeCamera() {
2069
String now = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(new Date());
2070
String name = getView().showStoreCameraDialog(now);
2072
getHomeController3D().storeCamera(name);
2077
* Detaches the given <code>view</code> from home view.
2079
public void detachView(View view) {
2081
getView().detachView(view);
2082
this.notUndoableModifications = true;
2083
home.setModified(true);
2088
* Attaches the given <code>view</code> to home view.
2090
public void attachView(View view) {
2092
getView().attachView(view);
2093
this.notUndoableModifications = true;
2094
home.setModified(true);
2099
* Displays help window.
2101
public void help() {
2102
if (helpController == null) {
2103
helpController = new HelpController(this.preferences, this.viewFactory);
2105
helpController.displayView();
2109
* Displays about dialog.
2111
public void about() {
2112
getView().showAboutDialog();
2116
* Controls the change of value of a visual property in home.
2118
public void setVisualProperty(String propertyName,
2119
Object propertyValue) {
2120
this.home.setVisualProperty(propertyName, propertyValue);