Coverage Report - org.argouml.uml.diagram.static_structure.layout.ClassdiagramNode
 
Classes in this File Line Coverage Branch Coverage Complexity
ClassdiagramNode
0%
0/83
0%
0/30
1.483
 
 1  
 /* $Id: ClassdiagramNode.java 17863 2010-01-12 20:07:22Z linus $
 2  
  *****************************************************************************
 3  
  * Copyright (c) 2009 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  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2008 The Regents of the University of California. All
 17  
 // Rights Reserved. Permission to use, copy, modify, and distribute this
 18  
 // software and its documentation without fee, and without a written
 19  
 // agreement is hereby granted, provided that the above copyright notice
 20  
 // and this paragraph appear in all copies.  This software program and
 21  
 // documentation are copyrighted by The Regents of the University of
 22  
 // California. The software program and documentation are supplied "AS
 23  
 // IS", without any accompanying services from The Regents. The Regents
 24  
 // does not warrant that the operation of the program will be
 25  
 // uninterrupted or error-free. The end-user understands that the program
 26  
 // was developed for research purposes and is advised not to rely
 27  
 // exclusively on the program for any reason.  IN NO EVENT SHALL THE
 28  
 // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
 29  
 // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
 30  
 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 31  
 // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 32  
 // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
 33  
 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 34  
 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 35  
 // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 36  
 // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
 37  
 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 38  
 
 39  
 package org.argouml.uml.diagram.static_structure.layout;
 40  
 
 41  
 import java.awt.Dimension;
 42  
 import java.awt.Point;
 43  
 import java.util.ArrayList;
 44  
 import java.util.List;
 45  
 
 46  
 import org.argouml.uml.diagram.layout.LayoutedNode;
 47  
 import org.argouml.uml.diagram.static_structure.ui.FigComment;
 48  
 import org.argouml.uml.diagram.static_structure.ui.FigInterface;
 49  
 import org.argouml.uml.diagram.static_structure.ui.FigPackage;
 50  
 import org.tigris.gef.presentation.Fig;
 51  
 import org.tigris.gef.presentation.FigNode;
 52  
 
 53  
 /**
 54  
  * This class represents a node in the classdiagram (a class, interface or
 55  
  * package).
 56  
  * <p>
 57  
  * 
 58  
  * Things a node has to know:
 59  
  * <ul>
 60  
  * <li>Up- and downlinks for positioning in the hierarchy
 61  
  * <li>Weight of this node. This weight has to be strongly influenced by the
 62  
  * parent-nodes, because otherwise the order of nodes in the current row will
 63  
  * not be compatible with the order of the nodes in the row above.
 64  
  * </ul>
 65  
  */
 66  
 class ClassdiagramNode implements LayoutedNode, Comparable {
 67  
 
 68  
     /**
 69  
      * Constant to be used as an initializer when this node is not placed at an
 70  
      * column.
 71  
      */
 72  
     public static final int NOCOLUMN = -1;
 73  
 
 74  
     /**
 75  
      * Constant to be used as an initializer when this node has no rank assigned
 76  
      * yet.
 77  
      */
 78  
     public static final int NORANK = -1;
 79  
 
 80  
     /**
 81  
      * Constant to be used as an initializer when this node has no weight.
 82  
      */
 83  
     public static final int NOWEIGHT = -1;
 84  
 
 85  
     /**
 86  
      * The current column of this node.
 87  
      */
 88  0
     private int column = NOCOLUMN;
 89  
 
 90  
     /**
 91  
      * List of the nodes that contain the figures, which
 92  
      * are sources of edges with the figure of this node as destination.
 93  
      */
 94  0
     private List<ClassdiagramNode> downlinks = 
 95  
         new ArrayList<ClassdiagramNode>();
 96  
 
 97  
     /**
 98  
      * Offset used for edges, which have this node as the "upper" node.
 99  
      */
 100  0
     private int edgeOffset = 0;
 101  
 
 102  
     /**
 103  
      * The Fig that this ClassdiagramNode represents during the layout process.
 104  
      */
 105  0
     private FigNode figure = null;
 106  
 
 107  
     /**
 108  
      * The preferred X coordinate for the node.  Hint only. May not be used.
 109  
      */
 110  0
     private int placementHint = -1;
 111  
 
 112  
     /**
 113  
      * The current rank (i.e. row number) of this node.
 114  
      */
 115  0
     private int rank = NORANK;
 116  
 
 117  
     /**
 118  
      * List of nodes that contain the figures, which are destinations of edges
 119  
      * with the figure of this node as source.
 120  
      */
 121  0
     private List<ClassdiagramNode> uplinks = new ArrayList<ClassdiagramNode>();
 122  
 
 123  
     /**
 124  
      * The 'weight' of this node. This is a computed
 125  
      * attribute that is used during the horizontal placement process. It's
 126  
      * based on the position of the 'uplinked' objects. The actual purpose is to
 127  
      * minimize the number of link crossings in the diagram. Since we don't
 128  
      * compute the actual number of link crossings, we look where our uplinked
 129  
      * objects are, and then try to place our object in a way, that we can
 130  
      * expect to have a minimal number of crossings.
 131  
      */
 132  0
     private float weight = NOWEIGHT;
 133  
 
 134  
     private static final float UPLINK_FACTOR = 5;
 135  
 
 136  
     /**
 137  
      * Construct a new ClassdiagramNode representing the given Fig.
 138  
      * 
 139  
      * @param f
 140  
      *            represents the figure in the diagram, that peers this layout
 141  
      *            node.
 142  
      */
 143  0
     public ClassdiagramNode(FigNode f) {
 144  0
         setFigure(f);
 145  0
     }
 146  
 
 147  
     /**
 148  
      * Add a new downlinked node to this node.
 149  
      * 
 150  
      * @param newDownlink
 151  
      *            The node to be added with a dowlink.
 152  
      */
 153  
     public void addDownlink(ClassdiagramNode newDownlink) {
 154  0
         downlinks.add(newDownlink);
 155  0
     }
 156  
 
 157  
     /**
 158  
      * Add a constant to the rank of this node.
 159  
      * 
 160  
      * @param n
 161  
      *            The value to add.
 162  
      */
 163  
     public void addRank(int n) {
 164  0
         setRank(n + getRank());
 165  0
     }
 166  
 
 167  
     /**
 168  
      * Add an uplink to this node.
 169  
      * 
 170  
      * @param newUplink
 171  
      *            represents the new uplinks.
 172  
      */
 173  
     public void addUplink(ClassdiagramNode newUplink) {
 174  0
         uplinks.add(newUplink);
 175  0
     }
 176  
 
 177  
     /**
 178  
      * Calculate the weight of this node. The function distinguishes between
 179  
      * note-nodes and standard-nodes, because a note should be positioned to the
 180  
      * right of its first related node, if it exists. Therefor the weight is a
 181  
      * function of the weight of the related node. For standard-nodes the weight
 182  
      * is a function of up-/downlinks, column and uplink factor.
 183  
      * 
 184  
      * @return The weight of this node.
 185  
      */
 186  
     public float calculateWeight() {
 187  0
         weight = 0;
 188  0
         for (ClassdiagramNode node : uplinks) {
 189  0
             weight = Math.max(weight, node.getWeight()
 190  
                     * UPLINK_FACTOR
 191  
                     * (1 + 1 / Math.max(1, node.getColumn() + UPLINK_FACTOR)));
 192  
         }
 193  0
         weight += getSubtreeWeight()
 194  
                 + (1 / Math.max(1, getColumn() + UPLINK_FACTOR));
 195  0
         return weight;
 196  
     }
 197  
 
 198  
     /**
 199  
      * The "natural order" for ClassdiagramNodes is defined by the following
 200  
      * order.
 201  
      * <ul>
 202  
      * <li>First standalone, then linked nodes
 203  
      * <li>First Packages, then Interfaces/Classes/Notes
 204  
      * <li>increasing rank (rownumber)
 205  
      * <li>decreasing weight
 206  
      * <li>name of model object
 207  
      * <li>increasing hashcode (for uniqueness)
 208  
      * </ul>
 209  
      * 
 210  
      * @see java.lang.Comparable#compareTo(java.lang.Object)
 211  
      */
 212  
     public int compareTo(Object arg0) {
 213  0
         ClassdiagramNode node = (ClassdiagramNode) arg0;
 214  0
         int result = 0;
 215  0
         result =
 216  
                 Boolean.valueOf(node.isStandalone()).compareTo(
 217  
                         Boolean.valueOf(isStandalone()));
 218  0
         if (result == 0) {
 219  0
             result = this.getTypeOrderNumer() - node.getTypeOrderNumer();
 220  
         }
 221  0
         if (result == 0) {
 222  0
             result = this.getRank() - node.getRank();
 223  
         }
 224  0
         if (result == 0) {
 225  0
             result = (int) Math.signum(node.getWeight() - this.getWeight());
 226  
         }
 227  0
         if (result == 0) {
 228  0
             result = String.valueOf(this.getFigure().getOwner()).compareTo(
 229  
                     String.valueOf(node.getFigure().getOwner()));
 230  
         }
 231  0
         if (result == 0) {
 232  0
             result = node.hashCode() - this.hashCode();
 233  
         }
 234  
         //LOG.debug(result + " node1: " + this + ", node2 " + node);
 235  0
         return result;
 236  
     }
 237  
 
 238  
     /**
 239  
      * @return The column of this node.
 240  
      */
 241  
     public int getColumn() {
 242  0
         return column;
 243  
     }
 244  
 
 245  
 
 246  
     /**
 247  
      * @return The downlinks of this node.
 248  
      */
 249  
     public List<ClassdiagramNode> getDownNodes() {
 250  0
         return downlinks;
 251  
     }
 252  
     
 253  
     /**
 254  
      * Get the offset which shall be used for edges with this node as parent.
 255  
      * 
 256  
      * @return The offset
 257  
      */
 258  
     public int getEdgeOffset() {
 259  0
         return edgeOffset;
 260  
     }
 261  
 
 262  
     /**
 263  
      * Get the underlying figure of this node.
 264  
      * 
 265  
      * @return The figure.
 266  
      */
 267  
     public FigNode getFigure() {
 268  0
         return figure;
 269  
     }
 270  
 
 271  
     /**
 272  
      * Get the level in the inheritance hierarchy for this node.
 273  
      * 
 274  
      * @return The level.
 275  
      */
 276  
     public int getLevel() {
 277  0
         int result = 0;
 278  0
         for (ClassdiagramNode node : uplinks) {
 279  0
             result =
 280  
                     (node == this) ? result : Math.max(
 281  
                             node.getLevel() + 1, result);
 282  
         }
 283  0
         return result;
 284  
     }
 285  
 
 286  
     /**
 287  
      * Get the location of the underlying figure in the diagram.
 288  
      * 
 289  
      * @return The location.
 290  
      */
 291  
     public Point getLocation() {
 292  0
         return getFigure().getLocation();
 293  
     }
 294  
 
 295  
     /**
 296  
      * Get the current placement hint (X coordinate in the row).
 297  
      * 
 298  
      * @return The placement hint for this node.
 299  
      */
 300  
     public int getPlacementHint() {
 301  0
         return placementHint;
 302  
     }
 303  
 
 304  
     /**
 305  
      * @return The rank for this node.
 306  
      */
 307  
     public int getRank() {
 308  0
         return rank == NORANK ? getLevel() : rank;
 309  
     }
 310  
 
 311  
     /**
 312  
      * Return the size of the figure associated with this
 313  
      * layout node.
 314  
      * 
 315  
      * @return The size of the associated figure.
 316  
      */
 317  
     public Dimension getSize() {
 318  0
         return getFigure().getSize();
 319  
     }
 320  
 
 321  
     /**
 322  
      * Get the weight of the subtree defined by this node. Impact on weight is
 323  
      * decreasing with increasing hierarchical distance
 324  
      * 
 325  
      * @return The weight of the subtree.
 326  
      */
 327  
     private float getSubtreeWeight() {
 328  
 
 329  0
         float w = 1;
 330  0
         for (ClassdiagramNode node : downlinks) {
 331  0
             w += node.getSubtreeWeight() / UPLINK_FACTOR;
 332  
         }
 333  0
         return w;
 334  
     }
 335  
 
 336  
     /**
 337  
      * Get the type order number of this node. This number may be used to
 338  
      * influence the sort order of ClassdiagramNodes.
 339  
      * 
 340  
      * @return Type order number.
 341  
      */
 342  
     public int getTypeOrderNumer() {
 343  0
         int result = 99;
 344  0
         if (getFigure() instanceof FigPackage) {
 345  0
             result = 0;
 346  0
         } else if (getFigure() instanceof FigInterface) {
 347  0
             result = 1;
 348  
         }
 349  0
         return result;
 350  
     }
 351  
 
 352  
     /**
 353  
      * Get the uplinks of this node.
 354  
      * 
 355  
      * @return The uplinks of this node.
 356  
      */
 357  
     public List<ClassdiagramNode> getUpNodes() {
 358  0
         return uplinks;
 359  
     }
 360  
     
 361  
     /**
 362  
      * Return the weight of this node, which is used for positioning in a row.
 363  
      * 
 364  
      * @return The weight of this node.
 365  
      */
 366  
     public float getWeight() {
 367  0
         return weight;
 368  
     }
 369  
 
 370  
     /**
 371  
      * Check if this node is associated with a note.
 372  
      * 
 373  
      * @return Result of test.
 374  
      */
 375  
     public boolean isComment() {
 376  0
         return (getFigure() instanceof FigComment);
 377  
     }
 378  
 
 379  
     /**
 380  
      * Check if this node is associated with a package.
 381  
      * 
 382  
      * @return Result of test.
 383  
      */
 384  
     public boolean isPackage() {
 385  0
         return (getFigure() instanceof FigPackage);
 386  
     }
 387  
 
 388  
     /**
 389  
      * Test whether this node has no connection to other nodes. Return
 390  
      * <code>true</code> if node has no connections, <code>false</code>
 391  
      * otherwise.
 392  
      * 
 393  
      * @return Result of test.
 394  
      */
 395  
     public boolean isStandalone() {
 396  0
         return uplinks.isEmpty() && downlinks.isEmpty();
 397  
     }
 398  
 
 399  
     /**
 400  
      * Set the column of this node. A re-calculation of the weight is performed,
 401  
      * because the column is an input parameter for the weight.
 402  
      * 
 403  
      * @param newColumn
 404  
      *            The new column.
 405  
      */
 406  
     public void setColumn(int newColumn) {
 407  0
         column = newColumn;
 408  0
         calculateWeight();
 409  0
     }
 410  
 
 411  
     /**
 412  
      * Set the offset for edges to this node.
 413  
      * 
 414  
      * @param newOffset
 415  
      *            Offset for edges with this node as one endpoint.
 416  
      */
 417  
     public void setEdgeOffset(int newOffset) {
 418  0
         edgeOffset = newOffset;
 419  0
     }
 420  
 
 421  
     /**
 422  
      * Set the Fig represented by this node.
 423  
      * 
 424  
      * @param newFigure
 425  
      *            represents the new value of figure.
 426  
      */
 427  
     public void setFigure(FigNode newFigure) {
 428  0
         figure = newFigure;
 429  0
     }
 430  
 
 431  
     /**
 432  
      * Set the location of the Fig associated with this node.
 433  
      * 
 434  
      * @param newLocation
 435  
      *            represents the new location for this figure.
 436  
      */
 437  
     @SuppressWarnings("unchecked")
 438  
     public void setLocation(Point newLocation) {
 439  0
         Point oldLocation = getFigure().getLocation();
 440  
 
 441  0
         getFigure().setLocation(newLocation);
 442  0
         int xTrans = newLocation.x - oldLocation.x;
 443  0
         int yTrans = newLocation.y - oldLocation.y;
 444  0
         for (Fig fig : (List<Fig>) getFigure().getEnclosedFigs()) {
 445  0
             fig.translate(xTrans, yTrans);
 446  
         }
 447  0
     }
 448  
 
 449  
     /**
 450  
      * A placementhint gives an indication where it might be feasible to place
 451  
      * this node. It is used by the layouter, and there is no guarantee that it
 452  
      * will be used.
 453  
      * 
 454  
      * @param hint
 455  
      *            x coordinate of the desired placement
 456  
      */
 457  
     public void setPlacementHint(int hint) {
 458  0
         placementHint = hint;
 459  0
     }
 460  
 
 461  
     /**
 462  
      * Set the rank
 463  
      * 
 464  
      * @param newRank
 465  
      *            represents the new value of rank.
 466  
      */
 467  
     public void setRank(int newRank) {
 468  0
         rank = newRank;
 469  0
     }
 470  
 
 471  
     /**
 472  
      * Set the weight for this node.
 473  
      * 
 474  
      * @param w
 475  
      *            The new weight of this node.
 476  
      */
 477  
     public void setWeight(float w) {
 478  0
         weight = w;
 479  0
     }
 480  
 
 481  
 }