view java/src/uk/ac/qmul/eecs/ccmi/diagrammodel/DiagramNode.java @ 8:ea7885bd9bff tip

fixed bug : render solid line as dotted/dashed when moving the stylus from dotted/dashed to solid
author ccmi-guest
date Thu, 03 Jul 2014 16:12:20 +0100
parents d66dd5880081
children
line wrap: on
line source
/*  
 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
  
 Copyright (C) 2011  Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)

 This program 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.

 This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package uk.ac.qmul.eecs.ccmi.diagrammodel;

import java.util.List;
import java.util.Set;

import uk.ac.qmul.eecs.ccmi.diagrammodel.ElementChangedEvent.PropertyChangeArgs;
import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeProperties.Modifiers;

/**
 * This class represents a node in the diagram.  
 *
 */
@SuppressWarnings("serial")
public abstract class DiagramNode extends DiagramElement {
	/**
	 * Constructor to be called by sub classes 
	 * 
	 * @param type the type of the new node. All nodes with this type will be 
	 * put under the same tree node in the tree representation 
	 * @param properties the properties of this node 
	 */
	public DiagramNode(String type, NodeProperties properties){
		setType(type);
		this.properties = properties;
	}

	/**
	 * Returns the properties of this node. Be aware that what is returned is the reference
	 * to the actual NodeProperties object inside this DiagramNode. Thereforemodifying the returned
	 * object will affect this node.
	 * @return the properties of this node
	 */
	public NodeProperties getProperties(){
		return properties;
	}

	/**
	 * Returns a copy of the properties of this node. The modifying the returned object 
	 * won't affect this Node.
	 * @return Returns a copy of the properties of this node
	 */
	public NodeProperties getPropertiesCopy(){
		NodeProperties p = (NodeProperties)properties.clone();
		for(String type : properties.getTypes()){
			Modifiers modifiers = properties.getModifiers(type);
			int index = 0;
			for(String value : properties.getValues(type)){
				if(properties.getModifiers(type).isNull())
					p.addValue(type, value);
				else
					p.addValue(type, value, modifiers.getIndexes(index++));
			}
		}
		return p;
	}

	/**
	 * Set the NodeProperties of this node
	 * @param properties  the properties to set for this node
	 * @param source the source of the action that triggered this method
	 */
	public void setProperties(NodeProperties properties, Object source){
		this.properties = properties;
		notifyChange(new ElementChangedEvent(this,this.properties,"properties",source));
	}

	/**
	 * Add a property to the NodeProperties of this node
	 * @see NodeProperties#addValue(String, String)
	 * 
	 * @param propertyType the type of the property to add 
	 * @param propertyValue the property to add  
	 * @param source the source of the action that triggered this method
	 */
	public void addProperty(String propertyType, String propertyValue, Object source){
		getProperties().addValue(propertyType, propertyValue);
		int index = getProperties().getValues(propertyType).size() - 1;
		notifyChange(new ElementChangedEvent(this,new PropertyChangeArgs(propertyType,index,""),"property.add",source));
	}

	/**
	 * Removes a property from the NodeProperties of this node
	 * @see NodeProperties#removeValue(String, int)
	 * 
	 * @param propertyType the type of the property to add
	 * @param valueIndex the index of the property to remove 
	 * @param source the source of the action that triggered this method
	 */
	public void removeProperty(String propertyType, int valueIndex, Object source){
		String oldValue = getProperties().getValues(propertyType).get(valueIndex);
		getProperties().removeValue(propertyType, valueIndex);
		notifyChange(new ElementChangedEvent(this,new PropertyChangeArgs(propertyType,valueIndex,oldValue),"property.remove",source));
	}

	/**
	 * Set a property on the NodeProperties of this node to a new value
	 * @see NodeProperties#setValue(String, int, String) 
	 * 
	 * @param propertyType the type of the property to add
	 * @param valueIndex the index of the property to remove 
	 * @param newValue the new value for this property 
	 * @param source the source of the action that triggered this method
	 */
	public void setProperty(String propertyType, int valueIndex, String newValue, Object source){
		String oldValue = getProperties().getValues(propertyType).get(valueIndex);
		getProperties().setValue(propertyType, valueIndex, newValue);
		notifyChange(new ElementChangedEvent(this,new PropertyChangeArgs(propertyType,valueIndex,oldValue),"property.set",source));
	}

