Coverage Report - org.argouml.uml.ui.TabProps
 
Classes in this File Line Coverage Branch Coverage Complexity
TabProps
66%
75/113
48%
31/64
2.737
 
 1  
 /* $Id: TabProps.java 18360 2010-05-03 21:17:15Z bobtarling $
 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  
  *    bobtarling
 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.ui;
 40  
 
 41  
 import java.awt.BorderLayout;
 42  
 import java.util.Enumeration;
 43  
 import java.util.Hashtable;
 44  
 
 45  
 import javax.swing.JPanel;
 46  
 import javax.swing.event.EventListenerList;
 47  
 
 48  
 import org.apache.log4j.Logger;
 49  
 import org.argouml.application.api.AbstractArgoJPanel;
 50  
 import org.argouml.cognitive.Critic;
 51  
 import org.argouml.model.Model;
 52  
 import org.argouml.swingext.UpArrowIcon;
 53  
 import org.argouml.ui.TabModelTarget;
 54  
 import org.argouml.ui.targetmanager.TargetEvent;
 55  
 import org.argouml.ui.targetmanager.TargetListener;
 56  
 import org.argouml.ui.targetmanager.TargetManager;
 57  
 import org.argouml.uml.diagram.ArgoDiagram;
 58  
 import org.argouml.uml.diagram.ui.PropPanelString;
 59  
 import org.tigris.gef.base.Diagram;
 60  
 import org.tigris.gef.presentation.Fig;
 61  
 import org.tigris.gef.presentation.FigText;
 62  
 import org.tigris.swidgets.Horizontal;
 63  
 import org.tigris.swidgets.Orientable;
 64  
 import org.tigris.swidgets.Orientation;
 65  
 
 66  
 /**
 67  
  * This is the tab on the details panel (DetailsPane) that holds the property
 68  
  * panel. On change of target, the property panel in TabProps is changed.
 69  
  * <p>
 70  
  * With the introduction of the TargetManager, this class holds its original
 71  
  * power of controlling its target. The property panels (subclasses of
 72  
  * PropPanel) for which this class is the container are being registered as
 73  
  * TargetListeners in the setTarget method of this class. They are not
 74  
  * registered with TargetManager but with this class to prevent race-conditions
 75  
  * while firing TargetEvents from TargetManager.
 76  
  */
 77  
 public class TabProps
 78  
     extends AbstractArgoJPanel
 79  
     implements TabModelTarget {
 80  
 
 81  
     /**
 82  
      * Logger.
 83  
      */
 84  900
     private static final Logger LOG = Logger.getLogger(TabProps.class);
 85  
     
 86  900
     private JPanel blankPanel = new JPanel();
 87  900
     private Hashtable<Class, JPanel> panels = 
 88  
         new Hashtable<Class, JPanel>();
 89  
     private JPanel lastPanel;
 90  900
     private String panelClassBaseName = "";
 91  
 
 92  
     /**
 93  
      * The panel currently displayed in center
 94  
      */
 95  
     private JPanel currentPanel;
 96  
     
 97  
     private Object target;
 98  
 
 99  
     /**
 100  
      * The list with targetlisteners, these are the property panels
 101  
      * managed by TabProps.
 102  
      * It should only contain one listener at a time.
 103  
      */
 104  900
     private EventListenerList listenerList = new EventListenerList();
 105  
 
 106  
     /**
 107  
      * The constructor.
 108  
      *
 109  
      */
 110  
     public TabProps() {
 111  900
         this("tab.properties", "ui.PropPanel");
 112  900
     }
 113  
 
 114  
     /**
 115  
      * The constructor.
 116  
      *
 117  
      * @param tabName the name of the tab
 118  
      * @param panelClassBase the panel class base
 119  
      */
 120  
     public TabProps(String tabName, String panelClassBase) {
 121  900
         super(tabName);
 122  900
         setIcon(new UpArrowIcon());
 123  
         // TODO: This should be managed by the DetailsPane TargetListener - tfm
 124  
         // remove the following line
 125  900
         TargetManager.getInstance().addTargetListener(this);
 126  900
         setOrientation(Horizontal.getInstance());
 127  900
         panelClassBaseName = panelClassBase;
 128  900
         setLayout(new BorderLayout());
 129  900
     }
 130  
 
 131  
     /**
 132  
      * Set the orientation of the property panel.
 133  
      *
 134  
      * @param orientation the new orientation for this property panel
 135  
      *
 136  
      * @see org.tigris.swidgets.Orientable#setOrientation(org.tigris.swidgets.Orientation)
 137  
      */
 138  
     @Override
 139  
     public void setOrientation(Orientation orientation) {
 140  900
         super.setOrientation(orientation);
 141  900
         Enumeration pps = panels.elements();
 142  900
         while (pps.hasMoreElements()) {
 143  0
             Object o = pps.nextElement();
 144  0
             if (o instanceof Orientable) {
 145  0
                 Orientable orientable = (Orientable) o;
 146  0
                 orientable.setOrientation(orientation);
 147  
             }
 148  0
         }
 149  900
     }
 150  
 
 151  
     /**
 152  
      * Adds a property panel to the internal list. This allows a plugin to
 153  
      * add / register a new property panel at run-time.
 154  
      * This property panel will then
 155  
      * be displayed in the detatils pane whenever an element
 156  
      * of the given metaclass is selected.
 157  
      *
 158  
      * @param clazz the metaclass whose details show be displayed
 159  
      *          in the property panel p
 160  
      * @param panel an instance of the property panel for the metaclass m
 161  
      *
 162  
      */
 163  
     public void addPanel(Class clazz, PropPanel panel) {
 164  0
         panels.put(clazz, panel);
 165  0
     }
 166  
 
 167  
 
 168  
     ////////////////////////////////////////////////////////////////
 169  
     // accessors
 170  
     /**
 171  
      * Sets the target of the property panel. The given target t
 172  
      * may either be a Diagram or a modelelement. If the target
 173  
      * given is a Fig, a check is made if the fig has an owning
 174  
      * modelelement and occurs on the current diagram.
 175  
      * If so, that modelelement is the target.
 176  
      *
 177  
      * @deprecated As of ArgoUml version 0.13.5,
 178  
      *         the visibility of this method will change in the future,
 179  
      *         replaced by {@link org.argouml.ui.targetmanager.TargetManager}.
 180  
      *         TODO: MVW: I think this should not be deprecated.
 181  
      *
 182  
      * @param target the new target
 183  
      * @see org.argouml.ui.TabTarget#setTarget(java.lang.Object)
 184  
      */
 185  
     @Deprecated
 186  
     public void setTarget(Object target) {
 187  
         // targets ought to be UML objects or diagrams
 188  2415
         LOG.info("setTarget: there are "
 189  
                 + TargetManager.getInstance().getTargets().size()
 190  
                 + " targets");
 191  
 
 192  2415
         target = (target instanceof Fig) ? ((Fig) target).getOwner() : target;
 193  2415
         if (!(target == null || Model.getFacade().isAUMLElement(target) 
 194  
                 || target instanceof ArgoDiagram
 195  
                 // TODO Improve extensibility of this!
 196  
                 || target instanceof Critic)) {
 197  0
             target = null;
 198  
         }
 199  
         
 200  2415
         if (lastPanel != null) {
 201  128
             remove(lastPanel);
 202  128
             if (lastPanel instanceof TargetListener) {
 203  
                 // TODO: We should assert this never happens before removing
 204  
                 // panels should control their own listeners
 205  0
                 removeTargetListener((TargetListener) lastPanel);
 206  
             }
 207  
         }
 208  
   
 209  
         // TODO: No need to do anything if we're not visible      
 210  
 //        if (!isVisible()) {
 211  
 //            return;
 212  
 //        }
 213  
         
 214  2415
         this.target = target;
 215  2415
         if (target == null) {
 216  126
             add(blankPanel, BorderLayout.CENTER);
 217  126
             validate();
 218  126
             repaint();
 219  126
             lastPanel = blankPanel;
 220  
         } else {
 221  2289
             JPanel newPanel = findPanelFor(target);
 222  2289
             if (newPanel != null && newPanel instanceof TabModelTarget) {
 223  2289
                 addTargetListener((TabModelTarget) newPanel);
 224  
             }
 225  
             
 226  2289
             if (currentPanel != null) {
 227  1389
                 remove(currentPanel);
 228  1389
                 currentPanel = null;
 229  
             }
 230  2289
             if (newPanel != null) {
 231  2289
                 currentPanel = newPanel;
 232  
             } else {
 233  0
                 currentPanel = blankPanel;
 234  0
                 lastPanel = blankPanel;
 235  
             }
 236  2289
             add(currentPanel);
 237  2289
             validate();
 238  2289
             repaint();
 239  
         }
 240  2415
     }
 241  
 
 242  
     /*
 243  
      * @see org.argouml.ui.TabTarget#refresh()
 244  
      */
 245  
     public void refresh() {
 246  0
         setTarget(TargetManager.getInstance().getTarget());
 247  0
     }
 248  
 
 249  
     /**
 250  
      * Find the correct properties panel for the target.
 251  
      *
 252  
      * @param trgt the target class
 253  
      * @return the tab panel
 254  
      */
 255  
     private JPanel findPanelFor(Object trgt) {
 256  
         // TODO: No test coverage for this or createPropPanel? - tfm
 257  
         
 258  2289
         JPanel panel = createPropPanel(trgt);
 259  2289
         if (panel != null) {
 260  2289
             LOG.debug("Factory created " + panel.getClass().getName()
 261  
                     + " for " + trgt.getClass().getName());
 262  2289
             panels.put(trgt.getClass(), panel);
 263  2289
             return panel;
 264  
         }
 265  
 
 266  0
         LOG.error("Failed to create a prop panel for : " + trgt);
 267  0
         return null;
 268  
     }
 269  
 
 270  
     /**
 271  
      * A factory method to create a PropPanel for a particular target (Diagram,
 272  
      * UML Element or GEF Fig).
 273  
      *
 274  
      * @param targetObject the target object
 275  
      * @return A new prop panel to display any model element of the given type
 276  
      */
 277  
     private JPanel createPropPanel(Object targetObject) {
 278  2289
         JPanel propPanel = null;
 279  
 
 280  
         for (PropPanelFactory factory
 281  2289
                 : PropPanelFactoryManager.getFactories()) {
 282  9404
             propPanel = factory.createPropPanel(targetObject);
 283  9404
             if (propPanel != null) return propPanel;
 284  
         }        
 285  
         
 286  
         /* This does not work (anymore/yet?), 
 287  
          * since we never have a FigText here: */
 288  0
         if (targetObject instanceof FigText) {
 289  0
             propPanel = new PropPanelString();
 290  
         }
 291  
 
 292  0
         if (propPanel instanceof Orientable) {
 293  0
             ((Orientable) propPanel).setOrientation(getOrientation());
 294  
         }
 295  
         
 296  
         // TODO: We shouldn't need this as well as the above.
 297  0
         if (propPanel instanceof PropPanel) {
 298  0
             ((PropPanel) propPanel).setOrientation(getOrientation());
 299  
         }
 300  
 
 301  0
         return propPanel;
 302  
     }
 303  
 
 304  
     /**
 305  
      * @return the name
 306  
      */
 307  
     protected String getClassBaseName() {
 308  0
         return panelClassBaseName;
 309  
     }
 310  
 
 311  
     /**
 312  
      * Returns the current target.
 313  
      * @deprecated As of ArgoUml version 0.13.5,
 314  
      * the visibility of this method will change in the future, replaced by
 315  
      * {@link org.argouml.ui.targetmanager.TargetManager#getTarget()
 316  
      * TargetManager.getInstance().getTarget()}.
 317  
      * TODO: MVW: I think this should not be deprecated.
 318  
      *
 319  
      * @return the target
 320  
      * @see org.argouml.ui.TabTarget#getTarget()
 321  
      */
 322  
     @Deprecated
 323  
     public Object getTarget() {
 324  0
         return target;
 325  
     }
 326  
 
 327  
     /**
 328  
      * Determines if the property panel should be enabled.
 329  
      * The property panel should always be enabled if the
 330  
      * target is an instance of a modelelement or an argodiagram.
 331  
      * If the target given is a Fig, a check is made if the fig
 332  
      * has an owning modelelement and occurs on
 333  
      * the current diagram. If so, that modelelement is the target.
 334  
      * @param target the target
 335  
      * @return true if property panel should be enabled
 336  
      * @see org.argouml.ui.TabTarget#shouldBeEnabled(Object)
 337  
      */
 338  
     public boolean shouldBeEnabled(Object target) {
 339  2528
         if (target instanceof Fig) {
 340  0
             target = ((Fig) target).getOwner();
 341  
         }
 342  
         
 343  
         // TODO: this should be more extensible... may be only 
 344  
         // "findPanelFor(target)" if there is a panel why not show it?
 345  2528
         return ((target instanceof Diagram || Model.getFacade().isAUMLElement(
 346  
                 target)) || target instanceof Critic
 347  
                 && findPanelFor(target) != null);
 348  
     }
 349  
 
 350  
     /*
 351  
      * @see org.argouml.ui.targetmanager.TargetListener#targetAdded(org.argouml.ui.targetmanager.TargetEvent)
 352  
      */
 353  
     public void targetAdded(TargetEvent targetEvent) {
 354  0
         setTarget(TargetManager.getInstance().getSingleTarget());
 355  0
         fireTargetAdded(targetEvent);
 356  0
         if (listenerList.getListenerCount() > 0) {
 357  0
             validate();
 358  0
             repaint();
 359  
         }
 360  
 
 361  0
     }
 362  
 
 363  
     /*
 364  
      * @see org.argouml.ui.targetmanager.TargetListener#targetRemoved(org.argouml.ui.targetmanager.TargetEvent)
 365  
      */
 366  
     public void targetRemoved(TargetEvent targetEvent) {
 367  88
         setTarget(TargetManager.getInstance().getSingleTarget());
 368  88
         fireTargetRemoved(targetEvent);
 369  88
         validate();
 370  88
         repaint();
 371  88
     }
 372  
 
 373  
     /*
 374  
      * @see org.argouml.ui.targetmanager.TargetListener#targetSet(org.argouml.ui.targetmanager.TargetEvent)
 375  
      */
 376  
     public void targetSet(TargetEvent targetEvent) {
 377  2327
         setTarget(TargetManager.getInstance().getSingleTarget());
 378  2327
         fireTargetSet(targetEvent);
 379  2327
         validate();
 380  2327
         repaint();
 381  2327
     }
 382  
 
 383  
     /**
 384  
      * Adds a listener.
 385  
      * @param listener the listener to add
 386  
      */
 387  
     private void addTargetListener(TargetListener listener) {
 388  2289
         listenerList.add(TargetListener.class, listener);
 389  2289
     }
 390  
 
 391  
     /**
 392  
      * Removes a target listener.
 393  
      * @param listener the listener to remove
 394  
      */
 395  
     private void removeTargetListener(TargetListener listener) {
 396  0
         listenerList.remove(TargetListener.class, listener);
 397  0
     }
 398  
 
 399  
     private void fireTargetSet(TargetEvent targetEvent) {
 400  
         //      Guaranteed to return a non-null array
 401  2327
         Object[] listeners = listenerList.getListenerList();
 402  6874
         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 403  4547
             if (listeners[i] == TargetListener.class) {
 404  
                 // Lazily create the event:
 405  4547
                 ((TargetListener) listeners[i + 1]).targetSet(targetEvent);
 406  
             }
 407  
         }
 408  2327
     }
 409  
 
 410  
     private void fireTargetAdded(TargetEvent targetEvent) {
 411  
         // Guaranteed to return a non-null array
 412  0
         Object[] listeners = listenerList.getListenerList();
 413  
 
 414  0
         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 415  0
             if (listeners[i] == TargetListener.class) {
 416  
                 // Lazily create the event:
 417  0
                 ((TargetListener) listeners[i + 1]).targetAdded(targetEvent);
 418  
             }
 419  
         }
 420  0
     }
 421  
 
 422  
     private void fireTargetRemoved(TargetEvent targetEvent) {
 423  
         // Guaranteed to return a non-null array
 424  88
         Object[] listeners = listenerList.getListenerList();
 425  264
         for (int i = listeners.length - 2; i >= 0; i -= 2) {
 426  176
             if (listeners[i] == TargetListener.class) {
 427  
                 // Lazily create the event:
 428  176
                 ((TargetListener) listeners[i + 1]).targetRemoved(targetEvent);
 429  
             }
 430  
         }
 431  88
     }
 432  
 } /* end class TabProps */