Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
TabProps |
|
| 2.736842105263158;2.737 |
1 | /* $Id: TabProps.java 18360 2010-05-03 21:17:15Z 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 | * bobtarling | |
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.uml.ui; | |
40 | ||
41 | import java.awt.BorderLayout; | |
42 | import java.util.Enumeration; | |
43 | import java.util.Hashtable; | |
44 | ||
45 | import javax.swing.JPanel; | |
46 | import javax.swing.event.EventListenerList; | |
47 | ||
48 | import org.apache.log4j.Logger; | |
49 | import org.argouml.application.api.AbstractArgoJPanel; | |
50 | import org.argouml.cognitive.Critic; | |
51 | import org.argouml.model.Model; | |
52 | import org.argouml.swingext.UpArrowIcon; | |
53 | import org.argouml.ui.TabModelTarget; | |
54 | import org.argouml.ui.targetmanager.TargetEvent; | |
55 | import org.argouml.ui.targetmanager.TargetListener; | |
56 | import org.argouml.ui.targetmanager.TargetManager; | |
57 | import org.argouml.uml.diagram.ArgoDiagram; | |
58 | import org.argouml.uml.diagram.ui.PropPanelString; | |
59 | import org.tigris.gef.base.Diagram; | |
60 | import org.tigris.gef.presentation.Fig; | |
61 | import org.tigris.gef.presentation.FigText; | |
62 | import org.tigris.swidgets.Horizontal; | |
63 | import org.tigris.swidgets.Orientable; | |
64 | import org.tigris.swidgets.Orientation; | |
65 | ||
66 | /** | |
67 | * This is the tab on the details panel (DetailsPane) that holds the property | |
68 | * panel. On change of target, the property panel in TabProps is changed. | |
69 | * <p> | |
70 | * With the introduction of the TargetManager, this class holds its original | |
71 | * power of controlling its target. The property panels (subclasses of | |
72 | * PropPanel) for which this class is the container are being registered as | |
73 | * TargetListeners in the setTarget method of this class. They are not | |
74 | * registered with TargetManager but with this class to prevent race-conditions | |
75 | * while firing TargetEvents from TargetManager. | |
76 | */ | |
77 | public class TabProps | |
78 | extends AbstractArgoJPanel | |
79 | implements TabModelTarget { | |
80 | ||
81 | /** | |
82 | * Logger. | |
83 | */ | |
84 | 900 | private static final Logger LOG = Logger.getLogger(TabProps.class); |
85 | ||
86 | 900 | private JPanel blankPanel = new JPanel(); |
87 | 900 | private Hashtable<Class, JPanel> panels = |
88 | new Hashtable<Class, JPanel>(); | |
89 | private JPanel lastPanel; | |
90 | 900 | private String panelClassBaseName = ""; |
91 | ||
92 | /** | |
93 | * The panel currently displayed in center | |
94 | */ | |
95 | private JPanel currentPanel; | |
96 | ||
97 | private Object target; | |
98 | ||
99 | /** | |
100 | * The list with targetlisteners, these are the property panels | |
101 | * managed by TabProps. | |
102 | * It should only contain one listener at a time. | |
103 | */ | |
104 | 900 | private EventListenerList listenerList = new EventListenerList(); |
105 | ||
106 | /** | |
107 | * The constructor. | |
108 | * | |
109 | */ | |
110 | public TabProps() { | |
111 | 900 | this("tab.properties", "ui.PropPanel"); |
112 | 900 | } |
113 | ||
114 | /** | |
115 | * The constructor. | |
116 | * | |
117 | * @param tabName the name of the tab | |
118 | * @param panelClassBase the panel class base | |
119 | */ | |
120 | public TabProps(String tabName, String panelClassBase) { | |
121 | 900 | super(tabName); |
122 | 900 | setIcon(new UpArrowIcon()); |
123 | // TODO: This should be managed by the DetailsPane TargetListener - tfm | |
124 | // remove the following line | |
125 | 900 | TargetManager.getInstance().addTargetListener(this); |
126 | 900 | setOrientation(Horizontal.getInstance()); |
127 | 900 | panelClassBaseName = panelClassBase; |
128 | 900 | setLayout(new BorderLayout()); |
129 | 900 | } |
130 | ||
131 | /** | |
132 | * Set the orientation of the property panel. | |
133 | * | |
134 | * @param orientation the new orientation for this property panel | |
135 | * | |
136 | * @see org.tigris.swidgets.Orientable#setOrientation(org.tigris.swidgets.Orientation) | |
137 | */ | |
138 | @Override | |
139 | public void setOrientation(Orientation orientation) { | |
140 | 900 | super.setOrientation(orientation); |
141 | 900 | Enumeration pps = panels.elements(); |
142 | 900 | while (pps.hasMoreElements()) { |
143 | 0 | Object o = pps.nextElement(); |
144 | 0 | if (o instanceof Orientable) { |
145 | 0 | Orientable orientable = (Orientable) o; |
146 | 0 | orientable.setOrientation(orientation); |
147 | } | |
148 | 0 | } |
149 | 900 | } |
150 | ||
151 | /** | |
152 | * Adds a property panel to the internal list. This allows a plugin to | |
153 | * add / register a new property panel at run-time. | |
154 | * This property panel will then | |
155 | * be displayed in the detatils pane whenever an element | |
156 | * of the given metaclass is selected. | |
157 | * | |
158 | * @param clazz the metaclass whose details show be displayed | |
159 | * in the property panel p | |
160 | * @param panel an instance of the property panel for the metaclass m | |
161 | * | |
162 | */ | |
163 | public void addPanel(Class clazz, PropPanel panel) { | |
164 | 0 | panels.put(clazz, panel); |
165 | 0 | } |
166 | ||
167 | ||
168 | //////////////////////////////////////////////////////////////// | |
169 | // accessors | |
170 | /** | |
171 | * Sets the target of the property panel. The given target t | |
172 | * may either be a Diagram or a modelelement. If the target | |
173 | * given is a Fig, a check is made if the fig has an owning | |
174 | * modelelement and occurs on the current diagram. | |
175 | * If so, that modelelement is the target. | |
176 | * | |
177 | * @deprecated As of ArgoUml version 0.13.5, | |
178 | * the visibility of this method will change in the future, | |
179 | * replaced by {@link org.argouml.ui.targetmanager.TargetManager}. | |
180 | * TODO: MVW: I think this should not be deprecated. | |
181 | * | |
182 | * @param target the new target | |
183 | * @see org.argouml.ui.TabTarget#setTarget(java.lang.Object) | |
184 | */ | |
185 | @Deprecated | |
186 | public void setTarget(Object target) { | |
187 | // targets ought to be UML objects or diagrams | |
188 | 2415 | LOG.info("setTarget: there are " |
189 | + TargetManager.getInstance().getTargets().size() | |
190 | + " targets"); | |
191 | ||
192 | 2415 | target = (target instanceof Fig) ? ((Fig) target).getOwner() : target; |
193 | 2415 | if (!(target == null || Model.getFacade().isAUMLElement(target) |
194 | || target instanceof ArgoDiagram | |
195 | // TODO Improve extensibility of this! | |
196 | || target instanceof Critic)) { | |
197 | 0 | target = null; |
198 | } | |
199 | ||
200 | 2415 | if (lastPanel != null) { |
201 | 128 | remove(lastPanel); |
202 | 128 | if (lastPanel instanceof TargetListener) { |
203 | // TODO: We should assert this never happens before removing | |
204 | // panels should control their own listeners | |
205 | 0 | removeTargetListener((TargetListener) lastPanel); |
206 | } | |
207 | } | |
208 | ||
209 | // TODO: No need to do anything if we're not visible | |
210 | // if (!isVisible()) { | |
211 | // return; | |
212 | // } | |
213 | ||
214 | 2415 | this.target = target; |
215 | 2415 | if (target == null) { |
216 | 126 | add(blankPanel, BorderLayout.CENTER); |
217 | 126 | validate(); |
218 | 126 | repaint(); |
219 | 126 | lastPanel = blankPanel; |
220 | } else { | |
221 | 2289 | JPanel newPanel = findPanelFor(target); |
222 | 2289 | if (newPanel != null && newPanel instanceof TabModelTarget) { |
223 | 2289 | addTargetListener((TabModelTarget) newPanel); |
224 | } | |
225 | ||
226 | 2289 | if (currentPanel != null) { |
227 | 1389 | remove(currentPanel); |
228 | 1389 | currentPanel = null; |
229 | } | |
230 | 2289 | if (newPanel != null) { |
231 | 2289 | currentPanel = newPanel; |
232 | } else { | |
233 | 0 | currentPanel = blankPanel; |
234 | 0 | lastPanel = blankPanel; |
235 | } | |
236 | 2289 | add(currentPanel); |
237 | 2289 | validate(); |
238 | 2289 | repaint(); |
239 | } | |
240 | 2415 | } |
241 | ||
242 | /* | |
243 | * @see org.argouml.ui.TabTarget#refresh() | |
244 | */ | |
245 | public void refresh() { | |
246 | 0 | setTarget(TargetManager.getInstance().getTarget()); |
247 | 0 | } |
248 | ||
249 | /** | |
250 | * Find the correct properties panel for the target. | |
251 | * | |
252 | * @param trgt the target class | |
253 | * @return the tab panel | |
254 | */ | |
255 | private JPanel findPanelFor(Object trgt) { | |
256 | // TODO: No test coverage for this or createPropPanel? - tfm | |
257 | ||
258 | 2289 | JPanel panel = createPropPanel(trgt); |
259 | 2289 | if (panel != null) { |
260 | 2289 | LOG.debug("Factory created " + panel.getClass().getName() |
261 | + " for " + trgt.getClass().getName()); | |
262 | 2289 | panels.put(trgt.getClass(), panel); |
263 | 2289 | return panel; |
264 | } | |
265 | ||
266 | 0 | LOG.error("Failed to create a prop panel for : " + trgt); |
267 | 0 | return null; |
268 | } | |
269 | ||
270 | /** | |
271 | * A factory method to create a PropPanel for a particular target (Diagram, | |
272 | * UML Element or GEF Fig). | |
273 | * | |
274 | * @param targetObject the target object | |
275 | * @return A new prop panel to display any model element of the given type | |
276 | */ | |
277 | private JPanel createPropPanel(Object targetObject) { | |
278 | 2289 | JPanel propPanel = null; |
279 | ||
280 | for (PropPanelFactory factory | |
281 | 2289 | : PropPanelFactoryManager.getFactories()) { |
282 | 9404 | propPanel = factory.createPropPanel(targetObject); |
283 | 9404 | if (propPanel != null) return propPanel; |
284 | } | |
285 | ||
286 | /* This does not work (anymore/yet?), | |
287 | * since we never have a FigText here: */ | |
288 | 0 | if (targetObject instanceof FigText) { |
289 | 0 | propPanel = new PropPanelString(); |
290 | } | |
291 | ||
292 | 0 | if (propPanel instanceof Orientable) { |
293 | 0 | ((Orientable) propPanel).setOrientation(getOrientation()); |
294 | } | |
295 | ||
296 | // TODO: We shouldn't need this as well as the above. | |
297 | 0 | if (propPanel instanceof PropPanel) { |
298 | 0 | ((PropPanel) propPanel).setOrientation(getOrientation()); |
299 | } | |
300 | ||
301 | 0 | return propPanel; |
302 | } | |
303 | ||
304 | /** | |
305 | * @return the name | |
306 | */ | |
307 | protected String getClassBaseName() { | |
308 | 0 | return panelClassBaseName; |
309 | } | |
310 | ||
311 | /** | |
312 | * Returns the current target. | |
313 | * @deprecated As of ArgoUml version 0.13.5, | |
314 | * the visibility of this method will change in the future, replaced by | |
315 | * {@link org.argouml.ui.targetmanager.TargetManager#getTarget() | |
316 | * TargetManager.getInstance().getTarget()}. | |
317 | * TODO: MVW: I think this should not be deprecated. | |
318 | * | |
319 | * @return the target | |
320 | * @see org.argouml.ui.TabTarget#getTarget() | |
321 | */ | |
322 | @Deprecated | |
323 | public Object getTarget() { | |
324 | 0 | return target; |
325 | } | |
326 | ||
327 | /** | |
328 | * Determines if the property panel should be enabled. | |
329 | * The property panel should always be enabled if the | |
330 | * target is an instance of a modelelement or an argodiagram. | |
331 | * If the target given is a Fig, a check is made if the fig | |
332 | * has an owning modelelement and occurs on | |
333 | * the current diagram. If so, that modelelement is the target. | |
334 | * @param target the target | |
335 | * @return true if property panel should be enabled | |
336 | * @see org.argouml.ui.TabTarget#shouldBeEnabled(Object) | |
337 | */ | |
338 | public boolean shouldBeEnabled(Object target) { | |
339 | 2528 | if (target instanceof Fig) { |
340 | 0 | target = ((Fig) target).getOwner(); |
341 | } | |
342 | ||
343 | // TODO: this should be more extensible... may be only | |
344 | // "findPanelFor(target)" if there is a panel why not show it? | |
345 | 2528 | return ((target instanceof Diagram || Model.getFacade().isAUMLElement( |
346 | target)) || target instanceof Critic | |
347 | && findPanelFor(target) != null); | |
348 | } | |
349 | ||
350 | /* | |
351 | * @see org.argouml.ui.targetmanager.TargetListener#targetAdded(org.argouml.ui.targetmanager.TargetEvent) | |
352 | */ | |
353 | public void targetAdded(TargetEvent targetEvent) { | |
354 | 0 | setTarget(TargetManager.getInstance().getSingleTarget()); |
355 | 0 | fireTargetAdded(targetEvent); |
356 | 0 | if (listenerList.getListenerCount() > 0) { |
357 | 0 | validate(); |
358 | 0 | repaint(); |
359 | } | |
360 | ||
361 | 0 | } |
362 | ||
363 | /* | |
364 | * @see org.argouml.ui.targetmanager.TargetListener#targetRemoved(org.argouml.ui.targetmanager.TargetEvent) | |
365 | */ | |
366 | public void targetRemoved(TargetEvent targetEvent) { | |
367 | 88 | setTarget(TargetManager.getInstance().getSingleTarget()); |
368 | 88 | fireTargetRemoved(targetEvent); |
369 | 88 | validate(); |
370 | 88 | repaint(); |
371 | 88 | } |
372 | ||
373 | /* | |
374 | * @see org.argouml.ui.targetmanager.TargetListener#targetSet(org.argouml.ui.targetmanager.TargetEvent) | |
375 | */ | |
376 | public void targetSet(TargetEvent targetEvent) { | |
377 | 2327 | setTarget(TargetManager.getInstance().getSingleTarget()); |
378 | 2327 | fireTargetSet(targetEvent); |
379 | 2327 | validate(); |
380 | 2327 | repaint(); |
381 | 2327 | } |
382 | ||
383 | /** | |
384 | * Adds a listener. | |
385 | * @param listener the listener to add | |
386 | */ | |
387 | private void addTargetListener(TargetListener listener) { | |
388 | 2289 | listenerList.add(TargetListener.class, listener); |
389 | 2289 | } |
390 | ||
391 | /** | |
392 | * Removes a target listener. | |
393 | * @param listener the listener to remove | |
394 | */ | |
395 | private void removeTargetListener(TargetListener listener) { | |
396 | 0 | listenerList.remove(TargetListener.class, listener); |
397 | 0 | } |
398 | ||
399 | private void fireTargetSet(TargetEvent targetEvent) { | |
400 | // Guaranteed to return a non-null array | |
401 | 2327 | Object[] listeners = listenerList.getListenerList(); |
402 | 6874 | for (int i = listeners.length - 2; i >= 0; i -= 2) { |
403 | 4547 | if (listeners[i] == TargetListener.class) { |
404 | // Lazily create the event: | |
405 | 4547 | ((TargetListener) listeners[i + 1]).targetSet(targetEvent); |
406 | } | |
407 | } | |
408 | 2327 | } |
409 | ||
410 | private void fireTargetAdded(TargetEvent targetEvent) { | |
411 | // Guaranteed to return a non-null array | |
412 | 0 | Object[] listeners = listenerList.getListenerList(); |
413 | ||
414 | 0 | for (int i = listeners.length - 2; i >= 0; i -= 2) { |
415 | 0 | if (listeners[i] == TargetListener.class) { |
416 | // Lazily create the event: | |
417 | 0 | ((TargetListener) listeners[i + 1]).targetAdded(targetEvent); |
418 | } | |
419 | } | |
420 | 0 | } |
421 | ||
422 | private void fireTargetRemoved(TargetEvent targetEvent) { | |
423 | // Guaranteed to return a non-null array | |
424 | 88 | Object[] listeners = listenerList.getListenerList(); |
425 | 264 | for (int i = listeners.length - 2; i >= 0; i -= 2) { |
426 | 176 | if (listeners[i] == TargetListener.class) { |
427 | // Lazily create the event: | |
428 | 176 | ((TargetListener) listeners[i + 1]).targetRemoved(targetEvent); |
429 | } | |
430 | } | |
431 | 88 | } |
432 | } /* end class TabProps */ |