/*
* (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.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;
import java.util.logging.Logger;
import javax.naming.InvalidNameException;
import org.openflexo.fge.GraphicalRepresentation;
import org.openflexo.foundation.NameChanged;
import org.openflexo.foundation.rm.DuplicateResourceException;
import org.openflexo.foundation.rm.FlexoProject;
import org.openflexo.foundation.rm.XMLStorageResourceData;
import org.openflexo.foundation.viewpoint.EditionPattern;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
public abstract class ViewObject extends AbstractViewObject implements PropertyChangeListener {
private static final Logger logger = Logger.getLogger(ViewObject.class.getPackage().getName());
private View _shema;
private String _name;
private ViewObject parent = null;
private Vector<ViewElement> childs;
// We dont want to import graphical engine in foundation
// But you can assert graphical representation is a org.openflexo.fge.GraphicalRepresentation.
// For a OEShema, graphicalRepresentation is a DrawingGraphicalRepresentation
// For a OEShape, graphicalRepresentation is a ShapeGraphicalRepresentation
// For a OEConnector, graphicalRepresentation is a ConnectorGraphicalRepresentation
private GraphicalRepresentation<?> _graphicalRepresentation;
// ==========================================================================
// ============================= Constructor
// ================================
// ==========================================================================
/**
* Never use this constructor except for ComponentLibrary
*/
public ViewObject(FlexoProject project) {
super(project);
childs = new Vector<ViewElement>();
}
/**
* Default constructor
*/
public ViewObject(View shema) {
this(shema.getProject());
setShema(shema);
}
public View getShema() {
return _shema;
}
public void setShema(View shema) {
_shema = shema;
}
/**
* Returns reference to the main object in which this XML-serializable object is contained relating to storing scheme: here it's the
* component library
*
* @return the component library
*/
@Override
public XMLStorageResourceData getXMLResourceData() {
return getShema();
}
@Override
public String getName() {
return _name;
}
@Override
public void setName(String name) throws DuplicateResourceException, InvalidNameException {
if (requireChange(_name, name)) {
String oldName = _name;
_name = name;
setChanged();
notifyObservers(new NameChanged(oldName, name));
}
}
public Vector<ViewElement> getChilds() {
return childs;
}
public void setChilds(Vector<ViewElement> someChilds) {
childs.addAll(someChilds);
}
public void addToChilds(ViewElement aChild) {
// logger.info("****** addToChild() put "+aChild+" under "+this);
childs.add(aChild);
aChild.setParent(this);
setChanged();
if (aChild instanceof ViewShape) {
notifyObservers(new ShapeInserted((ViewShape) aChild, this));
}
if (aChild instanceof ViewConnector) {
notifyObservers(new ConnectorInserted((ViewConnector) aChild));
}
}
public void removeFromChilds(ViewElement aChild) {
childs.remove(aChild);
setChanged();
if (aChild instanceof ViewShape) {
notifyObservers(new ShapeRemoved((ViewShape) aChild, this));
}
if (aChild instanceof ViewConnector) {
notifyObservers(new ConnectorRemoved((ViewConnector) aChild));
}
}
/**
* Re-index child, as it is defined in diagram hierarchy
*
* @param aChild
* @param newIndex
*/
protected void setIndexForChild(ViewElement aChild, int newIndex) {
if (childs.contains(aChild) && childs.indexOf(aChild) != newIndex) {
childs.remove(aChild);
childs.insertElementAt(aChild, newIndex);
for (ViewElement o : childs) {
o.notifyIndexChange();
}
}
}
/**
* Return the index of this ViewElement, as it is defined in diagram hierarchy
*
* @return
*/
public int getIndex() {
if (getParent() == null) {
return -1;
}
return getParent().getChilds().indexOf(this);
}
/**
* Sets the index of this ViewElement, as it is defined in diagram hierarchy
*
* @param index
*/
public void setIndex(int index) {
if (getIndex() != index && !isDeserializing() && this instanceof ViewElement) {
getParent().setIndexForChild((ViewElement) this, index);
}
}
/**
* Re-index child, relative to its position in the list of ViewObject declared to be of same EditionPattern
*
* @param aChild
* @param newIndex
*/
protected void setIndexForChildRelativeToEPType(ViewElement aChild, int newIndex) {
List<ViewElement> childsOfRightType = getChildsOfType(aChild.getEditionPattern());
if (childsOfRightType.contains(aChild) && childsOfRightType.indexOf(aChild) != newIndex) {
if (newIndex > 0) {
ViewElement previousElement = childsOfRightType.get(newIndex - 1);
int previousElementIndex = childs.indexOf(previousElement);
childs.remove(aChild);
if (previousElementIndex + 1 <= childs.size()) {
childs.insertElementAt(aChild, previousElementIndex + 1);
} else {
childs.insertElementAt(aChild, childs.size());
}
} else {
ViewElement firstElement = childsOfRightType.get(0);
int firstElementIndex = childs.indexOf(firstElement);
childs.remove(aChild);
childs.insertElementAt(aChild, firstElementIndex);
}
for (ViewElement o : childs) {
o.notifyIndexChange();
}
}
}
public List<ViewElement> getChildsOfType(EditionPattern editionPattern) {
ArrayList<ViewElement> returned = new ArrayList<ViewElement>();
for (ViewObject o : getChilds()) {
if (o instanceof ViewElement) {
ViewElement e = (ViewElement) o;
if (e.getEditionPattern() == editionPattern) {
returned.add(e);
}
}
}
return returned;
}
public <T extends ViewObject> Collection<T> getChildrenOfType(final Class<T> type) {
return getChildrenOfType(type, true);
}
@SuppressWarnings("unchecked")
// We can remove the warning because the code performs the necessary checks
public <T extends ViewObject> Collection<T> getChildrenOfType(final Class<T> type, boolean recursive) {
Collection<T> objects = (Collection<T>) Collections2.filter(new ArrayList<ViewObject>(childs), new Predicate<ViewObject>() {
@Override
public boolean apply(ViewObject input) {
return type.isAssignableFrom(input.getClass());
}
});
if (recursive) {
for (ViewObject object : childs) {
objects.addAll(object.getChildrenOfType(type, true));
}
}
return objects;
}
public ViewShape getShapeNamed(String name) {
for (ViewObject o : childs) {
if (o instanceof ViewShape && o.getName() != null && o.getName().equals(name)) {
return (ViewShape) o;
}
}
return null;
}
public ViewConnector getConnectorNamed(String name) {
for (ViewObject o : childs) {
if (o instanceof ViewConnector && o.getName() != null && o.getName().equals(name)) {
return (ViewConnector) o;
}
}
return null;
}
@Override
public void delete() {
if (this._graphicalRepresentation != null && this._graphicalRepresentation.getPropertyChangeSupport() != null) {
this._graphicalRepresentation.getPropertyChangeSupport().removePropertyChangeListener(this);
}
super.delete();
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
setChanged();
}
public GraphicalRepresentation<?> getGraphicalRepresentation() {
return _graphicalRepresentation;
}
public void setGraphicalRepresentation(GraphicalRepresentation<?> graphicalRepresentation) {
// logger.info("************************* setGraphicalRepresentation() dans " + this + " of " + getClass());
if (this._graphicalRepresentation != null) {
this._graphicalRepresentation.getPropertyChangeSupport().removePropertyChangeListener(this);
}
_graphicalRepresentation = graphicalRepresentation;
setChanged();
if (this._graphicalRepresentation != null) {
this._graphicalRepresentation.getPropertyChangeSupport().addPropertyChangeListener(this);
}
}
private Vector<ViewObject> ancestors;
public ViewObject getParent() {
return parent;
}
protected void setParent(ViewObject parent) {
this.parent = parent;
}
public Vector<ViewObject> getAncestors() {
if (ancestors == null) {
ancestors = new Vector<ViewObject>();
ViewObject current = getParent();
while (current != null) {
ancestors.add(current);
current = current.getParent();
}
}
return ancestors;
}
public static ViewObject getFirstCommonAncestor(ViewObject child1, ViewObject child2) {
Vector<ViewObject> ancestors1 = child1.getAncestors();
Vector<ViewObject> ancestors2 = child2.getAncestors();
for (int i = 0; i < ancestors1.size(); i++) {
ViewObject o1 = ancestors1.elementAt(i);
if (ancestors2.contains(o1)) {
return o1;
}
}
return null;
}
public abstract boolean isContainedIn(ViewObject o);
public final boolean contains(ViewObject o) {
return o.isContainedIn(this);
}
@Override
public abstract String getDisplayableDescription();
}