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: }