/* * (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.foundation.view; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.List; import java.util.Observable; import java.util.Observer; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.antar.binding.AbstractBinding.TargetObject; import org.openflexo.antar.binding.Bindable; import org.openflexo.antar.binding.BindingFactory; import org.openflexo.antar.binding.BindingModel; import org.openflexo.fge.GraphicalRepresentation; import org.openflexo.foundation.ontology.EditionPatternInstance; import org.openflexo.foundation.ontology.EditionPatternReference; import org.openflexo.foundation.viewpoint.EditionPattern; import org.openflexo.foundation.viewpoint.GraphicalElementPatternRole; import org.openflexo.foundation.viewpoint.GraphicalElementSpecification; import org.openflexo.foundation.viewpoint.binding.ViewPointDataBinding; import org.openflexo.foundation.xml.VEShemaBuilder; import org.openflexo.localization.FlexoLocalization; import org.openflexo.toolbox.HasPropertyChangeSupport; public abstract class ViewElement extends ViewObject implements Bindable, PropertyChangeListener, Observer { private static final Logger logger = Logger.getLogger(ViewElement.class.getPackage().getName()); private final Vector<TargetObject> dependingObjects = new Vector<TargetObject>(); private boolean dependingObjectsAreComputed = false; /** * Constructor invoked during deserialization * * @param componentDefinition */ public ViewElement(VEShemaBuilder builder) { this(builder.shema); initializeDeserialization(builder); } /** * Default constructor for OEShema * * @param shemaDefinition */ public ViewElement(View shema) { super(shema); } @Override public void delete() { if (getEditionPatternInstance() != null && !getEditionPatternInstance().isDeleted()) { getEditionPatternInstance().delete(); } for (TargetObject o : dependingObjects) { if (o.target instanceof HasPropertyChangeSupport) { PropertyChangeSupport pcSupport = ((HasPropertyChangeSupport) o.target).getPropertyChangeSupport(); // logger.info("Widget "+getWidget()+" remove property change listener: "+o.target+" property:"+o.propertyName); pcSupport.removePropertyChangeListener(o.propertyName, this); } else if (o.target instanceof Observable) { // logger.info("Widget "+getWidget()+" remove observable: "+o); ((Observable) o.target).deleteObserver(this); } } dependingObjects.clear(); super.delete(); } /*@Override public String getName() { if (isBoundInsideEditionPattern()) { return getLabelValue(); } return super.getName(); } @Override public void setName(String name) { // logger.info("setName of OEShemaElement with "+name); if (isBoundInsideEditionPattern()) { setLabelValue(name); } else { try { super.setName(name); } catch (DuplicateResourceException e) { // cannot happen e.printStackTrace(); } catch (InvalidNameException e) { // cannot happen e.printStackTrace(); } } }*/ // public abstract AddShemaElementAction getEditionAction(); /** * Return a flag indicating if current graphical element is bound inside an edition pattern, ie if there is one edition pattern instance * where this element plays a role as primary representation, or is included in an element declared as playing a role as primary * representation * * @return */ public boolean isBoundInsideEditionPattern() { return getPatternRole() != null; } @Override public GraphicalRepresentation<? extends ViewElement> getGraphicalRepresentation() { return (GraphicalRepresentation<? extends ViewElement>) super.getGraphicalRepresentation(); } /** * Return a flag indicating if current graphical element is bound inside an edition pattern, and if this element plays a role as primary * representation, * * @return */ public boolean playsPrimaryRole() { return getPatternRole() != null && getPatternRole().getIsPrimaryRepresentationRole(); } /*public String getLabelValue() { if (getPatternRole() != null) { //if (!dependingObjectsAreComputed) { // updateDependingObjects(); //} return (String) getPatternRole().getLabel().getBindingValue(getEditionPatternInstance()); } return null; } public void setLabelValue(String aValue) { if (getPatternRole() != null && !getPatternRole().getReadOnlyLabel()) { getPatternRole().getLabel().setBindingValue(aValue, getEditionPatternInstance()); } }*/ public EditionPattern getEditionPattern() { if (getEditionPatternInstance() != null) { return getEditionPatternInstance().getPattern(); } return null; } public GraphicalElementPatternRole getPatternRole() { EditionPatternReference ref = getEditionPatternReference(); if (ref != null && ref.getPatternRole() instanceof GraphicalElementPatternRole) { return (GraphicalElementPatternRole) ref.getPatternRole(); } return null; } /** * Return EditionPatternReference for that object<br> * * If many EditionPatternReferences are defined for this object, return preferabely an EditionPatternReference where this object plays a * primary role * * @return */ public EditionPatternReference getEditionPatternReference() { // Default behaviour is to have only one EditionPattern where // this graphical element plays a representation primitive role // When many, big pbs may happen !!!! if (getEditionPatternReferences() != null) { if (getEditionPatternReferences().size() > 0) { EditionPatternReference returned = null; for (EditionPatternReference r : getEditionPatternReferences()) { if (r.getPatternRole() instanceof GraphicalElementPatternRole) { GraphicalElementPatternRole grPatternRole = (GraphicalElementPatternRole) r.getPatternRole(); if (grPatternRole.getIsPrimaryRepresentationRole()) { if (returned != null) { if (logger.isLoggable(Level.WARNING)) { logger.warning("More than one edition pattern reference where element plays a primary role 1 !!!!"); } for (EditionPatternReference r2 : getEditionPatternReferences()) { if (logger.isLoggable(Level.WARNING)) { logger.warning("> " + r2.getEditionPatternInstance().debug()); } } } returned = r; } else if (grPatternRole.isIncludedInPrimaryRepresentationRole()) { if (returned != null) { if (logger.isLoggable(Level.WARNING)) { logger.warning("More than one edition pattern reference where element plays a primary role 2 !!!!"); } for (EditionPatternReference r2 : getEditionPatternReferences()) { if (logger.isLoggable(Level.WARNING)) { logger.warning("> " + r2.getEditionPatternInstance().debug()); } } } returned = r; } } } if (returned != null) { return returned; } } } if (getEditionPatternReferences() != null && getEditionPatternReferences().size() > 0) { return getEditionPatternReferences().get(0); } return null; } /** * Return EditionPatternInstance for that object<br> * * If many EditionPatternInstance are defined for this object, return preferabely an EditionPatternReference where this object plays a * primary role * * @return */ public EditionPatternInstance getEditionPatternInstance() { if (getEditionPatternReference() != null) { return getEditionPatternReference().getEditionPatternInstance(); } if (getEditionPatternReferences() != null && getEditionPatternReferences().size() > 0) { return getEditionPatternReferences().get(0).getEditionPatternInstance(); } return null; } @Override public String getInspectorTitle() { for (EditionPatternReference ref : getEditionPatternReferences()) { return FlexoLocalization.localizedForKey(ref.getEditionPattern().getName()); } // Otherwise, take default inspector name return super.getInspectorTitle(); } @Override public BindingFactory getBindingFactory() { // TODO Auto-generated method stub return null; } @Override public BindingModel getBindingModel() { // TODO Auto-generated method stub return null; } private synchronized void updateDependingObjects() { ArrayList<TargetObject> newDependingObjects = new ArrayList<TargetObject>(); ArrayList<TargetObject> deletedDependingObjects = new ArrayList<TargetObject>(); deletedDependingObjects.addAll(dependingObjects); if (getDependingObjects() != null) { for (TargetObject o : getDependingObjects()) { if (deletedDependingObjects.contains(o)) { deletedDependingObjects.remove(o); } else { newDependingObjects.add(o); } } } for (TargetObject o : deletedDependingObjects) { dependingObjects.remove(o); if (o.target instanceof HasPropertyChangeSupport) { PropertyChangeSupport pcSupport = ((HasPropertyChangeSupport) o.target).getPropertyChangeSupport(); // System.out.println("Element " + this + " remove property change listener: " + o.target + " property:" + o.propertyName); pcSupport.removePropertyChangeListener(o.propertyName, this); } else if (o.target instanceof Observable) { // System.out.println("Element " + this + " remove observable: " + o); ((Observable) o.target).deleteObserver(this); } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Element " + this + " cannot stop observe: " + o); } } } for (TargetObject o : newDependingObjects) { dependingObjects.add(o); if (o.target instanceof HasPropertyChangeSupport) { PropertyChangeSupport pcSupport = ((HasPropertyChangeSupport) o.target).getPropertyChangeSupport(); // System.out.println("Element " + this + " add property change listener: " + o.target + " property:" + o.propertyName); pcSupport.addPropertyChangeListener(o.propertyName, this); } else if (o.target instanceof Observable) { // System.out.println("Element " + this + " add observable: " + o); ((Observable) o.target).addObserver(this); } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Element " + this + " cannot observe: " + o); } } } // debug /*if (getPatternRole() != null && getPatternRole().getPatternRoleName().equals("conceptLabel")) { System.out.println("Je suis le conceptLabel, je depends de: " + getPatternRole().getLabel()); for (TargetObject o : dependingObjects) { System.out.println("> [" + o.propertyName + "] " + o.target); } }*/ dependingObjectsAreComputed = true; } protected synchronized void appendToDependingObjects(ViewPointDataBinding binding, List<TargetObject> returned) { if (binding.isSet()) { List<TargetObject> list = binding.getBinding().getTargetObjects(getEditionPatternInstance()); /*for (String patternRole : getEditionPatternInstance().getActors().keySet()) { list.add(new TargetObject(target, patternRole)); }*/ if (list != null) { for (TargetObject t : list) { if (!returned.contains(t)) { returned.add(t); } } } } } public synchronized List<TargetObject> getDependingObjects() { List<TargetObject> returned = new ArrayList<TargetObject>(); if (getPatternRole() != null) { appendToDependingObjects(getPatternRole().getLabel(), returned); } return returned; } @Override public void update(Observable o, Object arg) { // System.out.println("**************> ViewElement " + this + " : receive notification " + arg + " observable=" + o); update(); } @Override public void propertyChange(PropertyChangeEvent evt) { // Note: this object observes two kind of objects // - objects that are relevant in the context of the computing of their representation, such as label // - they also observe their GR // If the case of their GR observing, update() should not be invoked, only invoke setChanged() in order // to resource to be flagged as modified // logger.info("**************> ViewElement " + this + " : receive PropertyChangeEvent " + evt.getPropertyName() + " source=" // + evt.getSource().getClass().getSimpleName() + " evt=" + evt); if (evt.getSource() == getGraphicalRepresentation()) { // We just want here to track events such as object moving, just to flag the resource as modified // Ignore focused or selected events, because goal here is to mark resource as modified if (!evt.getPropertyName().equals(GraphicalRepresentation.Parameters.isFocused.name()) && !evt.getPropertyName().equals(GraphicalRepresentation.Parameters.isSelected.name())) { // System.out.println("setChanged() because of " + evt.getPropertyName() + " evt=" + evt); setChanged(); } } else { // In this case, we really need to update object, because an object involved in the computing of // the label for instance has changed update(); } } /** * This method is called whenever a change has been detected potentially affecting underlying graphical representation Depending objects * are recomputed, and notification of potential change is thrown, to be later caught by underlying GR (VEShapeGR or VEConnectorGR) */ public void update() { // System.out.println("Update in ViewElement " + this + ", text=" + getLabelValue()); updateDependingObjects(); setChanged(); notifyObservers(new ElementUpdated(this)); } /** * Apply all graphical element specifications as it was defined in related pattern role */ protected void applyGraphicalElementSpecifications() { if (getPatternRole() != null) { for (GraphicalElementSpecification grSpec : getPatternRole().getGrSpecifications()) { if (grSpec.getValue().isValid()) { grSpec.applyToGraphicalRepresentation(getGraphicalRepresentation(), this); } } } } /** * Reset graphical representation to be the one defined in related pattern role */ public abstract void resetGraphicalRepresentation(); /** * Refresh graphical representation */ public void refreshGraphicalRepresentation() { applyGraphicalElementSpecifications(); } @Override public void setGraphicalRepresentation(GraphicalRepresentation<?> graphicalRepresentation) { super.setGraphicalRepresentation(graphicalRepresentation); update(); } /** * Return the index of this ViewElement, relative to its position in the list of ViewObject declared to be of same EditionPattern * * @return */ public int getIndexRelativeToEPType() { if (getParent() == null) { return -1; } return getParent().getChildsOfType(getEditionPattern()).indexOf(this); } /** * Sets the index of this ViewElement, relative to its position in the list of ViewObject declared to be of same EditionPattern * * @param index */ public void setIndexRelativeToEPType(int index) { if (getIndexRelativeToEPType() != index && !isDeserializing()) { getParent().setIndexForChildRelativeToEPType(this, index); } } protected void notifyIndexChange() { refreshGraphicalRepresentation(); } }