Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ExplorerEventAdaptor |
|
| 3.3636363636363638;3.364 | ||||
ExplorerEventAdaptor$1 |
|
| 3.3636363636363638;3.364 | ||||
ExplorerEventAdaptor$ProfileChangeListener |
|
| 3.3636363636363638;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 | } |