/*
* FurnitureCatalogController.java 15 mai 2006
*
* Sweet Home 3D, Copyright (c) 2006 Emmanuel PUYBARET / eTeks <info@eteks.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.eteks.sweethome3d.viewcontroller;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.eteks.sweethome3d.model.CatalogPieceOfFurniture;
import com.eteks.sweethome3d.model.CollectionEvent;
import com.eteks.sweethome3d.model.CollectionListener;
import com.eteks.sweethome3d.model.FurnitureCatalog;
import com.eteks.sweethome3d.model.SelectionEvent;
import com.eteks.sweethome3d.model.SelectionListener;
import com.eteks.sweethome3d.model.UserPreferences;
/**
* A MVC controller for the furniture catalog.
* @author Emmanuel Puybaret
*/
public class FurnitureCatalogController implements Controller {
private final FurnitureCatalog catalog;
private final UserPreferences preferences;
private final ViewFactory viewFactory;
private final ContentManager contentManager;
private final List<SelectionListener> selectionListeners;
private List<CatalogPieceOfFurniture> selectedFurniture;
private View catalogView;
/**
* Creates a controller of the furniture catalog view.
* @param catalog the furniture catalog of the application
* @param viewFactory a factory able to create the furniture view managed by this controller
*/
public FurnitureCatalogController(FurnitureCatalog catalog,
ViewFactory viewFactory) {
this(catalog, null, viewFactory, null);
}
/**
* Creates a controller of the furniture catalog view.
* @param catalog the furniture catalog of the application
* @param preferences application user preferences
* @param viewFactory a factory able to create the furniture view managed by this controller
* @param contentManager content manager for furniture import
*/
public FurnitureCatalogController(FurnitureCatalog catalog,
UserPreferences preferences,
ViewFactory viewFactory,
ContentManager contentManager) {
this.catalog = catalog;
this.preferences = preferences;
this.viewFactory = viewFactory;
this.contentManager = contentManager;
this.selectionListeners = new ArrayList<SelectionListener>();
this.selectedFurniture = Collections.emptyList();
this.catalog.addFurnitureListener(new FurnitureCatalogChangeListener(this));
if (preferences != null) {
preferences.addPropertyChangeListener(UserPreferences.Property.FURNITURE_CATALOG_VIEWED_IN_TREE,
new FurnitureCatalogViewChangeListener(this));
}
}
/**
* Furniture catalog listener that deselects a piece removed from catalog.
*/
private static class FurnitureCatalogChangeListener implements CollectionListener<CatalogPieceOfFurniture> {
private WeakReference<FurnitureCatalogController> furnitureCatalogController;
public FurnitureCatalogChangeListener(FurnitureCatalogController furnitureCatalogController) {
this.furnitureCatalogController = new WeakReference<FurnitureCatalogController>(furnitureCatalogController);
}
public void collectionChanged(CollectionEvent<CatalogPieceOfFurniture> ev) {
// If controller was garbage collected, remove this listener from catalog
final FurnitureCatalogController controller = this.furnitureCatalogController.get();
if (controller == null) {
((FurnitureCatalog)ev.getSource()).removeFurnitureListener(this);
} else if (ev.getType() == CollectionEvent.Type.DELETE) {
controller.deselectPieceOfFurniture(ev.getItem());
}
}
}
/**
* Preferences listener that reset view when furniture catalog view should change.
*/
private static class FurnitureCatalogViewChangeListener implements PropertyChangeListener {
private WeakReference<FurnitureCatalogController> controller;
public FurnitureCatalogViewChangeListener(FurnitureCatalogController controller) {
this.controller = new WeakReference<FurnitureCatalogController>(controller);
}
public void propertyChange(PropertyChangeEvent ev) {
// If home pane was garbage collected, remove this listener from preferences
FurnitureCatalogController controller = this.controller.get();
if (controller == null) {
((UserPreferences)ev.getSource()).removePropertyChangeListener(
UserPreferences.Property.FURNITURE_CATALOG_VIEWED_IN_TREE, this);
} else {
// Forgot current view and create a new one at next getView call
controller.catalogView = null;
}
}
}
/**
* Returns the view associated with this controller.
*/
public View getView() {
// Create view lazily only once it's needed
if (this.catalogView == null) {
this.catalogView = viewFactory.createFurnitureCatalogView(this.catalog, this.preferences, this);
}
return this.catalogView;
}
/**
* Adds the selection <code>listener</code> in parameter to this controller.
*/
public void addSelectionListener(SelectionListener listener) {
this.selectionListeners.add(listener);
}
/**
* Removes the selection <code>listener</code> in parameter from this controller.
*/
public void removeSelectionListener(SelectionListener listener) {
this.selectionListeners.remove(listener);
}
/**
* Returns an unmodifiable list of the selected furniture in catalog.
*/
public List<CatalogPieceOfFurniture> getSelectedFurniture() {
return Collections.unmodifiableList(this.selectedFurniture);
}
/**
* Updates the selected furniture in catalog and notifies listeners selection change.
*/
public void setSelectedFurniture(List<CatalogPieceOfFurniture> selectedFurniture) {
this.selectedFurniture = new ArrayList<CatalogPieceOfFurniture>(selectedFurniture);
if (!this.selectionListeners.isEmpty()) {
SelectionEvent selectionEvent = new SelectionEvent(this, getSelectedFurniture());
// Work on a copy of selectionListeners to ensure a listener
// can modify safely listeners list
SelectionListener [] listeners = this.selectionListeners.
toArray(new SelectionListener [this.selectionListeners.size()]);
for (SelectionListener listener : listeners) {
listener.selectionChanged(selectionEvent);
}
}
}
/**
* Removes <code>piece</code> from selected furniture.
*/
private void deselectPieceOfFurniture(CatalogPieceOfFurniture piece) {
int pieceSelectionIndex = this.selectedFurniture.indexOf(piece);
if (pieceSelectionIndex != -1) {
List<CatalogPieceOfFurniture> selectedItems =
new ArrayList<CatalogPieceOfFurniture>(getSelectedFurniture());
selectedItems.remove(pieceSelectionIndex);
setSelectedFurniture(selectedItems);
}
}
/**
* Displays the wizard that helps to change the selected piece of furniture.
*/
public void modifySelectedFurniture() {
if (this.preferences != null) {
if (this.selectedFurniture.size() > 0) {
CatalogPieceOfFurniture piece = this.selectedFurniture.get(0);
if (piece.isModifiable()) {
AddedFurnitureSelector addedFurnitureListener = new AddedFurnitureSelector();
this.preferences.getFurnitureCatalog().addFurnitureListener(addedFurnitureListener);
new ImportedFurnitureWizardController(piece, this.preferences,
this.viewFactory, this.contentManager).displayView(getView());
addedFurnitureListener.selectAddedFurniture();
this.preferences.getFurnitureCatalog().removeFurnitureListener(addedFurnitureListener);
}
}
}
}
/**
* Listener that keeps track of the furniture added to catalog.
*/
private class AddedFurnitureSelector implements CollectionListener<CatalogPieceOfFurniture> {
private List<CatalogPieceOfFurniture> addedFurniture = new ArrayList<CatalogPieceOfFurniture>();
public void collectionChanged(CollectionEvent<CatalogPieceOfFurniture> ev) {
if (ev.getType() == CollectionEvent.Type.ADD) {
this.addedFurniture.add(ev.getItem());
}
}
public void selectAddedFurniture() {
if (this.addedFurniture.size() > 0) {
setSelectedFurniture(this.addedFurniture);
}
}
}
/**
* Displays the wizard that helps to import furniture to catalog.
*/
public void importFurniture() {
if (this.preferences != null) {
AddedFurnitureSelector addedFurnitureListener = new AddedFurnitureSelector();
this.preferences.getFurnitureCatalog().addFurnitureListener(addedFurnitureListener);
new ImportedFurnitureWizardController(this.preferences,
this.viewFactory, this.contentManager).displayView(getView());
addedFurnitureListener.selectAddedFurniture();
this.preferences.getFurnitureCatalog().removeFurnitureListener(addedFurnitureListener);
}
}
/**
* Displays the wizard that helps to import furniture to catalog.
*/
private void importFurniture(String modelName) {
if (this.preferences != null) {
new ImportedFurnitureWizardController(modelName, this.preferences,
this.viewFactory, this.contentManager).displayView(getView());
}
}
/**
* Deletes selected catalog furniture.
*/
public void deleteSelection() {
for (CatalogPieceOfFurniture piece : this.selectedFurniture) {
if (piece.isModifiable()) {
this.catalog.delete(piece);
}
}
}
/**
* Adds dropped files to catalog.
*/
public void dropFiles(List<String> importableModels) {
AddedFurnitureSelector addedFurnitureListener = new AddedFurnitureSelector();
this.preferences.getFurnitureCatalog().addFurnitureListener(addedFurnitureListener);
// Import furniture
for (String model : importableModels) {
importFurniture(model);
}
addedFurnitureListener.selectAddedFurniture();
this.preferences.getFurnitureCatalog().removeFurnitureListener(addedFurnitureListener);
}
}