Coverage Report - org.argouml.ui.explorer.ExplorerEventAdaptor
 
Classes in this File Line Coverage Branch Coverage Complexity
ExplorerEventAdaptor
84%
44/52
71%
27/38
3.364
ExplorerEventAdaptor$1
57%
4/7
0%
0/2
3.364
ExplorerEventAdaptor$ProfileChangeListener
60%
3/5
N/A
3.364
 
 1  
 /* $Id: ExplorerEventAdaptor.java 17843 2010-01-12 19:23:29Z 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.ui.explorer;
 40  
 
 41  
 import java.beans.PropertyChangeEvent;
 42  
 import java.beans.PropertyChangeListener;
 43  
 
 44  
 import javax.swing.SwingUtilities;
 45  
 
 46  
 import org.apache.log4j.Logger;
 47  
 import org.argouml.application.events.ArgoEventPump;
 48  
 import org.argouml.application.events.ArgoEventTypes;
 49  
 import org.argouml.application.events.ArgoProfileEvent;
 50  
 import org.argouml.application.events.ArgoProfileEventListener;
 51  
 import org.argouml.configuration.Configuration;
 52  
 import org.argouml.kernel.ProjectManager;
 53  
 import org.argouml.model.AddAssociationEvent;
 54  
 import org.argouml.model.AttributeChangeEvent;
 55  
 import org.argouml.model.DeleteInstanceEvent;
 56  
 import org.argouml.model.InvalidElementException;
 57  
 import org.argouml.model.Model;
 58  
 import org.argouml.model.RemoveAssociationEvent;
 59  
 import org.argouml.model.UmlChangeEvent;
 60  
 import org.argouml.notation.Notation;
 61  
 
 62  
 /**
 63  
  * All events going to the Explorer must pass through here first!<p>
 64  
  *
 65  
  * Most will come from the uml model via the EventAdapter interface.<p>
 66  
  *
 67  
  * TODO: In some cases (test cases) this object is created without setting
 68  
  * the treeModel. I (Linus) will add tests for this now. It would be better
 69  
  * if this is created only when the Explorer is created. <p>
 70  
  * 
 71  
  * TODO: The ExplorerTreeNode also listens to some events
 72  
  * (from Diagrams), so it does not follow the rule above.
 73  
  *
 74  
  * @since 0.15.2, Created on 16 September 2003, 23:13
 75  
  * @author  alexb
 76  
  */
 77  2314
 public final class ExplorerEventAdaptor
 78  
     implements PropertyChangeListener {
 79  
     
 80  900
     private static final Logger LOG =
 81  
         Logger.getLogger(ExplorerEventAdaptor.class);
 82  
 
 83  
     /**
 84  
      * The singleton instance.
 85  
      *
 86  
      * TODO: Why is this a singleton? Wouldn't it be better to have exactly
 87  
      * one for every Explorer?
 88  
      */
 89  
     private static ExplorerEventAdaptor instance;
 90  
 
 91  
     /**
 92  
      * The tree model to update.
 93  
      */
 94  
     private TreeModelUMLEventListener treeModel;
 95  
 
 96  
     /**
 97  
      * @return the instance (singleton)
 98  
      */
 99  
     public static ExplorerEventAdaptor getInstance() {
 100  1093
         if (instance == null) {
 101  900
             instance = new ExplorerEventAdaptor();
 102  
         }
 103  1093
         return instance;
 104  
     }
 105  
 
 106  
     /**
 107  
      * Creates a new instance of ExplorerUMLEventAdaptor.
 108  
      */
 109  900
     private ExplorerEventAdaptor() {
 110  
 
 111  900
         Configuration.addListener(Notation.KEY_USE_GUILLEMOTS, this);
 112  900
         Configuration.addListener(Notation.KEY_SHOW_STEREOTYPES, this);
 113  900
         ProjectManager.getManager().addPropertyChangeListener(this);
 114  
         // TODO: We really only care about events which affect things that
 115  
         // are visible in the current perspective (view).  This could be
 116  
         // tailored to cut down on event traffic. - tfm 20060410
 117  900
         Model.getPump().addClassModelEventListener(this,
 118  
                 Model.getMetaTypes().getModelElement(), (String[]) null);
 119  900
         ArgoEventPump.addListener(
 120  
                 ArgoEventTypes.ANY_PROFILE_EVENT, new ProfileChangeListener());
 121  900
     }
 122  
 
 123  
     /**
 124  
      * The tree structure has changed significantly.  
 125  
      * Inform the associated tree model.
 126  
      * 
 127  
      * TODO:  This shouldn't be public.  Components desiring to
 128  
      * inform the Explorer of changes should send events.
 129  
      * @deprecated by mvw in V0.25.4. Use events instead.
 130  
      */
 131  
     @Deprecated
 132  
     public void structureChanged() {
 133  2862
         if (treeModel == null) {
 134  0
             return;
 135  
         }
 136  2862
         treeModel.structureChanged();
 137  2862
     }
 138  
 
 139  
     
 140  
     /**
 141  
      * forwards this event to the tree model.
 142  
      *
 143  
      * @param element the modelelement to be added
 144  
      * 
 145  
      * TODO:  This shouldn't be public.  Components desiring to
 146  
      * inform the Explorer of changes should send events.
 147  
      */
 148  
     public void modelElementAdded(Object element) {
 149  193
         if (treeModel == null) {
 150  0
             return;
 151  
         }
 152  193
         treeModel.modelElementAdded(element);
 153  193
     }
 154  
 
 155  
     /**
 156  
      * forwards this event to the tree model.
 157  
      *
 158  
      * @param element the modelelement to be changed
 159  
      * 
 160  
      * TODO:  This shouldn't be public.  Components desiring to
 161  
      * inform the Explorer of changes should send events.
 162  
      */
 163  
     public void modelElementChanged(Object element) {
 164  0
         if (treeModel == null) {
 165  0
             return;
 166  
         }
 167  0
         treeModel.modelElementChanged(element);
 168  0
     }
 169  
 
 170  
     /**
 171  
      * sets the tree model that will receive events.
 172  
      *
 173  
      * @param newTreeModel the tree model to be used
 174  
      */
 175  
     public void setTreeModelUMLEventListener(
 176  
             TreeModelUMLEventListener newTreeModel) {
 177  900
         treeModel = newTreeModel;
 178  900
     }
 179  
 
 180  
     /**
 181  
      * Listens to events coming from the project manager, config manager, and
 182  
      * uml model, passes those events on to the explorer model.
 183  
      *
 184  
      * @since ARGO0.11.2
 185  
      *
 186  
      * @see PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
 187  
      */
 188  
     public void propertyChange(final PropertyChangeEvent pce) {
 189  6088
         if (treeModel == null) {
 190  0
             return;
 191  
         }
 192  
 
 193  
         // uml model events
 194  6088
         if (pce instanceof UmlChangeEvent) {
 195  2314
             Runnable doWorkRunnable = new Runnable() {
 196  
                 public void run() {
 197  
                     try {
 198  2314
                         modelChanged((UmlChangeEvent) pce);
 199  0
                     } catch (InvalidElementException e) {
 200  0
                         if (LOG.isDebugEnabled()) {
 201  0
                             LOG.debug("updateLayout method accessed "
 202  
                                     + "deleted element", e);
 203  
                         }
 204  2314
                     }
 205  2314
                 }  
 206  
             };
 207  2314
             SwingUtilities.invokeLater(doWorkRunnable);
 208  
             
 209  2314
         } else if (pce.getPropertyName().equals(
 210  
                 // TODO: No one should be sending the deprecated event
 211  
                 // from outside ArgoUML, but keep responding to it for now
 212  
                 // just in case
 213  
                 ProjectManager.CURRENT_PROJECT_PROPERTY_NAME)
 214  
                 || pce.getPropertyName().equals(
 215  
                         ProjectManager.OPEN_PROJECTS_PROPERTY)) {
 216  
             // project events
 217  3736
             if (pce.getNewValue() != null) {
 218  3736
                 treeModel.structureChanged();
 219  
             }
 220  3736
             return;
 221  38
         } else if (Notation.KEY_USE_GUILLEMOTS.isChangedProperty(pce)
 222  
             || Notation.KEY_SHOW_STEREOTYPES.isChangedProperty(pce)) {
 223  
             // notation events
 224  0
             treeModel.structureChanged();
 225  38
         } else if (pce.getSource() instanceof ProjectManager) {
 226  
             // Handle remove for non-UML elements (e.g. diagrams)
 227  38
             if ("remove".equals(pce.getPropertyName())) {
 228  38
                 treeModel.modelElementRemoved(pce.getOldValue());
 229  
             }
 230  
         }
 231  2352
     }
 232  
     
 233  
     private void modelChanged(UmlChangeEvent event) {
 234  2314
         if (event instanceof AttributeChangeEvent) {
 235  
             // TODO: Can this be made more restrictive?
 236  
             // Do we care about any attributes other than name? - tfm
 237  1654
             treeModel.modelElementChanged(event.getSource());
 238  660
         } else if (event instanceof RemoveAssociationEvent) {
 239  
             // TODO: This should really be coded the other way round,
 240  
             // to only act on associations which are important for
 241  
             // representing the current perspective (and to only act
 242  
             // on a single end of the association) - tfm
 243  158
             if (!("namespace".equals(event.getPropertyName()))) {
 244  157
                 treeModel.modelElementChanged(((RemoveAssociationEvent) event)
 245  
                         .getChangedValue());
 246  
             }
 247  502
         } else if (event instanceof AddAssociationEvent) {
 248  500
             if (!("namespace".equals(event.getPropertyName()))) {
 249  404
                 treeModel.modelElementAdded(
 250  
                         ((AddAssociationEvent) event).getSource());
 251  
             }
 252  2
         } else if (event instanceof DeleteInstanceEvent) {
 253  2
             treeModel.modelElementRemoved(((DeleteInstanceEvent) event)
 254  
                     .getSource());
 255  
         }
 256  2314
     }
 257  
     
 258  
     
 259  
     /**
 260  
      * Listener for additions and removals of profiles.
 261  
      * Since they generally have a major impact on the explorer tree, 
 262  
      * we simply update them completely.
 263  
      *
 264  
      * @author Michiel
 265  
      */
 266  900
     class ProfileChangeListener implements ArgoProfileEventListener {
 267  
 
 268  
         public void profileAdded(ArgoProfileEvent e) {
 269  2862
             structureChanged();
 270  2862
         }
 271  
 
 272  
         public void profileRemoved(ArgoProfileEvent e) {
 273  0
             structureChanged();
 274  0
         }
 275  
         
 276  
     }
 277  
 }