Ptidej-v5.2-master/POM Tests/data/ArgoUML_0.28/src/org/argouml/ui/explorer/ExplorerEventAdaptor.java
// $Id: ExplorerEventAdaptor.java 16651 2009-01-18 19:54:02Z tfmorris $
// Copyright (c) 1996-2008 The Regents of the University of California. All
// Rights Reserved. Permission to use, copy, modify, and distribute this
// software and its documentation without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph appear in all copies.  This software program and
// documentation are copyrighted by The Regents of the University of
// California. The software program and documentation are supplied "AS
// IS", without any accompanying services from The Regents. The Regents
// does not warrant that the operation of the program will be
// uninterrupted or error-free. The end-user understands that the program
// was developed for research purposes and is advised not to rely
// exclusively on the program for any reason.  IN NO EVENT SHALL THE
// UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
// UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

package org.argouml.ui.explorer;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.SwingUtilities;

import org.apache.log4j.Logger;
import org.argouml.application.events.ArgoEventPump;
import org.argouml.application.events.ArgoEventTypes;
import org.argouml.application.events.ArgoProfileEvent;
import org.argouml.application.events.ArgoProfileEventListener;
import org.argouml.configuration.Configuration;
import org.argouml.kernel.ProjectManager;
import org.argouml.model.AddAssociationEvent;
import org.argouml.model.AttributeChangeEvent;
import org.argouml.model.DeleteInstanceEvent;
import org.argouml.model.InvalidElementException;
import org.argouml.model.Model;
import org.argouml.model.RemoveAssociationEvent;
import org.argouml.model.UmlChangeEvent;
import org.argouml.notation.Notation;

/**
 * All events going to the Explorer must pass through here first!<p>
 *
 * Most will come from the uml model via the EventAdapter interface.<p>
 *
 * TODO: In some cases (test cases) this object is created without setting
 * the treeModel. I (Linus) will add tests for this now. It would be better
 * if this is created only when the Explorer is created. <p>
 * 
 * TODO: The ExplorerTreeNode also listens to some events
 * (from Diagrams), so it does not follow the rule above.
 *
 * @since 0.15.2, Created on 16 September 2003, 23:13
 * @author  alexb
 */
