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@0: import java.io.InputStream;
fiore@3: import java.util.concurrent.locks.ReentrantLock;
fiore@3:
fiore@0:
fiore@0: /**
fiore@0: * A Diagram Element is either a node or an edge of the diagram. It's an abstract
fiore@0: * class which is extended by DiagramEdge and DiagramNode.
fiore@0: *
fiore@0: */
fiore@0: @SuppressWarnings("serial")
fiore@3: public abstract class DiagramElement extends DiagramTreeNode implements Cloneable{
fiore@0:
fiore@0: protected DiagramElement(){
fiore@0: name = "";
fiore@0: id = NO_ID;
fiore@0: notifier = DUMMY_NOTIFIER; // initially set to no effect notifier
fiore@0: }
fiore@0:
fiore@0: /**
fiore@3: * Returns the type of this diagram element. The type is like the category this element belongs to.
fiore@3: * For instance in a public transport diagram one might have three types of diagram element: tube, train
fiore@3: * and busses.
fiore@3: *
fiore@0: * @return the type of this element
fiore@0: */
fiore@0: public String getType(){
fiore@0: return type;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Set the type of this diagram element. This method should be called as soon as the object is created
fiore@0: * and should not be called anymore on this object.
fiore@3: *
fiore@0: * @param type the type of this element
fiore@0: */
fiore@0: protected void setType(String type){
fiore@0: this.type = type;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Notifies the model of a changed that has happened on this element. If this element is not
fiore@0: * held by any model than this method will have no effect.
fiore@0: * @param evt an event representing the fact that the element is changed
fiore@0: */
fiore@0: protected void notifyChange(ElementChangedEvent evt){
fiore@0: notifier.notifyChange(evt);
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * returns the tree node name "as it is", without any decoration such as notes, bookmarks or cardinality.
fiore@0: * Unlike the String returned by toString
fiore@0: * @return the tree node name
fiore@0: */
fiore@0: public String getName(){
fiore@0: if(name.isEmpty() && id != NO_ID)
fiore@0: return "new " + getType() + " " + id;
fiore@0: return name;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Sets the name of this element instance.
fiore@0: *
fiore@3: * @param s the string to set as the name
fiore@3: * @param source the source of this action
fiore@0: */
fiore@3: public void setName(String s, Object source){
fiore@0: String name = s;
fiore@0: /* if the user enters an empty string we go back to the default name */
fiore@0: if(s.isEmpty() && id != NO_ID){
fiore@0: name = "new " + getType() + " " + id;
fiore@0: }
fiore@0: setUserObject(name);
fiore@0: this.name = name;
fiore@3: notifyChange(new ElementChangedEvent(this,this,"name",source));
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns an InputStream to a sound file with the sound of this element
fiore@0: * @return an InputStream
fiore@0: */
fiore@0: public abstract InputStream getSound();
fiore@0:
fiore@0: /**
fiore@0: * Sets the if for this element. The id is a number which uniquely identifies this instance
fiore@0: * within a DiagramModel.
fiore@0: * Unlike the name, which can be the same for two different instances.
fiore@0: * @param id a long number which must be greater than 0
fiore@0: * @throws IllegalArgumentException id the id passe as argument is lower or equal to 0.
fiore@0: */
fiore@0: public void setId(long id){
fiore@0: if (id < NO_ID)
fiore@0: throw new IllegalArgumentException();
fiore@0: else
fiore@0: this.id = id;
fiore@0: if(name.isEmpty() && id != NO_ID){
fiore@0: String s = "new " + getType() + " " + id;
fiore@0: this.name = s;
fiore@0: setUserObject(s);
fiore@0: }
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns the id of this instance of DiagramElement.
fiore@0: * @return a long representing the id of this instance of the element
fiore@0: * or NO_ID if it hasn't got one.
fiore@0: */
fiore@0: public long getId(){
fiore@0: return id;
fiore@0: }
fiore@3:
fiore@3: public ReentrantLock getMonitor(){
fiore@3: if(notifier == null)
fiore@3: return null;
fiore@3: return (ReentrantLock)notifier;
fiore@3: }
fiore@0:
fiore@0: /**
fiore@0: * Sets the notifier to be used for notification
fiore@0: * following an internal change of the node
fiore@0: * @param notifier the notifier call the notify method(s) on
fiore@0: */
fiore@3: void setNotifier(DiagramModel.ReentrantLockNotifier notifier){
fiore@0: this.notifier = notifier;
fiore@0: }
fiore@0:
fiore@0: @Override
fiore@0: public Object clone(){
fiore@0: DiagramElement clone = (DiagramElement)super.clone();
fiore@0: clone.name = "";
fiore@0: clone.id = NO_ID;
fiore@0: return clone;
fiore@0: }
fiore@0:
fiore@0: /**
fiore@0: * Returns a description of the DiagramElement passed as argument, suitable
fiore@0: * for logging purposes.
fiore@0: *
fiore@0: * @param de the diagram element to log stuff about
fiore@0: * @return a log entry describing the element passed as agument
fiore@0: */
fiore@0: public static String toLogString(DiagramElement de){
fiore@0: StringBuilder builder = new StringBuilder(de.getName());
fiore@0: builder.append('(');
fiore@0: if(de.getId() == DiagramElement.NO_ID)
fiore@0: builder.append("no id");
fiore@0: else
fiore@0: builder.append(de.getId());
fiore@0: builder.append(')');
fiore@0: return builder.toString();
fiore@0: }
fiore@0:
fiore@0: private long id = NO_ID;
fiore@0: private ElementNotifier notifier;
fiore@0: private String type;
fiore@0: private String name;
fiore@0: private static final ElementNotifier DUMMY_NOTIFIER = new ElementNotifier(){
fiore@0: @Override
fiore@0: public void notifyChange(ElementChangedEvent evt) {}
fiore@0: };
fiore@0: /**
fiore@0: * The value returned by getId() if the element instance has not been assigned any id
fiore@0: */
fiore@0: public static final long NO_ID = 0;
fiore@0: }