/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo 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 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.inspector;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.GeneralPreferences;
import org.openflexo.antar.binding.BooleanStaticBinding;
import org.openflexo.antar.binding.TypeUtils;
import org.openflexo.fib.FIBLibrary;
import org.openflexo.fib.model.DataBinding;
import org.openflexo.fib.model.FIBComponent;
import org.openflexo.fib.model.FIBContainer;
import org.openflexo.fib.model.FIBWidget;
import org.openflexo.foundation.FlexoModelObject;
import org.openflexo.inspector.selection.EmptySelection;
import org.openflexo.inspector.selection.InspectorSelection;
import org.openflexo.inspector.selection.MultipleSelection;
import org.openflexo.inspector.selection.UniqueSelection;
import org.openflexo.module.UserType;
import org.openflexo.toolbox.FileResource;
import org.openflexo.view.controller.FlexoController;
/**
* Represents the controller for all inspectors managed in the context of a module<br>
* It is connected with one or many FIBInspectorPanels sharing the same selection. In particular, manage the inspector dialog of the module.
*
* @author sylvain
*
*/
public class ModuleInspectorController extends Observable implements Observer {
private static final String CONTROLLER_EDITABLE_BINDING = "controller.flexoController.isEditable(data)";
static final Logger logger = Logger.getLogger(ModuleInspectorController.class.getPackage().getName());
private final FIBInspectorDialog inspectorDialog;
private final FlexoController flexoController;
private final Map<Class<?>, FIBInspector> inspectors;
private FIBInspector currentInspector = null;
private Object currentInspectedObject = null;
public ModuleInspectorController(FlexoController flexoController) {
this.flexoController = flexoController;
inspectors = new Hashtable<Class<?>, FIBInspector>();
inspectorDialog = new FIBInspectorDialog(this);
Boolean visible = GeneralPreferences.getPreferences().getBooleanProperty("FIBInspector.visible");
inspectorDialog.setVisible(visible == null || visible);
inspectorDialog.addComponentListener(new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent e) {
GeneralPreferences.getPreferences().setBooleanProperty("FIBInspector.visible", Boolean.TRUE);
GeneralPreferences.save();
}
@Override
public void componentHidden(ComponentEvent e) {
GeneralPreferences.getPreferences().setBooleanProperty("FIBInspector.visible", Boolean.FALSE);
GeneralPreferences.save();
};
});
File inspectorsDir = new FileResource("Inspectors/COMMON");
loadDirectory(inspectorsDir);
}
public FlexoController getFlexoController() {
return flexoController;
}
public void loadDirectory(File dir) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Loading directory: " + dir);
}
if (!dir.exists()) {
logger.warning("Directory does NOT exist: " + dir.getAbsolutePath());
// (new Exception("???")).printStackTrace();
// System.exit(-1);
return;
}
for (File f : dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
// logger.info("name="+name);
return name.endsWith(".inspector");
}
})) {
// System.out.println("Read "+f.getAbsolutePath());
FIBInspector inspector = (FIBInspector) FIBLibrary.instance().retrieveFIBComponent(f);
if (inspector != null) {
appendVisibleFor(inspector);
appendEditableCondition(inspector);
if (inspector.getDataClass() != null) {
// try {
inspectors.put(inspector.getDataClass(), inspector);
if (logger.isLoggable(Level.FINE)) {
logger.fine("Loaded inspector: " + f.getName() + " for " + inspector.getDataClass());
}
/*
* } catch (ClassNotFoundException e) {
* logger.warning("Not found: " +
* inspector.getDataClassName()); }
*/
}
} else {
logger.warning("Not found: " + f.getAbsolutePath());
}
}
for (FIBInspector inspector : inspectors.values()) {
inspector.appendSuperInspectors(this);
}
for (FIBInspector inspector : inspectors.values()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Initialized inspector for " + inspector.getDataClass());
}
}
setChanged();
notifyObservers(new NewInspectorsLoaded());
}
private void appendEditableCondition(FIBComponent component) {
if (component instanceof FIBWidget) {
FIBWidget widget = (FIBWidget) component;
if (widget.getEnable() != null && widget.getEnable().isValid()) {
DataBinding enable = widget.getEnable();
widget.setEnable(new DataBinding(enable.getBinding().getStringRepresentation() + " & " + CONTROLLER_EDITABLE_BINDING));
} else {
widget.setEnable(new DataBinding(CONTROLLER_EDITABLE_BINDING));
}
} else if (component instanceof FIBContainer) {
for (FIBComponent child : ((FIBContainer) component).getSubComponents()) {
appendEditableCondition(child);
}
}
}
private void appendVisibleFor(FIBComponent component) {
String visibleForParam = component.getParameter("visibleFor");
if (visibleForParam != null) {
String[] s = visibleForParam.split("[;,\"]");
if (s.length > 0) {
UserType userType = UserType.getCurrentUserType();
boolean ok = false;
for (String string : s) {
ok |= userType.getName().equalsIgnoreCase(string);
ok |= userType.getIdentifier().equalsIgnoreCase(string);
if (ok) {
break;
}
}
if (!ok) {
component.getVisible().setBinding(new BooleanStaticBinding(false));
}
}
}
if (component instanceof FIBContainer) {
for (FIBComponent child : ((FIBContainer) component).getSubComponents()) {
appendVisibleFor(child);
}
}
}
protected FIBInspector inspectorForObject(Object object) {
if (object == null) {
return null;
}
return inspectorForClass(object.getClass());
}
protected FIBInspector inspectorForClass(Class<?> aClass) {
if (aClass == null) {
return null;
}
FIBInspector returned = inspectors.get(aClass);
if (returned != null) {
return returned;
} else {
Class<?> superclass = aClass.getSuperclass();
if (superclass != null) {
returned = inspectors.get(aClass);
if (returned != null) {
return returned;
} else {
for (Class<?> superInterface : aClass.getInterfaces()) {
returned = inspectors.get(superInterface);
if (returned != null) {
return returned;
}
}
return inspectorForClass(superclass);
}
}
}
List<Class<?>> matchingClasses = new ArrayList<Class<?>>();
for (Class<?> cl : inspectors.keySet()) {
if (cl.isAssignableFrom(aClass)) {
matchingClasses.add(cl);
}
}
if (matchingClasses.size() > 0) {
return inspectors.get(TypeUtils.getMostSpecializedClass(matchingClasses));
}
return null;
}
protected Map<Class<?>, FIBInspector> getInspectors() {
return inspectors;
}
public FIBInspectorDialog getInspectorDialog() {
return inspectorDialog;
}
public void refreshComponentVisibility() {
inspectorDialog.getInspectorPanel().refreshComponentVisibility();
}
protected void switchToEmptyContent() {
// System.out.println("switchToEmptyContent()");
currentInspectedObject = null;
currentInspector = null;
setChanged();
notifyObservers(new EmptySelectionActivated());
}
private void switchToMultipleSelection() {
// System.out.println("switchToEmptyContent()");
currentInspectedObject = null;
currentInspector = null;
setChanged();
notifyObservers(new MultipleSelectionActivated());
}
private void switchToInspector(FIBInspector newInspector, boolean updateEPTabs) {
currentInspector = newInspector;
setChanged();
notifyObservers(new InspectorSwitching(newInspector, updateEPTabs));
}
private void displayObject(Object object) {
setChanged();
notifyObservers(new InspectedObjectChanged(object));
}
/**
* Returns boolean indicating if inspection change
*
* @param object
* @return
*/
public boolean inspectObject(Object object) {
if (object == currentInspectedObject) {
return false;
}
currentInspectedObject = object;
FIBInspector newInspector = inspectorForObject(object);
if (newInspector == null) {
logger.warning("No inspector for " + object);
switchToEmptyContent();
} else {
boolean updateEPTabs = false;
if (object instanceof FlexoModelObject) {
updateEPTabs = newInspector.updateEditionPatternReferences((FlexoModelObject) object);
}
if (newInspector != currentInspector || updateEPTabs) {
switchToInspector(newInspector, updateEPTabs);
}
displayObject(object);
}
return true;
}
public void resetInspector() {
switchToEmptyContent();
}
@Override
public void update(Observable o, Object notification) {
if (notification instanceof InspectorSelection) {
InspectorSelection inspectorSelection = (InspectorSelection) notification;
if (inspectorSelection instanceof EmptySelection) {
switchToEmptyContent();
} else if (inspectorSelection instanceof MultipleSelection) {
switchToMultipleSelection();
} else if (inspectorSelection instanceof UniqueSelection) {
inspectObject(((UniqueSelection) inspectorSelection).getInspectedObject());
}
}
// Reforward notification to all in inspector panels
setChanged();
notifyObservers(notification);
}
public static class NewInspectorsLoaded {
}
public static class EmptySelectionActivated {
}
public static class MultipleSelectionActivated {
}
public static class InspectorSwitching {
private boolean updateEPTabs;
private FIBInspector newInspector;
public InspectorSwitching(FIBInspector newInspector, boolean updateEPTabs) {
this.newInspector = newInspector;
this.updateEPTabs = updateEPTabs;
}
public boolean updateEPTabs() {
return updateEPTabs;
}
public FIBInspector getNewInspector() {
return newInspector;
}
}
public static class InspectedObjectChanged {
private Object inspectedObject;
public InspectedObjectChanged(Object inspectedObject) {
this.inspectedObject = inspectedObject;
}
public Object getInspectedObject() {
return inspectedObject;
}
}
public void delete() {
inspectorDialog.delete();
currentInspectedObject = null;
currentInspector = null;
}
}