/* $Id: ExplorerEventAdaptor.java 17843 2010-01-12 19:23:29Z linus $
*****************************************************************************
* Copyright (c) 2009 Contributors - see below
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* tfmorris
*****************************************************************************
*
* Some portions of this file was previously release using the BSD License:
*/
// 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();
}
}
}