fiore@0: /*
fiore@0: CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
fiore@0:
fiore@0: Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
fiore@0:
fiore@0: This program is free software: you can redistribute it and/or modify
fiore@0: it under the terms of the GNU General Public License as published by
fiore@0: the Free Software Foundation, either version 3 of the License, or
fiore@0: (at your option) any later version.
fiore@0:
fiore@0: This program is distributed in the hope that it will be useful,
fiore@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
fiore@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
fiore@0: GNU General Public License for more details.
fiore@0:
fiore@0: You should have received a copy of the GNU General Public License
fiore@0: along with this program. If not, see .
fiore@0: */
fiore@0: package uk.ac.qmul.eecs.ccmi.diagrammodel;
fiore@0:
fiore@3: import java.util.List;
fiore@0: import java.util.Set;
fiore@0:
fiore@3: import uk.ac.qmul.eecs.ccmi.diagrammodel.ElementChangedEvent.PropertyChangeArgs;
fiore@0: import uk.ac.qmul.eecs.ccmi.diagrammodel.NodeProperties.Modifiers;
fiore@0:
fiore@0: /**
fiore@0: * This class represents a node in the diagram.
fiore@0: *
fiore@0: */
fiore@0: @SuppressWarnings("serial")
fiore@0: public abstract class DiagramNode extends DiagramElement {
fiore@5: /**
fiore@5: * Constructor to be called by sub classes
fiore@5: *
fiore@5: * @param type the type of the new node. All nodes with this type will be
fiore@5: * put under the same tree node in the tree representation
fiore@5: * @param properties the properties of this node
fiore@5: */
fiore@0: public DiagramNode(String type, NodeProperties properties){
fiore@0: setType(type);
fiore@0: this.properties = properties;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns the properties of this node. Be aware that what is returned is the reference
fiore@0: * to the actual NodeProperties object inside this DiagramNode. Thereforemodifying the returned
fiore@0: * object will affect this node.
fiore@0: * @return the properties of this node
fiore@0: */
fiore@0: public NodeProperties getProperties(){
fiore@0: return properties;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns a copy of the properties of this node. The modifying the returned object
fiore@0: * won't affect this Node.
fiore@0: * @return Returns a copy of the properties of this node
fiore@0: */
fiore@0: public NodeProperties getPropertiesCopy(){
fiore@0: NodeProperties p = (NodeProperties)properties.clone();
fiore@0: for(String type : properties.getTypes()){
fiore@0: Modifiers modifiers = properties.getModifiers(type);
fiore@0: int index = 0;
fiore@0: for(String value : properties.getValues(type)){
fiore@0: if(properties.getModifiers(type).isNull())
fiore@0: p.addValue(type, value);
fiore@0: else
fiore@0: p.addValue(type, value, modifiers.getIndexes(index++));
fiore@0: }
fiore@0: }
fiore@0: return p;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Set the NodeProperties of this node
fiore@0: * @param properties the properties to set for this node
fiore@5: * @param source the source of the action that triggered this method
fiore@0: */
fiore@3: public void setProperties(NodeProperties properties, Object source){
fiore@0: this.properties = properties;
fiore@3: notifyChange(new ElementChangedEvent(this,this.properties,"properties",source));
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Add a property to the NodeProperties of this node
fiore@0: * @see NodeProperties#addValue(String, String)
fiore@0: *
fiore@5: * @param propertyType the type of the property to add
fiore@5: * @param propertyValue the property to add
fiore@5: * @param source the source of the action that triggered this method
fiore@0: */
fiore@3: public void addProperty(String propertyType, String propertyValue, Object source){
fiore@0: getProperties().addValue(propertyType, propertyValue);
fiore@0: int index = getProperties().getValues(propertyType).size() - 1;
fiore@3: notifyChange(new ElementChangedEvent(this,new PropertyChangeArgs(propertyType,index,""),"property.add",source));
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Removes a property from the NodeProperties of this node
fiore@0: * @see NodeProperties#removeValue(String, int)
fiore@5: *
fiore@5: * @param propertyType the type of the property to add
fiore@5: * @param valueIndex the index of the property to remove
fiore@5: * @param source the source of the action that triggered this method
fiore@0: */
fiore@3: public void removeProperty(String propertyType, int valueIndex, Object source){
fiore@3: String oldValue = getProperties().getValues(propertyType).get(valueIndex);
fiore@0: getProperties().removeValue(propertyType, valueIndex);
fiore@3: notifyChange(new ElementChangedEvent(this,new PropertyChangeArgs(propertyType,valueIndex,oldValue),"property.remove",source));
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Set a property on the NodeProperties of this node to a new value
fiore@0: * @see NodeProperties#setValue(String, int, String)
fiore@5: *
fiore@5: * @param propertyType the type of the property to add
fiore@5: * @param valueIndex the index of the property to remove
fiore@5: * @param newValue the new value for this property
fiore@5: * @param source the source of the action that triggered this method
fiore@0: */
fiore@3: public void setProperty(String propertyType, int valueIndex, String newValue, Object source){
fiore@3: String oldValue = getProperties().getValues(propertyType).get(valueIndex);
fiore@0: getProperties().setValue(propertyType, valueIndex, newValue);
fiore@3: notifyChange(new ElementChangedEvent(this,new PropertyChangeArgs(propertyType,valueIndex,oldValue),"property.set",source));
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Removes all the values in the NodeProperties of this node
fiore@0: * @see NodeProperties#clear()
fiore@5: *
fiore@5: * @param source the source of the action that triggered this method
fiore@0: */
fiore@3: public void clearProperties(Object source){
fiore@0: getProperties().clear();
fiore@3: notifyChange(new ElementChangedEvent(this,this,"properties.clear",source));
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * set the modifier indexes in the NodeProperties of this node
fiore@0: * @see Modifiers#setIndexes(int, Set)
fiore@5: *
fiore@5: * @param propertyType the type of the property to add
fiore@5: * @param propertyValueIndex the index of the property value whose modifiers
fiore@5: * are to be changed
fiore@5: * @param modifierIndexes the new modifiers (identified by their index )
fiore@5: * for this property value
fiore@5: * @param source the source of the action that triggered this method
fiore@0: */
fiore@3: public void setModifierIndexes(String propertyType, int propertyValueIndex, Set modifierIndexes,Object source){
fiore@3: StringBuilder oldIndexes = new StringBuilder();
fiore@3: List modifierTypes = getProperties().getModifiers(propertyType).getTypes();
fiore@3: Set indexes = getProperties().getModifiers(propertyType).getIndexes(propertyValueIndex);
fiore@3: for(Integer I : indexes){
fiore@3: oldIndexes.append(modifierTypes.get(I)).append(' ');
fiore@3: }
fiore@0: getProperties().getModifiers(propertyType).setIndexes(propertyValueIndex, modifierIndexes);
fiore@3: notifyChange(new ElementChangedEvent(this,new PropertyChangeArgs(propertyType,propertyValueIndex,oldIndexes.toString()),"property.modifiers",source));
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns a more detailed description of the node than {@link #spokenText()}.
fiore@0: * the description includes which how many properties the node has and
fiore@0: * how many edges are attached to it.
fiore@0: *
fiore@0: * @return a description of the node
fiore@0: */
fiore@0: @Override
fiore@0: public String detailedSpokenText(){
fiore@0: StringBuilder builder = new StringBuilder(getType());
fiore@0: builder.append(' ');
fiore@0: builder.append(getName());
fiore@0: builder.append('.').append(' ');
fiore@0: for(int i=0; i 0){
fiore@0: builder.append(treeNode.getChildCount())
fiore@0: .append(' ')
fiore@0: .append(treeNode.getName())
fiore@0: .append(';')
fiore@0: .append(' ');
fiore@0: }
fiore@0: }
fiore@0: return builder.toString();
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns the number of attached edges
fiore@0: * @return the number of attached edges
fiore@0: */
fiore@0: public abstract int getEdgesNum();
fiore@0:
fiore@0: /**
fiore@0: * Returns the attached edge at the specified index
fiore@0: * @param index an index into edge's list
fiore@0: * @return the attached edge at the specified index
fiore@0: */
fiore@0: public abstract DiagramEdge getEdgeAt(int index);
fiore@0:
fiore@0: /**
fiore@0: * add an edge to the attached edges list
fiore@3: * @param e the edge to be added
fiore@5: *
fiore@5: * @return {@code true} if internal collection of edges changed as a result of the call
fiore@0: */
fiore@0: public abstract boolean addEdge(DiagramEdge e);
fiore@0:
fiore@0: /**
fiore@0: * Removes an edge from the attached edges list
fiore@5: * @param e the edge to be removed
fiore@5: *
fiore@5: * @return {@code true} if internal collection of edges changed as a result of the call
fiore@0: */
fiore@0: public abstract boolean removeEdge(DiagramEdge e);
fiore@0:
fiore@0: /**
fiore@0: * Gets the node this node is within.
fiore@0: * @return the parent node, or null if the node
fiore@0: * has no parent
fiore@0: */
fiore@0: public abstract DiagramNode getExternalNode();
fiore@0:
fiore@0: /**
fiore@0: * Sets the node this node is within.
fiore@0: * @param node the parent node, or null if the node
fiore@0: * has no parent
fiore@0: */
fiore@0: public abstract void setExternalNode(DiagramNode node);
fiore@0:
fiore@0: /**
fiore@0: * Returns the number of internal nodes
fiore@0: * @return the number of internal nodes
fiore@0: */
fiore@0: public abstract int getInternalNodesNum();
fiore@0:
fiore@0: /**
fiore@0: * Gets the internal node at the specified index
fiore@0: * @param index an index into internal nodes list
fiore@0: * @return the internal node at the specified index
fiore@0: */
fiore@0: public abstract DiagramNode getInternalNodeAt(int index);
fiore@0:
fiore@0: /**
fiore@0: * Adds a node to the internal nodes list.
fiore@0: * @param node the internal node to add
fiore@0: */
fiore@0: public abstract void addInternalNode(DiagramNode node);
fiore@0:
fiore@0: /**
fiore@0: * Removes a node from the internal nodes list.
fiore@0: * @param node the internal node to remove
fiore@0: */
fiore@0: public abstract void removeInternalNode(DiagramNode node);
fiore@0:
fiore@0: @Override
fiore@0: public Object clone(){
fiore@0: DiagramNode clone = (DiagramNode)super.clone();
fiore@0: clone.properties = (NodeProperties)properties.clone();
fiore@0: return clone;
fiore@0: }
fiore@0:
fiore@0: private NodeProperties properties;
fiore@0: }