	/**
	 * Removes all the values in the NodeProperties of this node
	 * @see NodeProperties#clear()
	 * 
	 * @param source the source of the action that triggered this method
	 */
	public void clearProperties(Object source){
		getProperties().clear();
		notifyChange(new ElementChangedEvent(this,this,"properties.clear",source));
	}

	/**
	 * set the modifier indexes in the NodeProperties of this node
	 * @see Modifiers#setIndexes(int, Set)
	 * 
	 * @param propertyType the type of the property to add
	 * @param propertyValueIndex the index of the property value whose modifiers
	 *  are to be changed  
	 * @param modifierIndexes the new modifiers (identified by their index ) 
	 *  for this property value 
	 * @param source the source of the action that triggered this method
	 */
	public void setModifierIndexes(String propertyType, int propertyValueIndex, Set<Integer> modifierIndexes,Object source){
		StringBuilder oldIndexes = new StringBuilder();
		List<String> modifierTypes = getProperties().getModifiers(propertyType).getTypes();
		Set<Integer> indexes = getProperties().getModifiers(propertyType).getIndexes(propertyValueIndex);
		for(Integer I : indexes){
			oldIndexes.append(modifierTypes.get(I)).append(' ');
		}
		getProperties().getModifiers(propertyType).setIndexes(propertyValueIndex, modifierIndexes);
		notifyChange(new ElementChangedEvent(this,new PropertyChangeArgs(propertyType,propertyValueIndex,oldIndexes.toString()),"property.modifiers",source));
	}

	/**
	 * Returns a more detailed description of the node than {@link #spokenText()}.
	 * the description includes which how many properties the node has and 
	 * how many edges are attached to it. 
	 * 
	 *  @return a description of the node
	 */
	@Override
	public String detailedSpokenText(){
		StringBuilder builder = new StringBuilder(getType());
		builder.append(' ');
		builder.append(getName());
		builder.append('.').append(' ');
		for(int i=0; i<getChildCount();i++){
			DiagramTreeNode treeNode = (DiagramTreeNode) getChildAt(i);
			if(treeNode.getChildCount() > 0){
				builder.append(treeNode.getChildCount())
				.append(' ')
				.append(treeNode.getName())
				.append(';')
				.append(' ');
			}
		}		  
		return builder.toString();
	}

	/**
	 * Returns the number of attached edges
	 * @return the number of attached edges 
	 */
	public abstract int getEdgesNum();

	/**
	 * Returns the attached edge at the specified index  
	 * @param index an index into edge's list
	 * @return the attached edge at the specified index
	 */
	public abstract DiagramEdge getEdgeAt(int index);

	/**
	 * add an edge to the attached edges list
	 * @param e the edge to be added
	 * 
	 * @return {@code true} if internal collection of edges changed as a result of the call
	 */
	public abstract boolean addEdge(DiagramEdge e);

	/**
	 * Removes an edge from the attached edges list
	 * @param e the edge to be removed
	 * 
	 * @return {@code true} if internal collection of edges changed as a result of the call
	 */
	public abstract boolean removeEdge(DiagramEdge e);

	/**
	 * Gets the node this node is within.
	 * @return the parent node, or null if the node
	 * has no parent
	 */
	public abstract DiagramNode getExternalNode();

	/**
	 * Sets the node this node is within.
	 * @param node the parent node, or null if the node
	 * has no parent
	 */
	public abstract void setExternalNode(DiagramNode node);

	/**
	 * Returns the number of internal nodes
	 * @return the number of internal nodes
	 */
	public abstract int getInternalNodesNum();
	
	/**
	 * Gets the internal node at the specified index
	 * @param index an index into internal nodes list
	 * @return the internal node at the specified index
	 */
	public abstract DiagramNode getInternalNodeAt(int index);

	/**
	 * Adds a node to the internal nodes list.
	 * @param node the internal node to add
	 */
	public abstract void addInternalNode(DiagramNode node);

	/**
	 * Removes a node from the internal nodes list.
	 * @param node the internal node to remove
	 */
	public abstract void removeInternalNode(DiagramNode node);

	@Override
	public Object clone(){
		DiagramNode clone = (DiagramNode)super.clone();
		clone.properties = (NodeProperties)properties.clone();
		return clone;
	}

	private NodeProperties properties;
}