public final class ExplorerEventAdaptor
    implements PropertyChangeListener {
    
    private static final Logger LOG =
        Logger.getLogger(ExplorerEventAdaptor.class);

    /**
     * The singleton instance.
     *
     * TODO: Why is this a singleton? Wouldn't it be better to have exactly
     * one for every Explorer?
     */
    private static ExplorerEventAdaptor instance;

    /**
     * The tree model to update.
     */
    private TreeModelUMLEventListener treeModel;

    /**
     * @return the instance (singleton)
     */
    public static ExplorerEventAdaptor getInstance() {
        if (instance == null) {
            instance = new ExplorerEventAdaptor();
	}
	return instance;
    }

    /**
     * Creates a new instance of ExplorerUMLEventAdaptor.
     */
    private ExplorerEventAdaptor() {

        Configuration.addListener(Notation.KEY_USE_GUILLEMOTS, this);
        Configuration.addListener(Notation.KEY_SHOW_STEREOTYPES, this);
        ProjectManager.getManager().addPropertyChangeListener(this);
        // TODO: We really only care about events which affect things that
        // are visible in the current perspective (view).  This could be
        // tailored to cut down on event traffic. - tfm 20060410
        Model.getPump().addClassModelEventListener(this,
                Model.getMetaTypes().getModelElement(), (String[]) null);
        ArgoEventPump.addListener(
                ArgoEventTypes.ANY_PROFILE_EVENT, new ProfileChangeListener());
    }

    /**
     * The tree structure has changed significantly.  
     * Inform the associated tree model.
     * 
     * TODO:  This shouldn't be public.  Components desiring to
     * inform the Explorer of changes should send events.
     * @deprecated by mvw in V0.25.4. Use events instead.
     */
    @Deprecated
    public void structureChanged() {
        if (treeModel == null) {
            return;
        }
        treeModel.structureChanged();
    }

    
    /**
     * forwards this event to the tree model.
     *
     * @param element the modelelement to be added
     * 
     * TODO:  This shouldn't be public.  Components desiring to
     * inform the Explorer of changes should send events.
     */
    public void modelElementAdded(Object element) {
        if (treeModel == null) {
            return;
        }
        treeModel.modelElementAdded(element);
    }

    /**
     * forwards this event to the tree model.
     *
     * @param element the modelelement to be changed
     * 
     * TODO:  This shouldn't be public.  Components desiring to
     * inform the Explorer of changes should send events.
     */
    public void modelElementChanged(Object element) {
        if (treeModel == null) {
            return;
        }
        treeModel.modelElementChanged(element);
    }

    /**
     * sets the tree model that will receive events.
     *
     * @param newTreeModel the tree model to be used
     */
    public void setTreeModelUMLEventListener(
	    TreeModelUMLEventListener newTreeModel) {
        treeModel = newTreeModel;
    }

    /**
     * Listens to events coming from the project manager, config manager, and
     * uml model, passes those events on to the explorer model.
     *
     * @since ARGO0.11.2
     *
     * @see PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
     */
    public void propertyChange(final PropertyChangeEvent pce) {
        if (treeModel == null) {
            return;
        }

        // uml model events
        if (pce instanceof UmlChangeEvent) {
            Runnable doWorkRunnable = new Runnable() {
                public void run() {
                    try {
                        modelChanged((UmlChangeEvent) pce);
                    } catch (InvalidElementException e) {
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("updateLayout method accessed "
                                    + "deleted element", e);
                        }
                    }
                }  
            };
            SwingUtilities.invokeLater(doWorkRunnable);
            
        } else if (pce.getPropertyName().equals(
                // TODO: No one should be sending the deprecated event
                // from outside ArgoUML, but keep responding to it for now
                // just in case
                ProjectManager.CURRENT_PROJECT_PROPERTY_NAME)
                || pce.getPropertyName().equals(
                        ProjectManager.OPEN_PROJECTS_PROPERTY)) {
            // project events
            if (pce.getNewValue() != null) {
                treeModel.structureChanged();
            }
            return;
        } else if (Notation.KEY_USE_GUILLEMOTS.isChangedProperty(pce)
            || Notation.KEY_SHOW_STEREOTYPES.isChangedProperty(pce)) {
            // notation events
            treeModel.structureChanged();
        } else if (pce.getSource() instanceof ProjectManager) {
            // Handle remove for non-UML elements (e.g. diagrams)
            if ("remove".equals(pce.getPropertyName())) {
                treeModel.modelElementRemoved(pce.getOldValue());
            }
        }
    }
    
    private void modelChanged(UmlChangeEvent event) {
        if (event instanceof AttributeChangeEvent) {
            // TODO: Can this be made more restrictive?
            // Do we care about any attributes other than name? - tfm
            treeModel.modelElementChanged(event.getSource());
        } else if (event instanceof RemoveAssociationEvent) {
            // TODO: This should really be coded the other way round,
            // to only act on associations which are important for
            // representing the current perspective (and to only act
            // on a single end of the association) - tfm
            if (!("namespace".equals(event.getPropertyName()))) {
                treeModel.modelElementChanged(((RemoveAssociationEvent) event)
                        .getChangedValue());
            }
        } else if (event instanceof AddAssociationEvent) {
            if (!("namespace".equals(event.getPropertyName()))) {
                treeModel.modelElementAdded(
                        ((AddAssociationEvent) event).getSource());
            }
        } else if (event instanceof DeleteInstanceEvent) {
            treeModel.modelElementRemoved(((DeleteInstanceEvent) event)
                    .getSource());
        }
    }
    
    
    /**
     * Listener for additions and removals of profiles.
     * Since they generally have a major impact on the explorer tree, 
     * we simply update them completely.
     *
     * @author Michiel
     */
    class ProfileChangeListener implements ArgoProfileEventListener {

        public void profileAdded(ArgoProfileEvent e) {
            structureChanged();
        }

        public void profileRemoved(ArgoProfileEvent e) {
            structureChanged();
        }
        
    }
}
