Coverage Report - org.argouml.uml.diagram.ui.SelectionNodeClarifiers2
 
Classes in this File Line Coverage Branch Coverage Complexity
SelectionNodeClarifiers2
0%
0/122
0%
0/68
2.913
 
 1  
 /* $Id: SelectionNodeClarifiers2.java 17865 2010-01-12 20:45:26Z 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  
  *    mvw
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 1996-2007 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.ui;
 40  
 
 41  
 import java.awt.Graphics;
 42  
 import java.awt.Rectangle;
 43  
 
 44  
 import javax.swing.Icon;
 45  
 
 46  
 import org.apache.log4j.Logger;
 47  
 import org.tigris.gef.base.Editor;
 48  
 import org.tigris.gef.base.Globals;
 49  
 import org.tigris.gef.base.Mode;
 50  
 import org.tigris.gef.base.ModeCreateEdgeAndNode;
 51  
 import org.tigris.gef.base.ModeManager;
 52  
 import org.tigris.gef.base.ModeModify;
 53  
 import org.tigris.gef.base.ModePlace;
 54  
 import org.tigris.gef.base.SelectionButtons;
 55  
 import org.tigris.gef.base.SelectionManager;
 56  
 import org.tigris.gef.graph.MutableGraphModel;
 57  
 import org.tigris.gef.presentation.Fig;
 58  
 import org.tigris.gef.presentation.FigNode;
 59  
 import org.tigris.gef.presentation.Handle;
 60  
 
 61  
 /**
 62  
  * Enhanced version of SelectionNodeClarifiers with the new methods
 63  
  * necessary for the enhanced support marked as abstract so that implementors
 64  
  * are forced to implement them.  SelectionNodeClarifiers is simple
 65  
  * extension of this which implements null versions of the required 
 66  
  * methods for backward compatibility with the previous implementation.
 67  
  * <p>
 68  
  * To upgrade subtypes of SelectionNodeClarifiers, change them to 
 69  
  * extend this class instead and implement the required abstract methods.
 70  
  * The methods paintButtons, dragHandle, hitHandle, and createEdge* can
 71  
  * all usually be removed.
 72  
  *
 73  
  * @author jrobbins
 74  
  * @author Tom Morris
 75  
  */
 76  
 public abstract class SelectionNodeClarifiers2 extends SelectionButtons {
 77  
     
 78  0
     private static final Logger LOG =
 79  
             Logger.getLogger(SelectionNodeClarifiers2.class);
 80  
 
 81  
     /** Base index of array */
 82  
     protected static final int BASE = 10;
 83  
     /** Top Handle */
 84  
     protected static final int TOP = 10;
 85  
     /** Bottom Handle */
 86  
     protected static final int BOTTOM = 11;
 87  
     /** Left Handle */
 88  
     protected static final int LEFT = 12;
 89  
     /** Right Handle */
 90  
     protected static final int RIGHT = 13;
 91  
     /** Lower left corner Handle */
 92  
     protected static final int LOWER_LEFT = 14;
 93  
     
 94  
     private static final int OFFSET = 2; 
 95  
     
 96  0
     private Object newEdge = null;
 97  
 
 98  
     private int button;
 99  
     
 100  
     /**
 101  
      * Construct a new SelectionNodeClarifiers for the given Fig
 102  
      * 
 103  
      * @param f
 104  
      *            the given Fig
 105  
      */
 106  
     public SelectionNodeClarifiers2(Fig f) {
 107  0
         super(f);
 108  0
     }
 109  
     
 110  
     /*
 111  
      * @see org.tigris.gef.base.SelectionButtons#paint(java.awt.Graphics)
 112  
      */
 113  
     @Override
 114  
     public void paint(Graphics g) {
 115  0
         final Mode topMode = Globals.curEditor().getModeManager().top();
 116  0
         if (!(topMode instanceof ModePlace)) {
 117  
             // If the user has selected ModePlace either by a diagram
 118  
             // tool or AddToDiagram then we don't want to show the
 119  
             // clarifiers.
 120  0
             ((Clarifiable) getContent()).paintClarifiers(g);
 121  
         }
 122  0
         super.paint(g);
 123  0
     }
 124  
 
 125  
     /*
 126  
      * @see org.tigris.gef.base.SelectionButtons#paintButtons(Graphics)
 127  
      */
 128  
     public final void paintButtons(Graphics g) {
 129  0
         final Mode topMode = Globals.curEditor().getModeManager().top();
 130  0
         if (!(topMode instanceof ModePlace)) {
 131  
             // If the user has selected ModePlace either by a diagram
 132  
             // tool or AddToDiagram then we don't want to show the
 133  
             // toolbelt items.
 134  0
             Icon[] icons = getIcons();
 135  0
             if (icons == null) {
 136  0
                 return;
 137  
             }
 138  0
             int cx = getContent().getX();
 139  0
             int cy = getContent().getY();
 140  0
             int cw = getContent().getWidth();
 141  0
             int ch = getContent().getHeight();
 142  
             
 143  0
             if (icons[0] != null) {
 144  0
                 paintButtonAbove(icons[0], g, cx + cw / 2, cy - OFFSET, TOP);
 145  
             }
 146  0
             if (icons[1] != null) {
 147  0
                 paintButtonBelow(icons[1], g, cx + cw / 2, cy + ch + OFFSET, 
 148  
                         BOTTOM);
 149  
             }
 150  0
             if (icons[2] != null) {
 151  0
                 paintButtonLeft(icons[2], g, cx - OFFSET, cy + ch / 2, LEFT);
 152  
             }
 153  0
             if (icons[3] != null) {
 154  0
                 paintButtonRight(icons[3], g, cx + cw + OFFSET, cy + ch / 2,
 155  
                         RIGHT);
 156  
             }
 157  0
             if (icons[4] != null) {
 158  0
                 paintButtonLeft(icons[4], g, cx - OFFSET, cy + ch, LOWER_LEFT);
 159  
             }
 160  
         }
 161  0
     }
 162  
 
 163  
     /*
 164  
      * @see org.tigris.gef.base.SelectionButtons#getNewNode(int)
 165  
      */
 166  
     protected Object getNewNode(int arg0) {
 167  0
         return null;
 168  
     }
 169  
     
 170  
     /**
 171  
      * Compute handle selection, if any, from cursor location.
 172  
      * 
 173  
      * @param cursor
 174  
      *            cursor point represented by a 0-size rectangle
 175  
      * @param h
 176  
      *            handle in which to return selected Handle information (output
 177  
      *            parameter). A handle index of -1 indicates that the cursor is
 178  
      *            not over any handle.
 179  
      * 
 180  
      * If GEF had any API documentation you could see the following:
 181  
      * @see org.tigris.gef.base.SelectionResize#hitHandle(java.awt.Rectangle,
 182  
      *      org.tigris.gef.presentation.Handle)
 183  
      */
 184  
     public void hitHandle(Rectangle cursor, Handle h) {
 185  0
         super.hitHandle(cursor, h);
 186  0
         if (h.index != -1) {
 187  
             // super implementation found a hit
 188  0
             return;
 189  
         }
 190  0
         if (!isPaintButtons()) {
 191  0
             return;
 192  
         }
 193  0
         Icon[] icons = getIcons();
 194  0
         if (icons == null) {
 195  0
             return;
 196  
         }
 197  0
         Editor ce = Globals.curEditor();
 198  0
         SelectionManager sm = ce.getSelectionManager();
 199  0
         if (sm.size() != 1) {
 200  0
             return;
 201  
         }
 202  0
         ModeManager mm = ce.getModeManager();
 203  0
         if (mm.includes(ModeModify.class) && getPressedButton() == -1) {
 204  0
             return;
 205  
         }
 206  0
         int cx = getContent().getX();
 207  0
         int cy = getContent().getY();
 208  0
         int cw = getContent().getWidth();
 209  0
         int ch = getContent().getHeight();
 210  
 
 211  
         /*
 212  
          * Crazy numbering scheme at work here.  Here's how the handle numbers
 213  
          * are laid out.  Values 0-7 are defined by GEF and go left to
 214  
          * right, top to bottom (ie not clockwise or counterclockwise).
 215  
          * Values 10-14 zigzag North, South, West, East, Southwest.
 216  
          * If you can correctly guess where 15 will go, you should buy
 217  
          * a lottery ticket immediately.
 218  
          *  <pre>
 219  
          *            10
 220  
          *     0-------1-------2
 221  
          *     |               |
 222  
          *  12 3               4 13
 223  
          *     |               |
 224  
          *  14 5-------6-------7
 225  
          *            11
 226  
          * </pre>
 227  
          */
 228  0
         if (icons[0] != null && hitAbove(cx + cw / 2, cy, 
 229  
                 icons[0].getIconWidth(), icons[0].getIconHeight(), 
 230  
                 cursor)) {
 231  0
             h.index = TOP;
 232  0
         } else if (icons[1] != null && hitBelow(cx + cw / 2, cy + ch, 
 233  
                 icons[1].getIconWidth(), icons[1].getIconHeight(), 
 234  
                 cursor)) {
 235  0
             h.index = BOTTOM;
 236  0
         } else if (icons[2] != null && hitLeft(cx, cy + ch / 2, 
 237  
                 icons[2].getIconWidth(), icons[2].getIconHeight(), 
 238  
                 cursor)) {
 239  0
             h.index = LEFT;
 240  0
         } else if (icons[3] != null && hitRight(cx + cw, cy + ch / 2, 
 241  
                 icons[3].getIconWidth(), icons[3].getIconHeight(), 
 242  
                 cursor)) {
 243  0
             h.index = RIGHT;
 244  0
         } else if (icons[4] != null && hitLeft(cx, cy + ch, 
 245  
                 icons[4].getIconWidth(), icons[4].getIconHeight(), 
 246  
                 cursor)) {
 247  0
             h.index = LOWER_LEFT;
 248  
         } else {
 249  0
             h.index = -1;
 250  
         }
 251  0
         if (h.index == -1) {
 252  0
             h.instructions = getInstructions(15);
 253  
         } else {
 254  0
             h.instructions = getInstructions(h.index);
 255  
         }
 256  0
     }
 257  
 
 258  
     /*
 259  
      * @see org.tigris.gef.base.Selection#dragHandle(int, int, int, int,
 260  
      * org.tigris.gef.presentation.Handle)
 261  
      */
 262  
     public void dragHandle(int mX, int mY, int anX, int anY, Handle hand) {
 263  
         
 264  
         // Don't allow drag outside of bounds of diagram
 265  0
         mX = Math.max(mX, 0);
 266  0
         mY = Math.max(mY, 0);
 267  
         
 268  0
         if (hand.index < 10) {
 269  0
             setPaintButtons(false);
 270  0
             super.dragHandle(mX, mY, anX, anY, hand);
 271  0
             return;
 272  
         }
 273  0
         if (!isDraggableHandle(hand.index)) {
 274  0
             return;
 275  
         }
 276  0
         int cx = getContent().getX(), cy = getContent().getY();
 277  0
         int cw = getContent().getWidth(), ch = getContent().getHeight();
 278  
 
 279  0
         int bx = mX, by = mY;
 280  
         
 281  
         // Remember what handle was clicked for the case where the drag
 282  
         // is released over empty space
 283  0
         button = hand.index;
 284  
         
 285  0
         switch (hand.index) {
 286  
         case TOP:
 287  0
             by = cy;
 288  0
             bx = cx + cw / 2;
 289  0
             break;
 290  
         case BOTTOM:
 291  0
             by = cy + ch;
 292  0
             bx = cx + cw / 2;
 293  0
             break;
 294  
         case LEFT:
 295  0
             by = cy + ch / 2;
 296  0
             bx = cx;
 297  0
             break;
 298  
         case RIGHT:
 299  0
             by = cy + ch / 2;
 300  0
             bx = cx + cw;
 301  0
             break;
 302  
         case LOWER_LEFT:
 303  0
             by = cy + ch;
 304  0
             bx = cx;
 305  0
             break;
 306  
         default:
 307  0
             LOG.warn("invalid handle number");
 308  
             break;
 309  
         }
 310  
         
 311  0
         Object nodeType = getNewNodeType(hand.index);
 312  0
         Object edgeType = getNewEdgeType(hand.index);
 313  0
         boolean reverse = isReverseEdge(hand.index);
 314  
         
 315  0
         if (edgeType != null && nodeType != null) {
 316  0
             Editor ce = Globals.curEditor();
 317  0
             ModeCreateEdgeAndNode m =
 318  
                 getNewModeCreateEdgeAndNode(ce,
 319  
                         edgeType, isEdgePostProcessRequested(), this);
 320  0
             m.setup((FigNode) getContent(), getContent().getOwner(),
 321  
                     bx, by, reverse);
 322  0
             ce.pushMode(m);
 323  
         }
 324  0
     }
 325  
     
 326  
     /**
 327  
      * Override this to implement post-processing.
 328  
      * 
 329  
      * @param ce the current Editor
 330  
      * @param edgeType the new edge type
 331  
      * @param postProcess true if post-processing is wanted
 332  
      * @param nodeCreator this class will create the node
 333  
      * @return the ModeCreate
 334  
      */
 335  
     protected ModeCreateEdgeAndNode getNewModeCreateEdgeAndNode(
 336  
             Editor ce, Object edgeType, boolean postProcess, 
 337  
             SelectionNodeClarifiers2 nodeCreator) {
 338  0
         return  new ModeCreateEdgeAndNode(ce,
 339  
               edgeType, postProcess, nodeCreator);
 340  
     }
 341  
     
 342  
     @Override
 343  
     public void buttonClicked(int buttonCode) {
 344  0
         super.buttonClicked(buttonCode);
 345  0
         if (isEdgePostProcessRequested()) {
 346  0
             postProcessEdge2(newEdge);
 347  
         }
 348  0
     }
 349  
 
 350  
     protected Object createEdgeAbove(MutableGraphModel gm, Object newNode) {
 351  0
         return createEdge(gm, newNode, TOP);
 352  
     }
 353  
 
 354  
     protected Object createEdgeUnder(MutableGraphModel gm, Object newNode) {
 355  0
         return createEdge(gm, newNode, BOTTOM);
 356  
     }
 357  
 
 358  
     protected Object createEdgeLeft(MutableGraphModel gm, Object newNode) {
 359  0
         return createEdge(gm, newNode, LEFT);
 360  
     }
 361  
 
 362  
     protected Object createEdgeRight(MutableGraphModel gm, Object newNode) {
 363  0
         return createEdge(gm, newNode, RIGHT);
 364  
     }
 365  
 
 366  
     private Object createEdge(MutableGraphModel gm, Object newNode, int index) {
 367  0
         if (isReverseEdge(index)) {
 368  0
             newEdge = gm.connect(
 369  
                     newNode, getContent().getOwner(), getNewEdgeType(index));
 370  
         } else {
 371  0
             newEdge = gm.connect(
 372  
                     getContent().getOwner(), newNode, getNewEdgeType(index));
 373  
         }
 374  0
         return newEdge;
 375  
     }
 376  
     
 377  
     protected Object createEdgeToSelf(MutableGraphModel gm) {
 378  0
         Object edge = gm.connect(
 379  
                 getContent().getOwner(), getContent().getOwner(),
 380  
                 getNewEdgeType(LOWER_LEFT));
 381  0
         return edge;
 382  
     }
 383  
 
 384  
     /**
 385  
      * Get array of icons to use when drawing handles.
 386  
      * @return icon or null
 387  
      */
 388  
     protected abstract Icon[] getIcons();
 389  
 
 390  
     /**
 391  
      * Get the "instructions" string to pass to GEF for the given handle number.
 392  
      * 
 393  
      * @param index
 394  
      *            handle number that is being dragged from
 395  
      * @return string or null
 396  
      */
 397  
     protected abstract String getInstructions(int index);
 398  
     
 399  
     /**
 400  
      * Get the node type to create when dragging from the given handle number.
 401  
      * 
 402  
      * @param index
 403  
      *            handle number that is being dragged from
 404  
      * @return metatype for model element. Null to disallow drag.
 405  
      */
 406  
     protected abstract Object getNewNodeType(int index);
 407  
 
 408  
     /**
 409  
      * Get the edge type to create when dragging from the given handle number.
 410  
      * 
 411  
      * @param index
 412  
      *            handle number that is being dragged from
 413  
      * @return metatype for model element. Null to disallow drag.
 414  
      */
 415  
     protected abstract Object getNewEdgeType(int index);
 416  
     
 417  
     /**
 418  
      * Get the node type to create when dragging from the given handle number.
 419  
      * 
 420  
      * @param index
 421  
      *            handle number that is being dragged from
 422  
      * @return true to reverse direction of assocation from direction of drag.
 423  
      *         eg. specialization instead of generalization.  Default
 424  
      *         implementation always returns false.
 425  
      */
 426  
     protected boolean isReverseEdge(int index) {
 427  0
         return false;
 428  
     }
 429  
     
 430  
     /**
 431  
      * Get the draggability of a particular handle. Default implementation
 432  
      * always returns true. Override to return false for handles which shouldn't
 433  
      * be draggable (i.e. they only support clicks, not drags).
 434  
      * 
 435  
      * @param index
 436  
      *            handle index to check draggability for
 437  
      * @return true if this handle is draggable, false otherwise
 438  
      */
 439  
     protected boolean isDraggableHandle(int index) {
 440  0
         return true;
 441  
     }
 442  
     
 443  
     /**
 444  
      * Request post processing of edge by GEF after it is created using
 445  
      * {@link ModeCreateEdgeAndNode#ModeCreateEdgeAndNode(Editor, Object, Object, boolean)}
 446  
      * 
 447  
      * @return true if postprocessing requested
 448  
      */
 449  
     protected boolean isEdgePostProcessRequested() {
 450  0
         return false;
 451  
     }
 452  
 
 453  
     /**
 454  
      * @param newEdge the new edge to post-process
 455  
      */
 456  
     protected void postProcessEdge2(Object newEdge) {
 457  
         // do nothing by default
 458  0
     }
 459  
 
 460  
     /**
 461  
      * @return index of last button/handle that was clicked
 462  
      */
 463  
     protected int getButton() {
 464  0
         return button;
 465  
     }
 466  
     
 467  
 } 
 468