blob: 8ec65226921efd045d9c0c0d40e9de95ff751935 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 Boeing.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Boeing - initial API and implementation
*******************************************************************************/
package org.eclipse.osee.ats.workflow.editor.model;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.jface.viewers.ICellEditorValidator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.PropertyDescriptor;
import org.eclipse.ui.views.properties.TextPropertyDescriptor;
/**
* Abstract prototype of a shape. Has a size (width and height), a location (x and y position) and a list of incoming
* and outgoing connections. Use subclasses to instantiate a specific shape.
*
* @see org.eclipse.osee.ats.workflow.editor.model.WorkPageShape
* @see org.eclipse.osee.ats.workflow.editor.model.EllipticalShape
* @author Donald G. Dunne
*/
public abstract class Shape extends ModelElement {
/**
* A static array of property descriptors. There is one IPropertyDescriptor entry per editable property.
*
* @see #getPropertyDescriptors()
* @see #getPropertyValue(Object)
* @see #setPropertyValue(Object, Object)
*/
private IPropertyDescriptor[] descriptors;
private final List<IPropertyDescriptor> descriptorList = new ArrayList<IPropertyDescriptor>();
/** ID for the Height property value (used for by the corresponding property descriptor). */
private static final String HEIGHT_PROP = "Shape.Height";
/** Property ID to use when the location of this shape is modified. */
public static final String LOCATION_PROP = "Shape.Location";
private static final long serialVersionUID = 1;
/** Property ID to use then the size of this shape is modified. */
public static final String SIZE_PROP = "Shape.Size";
/** Property ID to use when the list of outgoing connections is modified. */
public static final String SOURCE_CONNECTIONS_PROP = "Shape.SourceConn";
/** Property ID to use when the list of incoming connections is modified. */
public static final String TARGET_CONNECTIONS_PROP = "Shape.TargetConn";
/** ID for the Width property value (used for by the corresponding property descriptor). */
private static final String WIDTH_PROP = "Shape.Width";
/** ID for the X property value (used for by the corresponding property descriptor). */
private static final String XPOS_PROP = "Shape.xPos";
/** ID for the Y property value (used for by the corresponding property descriptor). */
private static final String YPOS_PROP = "Shape.yPos";
protected abstract String getName();
protected abstract String getToolTip();
/** Location of this shape. */
private final Point location = new Point(0, 0);
/** Size of this shape. */
private final Dimension size = new Dimension(50, 50);
/** List of outgoing Connections. */
private final List<Relation> sourceConnections = new ArrayList<Relation>();
/** List of incoming Connections. */
private final List<Relation> targetConnections = new ArrayList<Relation>();
private WorkflowDiagram workflowDiagram;
/**
* Add an incoming or outgoing connection to this shape.
*
* @param conn a non-null connection instance
* @throws IllegalArgumentException if the connection is null or has not distinct endpoints
*/
void addConnection(Relation conn) {
if (conn == null || conn.getSource() == conn.getTarget()) {
throw new IllegalArgumentException();
}
if (conn.getSource() == this) {
sourceConnections.add(conn);
firePropertyChange(SOURCE_CONNECTIONS_PROP, null, conn);
} else if (conn.getTarget() == this) {
targetConnections.add(conn);
firePropertyChange(TARGET_CONNECTIONS_PROP, null, conn);
}
}
/**
* Return a pictogram (small icon) describing this model element. Children should override this method and return an
* appropriate Image.
*
* @return a 16x16 Image or null
*/
public abstract Image getIcon();
/**
* Return the Location of this shape.
*
* @return a non-null location instance
*/
public Point getLocation() {
return location.getCopy();
}
/**
* Returns an array of IPropertyDescriptors for this shape.
* <p>
* The returned array is used to fill the property view, when the edit-part corresponding to this model element is
* selected.
* </p>
*
* @see #descriptors
* @see #getPropertyValue(Object)
* @see #setPropertyValue(Object, Object)
*/
@Override
public IPropertyDescriptor[] getPropertyDescriptors() {
if (descriptors == null) {
initializePropertyDescriptors(descriptorList);
descriptors = descriptorList.toArray(new IPropertyDescriptor[descriptorList.size()]);
}
return descriptors;
}
protected void initializePropertyDescriptors(List<IPropertyDescriptor> descriptorList) {
descriptorList.add(new TextPropertyDescriptor(XPOS_PROP, "X")); // id and description pair
descriptorList.add(new TextPropertyDescriptor(YPOS_PROP, "Y"));
descriptorList.add(new TextPropertyDescriptor(WIDTH_PROP, "Width"));
descriptorList.add(new TextPropertyDescriptor(HEIGHT_PROP, "Height"));
// use a custom cell editor validator for all four array entries
for (IPropertyDescriptor descriptor : descriptorList) {
((PropertyDescriptor) descriptor).setValidator(new ICellEditorValidator() {
@Override
public String isValid(Object value) {
int intValue = -1;
try {
intValue = Integer.parseInt((String) value);
} catch (NumberFormatException exc) {
return "Not a number";
}
return intValue >= 0 ? null : "Value must be >= 0";
}
});
}
}
/**
* Return the property value for the given propertyId, or null.
* <p>
* The property view uses the IDs from the IPropertyDescriptors array to obtain the value of the corresponding
* properties.
* </p>
*
* @see #descriptors
* @see #getPropertyDescriptors()
*/
@Override
public Object getPropertyValue(Object propertyId) {
if (XPOS_PROP.equals(propertyId)) {
return Integer.toString(location.x);
}
if (YPOS_PROP.equals(propertyId)) {
return Integer.toString(location.y);
}
if (HEIGHT_PROP.equals(propertyId)) {
return Integer.toString(size.height);
}
if (WIDTH_PROP.equals(propertyId)) {
return Integer.toString(size.width);
}
return super.getPropertyValue(propertyId);
}
/**
* Return the Size of this shape.
*
* @return a non-null Dimension instance
*/
public Dimension getSize() {
return size.getCopy();
}
/**
* Return a List of outgoing Connections.
*/
public List<Relation> getSourceConnections() {
return new ArrayList<Relation>(sourceConnections);
}
/**
* Return a List of incoming Connections.
*/
public List<Relation> getTargetConnections() {
return new ArrayList<Relation>(targetConnections);
}
/**
* Remove an incoming or outgoing connection from this shape.
*
* @param conn a non-null connection instance
* @throws IllegalArgumentException if the parameter is null
*/
void removeConnection(Relation conn) {
if (conn == null) {
throw new IllegalArgumentException();
}
if (conn.getSource() == this) {
sourceConnections.remove(conn);
firePropertyChange(SOURCE_CONNECTIONS_PROP, null, conn);
} else if (conn.getTarget() == this) {
targetConnections.remove(conn);
firePropertyChange(TARGET_CONNECTIONS_PROP, null, conn);
}
}
/**
* Set the Location of this shape.
*
* @param newLocation a non-null Point instance
* @throws IllegalArgumentException if the parameter is null
*/
public void setLocation(Point newLocation) {
if (newLocation == null) {
throw new IllegalArgumentException();
}
location.setLocation(newLocation);
firePropertyChange(LOCATION_PROP, null, location);
}
/**
* Set the property value for the given property id. If no matching id is found, the call is forwarded to the
* superclass.
* <p>
* The property view uses the IDs from the IPropertyDescriptors array to set the values of the corresponding
* properties.
* </p>
*
* @see #descriptors
* @see #getPropertyDescriptors()
*/
@Override
public void setPropertyValue(Object propertyId, Object value) {
if (XPOS_PROP.equals(propertyId)) {
int x = Integer.parseInt((String) value);
setLocation(new Point(x, location.y));
} else if (YPOS_PROP.equals(propertyId)) {
int y = Integer.parseInt((String) value);
setLocation(new Point(location.x, y));
} else if (HEIGHT_PROP.equals(propertyId)) {
int height = Integer.parseInt((String) value);
setSize(new Dimension(size.width, height));
} else if (WIDTH_PROP.equals(propertyId)) {
int width = Integer.parseInt((String) value);
setSize(new Dimension(width, size.height));
} else {
super.setPropertyValue(propertyId, value);
}
}
/**
* Set the Size of this shape. Will not modify the size if newSize is null.
*
* @param newSize a non-null Dimension instance or null
*/
public void setSize(Dimension newSize) {
if (newSize != null) {
size.setSize(newSize);
firePropertyChange(SIZE_PROP, null, size);
}
}
/**
* @return the workflowDiagram
*/
public WorkflowDiagram getWorkflowDiagram() {
return workflowDiagram;
}
/**
* @param workflowDiagram the workflowDiagram to set
*/
public void setWorkflowDiagram(WorkflowDiagram workflowDiagram) {
this.workflowDiagram = workflowDiagram;
}
}