Coverage Report - org.argouml.notation.NotationProvider
 
Classes in this File Line Coverage Branch Coverage Complexity
NotationProvider
0%
0/79
0%
0/36
2.389
 
 1  
 /* $Id: NotationProvider.java 18852 2010-11-20 19:27:11Z mvw $
 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  
  *    Michiel van der Wulp
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 2005-2009 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.notation;
 40  
 
 41  
 import java.beans.PropertyChangeEvent;
 42  
 import java.beans.PropertyChangeListener;
 43  
 import java.util.ArrayList;
 44  
 import java.util.Collection;
 45  
 
 46  
 import org.apache.log4j.Logger;
 47  
 import org.argouml.model.AddAssociationEvent;
 48  
 import org.argouml.model.DeleteInstanceEvent;
 49  
 import org.argouml.model.Model;
 50  
 import org.argouml.model.RemoveAssociationEvent;
 51  
 
 52  
 /**
 53  
  * A class that implements this abstract class manages a text
 54  
  * shown on a diagram. This means it is able to generate
 55  
  * text that represents one or more UML objects.
 56  
  * And when the user has edited this text, the model may be adapted
 57  
  * by parsing the text.
 58  
  * Additionally, a help text for the parsing is provided,
 59  
  * so that the user knows the syntax.
 60  
  * 
 61  
  * @author Michiel van der Wulp
 62  
  */
 63  0
 public abstract class NotationProvider implements PropertyChangeListener {
 64  
 
 65  0
     private static final Logger LOG = Logger.getLogger(NotationProvider.class);
 66  
     private NotationRenderer renderer;
 67  
 
 68  
     /**
 69  
      * A collection of properties of listeners registered for this notation.
 70  
      * Each entry is a 2 element array containing the element and the property
 71  
      * name(s) for which a listener is registered. This facilitates easy removal
 72  
      * of a complex set of listeners.
 73  
      */
 74  0
     private final Collection<Object[]> listeners = new ArrayList<Object[]>();
 75  
 
 76  
     /**
 77  
      * @return a i18 key that represents a help string
 78  
      *         giving an explanation to the user of the syntax
 79  
      */
 80  
     public abstract String getParsingHelp();
 81  
 
 82  
     /**
 83  
      * Parses the given text, and adapts the modelElement and
 84  
      * maybe related elements accordingly.
 85  
      * 
 86  
      * @param modelElement the modelelement to adapt
 87  
      * @param text the string given by the user to be parsed
 88  
      * to adapt the model
 89  
      */
 90  
     public abstract void parse(Object modelElement, String text);
 91  
 
 92  
     /**
 93  
      * Generate a string representation for the given model element.
 94  
      * 
 95  
      * @param modelElement the base UML element
 96  
      * @param settings settings that control rendering of the text
 97  
      * @return the string written in the correct notation
 98  
      */
 99  
     public abstract String toString(Object modelElement,
 100  
             NotationSettings settings);
 101  
     
 102  
     /**
 103  
      * Initialize the appropriate model change listeners 
 104  
      * for the given modelelement to the given listener.
 105  
      * Overrule this when you need more than 
 106  
      * listening to all events from the base modelelement.
 107  
      * 
 108  
      * @param modelElement the modelelement that we provide 
 109  
      * notation for
 110  
      */
 111  
     public void initialiseListener(Object modelElement) {
 112  0
         addElementListener(modelElement);
 113  0
     }
 114  
     
 115  
     /**
 116  
      * Clean out the listeners registered before.
 117  
      * <p>
 118  
      * The default implementation is to remove all listeners 
 119  
      * that were remembered by the utility functions below.
 120  
      */
 121  
     public void cleanListener() {
 122  0
         removeAllElementListeners();
 123  0
     }
 124  
     
 125  
     /**
 126  
      * Update the set of listeners based on the given event. <p>
 127  
      * 
 128  
      * The default implementation just removes all listeners, and then 
 129  
      * re-initializes completely - this is method 1. 
 130  
      * A more efficient way would be to dissect 
 131  
      * the propertyChangeEvent, and only adapt the listeners
 132  
      * that need to be adapted - this is method 2. <p>
 133  
      * 
 134  
      * Method 2 is explained by the code below that is commented out.
 135  
      * Method 1 is the easiest to implement, since at every arrival of an event,
 136  
      * we just remove all old listeners, and then inspect the current model, 
 137  
      * and add listeners where we need them. I.e. the advantage is 
 138  
      * that we only need to traverse the model structure in one location, i.e. 
 139  
      * the initialiseListener() method.
 140  
      * 
 141  
      * @param modelElement the modelelement that we provide 
 142  
      * notation for
 143  
      * @param pce the received event, that we base the changes on
 144  
      */
 145  
     public void updateListener(Object modelElement, PropertyChangeEvent pce) {
 146  
         // e.g. for an operation:
 147  
         // if pce.getSource() == modelElement
 148  
         // && event.propertyName = "parameter"
 149  
         //     if event instanceof AddAssociationEvent
 150  
         //         Get the parameter instance from event.newValue
 151  
         //         Call model to add listener on parameter on change 
 152  
         //             of "name", "type"
 153  
         //     else if event instanceof RemoveAssociationEvent
 154  
         //         Get the parameter instance from event.oldValue
 155  
         //         Call model to remove listener on parameter on change 
 156  
         //             of "name", "type"
 157  
         //     end if
 158  
         // end if 
 159  0
         if (Model.getUmlFactory().isRemoved(modelElement)) {
 160  0
             LOG.warn("Encountered deleted object during delete of " 
 161  
                     + modelElement);
 162  0
             return;
 163  
         }
 164  0
         cleanListener();
 165  0
         initialiseListener(modelElement);
 166  0
     }
 167  
 
 168  
     public void propertyChange(PropertyChangeEvent evt) {
 169  0
         if (renderer != null) {
 170  0
             Object owner = renderer.getOwner(this);
 171  0
             if ((owner == evt.getSource()) 
 172  
                     && (evt instanceof DeleteInstanceEvent)) {
 173  0
                 return;
 174  
             }
 175  0
             if (owner != null) {
 176  0
                 if (Model.getUmlFactory().isRemoved(owner)) {
 177  0
                     LOG.warn("Encountered deleted object during delete of " 
 178  
                             + owner);
 179  0
                     return;
 180  
                 }
 181  0
                 renderer.notationRenderingChanged(this,
 182  
                         toString(owner, renderer.getNotationSettings(this)));
 183  0
                 if (evt instanceof AddAssociationEvent 
 184  
                         || evt instanceof RemoveAssociationEvent) {
 185  0
                     initialiseListener(owner);
 186  
                 }
 187  
             }
 188  
         }
 189  0
     }
 190  
 
 191  
     /*
 192  
      * Add an element listener and remember the registration.
 193  
      * 
 194  
      * @param element
 195  
      *            element to listen for changes on
 196  
      * @see org.argouml.model.ModelEventPump#addModelEventListener(PropertyChangeListener, Object, String)
 197  
      */
 198  
     protected final void addElementListener(PropertyChangeListener listener, 
 199  
             Object element) {
 200  0
         if (Model.getUmlFactory().isRemoved(element)) {
 201  0
             LOG.warn("Encountered deleted object during delete of " + element);
 202  0
             return;
 203  
         }
 204  0
         Object[] entry = new Object[] {element, null};
 205  0
         if (!listeners.contains(entry)) {
 206  0
             listeners.add(entry);
 207  0
             Model.getPump().addModelEventListener(listener, element);
 208  
         } else {
 209  0
             LOG.warn("Attempted duplicate registration of event listener"
 210  
                     + " - Element: " + element + " Listener: " + listener);
 211  
         }
 212  0
     }
 213  
     
 214  
     /**
 215  
      * Utility function to add a listener for an array of property names 
 216  
      * and remember the registration.
 217  
      * 
 218  
      * @param element element to listen for changes on
 219  
      */
 220  
     public final void addElementListener(Object element) {
 221  0
         addElementListener(this, element);
 222  0
     }
 223  
     
 224  
     /*
 225  
      * Utility function to add a listener for a given property name 
 226  
      * and remember the registration.
 227  
      * 
 228  
      * @param element
 229  
      *            element to listen for changes on
 230  
      * @param property
 231  
      *            name of property to listen for changes of
 232  
      * @see org.argouml.model.ModelEventPump#addModelEventListener(PropertyChangeListener,
 233  
      *      Object, String)
 234  
      */
 235  
     protected final void addElementListener(PropertyChangeListener listener, 
 236  
             Object element, String property) {
 237  0
         if (Model.getUmlFactory().isRemoved(element)) {
 238  0
             LOG.warn("Encountered deleted object during delete of " + element);
 239  0
             return;
 240  
         }
 241  0
         Object[] entry = new Object[] {element, property};
 242  0
         if (!listeners.contains(entry)) {
 243  0
             listeners.add(entry);
 244  0
             Model.getPump().addModelEventListener(listener, element, property);
 245  
         } else {
 246  0
             LOG.debug("Attempted duplicate registration of event listener"
 247  
                     + " - Element: " + element + " Listener: " + listener);
 248  
         }
 249  0
     }
 250  
     
 251  
     /**
 252  
      * Utility function to add a listener for an array of property names 
 253  
      * and remember the registration.
 254  
      * 
 255  
      * @param element element to listen for changes on
 256  
      * @param property name of property to listen for changes of
 257  
      */
 258  
     public final void addElementListener(Object element, String property) {
 259  0
         addElementListener(this, element, property);
 260  0
     }
 261  
 
 262  
     /*
 263  
      * Utility function to add a listener for an array of property names 
 264  
      * and remember the registration.
 265  
      * 
 266  
      * @param element
 267  
      *            element to listen for changes on
 268  
      * @param property
 269  
      *            array of property names (Strings) to listen for changes of
 270  
      * @see org.argouml.model.ModelEventPump#addModelEventListener(PropertyChangeListener,
 271  
      *      Object, String)
 272  
      */
 273  
     protected final void addElementListener(PropertyChangeListener listener, 
 274  
             Object element, String[] property) {
 275  0
         if (Model.getUmlFactory().isRemoved(element)) {
 276  0
             LOG.warn("Encountered deleted object during delete of " + element);
 277  0
             return;
 278  
         }
 279  0
         Object[] entry = new Object[] {element, property};
 280  0
         if (!listeners.contains(entry)) {
 281  0
             listeners.add(entry);
 282  0
             Model.getPump().addModelEventListener(listener, element, property);
 283  
         } else {
 284  0
             LOG.debug("Attempted duplicate registration of event listener"
 285  
                     + " - Element: " + element + " Listener: " + listener);
 286  
         }
 287  0
     }
 288  
     
 289  
     /**
 290  
      * Utility function to add a listener for an array of property names 
 291  
      * and remember the registration.
 292  
      * 
 293  
      * @param element element to listen for changes on
 294  
      * @param property array of property names (Strings) 
 295  
      * to listen for changes of
 296  
      */
 297  
     public final void addElementListener(Object element, String[] property) {
 298  0
         addElementListener(this, element, property);
 299  0
     }
 300  
     
 301  
     /*
 302  
      * Utility function to remove an element listener 
 303  
      * and adapt the remembered list of registration.
 304  
      * 
 305  
      * @param element
 306  
      *            element to listen for changes on
 307  
      * @see org.argouml.model.ModelEventPump#addModelEventListener(PropertyChangeListener, Object, String)
 308  
      */
 309  
     protected final void removeElementListener(PropertyChangeListener listener, 
 310  
             Object element) {
 311  0
         listeners.remove(new Object[] {element, null});
 312  0
         Model.getPump().removeModelEventListener(listener, element);
 313  0
     }
 314  
     
 315  
     /**
 316  
      * Utility function to remove an element listener 
 317  
      * and adapt the remembered list of registration.
 318  
      * 
 319  
      * @param element element to listen for changes on
 320  
      */
 321  
     public final void removeElementListener(Object element) {
 322  0
         removeElementListener(this, element);
 323  0
     }
 324  
     
 325  
     /*
 326  
      * Utility function to unregister all listeners 
 327  
      * registered through addElementListener.
 328  
      * 
 329  
      * @see #addElementListener(Object, String)
 330  
      */
 331  
     protected final void removeAllElementListeners(
 332  
             PropertyChangeListener listener) {
 333  0
         for (Object[] lis : listeners) {
 334  0
             Object property = lis[1];
 335  0
             if (property == null) {
 336  0
                 Model.getPump().removeModelEventListener(listener, lis[0]);
 337  0
             } else if (property instanceof String[]) {
 338  0
                 Model.getPump().removeModelEventListener(listener, lis[0],
 339  
                         (String[]) property);
 340  0
             } else if (property instanceof String) {
 341  0
                 Model.getPump().removeModelEventListener(listener, lis[0],
 342  
                         (String) property);
 343  
             } else {
 344  0
                 throw new RuntimeException(
 345  
                         "Internal error in removeAllElementListeners");
 346  
             }
 347  0
         }
 348  0
         listeners.clear();
 349  0
     }
 350  
     
 351  
     /**
 352  
      * Utility function to unregister all listeners 
 353  
      * registered through addElementListener.
 354  
      */
 355  
     public final void removeAllElementListeners() {
 356  0
         removeAllElementListeners(this);
 357  0
     }
 358  
 
 359  
     /**
 360  
      * @param nr the NotationRenderer
 361  
      */
 362  
     void setRenderer(NotationRenderer nr) {
 363  0
         renderer = nr;
 364  0
     }
 365  
 }