Coverage Report - org.argouml.ui.DisplayTextTree
 
Classes in this File Line Coverage Branch Coverage Complexity
DisplayTextTree
47%
65/136
40%
32/80
5.071
 
 1  
 /* $Id: DisplayTextTree.java 18886 2010-12-05 12:22:01Z thn $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009-2010 Contributors - see below
 4  
  * All rights reserved. This program and the accompanying materials
 5  
  * are made available under the terms of the Eclipse Public License v1.0
 6  
  * which accompanies this distribution, and is available at
 7  
  * http://www.eclipse.org/legal/epl-v10.html
 8  
  *
 9  
  * Contributors:
 10  
  *    tfmorris
 11  
  *    mvw
 12  
  *****************************************************************************
 13  
  *
 14  
  * Some portions of this file was previously release using the BSD License:
 15  
  */
 16  
 
 17  
 // Copyright (c) 1996-2008 The Regents of the University of California. All
 18  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 19  
 // software and its documentation without fee, and without a written
 20  
 // agreement is hereby granted, provided that the above copyright notice
 21  
 // and this paragraph appear in all copies.  This software program and
 22  
 // documentation are copyrighted by The Regents of the University of
 23  
 // California. The software program and documentation are supplied "AS
 24  
 // IS", without any accompanying services from The Regents. The Regents
 25  
 // does not warrant that the operation of the program will be
 26  
 // uninterrupted or error-free. The end-user understands that the program
 27  
 // was developed for research purposes and is advised not to rely
 28  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 29  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 30  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 31  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 32  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 33  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 34  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 35  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 36  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 37  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 38  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 39  
 
 40  
 package org.argouml.ui;
 41  
 
 42  
 import java.text.MessageFormat;
 43  
 import java.util.ArrayList;
 44  
 import java.util.Collection;
 45  
 import java.util.Hashtable;
 46  
 import java.util.Iterator;
 47  
 import java.util.List;
 48  
 
 49  
 import javax.swing.JTree;
 50  
 import javax.swing.tree.TreeModel;
 51  
 import javax.swing.tree.TreePath;
 52  
 
 53  
 import org.apache.log4j.Logger;
 54  
 import org.argouml.cognitive.ToDoItem;
 55  
 import org.argouml.cognitive.ToDoList;
 56  
 import org.argouml.i18n.Translator;
 57  
 import org.argouml.kernel.Project;
 58  
 import org.argouml.kernel.ProjectManager;
 59  
 import org.argouml.model.InvalidElementException;
 60  
 import org.argouml.model.Model;
 61  
 import org.argouml.notation.Notation;
 62  
 import org.argouml.notation.NotationProvider;
 63  
 import org.argouml.notation.NotationProviderFactory2;
 64  
 import org.argouml.notation.NotationSettings;
 65  
 import org.argouml.notation.providers.uml.NotationUtilityUml;
 66  
 import org.argouml.uml.diagram.ArgoDiagram;
 67  
 import org.argouml.uml.ui.UMLTreeCellRenderer;
 68  
 
 69  
 /**
 70  
  * This is the JTree that is the GUI component view of the UML model
 71  
  * navigation (the explorer) and the todo list.
 72  
  */
 73  
 public class DisplayTextTree extends JTree {
 74  
 
 75  900
     private static final Logger LOG = Logger.getLogger(DisplayTextTree.class);
 76  
 
 77  
     /**
 78  
      * A Map helping the tree maintain a consistent expanded paths state.
 79  
      *
 80  
      * <pre>
 81  
      *  keys are the current TreeModel of this Tree
 82  
      *  values are Lists of currently expanded paths.
 83  
      * </pre>
 84  
      */
 85  
     private Hashtable<TreeModel, List<TreePath>> expandedPathsInModel;
 86  
 
 87  
     private boolean reexpanding;
 88  
 
 89  
     /**
 90  
      * This determines if stereotypes are to be shown in the explorer.
 91  
      */
 92  
     private boolean showStereotype;
 93  
 
 94  
     /**
 95  
      * Sets the label renderer, line style angled, enable tooltips,
 96  
      * sets row height to 18 pixels.
 97  
      */
 98  
     public DisplayTextTree() {
 99  
 
 100  1800
         super();
 101  
 
 102  
         /* MVW: We should use default font sizes as much as possible.
 103  
          * BTW, this impacts only the width, and reduces readibility:
 104  
          */
 105  
 //        setFont(LookAndFeelMgr.getInstance().getSmallFont());
 106  
 
 107  1800
         setCellRenderer(new UMLTreeCellRenderer());
 108  1800
         setRootVisible(false);
 109  1800
         setShowsRootHandles(true);
 110  
 
 111  
         // This enables tooltips for tree; this one won't be shown:
 112  1800
         setToolTipText("Tree");
 113  
 
 114  
         /* The default (16) puts the icons too close together: */
 115  1800
         setRowHeight(18);
 116  
 
 117  1800
         expandedPathsInModel = new Hashtable<TreeModel, List<TreePath>>();
 118  1800
         reexpanding = false;
 119  1800
     }
 120  
 
 121  
     // ------------ methods that override JTree methods ---------
 122  
 
 123  
     /**
 124  
      * Override the default JTree implementation to display the appropriate text
 125  
      * for any object that will be displayed in the todo list. <p>
 126  
      *
 127  
      * This is used for the Todo list as well as the Explorer list.
 128  
      *
 129  
      * @param value
 130  
      *            the given object
 131  
      * @param selected
 132  
      *            ignored
 133  
      * @param expanded
 134  
      *            ignored
 135  
      * @param leaf
 136  
      *            ignored
 137  
      * @param row
 138  
      *            ignored
 139  
      * @param hasFocus
 140  
      *            ignored
 141  
      *
 142  
      * @return the value converted to text.
 143  
      *
 144  
      * @see javax.swing.JTree#convertValueToText(java.lang.Object, boolean,
 145  
      *      boolean, boolean, int, boolean)
 146  
      */
 147  
     public String convertValueToText(Object value, boolean selected,
 148  
             boolean expanded, boolean leaf, int row, boolean hasFocus) {
 149  
 
 150  80554
         if (value instanceof ToDoItem) {
 151  0
             return ((ToDoItem) value).getHeadline();
 152  
         }
 153  80554
         if (value instanceof ToDoList) {
 154  
             // TODO: Localize
 155  1800
             return "ToDoList";
 156  
         }
 157  
 
 158  78754
         if (Model.getFacade().isAModelElement(value)) {
 159  9318
             String name = null;
 160  
             try {
 161  9318
                 if (Model.getFacade().isATransition(value)) {
 162  0
                     name = formatTransitionLabel(value);
 163  9318
                 } else if (Model.getFacade().isAExtensionPoint(value)) {
 164  0
                     name = formatExtensionPoint(value);
 165  9318
                 } else if (Model.getFacade().isAComment(value)) {
 166  0
                     name = (String) Model.getFacade().getBody(value);
 167  9318
                 } else if (Model.getFacade().isATaggedValue(value)) {
 168  0
                     name = formatTaggedValueLabel(value);
 169  
                 } else {
 170  9318
                     name = getModelElementDisplayName(value);
 171  
                 }
 172  
 
 173  
                 /*
 174  
                  * If the name is too long or multi-line (e.g. for comments)
 175  
                  * then we reduce to the first line or 80 chars.
 176  
                  */
 177  
                 // TODO: Localize
 178  9318
                 if (name != null
 179  
                         && name.indexOf("\n") < 80
 180  
                         && name.indexOf("\n") > -1) {
 181  0
                     name = name.substring(0, name.indexOf("\n")) + "...";
 182  9318
                 } else if (name != null && name.length() > 80) {
 183  0
                     name = name.substring(0, 80) + "...";
 184  
                 }
 185  
 
 186  
                 // Look for stereotype
 187  9318
                 if (showStereotype) {
 188  0
                     Collection<Object> stereos =
 189  
                         Model.getFacade().getStereotypes(value);
 190  0
                     name += " " + generateStereotype(stereos);
 191  0
                     if (name != null && name.length() > 80) {
 192  0
                         name = name.substring(0, 80) + "...";
 193  
                     }
 194  
                 }
 195  0
             } catch (InvalidElementException e) {
 196  0
                 name = Translator.localize("misc.name.deleted");
 197  9318
             }
 198  
 
 199  9318
             return name;
 200  
         }
 201  
 
 202  
         // TODO: This duplicates code in Facade.toString(), but this version
 203  
         // is localized, so we'll leave it for now.
 204  69436
         if (Model.getFacade().isAElementImport(value)) {
 205  
             try {
 206  0
                 Object me = Model.getFacade().getImportedElement(value);
 207  0
                 String typeName = Model.getFacade().getUMLClassName(me);
 208  0
                 String elemName = convertValueToText(me, selected, 
 209  
                         expanded, leaf, row,
 210  
                         hasFocus);
 211  0
                 String alias = Model.getFacade().getAlias(value);
 212  0
                 if (alias != null && alias.length() > 0) {
 213  0
                     Object[] args = {typeName, elemName, alias};
 214  0
                     return Translator.localize(
 215  
                             "misc.name.element-import.alias", args);
 216  
                 } else {
 217  0
                     Object[] args = {typeName, elemName};
 218  0
                     return Translator.localize(
 219  
                             "misc.name.element-import", args);
 220  
                 }
 221  0
             } catch (InvalidElementException e) {
 222  0
                 return Translator.localize("misc.name.deleted");
 223  
             }
 224  
         }
 225  
 
 226  
         // Use default formatting for any other type of UML element
 227  69436
         if (Model.getFacade().isAUMLElement(value)) {
 228  
             try {
 229  0
                 return Model.getFacade().toString(value);
 230  0
             } catch (InvalidElementException e) {
 231  0
                 return Translator.localize("misc.name.deleted");
 232  
             }
 233  
         }
 234  
 
 235  69436
         if (Model.getFacade().isAAppliedProfileElement(value)) {
 236  0
             return Model.getFacade().getName(value);
 237  
         }
 238  
         
 239  69436
         if (value instanceof ArgoDiagram) {
 240  22
             return ((ArgoDiagram) value).getName();
 241  
         }
 242  
 
 243  69414
         if (value != null) {
 244  64914
             return value.toString();
 245  
         }
 246  4500
         return "-";
 247  
     }
 248  
 
 249  
     private String formatExtensionPoint(Object value) {
 250  0
         NotationSettings settings = getNotationSettings();
 251  0
         NotationProvider notationProvider = NotationProviderFactory2
 252  
                 .getInstance().getNotationProvider(
 253  
                         NotationProviderFactory2.TYPE_EXTENSION_POINT, value,
 254  
                         Notation.findNotation(settings.getNotationLanguage()));
 255  0
         String name = notationProvider.toString(value, settings);
 256  0
         return name;
 257  
     }
 258  
 
 259  
     private static NotationSettings getNotationSettings() {
 260  0
         Project p = ProjectManager.getManager().getCurrentProject();
 261  
         NotationSettings settings;
 262  0
         if (p != null) {
 263  0
             settings = p.getProjectSettings().getNotationSettings();
 264  
         } else {
 265  0
             settings = NotationSettings.getDefaultSettings();
 266  
         }
 267  0
         return settings;
 268  
     }
 269  
 
 270  
     private String formatTaggedValueLabel(Object value) {
 271  
         String name;
 272  0
         String tagName = Model.getFacade().getTag(value);
 273  0
         if (tagName == null || tagName.equals("")) {
 274  0
             name = MessageFormat.format(
 275  
                     Translator.localize("misc.unnamed"),
 276  
                     new Object[] {
 277  
                         Model.getFacade().getUMLClassName(value)
 278  
                     });
 279  
         }
 280  0
         Collection referenceValues = 
 281  
             Model.getFacade().getReferenceValue(value);
 282  0
         Collection dataValues = 
 283  
             Model.getFacade().getDataValue(value);
 284  
         Iterator i;
 285  0
         if (referenceValues.size() > 0) {
 286  0
             i = referenceValues.iterator();
 287  
         } else {
 288  0
             i = dataValues.iterator();
 289  
         }
 290  0
         String theValue = "";
 291  0
         if (i.hasNext()) {
 292  0
             theValue = i.next().toString();
 293  
         }
 294  0
         if (i.hasNext()) {
 295  0
             theValue += " , ...";
 296  
         }
 297  0
         name = (tagName + " = " + theValue);
 298  0
         return name;
 299  
     }
 300  
 
 301  
     /**
 302  
      * Generate the text to represent a Transition.
 303  
      * 
 304  
      * @param value a Transition UML object
 305  
      * @return a representation of the Transition with trigger, guard 
 306  
      * and effect
 307  
      */
 308  
     private String formatTransitionLabel(Object value) {
 309  
         String name;
 310  0
         name = Model.getFacade().getName(value);
 311  0
         NotationSettings settings = getNotationSettings();
 312  0
         NotationProvider notationProvider =
 313  
             NotationProviderFactory2.getInstance()
 314  
                 .getNotationProvider(
 315  
                         NotationProviderFactory2.TYPE_TRANSITION,
 316  
                         value,
 317  
                         Notation.findNotation(settings.getNotationLanguage()));
 318  0
         String signature = notationProvider.toString(value, 
 319  
                 NotationSettings.getDefaultSettings());
 320  0
         if (name != null && name.length() > 0) {
 321  0
             name += ": " + signature;
 322  
         } else {
 323  0
             name = signature;
 324  
         }
 325  0
         return name;
 326  
     }
 327  
 
 328  
     /**
 329  
      * @param st a collection of stereotypes
 330  
      * @return a string representing the given stereotype(s)
 331  
      */
 332  
     public static String generateStereotype(Collection<Object> st) {
 333  0
         return NotationUtilityUml.generateStereotype(st, 
 334  
                 getNotationSettings().isUseGuillemets());
 335  
     }
 336  
 
 337  
     /**
 338  
      * Create a string representing the given modelelement. Normally this is 
 339  
      * just the name, but if the element is not named, something like 
 340  
      * "anonymous Classifier" is returned with i18n applied.
 341  
      * 
 342  
      * @param modelElement the given element
 343  
      * @return a recognizable name for the element 
 344  
      * (guaranteed with length > 0)
 345  
      */
 346  
     public static final String getModelElementDisplayName(Object modelElement) {
 347  9318
         String name = Model.getFacade().getName(modelElement);
 348  9318
         if (name == null || name.equals("")) {
 349  0
             name = MessageFormat.format(
 350  
                     Translator.localize("misc.unnamed"),
 351  
                     new Object[] {
 352  
                         Model.getFacade().getUMLClassName(modelElement)
 353  
                     }
 354  
                 );
 355  
         }
 356  9318
         return name;
 357  
     }
 358  
 
 359  
     /**
 360  
      * Tree Model Expansion notification.<p>
 361  
      *
 362  
      * @param path
 363  
      *            a Tree node insertion event
 364  
      */
 365  
     public void fireTreeExpanded(TreePath path) {
 366  
 
 367  10
         super.fireTreeExpanded(path);
 368  
 
 369  10
         LOG.debug("fireTreeExpanded");
 370  10
         if (reexpanding || path == null) {
 371  0
             return;
 372  
         }
 373  10
         List<TreePath> expanded = getExpandedPaths();
 374  10
         expanded.remove(path);
 375  10
         expanded.add(path);
 376  10
     }
 377  
 
 378  
     /*
 379  
      * @see javax.swing.JTree#fireTreeCollapsed(javax.swing.tree.TreePath)
 380  
      */
 381  
     public void fireTreeCollapsed(TreePath path) {
 382  
 
 383  0
         super.fireTreeCollapsed(path);
 384  
 
 385  0
         LOG.debug("fireTreeCollapsed");
 386  0
         if (path == null || expandedPathsInModel == null) {
 387  0
             return;
 388  
         }
 389  0
         List<TreePath> expanded = getExpandedPaths();
 390  0
         expanded.remove(path);
 391  0
     }
 392  
 
 393  
     /*
 394  
      * @see javax.swing.JTree#setModel(javax.swing.tree.TreeModel)
 395  
      */
 396  
     public void setModel(TreeModel newModel) {
 397  
 
 398  4500
         LOG.debug("setModel");
 399  4500
         Object r = newModel.getRoot();
 400  4500
         if (r != null) {
 401  4500
             super.setModel(newModel);
 402  
         }
 403  4500
         reexpand();
 404  4500
     }
 405  
 
 406  
     // ------------- other methods ------------------
 407  
 
 408  
     /**
 409  
      * Called in reexpand().
 410  
      *
 411  
      * @return a List containing all expanded paths
 412  
      */
 413  
     protected List<TreePath> getExpandedPaths() {
 414  
 
 415  2710
         LOG.debug("getExpandedPaths");
 416  2710
         TreeModel tm = getModel();
 417  2710
         List<TreePath> res = expandedPathsInModel.get(tm);
 418  2710
         if (res == null) {
 419  1800
             res = new ArrayList<TreePath>();
 420  1800
             expandedPathsInModel.put(tm, res);
 421  
         }
 422  2710
         return res;
 423  
     }
 424  
 
 425  
     /**
 426  
      * We re-expand the ones that were open before to maintain the same viewable
 427  
      * tree.
 428  
      *
 429  
      * called by doForceUpdate(), setModel()
 430  
      */
 431  
     private void reexpand() {
 432  
 
 433  4500
         LOG.debug("reexpand");
 434  4500
         if (expandedPathsInModel == null) {
 435  1800
             return;
 436  
         }
 437  
 
 438  2700
         reexpanding = true;
 439  
 
 440  2700
         for (TreePath path : getExpandedPaths()) {
 441  0
             expandPath(path);
 442  
         }
 443  2700
         reexpanding = false;
 444  2700
     }
 445  
 
 446  
     /**
 447  
      * @param show true if stereotypes have to be shown
 448  
      */
 449  
     protected void setShowStereotype(boolean show) {
 450  10
         this.showStereotype = show;
 451  10
     }
 452  
 
 453  
     /**
 454  
      * The UID.
 455  
      */
 456  
     private static final long serialVersionUID = 949560309817566838L;
 457  
 }