Coverage Report - org.argouml.uml.ui.UMLModelElementListModel2
 
Classes in this File Line Coverage Branch Coverage Complexity
UMLModelElementListModel2
0%
0/163
0%
0/92
2.719
 
 1  
 /* $Id: UMLModelElementListModel2.java 18588 2010-07-28 21:30:25Z 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  
  *    mvw
 11  
  *****************************************************************************
 12  
  *
 13  
  * Some portions of this file was previously release using the BSD License:
 14  
  */
 15  
 
 16  
 // Copyright (c) 2002-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.beans.PropertyChangeEvent;
 42  
 import java.beans.PropertyChangeListener;
 43  
 import java.util.ArrayList;
 44  
 import java.util.Collection;
 45  
 import java.util.Iterator;
 46  
 
 47  
 import javax.swing.DefaultListModel;
 48  
 import javax.swing.JPopupMenu;
 49  
 
 50  
 import org.apache.log4j.Logger;
 51  
 import org.argouml.model.AddAssociationEvent;
 52  
 import org.argouml.model.AssociationChangeEvent;
 53  
 import org.argouml.model.AttributeChangeEvent;
 54  
 import org.argouml.model.InvalidElementException;
 55  
 import org.argouml.model.Model;
 56  
 import org.argouml.model.RemoveAssociationEvent;
 57  
 import org.argouml.ui.targetmanager.TargetEvent;
 58  
 import org.argouml.ui.targetmanager.TargetListener;
 59  
 import org.tigris.gef.base.Diagram;
 60  
 import org.tigris.gef.presentation.Fig;
 61  
 
 62  
 /**
 63  
  * The model for a list that contains ModelElements. The state of the Element is
 64  
  * still kept in the model subsystem itself. This list is only to be used as the
 65  
  * model for some GUI element like UMLLinkedList.
 66  
  *
 67  
  * @since Oct 2, 2002
 68  
  * @author jaap.branderhorst@xs4all.nl
 69  
  * @deprecated in 0.31.2 by Bob Tarling  This is replaced by the XML property
 70  
  * panels module
 71  
  */
 72  
 @Deprecated
 73  
 public abstract class UMLModelElementListModel2 extends DefaultListModel
 74  
         implements TargetListener, PropertyChangeListener {
 75  
 
 76  0
     private static final Logger LOG = 
 77  
         Logger.getLogger(UMLModelElementListModel2.class);
 78  
     
 79  0
     private String eventName = null;
 80  0
     private Object listTarget = null;
 81  
 
 82  
     /**
 83  
      * Flag to indicate wether list events should be fired
 84  
      */
 85  0
     private boolean fireListEvents = true;
 86  
 
 87  
     /**
 88  
      * Flag to indicate wether the model is being build
 89  
      */
 90  0
     private boolean buildingModel = false;
 91  
 
 92  
     /**
 93  
      * The type of model elements this list model is designed to hold.
 94  
      */
 95  
     private Object metaType;
 96  
     
 97  
     /**
 98  
      * Indicates that drops onto this list should connect in the opposite
 99  
      * way to standard.
 100  
      */
 101  
     private boolean reverseDropConnection;
 102  
 
 103  
     /**
 104  
      * Constructor to be used if the subclass does not depend on the
 105  
      * MELementListener methods and setTarget method implemented in this
 106  
      * class.
 107  
      */
 108  
     public UMLModelElementListModel2() {
 109  0
         super();
 110  0
     }
 111  
 
 112  
     /**
 113  
      * Constructor for UMLModelElementListModel2.
 114  
      *
 115  
      * @param name the name of the event to listen to, which triggers us
 116  
      *             to update the list model from the UML data
 117  
      */
 118  
     public UMLModelElementListModel2(String name) {
 119  0
         super();
 120  0
         eventName = name;
 121  0
     }
 122  
     
 123  
     /**
 124  
      * Constructor for UMLModelElementListModel2.
 125  
      *
 126  
      * @param name the name of the event to listen to, which triggers us
 127  
      *             to update the list model from the UML data
 128  
      * @param theMetaType the type of model element that the list model
 129  
      *                 is designed to contain.
 130  
      */
 131  
     public UMLModelElementListModel2(String name, Object theMetaType) {
 132  0
         super();
 133  0
         this.metaType = theMetaType;
 134  0
         eventName = name;
 135  0
     }
 136  
     
 137  
     /**
 138  
      * Constructor for UMLModelElementListModel2.
 139  
      *
 140  
      * @param name the name of the event to listen to, which triggers us
 141  
      *             to update the list model from the UML data
 142  
      * @param theMetaType the type of model element that the list model
 143  
      *                 is designed to contain.
 144  
      * @param reverseTheDropConnection tells the JList to reverse the
 145  
      *              connection made and drop during dnd.
 146  
      */
 147  
     public UMLModelElementListModel2(
 148  
             String name, 
 149  
             Object theMetaType, 
 150  
             boolean reverseTheDropConnection) {
 151  0
         super();
 152  0
         this.metaType = theMetaType;
 153  0
         eventName = name;
 154  0
         this.reverseDropConnection = reverseTheDropConnection;
 155  0
     }
 156  
     
 157  
     /**
 158  
      * Get the type of objects that this list model is designed to contain.
 159  
      * @return metaType the meta type.
 160  
      */
 161  
     public Object getMetaType() {
 162  0
         return metaType;
 163  
     }
 164  
     
 165  
     public boolean isReverseDropConnection() {
 166  0
         return reverseDropConnection;
 167  
     }
 168  
 
 169  
     /**
 170  
      * @param building The buildingModel to set.
 171  
      */
 172  
     protected void setBuildingModel(boolean building) {
 173  0
         this.buildingModel = building;
 174  0
     }
 175  
 
 176  
     /**
 177  
      * @param t the list target to set
 178  
      */
 179  
     protected void setListTarget(Object t) {
 180  0
         this.listTarget = t;
 181  0
     }
 182  
 
 183  
     /*
 184  
      * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
 185  
      * 
 186  
      * TODO: This should be reviewed to see if it can be improved with a view
 187  
      * towards removing some of the overrriding methods used as workarounds for 
 188  
      * differences between NSUML and MDR - tfm - 20060302
 189  
      */
 190  
     public void propertyChange(PropertyChangeEvent e) {
 191  0
         if (e instanceof AttributeChangeEvent) {
 192  
             try {
 193  0
                 if (isValidEvent(e)) {
 194  0
                     rebuildModelList();
 195  
                 }
 196  0
             } catch (InvalidElementException iee) {
 197  0
                 return;
 198  0
             }
 199  0
         } else if (e instanceof AddAssociationEvent) {
 200  0
             if (isValidEvent(e)) {
 201  0
                 Object o = getChangedElement(e);
 202  0
                 if (o instanceof Collection) {
 203  0
                     ArrayList tempList = new ArrayList((Collection) o);
 204  0
                     Iterator it = tempList.iterator();
 205  0
                     while (it.hasNext()) {
 206  0
                         Object o2 = it.next();
 207  0
                         addElement(o2);
 208  0
                     }
 209  0
                 } else {
 210  
                     /* TODO: If this is an ordered list, then you have to 
 211  
                         add in the right location! */
 212  0
                     addElement(o); 
 213  
                 }
 214  0
             }
 215  0
         } else if (e instanceof RemoveAssociationEvent) {
 216  0
             boolean valid = false;
 217  0
             if (!(getChangedElement(e) instanceof Collection)) {
 218  0
                 valid = contains(getChangedElement(e));
 219  
             } else {
 220  0
                 Collection col = (Collection) getChangedElement(e);
 221  0
                 Iterator it = col.iterator();
 222  0
                 valid = true;
 223  0
                 while (it.hasNext()) {
 224  0
                     Object o = it.next();
 225  0
                     if (!contains(o)) {
 226  0
                         valid = false;
 227  0
                         break;
 228  
                     }
 229  0
                 }
 230  
             }
 231  0
             if (valid) {
 232  0
                 Object o = getChangedElement(e);
 233  0
                 if (o instanceof Collection) {
 234  0
                     Iterator it = ((Collection) o).iterator();
 235  0
                     while (it.hasNext()) {
 236  0
                         Object o3 = it.next();
 237  0
                         removeElement(o3);
 238  0
                     }
 239  0
                 } else {
 240  0
                     removeElement(o);
 241  
                 }
 242  
             }
 243  
         }
 244  0
     }
 245  
 
 246  
     /**
 247  
      * Delete and rebuild the model list from scratch.
 248  
      */
 249  
     private void rebuildModelList() {
 250  0
         removeAllElements();
 251  0
         buildingModel = true;
 252  
         try {
 253  0
             buildModelList();
 254  0
         } catch (InvalidElementException exception) {
 255  
             /*
 256  
              * This can throw an exception if the target has been
 257  
              * deleted. We don't want to try locking the repository
 258  
              * because this is called from the event delivery thread and
 259  
              * could cause a deadlock. Instead catch the exception and
 260  
              * leave the model empty.
 261  
              */
 262  0
             LOG.debug("buildModelList threw exception for target " 
 263  
                     + getTarget() + ": "
 264  
                     + exception);
 265  
         } finally {
 266  0
             buildingModel = false;
 267  0
         }
 268  0
         if (getSize() > 0) {
 269  0
             fireIntervalAdded(this, 0, getSize() - 1);
 270  
         }
 271  0
     }
 272  
 
 273  
     /**
 274  
      * Builds the list of elements. Called from targetChanged every time the
 275  
      * target of the proppanel is changed. Usually the method setAllElements is
 276  
      * called with the result.
 277  
      */
 278  
     protected abstract void buildModelList();
 279  
 
 280  
     /**
 281  
      * Utility method to set the elements of this list to the contents of the
 282  
      * given collection.
 283  
      * @param col the given collection
 284  
      */
 285  
     protected void setAllElements(Collection col) {
 286  0
         if (!isEmpty())
 287  0
             removeAllElements();
 288  0
         addAll(col);
 289  0
     }
 290  
 
 291  
     /**
 292  
      * Utility method to add a collection of elements to the model
 293  
      * @param col the given collection
 294  
      */
 295  
     protected void addAll(Collection col) {
 296  0
         if (col.size() == 0) return;
 297  0
         Iterator it = col.iterator();
 298  0
         fireListEvents = false;
 299  0
         int intervalStart = getSize() == 0 ? 0 : getSize() - 1;
 300  0
         while (it.hasNext()) {
 301  0
             Object o = it.next();
 302  0
             addElement(o);
 303  0
         }
 304  0
         fireListEvents = true;
 305  0
         fireIntervalAdded(this, intervalStart, getSize() - 1);
 306  0
     }
 307  
 
 308  
     /**
 309  
      * Utility method to get the target. Sets the target if the target is null
 310  
      * via the method setTarget().
 311  
      * @return MModelElement
 312  
      */
 313  
     public Object getTarget() {
 314  0
         return listTarget;
 315  
     }
 316  
 
 317  
     /**
 318  
      * Utility method to get the changed element from some event e
 319  
      * @param e the event
 320  
      * @return Object the changed element
 321  
      */
 322  
     protected Object getChangedElement(PropertyChangeEvent e) {
 323  0
         if (e instanceof AssociationChangeEvent) {
 324  0
             return ((AssociationChangeEvent) e).getChangedValue();
 325  
         }
 326  0
         if (e instanceof AttributeChangeEvent) {
 327  0
             return ((AttributeChangeEvent) e).getSource();
 328  
         }
 329  0
         return e.getNewValue();
 330  
     }
 331  
 
 332  
     /*
 333  
      * @see javax.swing.DefaultListModel#contains(java.lang.Object)
 334  
      */
 335  
     public boolean contains(Object elem) {
 336  0
         if (super.contains(elem)) {
 337  0
             return true;
 338  
         }
 339  0
         if (elem instanceof Collection) {
 340  0
             Iterator it = ((Collection) elem).iterator();
 341  0
             while (it.hasNext()) {
 342  0
                 if (!super.contains(it.next())) {
 343  0
                     return false;
 344  
                 }
 345  
             }
 346  0
             return true;
 347  
         }
 348  0
         return false;
 349  
     }
 350  
 
 351  
     /**
 352  
      * Sets the target. If the old target is a ModelElement, it also removes
 353  
      * the model from the element listener list of the target. If the new target
 354  
      * is instanceof ModelElement, the model is added as element listener to the
 355  
      * new target. <p>
 356  
      *      
 357  
      * This function is called when the user changes the target. 
 358  
      * Hence, this shall not result in any UML model changes.
 359  
      * Hence, we block firing list events completely by setting 
 360  
      * buildingModel to true for the duration of this function. <p>
 361  
      * 
 362  
      * This function looks a lot like the one in UMLComboBoxModel2.
 363  
      * 
 364  
      * @param theNewTarget the new target
 365  
      */
 366  
     public void setTarget(Object theNewTarget) {
 367  0
         theNewTarget = theNewTarget instanceof Fig
 368  
             ? ((Fig) theNewTarget).getOwner() : theNewTarget;
 369  0
         if (Model.getFacade().isAUMLElement(theNewTarget)
 370  
                 || theNewTarget instanceof Diagram) {
 371  0
             if (Model.getFacade().isAUMLElement(listTarget)) {
 372  0
                 Model.getPump().removeModelEventListener(this, listTarget,
 373  
                         eventName);
 374  
                 // Allow listening to other elements:
 375  0
                 removeOtherModelEventListeners(listTarget);
 376  
             }
 377  
 
 378  0
             if (Model.getFacade().isAUMLElement(theNewTarget)) {
 379  0
                 listTarget = theNewTarget;
 380  0
                 Model.getPump().addModelEventListener(this, listTarget,
 381  
                         eventName);
 382  
                 // Allow listening to other elements:
 383  0
                 addOtherModelEventListeners(listTarget);
 384  
 
 385  0
                 rebuildModelList();
 386  
 
 387  
             } else {
 388  0
                 listTarget = null;
 389  0
                 removeAllElements();
 390  
             }
 391  
         }
 392  0
     }
 393  
 
 394  
     /**
 395  
      * This function allows subclasses to listen to more modelelements.
 396  
      * The given target is guaranteed to be a UML modelelement.
 397  
      * 
 398  
      * @param oldTarget the UML modelelement
 399  
      */
 400  
     protected void removeOtherModelEventListeners(Object oldTarget) {
 401  
         /* Do nothing by default. */
 402  0
     }
 403  
 
 404  
     /**
 405  
      * This function allows subclasses to listen to more modelelements.
 406  
      * The given target is guaranteed to be a UML modelelement.
 407  
      * 
 408  
      * @param newTarget the UML modelelement
 409  
      */
 410  
     protected void addOtherModelEventListeners(Object newTarget) {
 411  
         /* Do nothing by default. */
 412  0
     }
 413  
 
 414  
     /**
 415  
      * Returns true if the given element is valid, i.e. it may be added to the
 416  
      * list of elements.
 417  
      *
 418  
      * @param element the element to be tested
 419  
      * @return true if valid
 420  
      */
 421  
     protected abstract boolean isValidElement(Object element);
 422  
 
 423  
     /**
 424  
      * Returns true if some event is valid. An event is valid if the
 425  
      * element changed in the event is valid. This is determined via a
 426  
      * call to isValidElement.  This method can be overriden by
 427  
      * subclasses if they cannot determine if it is a valid event just
 428  
      * by checking the changed element.
 429  
      *
 430  
      * @param e the event
 431  
      * @return boolean true if valid
 432  
      */
 433  
     protected boolean isValidEvent(PropertyChangeEvent e) {
 434  0
         boolean valid = false;
 435  0
         if (!(getChangedElement(e) instanceof Collection)) {
 436  
             // TODO: Considering all delete events to be valid like below
 437  
             // is going to cause lots of unecessary work and some problems
 438  0
             if ((e.getNewValue() == null && e.getOldValue() != null)
 439  
                     // Don't test changed element if it was deleted
 440  
                     || isValidElement(getChangedElement(e))) {
 441  0
                 valid = true; // we tried to remove a value
 442  
             }
 443  
         } else {
 444  0
             Collection col = (Collection) getChangedElement(e);
 445  0
             Iterator it = col.iterator();
 446  0
             if (!col.isEmpty()) {
 447  0
                 valid = true;
 448  0
                 while (it.hasNext()) {
 449  0
                     Object o = it.next();
 450  0
                     if (!isValidElement(o)) {
 451  0
                         valid = false;
 452  0
                         break;
 453  
                     }
 454  0
                 }
 455  
             } else {
 456  0
                 if (e.getOldValue() instanceof Collection
 457  
                     && !((Collection) e.getOldValue()).isEmpty()) {
 458  0
                     valid = true;
 459  
                 }
 460  
             }
 461  
         }
 462  0
         return valid;
 463  
     }
 464  
 
 465  
     /*
 466  
      * @see javax.swing.DefaultListModel#addElement(java.lang.Object)
 467  
      */
 468  
     public void addElement(Object obj) {
 469  0
         if (obj != null && !contains(obj)) {
 470  0
             super.addElement(obj);
 471  
         }
 472  0
     }
 473  
 
 474  
     /**
 475  
      * Returns the eventName. This method is only here for testing goals.
 476  
      * @return String
 477  
      */
 478  
     String getEventName() {
 479  0
         return eventName;
 480  
     }
 481  
 
 482  
     /**
 483  
      * Sets the eventName. The eventName is the name of the
 484  
      * MElementEvent to which the list should listen. The list is
 485  
      * registred with UMLModelEventPump and only gets events that have
 486  
      * a name like eventName.  This method should be called in the
 487  
      * constructor of every subclass.
 488  
      *
 489  
      * @param theEventName The eventName to set
 490  
      */
 491  
     protected void setEventName(String theEventName) {
 492  0
         eventName = theEventName;
 493  0
     }
 494  
 
 495  
     /*
 496  
      * @see TargetListener#targetAdded(TargetEvent)
 497  
      */
 498  
     public void targetAdded(TargetEvent e) {
 499  0
         setTarget(e.getNewTarget());
 500  0
     }
 501  
 
 502  
     /*
 503  
      * @see TargetListener#targetRemoved(TargetEvent)
 504  
      */
 505  
     public void targetRemoved(TargetEvent e) {
 506  0
         setTarget(e.getNewTarget());
 507  0
     }
 508  
 
 509  
     /*
 510  
      * @see TargetListener#targetSet(TargetEvent)
 511  
      */
 512  
     public void targetSet(TargetEvent e) {
 513  0
         setTarget(e.getNewTarget());
 514  0
     }
 515  
 
 516  
     /*
 517  
      * @see javax.swing.AbstractListModel#fireContentsChanged(
 518  
      *          Object, int, int)
 519  
      */
 520  
     protected void fireContentsChanged(Object source, int index0, int index1) {
 521  0
         if (fireListEvents && !buildingModel)
 522  0
             super.fireContentsChanged(source, index0, index1);
 523  0
     }
 524  
 
 525  
     /*
 526  
      * @see javax.swing.AbstractListModel#fireIntervalAdded(
 527  
      *          Object, int, int)
 528  
      */
 529  
     protected void fireIntervalAdded(Object source, int index0, int index1) {
 530  0
         if (fireListEvents && !buildingModel)
 531  0
             super.fireIntervalAdded(source, index0, index1);
 532  0
     }
 533  
 
 534  
     /*
 535  
      * @see javax.swing.AbstractListModel#fireIntervalRemoved(
 536  
      *          Object, int, int)
 537  
      */
 538  
     protected void fireIntervalRemoved(Object source, int index0, int index1) {
 539  0
         if (fireListEvents && !buildingModel)
 540  0
             super.fireIntervalRemoved(source, index0, index1);
 541  0
     }
 542  
 
 543  
     /**
 544  
      * Override this if you want a popup menu.
 545  
      * See for an example UMLModelElementOrderedListModel2.
 546  
      *
 547  
      * @param popup the popup menu
 548  
      * @param index the selected item in the list at the moment
 549  
      *              the mouse was clicked
 550  
      * @return true if a popup menu is created, and needs to be shown
 551  
      */
 552  
     public boolean buildPopup(JPopupMenu popup, int index) {
 553  0
         return false;
 554  
     }
 555  
     
 556  
     protected boolean hasPopup() {
 557  0
         return false;
 558  
     }
 559  
 
 560  
 }