blob: e2240ba6de5531245aaa76fdac9e8d7d929296db [file] [log] [blame]
/*******************************************************************************
* Copyright 2005-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
* 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:
* The Chisel Group, University of Victoria
*******************************************************************************/
package org.eclipse.mylar.zest.core.internal.graphmodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.draw2d.FigureUtilities;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.mylar.zest.layouts.constraints.LayoutConstraint;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
/**
* A model object that indirectly references a node. It is used at times when a
* graph model node needs to be virtually duplicated on the display, but not in
* the actual model.
*
* Note: almost all calls are sent directly to the proxy. This means, color changes,
* font changes, etc. Will be forwarded to the proxy. Calls that are not forwarded
* are noted in the javadocs.
* @author Del Myers
*
*/
//@tag bug(153466-NoNestedClientSupply(fix)) : don't nest nodes in the client/supplier panes.
//@tag bug(154259-Abstraction(fix)) : implement IGraphModelNode.
public class NonNestedProxyNode extends GraphItem implements IGraphModelNode {
private IGraphModelNode proxy;
private ArrayList sourceConnections;
private ArrayList targetConnections;
private ProxyListener proxyListener;
private Point currentLocation;
private Dimension currentSize;
private boolean preferredLocation;
private boolean selected;
private boolean highlighted;
private Object internalNode;
private Dimension labelSize;
private class ProxyListener implements PropertyChangeListener {
/* (non-Javadoc)
* @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent evt) {
String property = evt.getPropertyName();
if (
LOCATION_PROP.equals(property) ||
SIZE_PROP.equals(property) ||
SOURCE_CONNECTIONS_PROP.equals(property) ||
TARGET_CONNECTIONS_PROP.equals(property) ||
HIGHLIGHT_PROP.equals(property) ||
VISIBLE_PROP.equals(property)
) return;
firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
}
}
/**
* Creates a new node that references the given proxy. Initial display information
* will be taken from the proxy.
*/
protected NonNestedProxyNode(IGraphModelNode proxy) {
super(proxy.getGraphModel());
this.proxy = proxy;
setData(proxy.getExternalNode());
proxyListener = new ProxyListener();
sourceConnections = new ArrayList();
targetConnections = new ArrayList();
currentLocation = proxy.getLocation().getCopy();
currentSize = proxy.getSize().getCopy();
this.preferredLocation = proxy.hasPreferredLocation();
}
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Widget#getData()
*/
public Object getData() {
return getExternalNode();
}
/**
* Connects this node to its proxy to start listening for property changes on
* the proxy. Any overriders must call super on this methd.
*
*/
protected void activate() {
proxy.addPropertyChangeListener(proxyListener);
}
/**
* Disconnects this node from its proxy and stops listening for changes.
* Any overriders must call super on this methd.
*
*/
protected void deactivate() {
proxy.removePropertyChangeListener(proxyListener);
}
/**
* Adds the given connection to the list of connections. This is not forwarded
* to the proxy. All connections must be added manually to this node
* because it is impossible to infer from the model which connections should
* be copied from the proxy.
* @param connection
* @param source true if the given connection should be added as a source.
*/
public void addConnection(IGraphModelConnection connection, boolean source) {
if (connection != null) {
if (source) {
if (connection.getSource() == this) {
sourceConnections.add(connection);
firePropertyChange(SOURCE_CONNECTIONS_PROP, null, connection);
}
} else {
if (connection.getDestination() == this) {
targetConnections.add(connection);
firePropertyChange(TARGET_CONNECTIONS_PROP, null, connection);
}
}
}
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#changeBackgroundColor(org.eclipse.swt.graphics.Color)
*/
public void changeBackgroundColor(Color c) {
proxy.changeBackgroundColor(c);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getBackgroundColor()
*/
public Color getBackgroundColor() {
return proxy.getBackgroundColor();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getBorderColor()
*/
public Color getBorderColor() {
return proxy.getBorderColor();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getBorderWidth()
*/
public int getBorderWidth() {
return proxy.getBorderWidth();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getExternalNode()
*/
public Object getExternalNode() {
return proxy.getExternalNode();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getFont()
*/
public Font getFont() {
return proxy.getFont();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getForegroundColor()
*/
public Color getForegroundColor() {
return proxy.getForegroundColor();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getGraphModel()
*/
public GraphModel getGraphModel() {
return proxy.getGraphModel();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getHighlightAdjacentColor()
*/
public Color getHighlightAdjacentColor() {
return proxy.getHighlightAdjacentColor();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getHighlightColor()
*/
public Color getHighlightColor() {
return proxy.getHighlightColor();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getImage()
*/
public Image getImage() {
return proxy.getImage();
}
/**
* Not forwarded to the proxy.
*/
public Point getLocation() {
return currentLocation.getCopy();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getNodeStyle()
*/
public int getNodeStyle() {
return proxy.getNodeStyle();
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getSize()
*/
public Dimension getSize() {
return currentSize.getCopy();
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getSourceConnections()
*/
public List getSourceConnections() {
return sourceConnections;
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getTargetConnections()
*/
public List getTargetConnections() {
return targetConnections;
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getText()
*/
public String getText() {
return proxy.getText();
}
/**
* Highlights the node changing the background color and border color.
* The source and destination connections are also highlighted,
* and the adjacent nodes are highlighted too in a different color.
*/
public void highlight() {
if (isHighlighted()) return;
changeBackgroundColor(getHighlightColor());
// highlight the adjacent nodes
for (Iterator iter = sourceConnections.iterator(); iter.hasNext();) {
IGraphModelConnection conn = (IGraphModelConnection)iter.next();
conn.highlight();
conn.getDestination().highlightAdjacent();
}
for (Iterator iter = targetConnections.iterator(); iter.hasNext();) {
IGraphModelConnection conn = (IGraphModelConnection)iter.next();
conn.highlight();
conn.getSource().highlightAdjacent();
}
highlighted = true;
firePropertyChange(HIGHLIGHT_PROP, Boolean.FALSE, Boolean.TRUE);
}
public boolean isHighlighted() {
return highlighted;
}
/**
* Restores the nodes original background color and border width.
*/
public void unhighlight() {
if (!isHighlighted()) return;
changeBackgroundColor(getUnhiglightColor());
// unhighlight the adjacent edges
for (Iterator iter = sourceConnections.iterator(); iter.hasNext();) {
IGraphModelConnection conn = (IGraphModelConnection)iter.next();
conn.unhighlight();
conn.getDestination().unhighlight();
}
for (Iterator iter = targetConnections.iterator(); iter.hasNext();) {
IGraphModelConnection conn = (IGraphModelConnection)iter.next();
conn.unhighlight();
conn.getSource().unhighlight();
}
highlighted = false;
firePropertyChange(HIGHLIGHT_PROP, Boolean.TRUE, Boolean.FALSE);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#highlightAdjacent()
*/
public void highlightAdjacent() {
proxy.highlightAdjacent();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#isHighlightAdjacentNodes()
*/
public boolean isHighlightAdjacentNodes() {
return proxy.isHighlightAdjacentNodes();
}
/**
* Not forwarded to the proxy
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#removeConnection(org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelConnection)
*/
public boolean removeConnection(IGraphModelConnection connection) {
boolean removed = false;
if (connection != null) {
if (connection.getSource() == this) {
removed = sourceConnections.remove(connection);
if (removed) {
firePropertyChange(SOURCE_CONNECTIONS_PROP, null, connection);
}
}
if (connection.getDestination() == this) {
removed = targetConnections.remove(connection);
if (removed) {
firePropertyChange(TARGET_CONNECTIONS_PROP, null, connection);
}
}
}
return removed;
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setBackgroundColor(org.eclipse.swt.graphics.Color)
*/
public void setBackgroundColor(Color c) {
proxy.setBackgroundColor(c);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setBorderColor(org.eclipse.swt.graphics.Color)
*/
public void setBorderColor(Color c) {
proxy.setBorderColor(c);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setBorderHighlightColor(org.eclipse.swt.graphics.Color)
*/
public void setBorderHighlightColor(Color c) {
proxy.setBorderHighlightColor(c);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setBorderWidth(int)
*/
public void setBorderWidth(int width) {
proxy.setBorderWidth(width);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setFont(org.eclipse.swt.graphics.Font)
*/
public void setFont(Font f) {
proxy.setFont(f);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setForegroundColor(org.eclipse.swt.graphics.Color)
*/
public void setForegroundColor(Color c) {
proxy.setForegroundColor(c);
}
/**
* Not forarded to the proxy.
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setHasPreferredLocation(boolean)
*/
public void setHasPreferredLocation(boolean hasPreferredLocation) {
this.preferredLocation = hasPreferredLocation;
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#hasPreferredLocation()
*/
public boolean hasPreferredLocation() {
return preferredLocation;
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setHighlightAdjacentColor(org.eclipse.swt.graphics.Color)
*/
public void setHighlightAdjacentColor(Color c) {
proxy.setHighlightAdjacentColor(c);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setHighlightAdjacentNodes(boolean)
*/
public void setHighlightAdjacentNodes(boolean highlightAdjacent) {
proxy.setHighlightAdjacentNodes(highlightAdjacent);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setHighlightColor(org.eclipse.swt.graphics.Color)
*/
public void setHighlightColor(Color c) {
proxy.setHighlightColor(c);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setImage(org.eclipse.swt.graphics.Image)
*/
public void setImage(Image image) {
proxy.setImage(image);
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setLocation(double, double)
*/
public void setLocation( double x, double y ) {
Point oldPoint = getLocation();
currentLocation.setLocation((int)x, (int)y);
firePropertyChange(LOCATION_PROP, oldPoint, currentLocation);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setNodeStyle(int)
*/
public void setNodeStyle(int style) {
proxy.setNodeStyle(style);
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setPreferredLocation(double, double)
*/
public void setPreferredLocation(double x, double y) {
setLocation(x,y);
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setSelected(boolean)
*/
public void setSelected( boolean selected ) {
if (selected = isSelected()) return;
if (selected) {
highlight();
} else {
unhighlight();
}
this.selected = selected;
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#isSelected()
*/
public boolean isSelected() {
return selected;
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setText(java.lang.String)
*/
public void setText(String text) {
proxy.setText(text);
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.layouts.LayoutEntity#getHeightInLayout()
*/
public double getHeightInLayout() {
return getSize().height;
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.layouts.LayoutEntity#getLayoutInformation()
*/
public Object getLayoutInformation() {
return internalNode;
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.layouts.LayoutEntity#getWidthInLayout()
*/
public double getWidthInLayout() {
return getSize().width;
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.layouts.LayoutEntity#getXInLayout()
*/
public double getXInLayout() {
return getLocation().x;
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.layouts.LayoutEntity#getYInLayout()
*/
public double getYInLayout() {
return getLocation().y;
}
/**
* Does nothing.
* @see org.eclipse.mylar.zest.layouts.LayoutEntity#populateLayoutConstraint(org.eclipse.mylar.zest.layouts.constraints.LayoutConstraint)
*/
public void populateLayoutConstraint(LayoutConstraint constraint) {
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.layouts.LayoutEntity#setLayoutInformation(java.lang.Object)
*/
public void setLayoutInformation(Object internalEntity) {
this.internalNode = internalEntity;
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.layouts.LayoutEntity#setLocationInLayout(double, double)
*/
public void setLocationInLayout(double x, double y) {
setLocation(x, y);
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.layouts.LayoutEntity#setSizeInLayout(double, double)
*/
public void setSizeInLayout(double width, double height) {
setSize(width, height);
}
/**
* Not forwarded to the proxy.
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#setSize(double, double)
*/
public void setSize(double width, double height) {
Object old = getSize();
currentSize.setSize(new Dimension((int)width, (int)height));
firePropertyChange(SIZE_PROP, old, currentSize);
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Object otherNode) {
int rv = 0;
if (otherNode instanceof IGraphModelNode) {
IGraphModelNode node = (IGraphModelNode)otherNode;
if (this.getText() != null) {
rv = this.getText().compareTo(node.getText());
}
}
return rv;
}
public IGraphModelNode getProxy() {
return proxy;
}
/**
* Returns the extent of the text and the image with some padding.
* @return Dimension the minimum size needed to display the text and the image
*/
public Dimension calculateMinimumLabelSize() {
if (labelSize == null) {
Dimension text = calculateTextExtents();
Dimension icon = calculateImageExtents();
labelSize = new Dimension(text.width + icon.width, Math.max(text.height, icon.height));
labelSize.expand(12, 6);
}
return labelSize;
}
private Dimension calculateTextExtents() {
Dimension dim = new Dimension(0, 0);
String text = getText();
if (text != null) {
Font font = getFont();
if (font == null) {
font = JFaceResources.getDefaultFont();
}
dim.setSize(FigureUtilities.getTextExtents(text + " ", font));
}
return dim;
}
private Dimension calculateImageExtents() {
Dimension dim = new Dimension(0, 0);
Image image = getImage();
if (image != null) {
dim.setSize(new Dimension(image.getBounds().width + 4, image.getBounds().height));
}
return dim;
}
/**
* Gets the minimum size for this node. This is the minimum size of the label (text & icon)
* @return Dimension
*/
public Dimension calculateMinimumSize() {
return calculateMinimumLabelSize();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getUnhiglightColor()
*/
public Color getUnhiglightColor() {
return proxy.getUnhiglightColor();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getBorderHighlightColor()
*/
public Color getBorderHighlightColor() {
return proxy.getBorderHighlightColor();
}
/* (non-Javadoc)
* @see org.eclipse.mylar.zest.core.internal.graphmodel.IGraphModelNode#getBorderUnhiglightColor()
*/
public Color getBorderUnhiglightColor() {
return proxy.getBorderUnhiglightColor();
}
public boolean cacheLabel() {
// TODO Auto-generated method stub
return false;
}
public void setCacheLabel(boolean cacheLabel) {
// TODO Auto-generated method stub
}
}