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