view java/src/uk/ac/qmul/eecs/ccmi/diagrammodel/DiagramElement.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 9e67171477bc
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.io.InputStream;
import java.util.concurrent.locks.ReentrantLock;


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