f@0: /*
f@0: CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
f@0:
f@0: Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
f@0:
f@0: This program is free software: you can redistribute it and/or modify
f@0: it under the terms of the GNU General Public License as published by
f@0: the Free Software Foundation, either version 3 of the License, or
f@0: (at your option) any later version.
f@0:
f@0: This program is distributed in the hope that it will be useful,
f@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
f@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f@0: GNU General Public License for more details.
f@0:
f@0: You should have received a copy of the GNU General Public License
f@0: along with this program. If not, see .
f@0: */
f@0: package uk.ac.qmul.eecs.ccmi.diagrammodel;
f@0:
f@0: import java.util.ArrayList;
f@0: import java.util.Collections;
f@0: import java.util.List;
f@0:
f@0: import javax.swing.tree.DefaultMutableTreeNode;
f@0:
f@0: /**
f@0: * This class represent a general node in a TreeModel
f@0: *
f@0: */
f@0: @SuppressWarnings("serial")
f@0: public abstract class DiagramTreeNode extends DefaultMutableTreeNode {
f@0: /**
f@0: * Creates a tree node with the default user object. The default user object has no label. Therefore
f@0: * this node will have no label when displayed on a tree.
f@0: */
f@0: public DiagramTreeNode() {
f@0: super();
f@0: notes = "";
f@0: userObject = new UserObject();
f@0: setSuperClassUserObject(userObject);
f@0: bookmarkKeys = new ArrayList();
f@0: }
f@0:
f@0: /**
f@0: * Creates a tree node, holding the user object passed as argument. The label of the
f@0: * tree node will be the string returned by {@code userObject.toString()}
f@0: *
f@0: * @param userObject the user object for this tree node
f@0: *
f@0: * @see javax.swing.tree.DefaultMutableTreeNode
f@0: */
f@0: public DiagramTreeNode(Object userObject) {
f@0: this();
f@0: setUserObject(userObject);
f@0: }
f@0:
f@0: /**
f@0: * Each DiagramModelTreeNode keeps track of the bookmarks it has been assigned. Bookmarks
f@0: * will affect how this tree node will be represented on a JTree: when a tree node is bookmarked
f@0: * an apex appears at the right of its name.
f@0: *
f@0: * @param key the bookmark
f@0: * @return true if this bookmark inner collection changed as a result of the call
f@0: */
f@0: boolean addBookmarkKey(String key){
f@0: return bookmarkKeys.add(key);
f@0: }
f@0:
f@0: /**
f@0: * Removes a bookmark key from the inner collection.
f@0: *
f@0: * @param key the key to remove
f@0: * @return true if this bookmark inner collection changed as a result of the call
f@0: */
f@0: boolean removeBookmarkKey(String key){
f@0: return bookmarkKeys.remove(key);
f@0: }
f@0:
f@0: /**
f@0: * Returns the the bookmark keys currently associated to this tree node in the tree model.
f@0: *
f@0: * @return a n unmodifiable list of strings used as keys for bookmarks
f@0: */
f@0: public List getBookmarkKeys(){
f@0: return Collections.unmodifiableList(bookmarkKeys);
f@0: }
f@0:
f@0: public String getNotes(){
f@0: return notes;
f@0: }
f@0:
f@0: /**
f@0: * Set a note for this tree node. A Note is a text the user wants to attach to a tree node. Notes
f@0: * will affect how this tree node will be represented on a JTree: when a tree node is assigned a note
f@0: * a number sign (#) appears at the right of its name.
f@0: *
f@0: * @param note the text of the note
f@0: * @param source used by {@code DiagramElement} to trigger {@code ElementChangeEvents}
f@0: *
f@0: * @see DiagramElement#setNotes(String, Object)
f@0: */
f@0: protected void setNotes(String note, Object source){
f@0: this.notes = note;
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getParent(){
f@0: return (DiagramTreeNode)super.getParent();
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getChildAt(int i){
f@0: return (DiagramTreeNode)super.getChildAt(i);
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getRoot(){
f@0: return (DiagramTreeNode)super.getRoot();
f@0: }
f@0:
f@0: @Override
f@0: public void setUserObject(Object userObject){
f@0: ((UserObject)this.userObject).setObject(userObject);
f@0: }
f@0:
f@0: @Override
f@0: public Object getUserObject(){
f@0: return userObject;
f@0: }
f@0:
f@0: /**
f@0: * Return a String representing this object for this tree node in a way more suitable
f@0: * for a text to speech synthesizer to read, than toString().
f@0: *
f@0: * @return a String suitable for text to speech synthesis
f@0: */
f@0: public String spokenText(){
f@0: return ((UserObject)userObject).spokenText();
f@0: }
f@0:
f@0: /**
f@0: * Returns a more detailed description of the tree node than {@link #spokenText()}.
f@0: *
f@0: * @return a description of the tree node
f@0: */
f@0: public String detailedSpokenText(){
f@0: return spokenText();
f@0: }
f@0:
f@0: /**
f@0: * returns the tree node name "as it is", without any decoration such as notes, bookmarks or cardinality;
f@0: * unlike the String returned by toString.
f@0: *
f@0: * @return the tree node name
f@0: */
f@0: public String getName(){
f@0: return ((UserObject)userObject).getName();
f@0: }
f@0:
f@0: @Override
f@0: public boolean isRoot(){
f@0: return false; // root node overwrites this method
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getLastLeaf() {
f@0: return (DiagramTreeNode)super.getLastLeaf();
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getNextLeaf() {
f@0: return (DiagramTreeNode)super.getNextLeaf();
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getNextNode() {
f@0: return (DiagramTreeNode)super.getNextNode();
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getNextSibling() {
f@0: return (DiagramTreeNode)super.getNextSibling();
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getPreviousLeaf() {
f@0: return (DiagramTreeNode)super.getPreviousLeaf();
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getPreviousNode() {
f@0: return (DiagramTreeNode)super.getPreviousNode();
f@0: }
f@0:
f@0: @Override
f@0: public DiagramTreeNode getPreviousSibling() {
f@0: return (DiagramTreeNode)super.getPreviousSibling();
f@0: }
f@0:
f@0: private void setSuperClassUserObject(Object u){
f@0: super.setUserObject(u);
f@0: }
f@0:
f@0: private UserObject getUserObjectInstance(){
f@0: return new UserObject();
f@0: }
f@0:
f@0: /**
f@0: * The bookmarks, involving this node, entered by the user in the DiagramTree this node belongs to.
f@0: */
f@0: protected List bookmarkKeys;
f@0: /**
f@0: * The notes set by the user for this node.
f@0: */
f@0: protected String notes;
f@0: /* hides the DefaultMutableTreeNode protected field */
f@0: private Object userObject;
f@0: /**
f@0: * The character that is appended to the label of this node when the user enters some notes for it.
f@0: */
f@0: protected static final char NOTES_CHAR = '#';
f@0: /**
f@0: * The character that is appended to the label of this node when it's bookmarked by the user.
f@0: */
f@0: protected static final char BOOKMARK_CHAR = '\'';
f@0: /**
f@0: * The string that is appended to the spoken text of this node when the user enters some notes for it.
f@0: *
f@0: * @see #spokenText()
f@0: */
f@0: protected static final String BOOKMARK_SPEAK = ", bookmarked";
f@0: /**
f@0: * The string that is appended to the spoken text of this node when it's bookmarked by the user.
f@0: *
f@0: * @see #spokenText()
f@0: */
f@0: protected static final String NOTES_SPEAK = ", has notes";
f@0:
f@0: @Override
f@0: public Object clone(){
f@0: DiagramTreeNode clone = (DiagramTreeNode )super.clone();
f@0: clone.notes = "";
f@0: clone.bookmarkKeys = new ArrayList();
f@0: clone.userObject = clone.getUserObjectInstance();
f@0: clone.setSuperClassUserObject(clone.userObject);
f@0: return clone;
f@0: }
f@0:
f@0: /* this works as a wrapper for the real user object in order to provide */
f@0: /* decoration on the treeNode label to signal and/or bookmarks */
f@0: private class UserObject {
f@0: private Object object;
f@0:
f@0: public UserObject(){
f@0: object = "";
f@0: }
f@0: public void setObject(Object o){
f@0: this.object = o;
f@0: }
f@0:
f@0: @Override
f@0: public boolean equals(Object o){
f@0: return this.object.equals(o);
f@0: }
f@0:
f@0: @Override
f@0: public String toString(){
f@0: StringBuilder builder = new StringBuilder(object.toString());
f@0: if(!"".equals(notes)){
f@0: builder.append(NOTES_CHAR);
f@0: }
f@0: if(!bookmarkKeys.isEmpty())
f@0: builder.append(BOOKMARK_CHAR);
f@0: return builder.toString();
f@0: }
f@0:
f@0: public String spokenText(){
f@0: StringBuilder builder = new StringBuilder(object.toString());
f@0: if(!"".equals(notes)){
f@0: builder.append(NOTES_SPEAK);
f@0: }
f@0: if(!bookmarkKeys.isEmpty())
f@0: builder.append(BOOKMARK_SPEAK);
f@0: return builder.toString();
f@0: }
f@0:
f@0: public String getName(){
f@0: return object.toString();
f@0: }
f@0: }
f@0: }