Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
DiagramInterface |
|
| 2.176470588235294;2.176 |
1 | /* $Id: DiagramInterface.java 17870 2010-01-12 20:49:32Z 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 | * mvw | |
11 | ***************************************************************************** | |
12 | * | |
13 | * Some portions of this file was previously release using the BSD License: | |
14 | */ | |
15 | ||
16 | // Copyright (c) 1996-2009 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.reveng; | |
40 | ||
41 | import java.awt.Rectangle; | |
42 | import java.beans.PropertyVetoException; | |
43 | import java.util.ArrayList; | |
44 | import java.util.List; | |
45 | ||
46 | import org.apache.log4j.Logger; | |
47 | import org.argouml.kernel.Project; | |
48 | import org.argouml.model.Model; | |
49 | import org.argouml.uml.diagram.ArgoDiagram; | |
50 | import org.argouml.uml.diagram.DiagramElement; | |
51 | import org.argouml.uml.diagram.DiagramFactory; | |
52 | import org.argouml.uml.diagram.static_structure.ClassDiagramGraphModel; | |
53 | import org.argouml.uml.diagram.static_structure.ui.FigClassifierBox; | |
54 | import org.argouml.uml.diagram.ui.FigNodeModelElement; | |
55 | import org.tigris.gef.base.Editor; | |
56 | import org.tigris.gef.base.LayerPerspective; | |
57 | import org.tigris.gef.presentation.Fig; | |
58 | ||
59 | /** | |
60 | * Instances of this class interface the current Class diagram.<p> | |
61 | * | |
62 | * This class is used by the import mechanism to create packages, | |
63 | * interfaces and classes within the diagrams. | |
64 | * It is also used to find the correct diagram to work in. | |
65 | * | |
66 | * @author Andreas Rueckert | |
67 | * @since 0.9 | |
68 | */ | |
69 | public class DiagramInterface { | |
70 | ||
71 | private static final char DIAGRAM_NAME_SEPARATOR = '_'; | |
72 | private static final String DIAGRAM_NAME_SUFFIX = "classes"; | |
73 | ||
74 | 0 | private static final Logger LOG = |
75 | Logger.getLogger(DiagramInterface.class); | |
76 | ||
77 | private Editor currentEditor; | |
78 | ||
79 | /** | |
80 | * To know what diagrams we have to layout after the import, | |
81 | * we store them in this list. | |
82 | */ | |
83 | 0 | private List<ArgoDiagram> modifiedDiagrams = |
84 | new ArrayList<ArgoDiagram>(); | |
85 | ||
86 | /** | |
87 | * The current GraphModel of the current classdiagram. | |
88 | */ | |
89 | private ClassDiagramGraphModel currentGM; | |
90 | ||
91 | /** | |
92 | * The current Layer of the current classdiagram. | |
93 | */ | |
94 | private LayerPerspective currentLayer; | |
95 | ||
96 | /** | |
97 | * The current diagram for the isInDiagram method. | |
98 | */ | |
99 | private ArgoDiagram currentDiagram; | |
100 | ||
101 | private Project currentProject; | |
102 | ||
103 | /** | |
104 | * Creates a new DiagramInterface. | |
105 | * | |
106 | * @param editor The editor to operate on. | |
107 | */ | |
108 | 0 | public DiagramInterface(Editor editor) { |
109 | 0 | currentEditor = editor; |
110 | 0 | LayerPerspective layer = |
111 | (LayerPerspective) editor.getLayerManager().getActiveLayer(); | |
112 | 0 | currentProject = ((ArgoDiagram) layer.getDiagram()).getProject(); |
113 | 0 | } |
114 | ||
115 | /** | |
116 | * Creates a new DiagramInterface. | |
117 | * | |
118 | * @param editor The editor to operate on. | |
119 | * @param project the project being operated on | |
120 | */ | |
121 | 0 | public DiagramInterface(Editor editor, Project project) { |
122 | 0 | currentEditor = editor; |
123 | 0 | } |
124 | ||
125 | /** | |
126 | * Get the current editor. | |
127 | * | |
128 | * @return The current editor. | |
129 | */ | |
130 | Editor getEditor() { | |
131 | 0 | return currentEditor; |
132 | } | |
133 | ||
134 | /** | |
135 | * Mark a diagram as modified, so we can layout it, after the | |
136 | * import is complete.<p> | |
137 | * | |
138 | * If the diagram is not already marked, add it to the list.<p> | |
139 | * | |
140 | * @param diagram The diagram to mark as modified. | |
141 | */ | |
142 | void markDiagramAsModified(ArgoDiagram diagram) { | |
143 | 0 | if (!modifiedDiagrams.contains(diagram)) { |
144 | 0 | modifiedDiagrams.add(diagram); |
145 | } | |
146 | 0 | } |
147 | ||
148 | ||
149 | /** | |
150 | * Get the list of modified diagrams. | |
151 | * | |
152 | * @return The list of modified diagrams. | |
153 | */ | |
154 | public List<ArgoDiagram> getModifiedDiagramList() { | |
155 | 0 | return modifiedDiagrams; |
156 | } | |
157 | ||
158 | /** | |
159 | * Reset the list of modified diagrams. | |
160 | */ | |
161 | void resetModifiedDiagrams() { | |
162 | 0 | modifiedDiagrams = new ArrayList<ArgoDiagram>(); |
163 | 0 | } |
164 | ||
165 | /** | |
166 | * Add a package to the current diagram. If the package already has | |
167 | * a representation in the current diagram, it is not(!) added. | |
168 | * | |
169 | * @param newPackage The package to add. | |
170 | */ | |
171 | public void addPackage(Object newPackage) { | |
172 | 0 | if (!isInDiagram(newPackage)) { |
173 | 0 | if (currentGM.canAddNode(newPackage)) { |
174 | 0 | DiagramElement newPackageFig = |
175 | currentDiagram.createDiagramElement( | |
176 | newPackage, | |
177 | new Rectangle(0, 0, 0, 0)); | |
178 | 0 | currentLayer.add((FigNodeModelElement) newPackageFig); |
179 | 0 | currentGM.addNode(newPackage); |
180 | 0 | currentLayer.putInPosition((FigNodeModelElement) newPackageFig); |
181 | } | |
182 | } | |
183 | 0 | } |
184 | ||
185 | /** | |
186 | * Check if a given package has a representation in the current | |
187 | * diagram. | |
188 | * | |
189 | * @param p The package to lookup in the current diagram. | |
190 | * @return true if this package has a figure in the current diagram, | |
191 | * false otherwise. | |
192 | */ | |
193 | public boolean isInDiagram(Object p) { | |
194 | 0 | if (currentDiagram == null) { |
195 | 0 | return false; |
196 | } else { | |
197 | 0 | return currentDiagram.getNodes().contains(p); |
198 | } | |
199 | } | |
200 | ||
201 | /** | |
202 | * Check if this diagram already exists in the project.<p> | |
203 | * | |
204 | * @param name package name (converted to class name) | |
205 | * @return true if diagram exists in project. | |
206 | */ | |
207 | public boolean isDiagramInProject(String name) { | |
208 | 0 | if (currentProject == null) { |
209 | 0 | throw new RuntimeException("current project not set yet"); |
210 | } | |
211 | 0 | return currentProject.getDiagram(getDiagramName(name)) != null; |
212 | } | |
213 | ||
214 | /** | |
215 | * Create a diagram name from a package name. | |
216 | * | |
217 | * @param packageName The package name. | |
218 | * @return The name for the diagram. | |
219 | */ | |
220 | private String getDiagramName(String packageName) { | |
221 | /* | |
222 | * TODO: This transformation is Java specific. We need a more | |
223 | * language/notation scheme for specifying qualified names. | |
224 | * Possible algorithm - replace all punctuation with our | |
225 | * internal separator, replace multiple separators with a single | |
226 | * instance (for languages like C++). What about I18N? - tfm | |
227 | */ | |
228 | 0 | return packageName.replace('.', DIAGRAM_NAME_SEPARATOR) |
229 | + DIAGRAM_NAME_SEPARATOR + DIAGRAM_NAME_SUFFIX; | |
230 | } | |
231 | ||
232 | /** | |
233 | * Select a class diagram as the current diagram, creating it | |
234 | * if necessary. | |
235 | * | |
236 | * @param p The package. | |
237 | * @param name The fully qualified name of this package. | |
238 | */ | |
239 | public void selectClassDiagram(Object p, String name) { | |
240 | // Check if this diagram already exists in the project | |
241 | 0 | if (currentProject == null) { |
242 | 0 | throw new RuntimeException("current project not set yet"); |
243 | } | |
244 | 0 | ArgoDiagram m = currentProject.getDiagram(getDiagramName(name)); |
245 | 0 | if (m != null) { |
246 | // The diagram already exists in this project. Select it | |
247 | // as the current target. | |
248 | 0 | setCurrentDiagram(m); |
249 | } else { | |
250 | // Otherwise create a new classdiagram for the package. | |
251 | 0 | addClassDiagram(p, name); |
252 | } | |
253 | 0 | } |
254 | ||
255 | /** | |
256 | * Add a new class diagram for a package to the project. | |
257 | * | |
258 | * @param ns | |
259 | * The namespace to contain the diagram. If null, the root model | |
260 | * will be used. | |
261 | * @param name | |
262 | * The fully qualified name of the package, which is used to | |
263 | * generate the diagram name from. | |
264 | */ | |
265 | public void addClassDiagram(Object ns, String name) { | |
266 | 0 | if (currentProject == null) { |
267 | 0 | throw new RuntimeException("current project not set yet"); |
268 | } | |
269 | 0 | ArgoDiagram d = DiagramFactory.getInstance().createDiagram( |
270 | DiagramFactory.DiagramType.Class, | |
271 | ns == null ? currentProject.getRoot() : ns, null); | |
272 | ||
273 | try { | |
274 | 0 | d.setName(getDiagramName(name)); |
275 | 0 | } catch (PropertyVetoException pve) { |
276 | 0 | LOG.error("Failed to set diagram name.", pve); |
277 | 0 | } |
278 | 0 | currentProject.addMember(d); |
279 | 0 | setCurrentDiagram(d); |
280 | 0 | } |
281 | ||
282 | /** | |
283 | * Add a class to the current diagram. | |
284 | * | |
285 | * @param newClass The new class to add to the editor. | |
286 | * @param minimise minimise the class fig by hiding compartiments | |
287 | * (of attributes and operations) | |
288 | */ | |
289 | public void addClass(Object newClass, boolean minimise) { | |
290 | 0 | addClassifier(newClass, minimise); |
291 | 0 | } |
292 | ||
293 | /** | |
294 | * Add a classier to the current diagram. | |
295 | * | |
296 | * @param classifier The new class or interface to add to the editor. | |
297 | * @param minimise minimise the class fig by hiding compartments | |
298 | * (of attributes and operations) | |
299 | */ | |
300 | private void addClassifier(Object classifier, boolean minimise) { | |
301 | // if the classifier is not in the current diagram, add it: | |
302 | 0 | if (currentGM.canAddNode(classifier)) { |
303 | 0 | FigClassifierBox newFig = |
304 | (FigClassifierBox) currentDiagram.createDiagramElement( | |
305 | classifier, | |
306 | new Rectangle(0, 0, 0, 0)); | |
307 | ||
308 | /* | |
309 | * The following calls are ORDER DEPENDENT. Not sure why, but the | |
310 | * layer add must come before the model add or we'll end up with | |
311 | * duplicate figures in the diagram. - tfm | |
312 | */ | |
313 | 0 | currentLayer.add(newFig); |
314 | 0 | currentGM.addNode(classifier); |
315 | 0 | currentLayer.putInPosition(newFig); |
316 | ||
317 | 0 | newFig.setOperationsVisible(!minimise); |
318 | 0 | if (Model.getFacade().isAClass(classifier)) { |
319 | 0 | newFig.setAttributesVisible(!minimise); |
320 | } | |
321 | ||
322 | 0 | newFig.renderingChanged(); |
323 | 0 | } else { |
324 | // the class is in the diagram | |
325 | // so we are on a second pass, | |
326 | // find the fig for this class can update its visible state. | |
327 | 0 | FigClassifierBox existingFig = null; |
328 | 0 | List figs = currentLayer.getContentsNoEdges(); |
329 | 0 | for (int i = 0; i < figs.size(); i++) { |
330 | 0 | Fig fig = (Fig) figs.get(i); |
331 | 0 | if (classifier == fig.getOwner()) { |
332 | 0 | existingFig = (FigClassifierBox) fig; |
333 | } | |
334 | } | |
335 | 0 | existingFig.renderingChanged(); |
336 | } | |
337 | ||
338 | // add edges | |
339 | // for a 2-pass r.e. process we might have already added the | |
340 | // class but not its edges | |
341 | 0 | currentGM.addNodeRelatedEdges(classifier); |
342 | 0 | } |
343 | ||
344 | /** | |
345 | * Add a interface to the current diagram. | |
346 | * | |
347 | * @param newInterface The interface to add. | |
348 | * @param minimise minimise the class fig by hiding compartiments | |
349 | * (of attributes and operations) | |
350 | */ | |
351 | public void addInterface(Object newInterface, boolean minimise) { | |
352 | 0 | addClassifier(newInterface, minimise); |
353 | 0 | } |
354 | ||
355 | ||
356 | /** | |
357 | * Creates class diagram under the root. | |
358 | * Is used for classes out of packages. | |
359 | * | |
360 | */ | |
361 | public void createRootClassDiagram() { | |
362 | 0 | selectClassDiagram(null, ""); |
363 | 0 | } |
364 | ||
365 | /** | |
366 | * selects a diagram without affecting the gui. | |
367 | * | |
368 | * @param diagram the diagram | |
369 | */ | |
370 | public void setCurrentDiagram(ArgoDiagram diagram) { | |
371 | 0 | if (diagram == null) { |
372 | 0 | throw new RuntimeException("you can't select a null diagram"); |
373 | } | |
374 | ||
375 | 0 | currentGM = (ClassDiagramGraphModel) diagram.getGraphModel(); |
376 | 0 | currentLayer = diagram.getLayer(); |
377 | 0 | currentDiagram = diagram; |
378 | 0 | currentProject = diagram.getProject(); |
379 | ||
380 | 0 | markDiagramAsModified(diagram); |
381 | 0 | } |
382 | ||
383 | } | |
384 | ||
385 | ||
386 | ||
387 | ||
388 | ||
389 | ||
390 | ||
391 | ||
392 | ||
393 | ||
394 | ||
395 | ||
396 | ||
397 | ||
398 | ||
399 | ||
400 | ||
401 | ||
402 | ||
403 | ||
404 | ||
405 | ||
406 | ||
407 | ||
408 |