view java/src/uk/ac/qmul/eecs/ccmi/diagrammodel/DiagramTreeNode.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.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.tree.DefaultMutableTreeNode;

/**
 * This class represent a general node in a TreeModel
 *
 */
@SuppressWarnings("serial")
public abstract class DiagramTreeNode extends DefaultMutableTreeNode {
	/**
	 * Creates a tree node with the default user object. The default user object has no label. Therefore 
	 * this node will have no label when displayed on a tree.
	 */
	public DiagramTreeNode() {
		super();
		notes = "";
		userObject = new UserObject();
		setSuperClassUserObject(userObject);
		bookmarkKeys = new ArrayList<String>();
	}

	/**
	 * Creates a tree node, holding the user object passed as argument. The label of the 
	 * tree node will be the string returned by {@code userObject.toString()}
	 * 
	 * @param userObject the user object for this tree node
	 * 
	 * @see javax.swing.tree.DefaultMutableTreeNode
	 */
	public DiagramTreeNode(Object userObject) {
		this();
		setUserObject(userObject);
	}
	
	/**
	 * Each DiagramModelTreeNode keeps track of the bookmarks it has been assigned. Bookmarks
	 * will affect how this tree node will be represented on a JTree: when a tree node is bookmarked 
	 * an apex appears at the right of its name. 
	 * 
	 * @param key the bookmark 
	 * @return true if this bookmark inner collection changed as a result of the call
	 */
	boolean addBookmarkKey(String key){
		return bookmarkKeys.add(key);
	}
	
	/**
	 * Removes a bookmark key from the inner collection.
	 * 
	 * @param key the key to remove 
	 * @return true if this bookmark inner collection changed as a result of the call
	 */
	boolean removeBookmarkKey(String key){
		return bookmarkKeys.remove(key);
	}
		
	/**
	 * Returns the the bookmark keys currently associated to this tree node in the tree model.
	 * 
	 * @return a n unmodifiable list of strings used as keys for bookmarks
	 */
	public List<String> getBookmarkKeys(){
		return Collections.unmodifiableList(bookmarkKeys);
	}
	
	public String getNotes(){
		return notes;
	}
	
	/**
	 * Set a note for this tree node. A Note is a text the user wants to attach to a tree node. Notes
	 * will affect how this tree node will be represented on a JTree: when a tree node is assigned a note 
	 * a number sign (#) appears at the right of its name. 
	 * 
	 * @param note the text of the note
	 * @param source used by {@code DiagramElement} to trigger {@code ElementChangeEvents}     
	 * 
	 * @see DiagramElement#setNotes(String, Object)
	 */
	protected void setNotes(String note, Object source){
		this.notes = note;
	}
	
	@Override
	public DiagramTreeNode getParent(){
		return (DiagramTreeNode)super.getParent();
	}
	
	@Override
	public DiagramTreeNode getChildAt(int i){
		return (DiagramTreeNode)super.getChildAt(i);
	}
	
	@Override
	public DiagramTreeNode getRoot(){
		return (DiagramTreeNode)super.getRoot();
	}
	
	@Override
	public void	setUserObject(Object userObject){
		((UserObject)this.userObject).setObject(userObject);
	}
	
	@Override
	public Object getUserObject(){
		return userObject;
	}
	
	/**
	 * Return a String representing this object for this tree node in a way more suitable 
	 * for a text to speech synthesizer to read, than toString(). 
	 * 
	 * @return a String suitable for text to speech synthesis
	 */
	public String spokenText(){
		return ((UserObject)userObject).spokenText();
	}
	
	/**
	 * Returns a more detailed description of the tree node than {@link #spokenText()}.
	 * 
	 *  @return a description of the tree node
	 */
	public String detailedSpokenText(){
		return spokenText();
	}
	
	/**
	 * 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(){
		return ((UserObject)userObject).getName();
	}
	
	@Override
	public boolean isRoot(){
		return false; // root node overwrites this method
	}

	@Override
	public DiagramTreeNode getLastLeaf() {
		return (DiagramTreeNode)super.getLastLeaf();
	}

	@Override
	public DiagramTreeNode getNextLeaf() {
		return (DiagramTreeNode)super.getNextLeaf();
	}

	@Override
	public DiagramTreeNode getNextNode() {
		return (DiagramTreeNode)super.getNextNode();
	}

	@Override
	public DiagramTreeNode getNextSibling() {
		return (DiagramTreeNode)super.getNextSibling();
	}

	@Override
	public DiagramTreeNode getPreviousLeaf() {
		return (DiagramTreeNode)super.getPreviousLeaf();
	}

	@Override
	public DiagramTreeNode getPreviousNode() {
		return (DiagramTreeNode)super.getPreviousNode();
	}

	@Override
	public DiagramTreeNode getPreviousSibling() {
		return (DiagramTreeNode)super.getPreviousSibling();
	}
	
	private void setSuperClassUserObject(Object u){
		super.setUserObject(u);
	}
	
	private UserObject getUserObjectInstance(){
		return new UserObject();
	}
	
	/**
	 * The bookmarks, involving this node, entered by the user in the DiagramTree this node belongs to. 
	 */
	protected List<String> bookmarkKeys;
	/**
	 * The notes set by the user for this node.
	 */
	protected String notes;
	/* hides the DefaultMutableTreeNode protected field */
	private Object userObject;
	/**
	 * The character that is appended to the label of this node when the user enters some notes for it. 
	 */
	protected static final char NOTES_CHAR = '#';
	/**
	 * The character that is appended to the label of this node when it's bookmarked by the user.
	 */
	protected static final char BOOKMARK_CHAR = '\'';
	/**
	 * The string that is appended to the spoken text of this node when the user enters some notes for it.
	 * 
	 * @see #spokenText()
	 */
	protected static final String BOOKMARK_SPEAK = ", bookmarked";
	/**
	 * The string that is appended to the spoken text of this node when it's bookmarked by the user.
	 * 
	 * @see #spokenText()
	 */
	protected static final String NOTES_SPEAK = ", has notes";
	
	@Override
	public Object clone(){
		DiagramTreeNode clone = (DiagramTreeNode )super.clone();
		clone.notes = "";
		clone.bookmarkKeys = new ArrayList<String>();
		clone.userObject = clone.getUserObjectInstance();	
		clone.setSuperClassUserObject(clone.userObject);
		return clone;
	}
	
	/* this works as a wrapper for the real user object in order to provide */
	/* decoration on the treeNode label to signal and/or bookmarks          */
	private class UserObject {
		private Object object;

		public UserObject(){
			object = "";
		}
		public void setObject(Object o){
			this.object = o;
		}

		@Override
		public boolean equals(Object o){
			return this.object.equals(o);
		}
		
		@Override
		public String toString(){
			StringBuilder builder = new StringBuilder(object.toString());
			if(!"".equals(notes)){
				builder.append(NOTES_CHAR);
			}
			if(!bookmarkKeys.isEmpty())
				builder.append(BOOKMARK_CHAR);
			return builder.toString();
		}
		
		public String spokenText(){
			StringBuilder builder = new StringBuilder(object.toString());
			if(!"".equals(notes)){
				builder.append(NOTES_SPEAK);
			}
			if(!bookmarkKeys.isEmpty())
				builder.append(BOOKMARK_SPEAK);
			return builder.toString();
		}
		
		public String getName(){
			return object.toString();
		}
	}
}