1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.view.uml;
29  
30  import y.geom.YPoint;
31  import y.view.Arrow;
32  import y.view.EdgeRealizer;
33  import y.view.GenericNodeRealizer;
34  import y.view.LineType;
35  import y.view.NodeLabel;
36  import y.view.NodePort;
37  import y.view.NodeRealizer;
38  import y.view.NodeScaledPortLocationModel;
39  import y.view.PolyLineEdgeRealizer;
40  import y.view.ShapePortConfiguration;
41  import y.view.SimpleUserDataHandler;
42  import y.view.YLabel;
43  
44  import java.awt.Color;
45  import java.util.Map;
46  
47  /**
48   * This is a factory for uml class elements conforming to the UML diagrams.
49   */
50  class UmlRealizerFactory {
51  
52    /** The name of the node configuration which represents an uml class. */
53    private static final String CLASS_CONFIG_NAME = "com.yworks.umlDiagram.class";
54  
55    /** The name of the label configuration of an uml class. */
56    public static final String LABEL_CONFIG_NAME = "com.yworks.umlDiagram.label";
57  
58    /** The name of the dummy node port configuration for edge animation. */
59    private static final String DUMMY_NODE_PORT = "com.yworks.umlDiagram.dummyNodePort";
60  
61    /** The name of a style property used to check on which button the mouse currently is. */
62    private static final String PROPERTY_MOUSE_OVER_BUTTON = "com.yworks.umlDiagram.style.mouseOverButton";
63  
64    /** Constant that is used to notify that the mouse is currently on no button. */
65    public static final int BUTTON_NONE = -1;
66  
67    /** Constant that is used to notify that the mouse is currently on the button that opens/closes the attribute section. */
68    public static final int BUTTON_OPEN_CLOSE_ATTRIBUTE_SECTION = 0;
69  
70    /** Constant that is used to notify that the mouse is currently on the button that opens/closes the operation section. */
71    public static final int BUTTON_OPEN_CLOSE_OPERATION_SECTION = 1;
72  
73    /** Constant that is used to notify that the mouse is currently on the button that opens/closes the class details. */
74    public static final int BUTTON_OPEN_CLOSE_CLASS_SECTIONS = 2;
75  
76    /** Constant that is used to notify that the mouse is currently on the button that adds an attribute. */
77    public static final int BUTTON_ADD_ATTRIBUTE = 3;
78  
79    /** Constant that is used to notify that the mouse is currently on the button that adds an operation. */
80    public static final int BUTTON_ADD_OPERATION = 4;
81  
82    /** Constant that is used to notify that the mouse is currently on the button that removes an attribute. */
83    public static final int BUTTON_SUB_ATTRIBUTE = 5;
84  
85    /** Constant that is used to notify that the mouse is currently on the button that removes an operation. */
86    public static final int BUTTON_SUB_OPERATION = 6;
87  
88    /** The name of a style property used to store the opacity of the attribute buttons. */
89    private static final String PROPERTY_ATTRIBUTE_BUTTON_OPACITY = "com.yworks.umlDiagram.style.attributeButtonOpacity";
90  
91    /** The name of a style property used to store the opacity of the operation buttons. */
92    private static final String PROPERTY_OPERATION_BUTTON_OPACITY = "com.yworks.umlDiagram.style.operationButtonOpacity";
93  
94    /** The name of a style property used to store the opacity of the selected item. */
95    private static final String PROPERTY_SELECTION_OPACITY = "com.yworks.umlDiagram.style.selectionOpacity";
96  
97    /** The name of a style property used to store the opacity of the node. */
98    private static final String PROPERTY_NODE_OPACITY = "com.yworks.umlDiagram.style.nodeOpacity";
99  
100   /** Constant that is used to specify that the currently selected item belongs to the attribute list. */
101   public static final int LIST_ATTRIBUTES =  0;
102 
103   /** Constant that is used to specify that the currently selected item belongs to the operation list. */
104   public static final int LIST_OPERATIONS =  1;
105 
106   /** Constant that is used to specify the alpha value of an opaque color. */
107   public static final float OPAQUE = 1.0f;
108 
109   /** Constant that is used to specify the alpha value of an semi transparent color. */
110   public static final float TRANSPARENT = 0.5f;
111 
112   private static final Color COLOR_GREEN = new Color(34,139,34);
113   private static final Color COLOR_YELLOW = new Color(213, 255, 179);
114 
115   /** Color that is used to paint foreground areas of the class realizers. */
116   public static final Color COLOR_FOREGROUND = COLOR_GREEN;
117 
118   /** Color that is used to paint background areas of the class realizers. */
119   public static final Color COLOR_BACKGROUND = Color.WHITE;
120 
121   /** Color that is used to paint selected areas like button or list items. */
122   public static final Color COLOR_SELECTION = COLOR_YELLOW;
123 
124   /** Color that is used to paint the background of buttons where the mouse is over. */
125   public static final Color COLOR_BUTTON_BACKGROUND_ACTIVE = COLOR_YELLOW;
126 
127   /** Color that is used to paint the background of buttons where the mouse is not over. */
128   public static final Color COLOR_BUTTON_BACKGROUND_BLANK = Color.WHITE;
129 
130   /** Color that is used to paint the foreground of buttons that are enabled. */
131   public static final Color COLOR_BUTTON_FOREGROUND_ENABLED = COLOR_GREEN;
132 
133   /** Color that is used to paint the foreground of buttons that are disabled. */
134   public static final Color COLOR_BUTTON_FOREGROUND_DISABLED = Color.LIGHT_GRAY;
135 
136   /** Line type for the outline of the edge creation buttons. */
137   public static final LineType LINE_EDGE_CREATION_BUTTON_OUTLINE = LineType.LINE_2;
138 
139   /** Line type for edges that specify relation between classes. */
140   public static final LineType LINE_TYPE_RELATION = LineType.LINE_1;
141 
142   /** Line type for edges that specify inheritance between classes. */
143   public static final LineType LINE_TYPE_INHERITANCE = LineType.DASHED_1;
144 
145   /** Color that is used to paint edges. */
146   public static final Color COLOR_EDGE = Color.DARK_GRAY;
147 
148   static {
149     registerUmlClassConfiguration();
150     registerUmlClassLabelConfiguration();
151     registerDummyNodePortConfiguration();
152   }
153 
154   private UmlRealizerFactory() {
155   }
156 
157   private static void registerUmlClassConfiguration() {
158     final GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
159     final Map implementations = factory.createDefaultConfigurationMap();
160     final GenericNodeRealizer.Painter configuration = new UmlClassConfiguration();
161     implementations.put(GenericNodeRealizer.Painter.class, configuration);
162     implementations.put(GenericNodeRealizer.GenericMouseInputEditorProvider.class, configuration);
163     implementations.put(GenericNodeRealizer.GenericSizeConstraintProvider.class, configuration);
164     implementations.put(GenericNodeRealizer.UserDataHandler.class, new SimpleUserDataHandler(SimpleUserDataHandler.EXCEPTION_ON_FAILURE));
165     factory.addConfiguration(CLASS_CONFIG_NAME, implementations);
166   }
167 
168   private static void registerUmlClassLabelConfiguration() {
169     final YLabel.Factory factory = NodeLabel.getFactory();
170     final Map implementations = factory.createDefaultConfigurationMap();
171     implementations.put(YLabel.Painter.class, new UmlClassLabelPainter());
172     factory.addConfiguration(LABEL_CONFIG_NAME, implementations);
173   }
174 
175   private static void registerDummyNodePortConfiguration() {
176     final ShapePortConfiguration configuration = new ShapePortConfiguration();
177     configuration.setSize(1, 1);
178     final NodePort.Factory factory = NodePort.getFactory();
179     final Map map = factory.createDefaultConfigurationMap();
180     map.put(NodePort.Painter.class, configuration);
181     map.put(NodePort.IntersectionTest.class, configuration);
182     map.put(NodePort.ContainsTest.class, configuration);
183     map.put(NodePort.BoundsProvider.class, configuration);
184     map.put(NodePort.UnionRectCalculator.class, configuration);
185     factory.addConfiguration(DUMMY_NODE_PORT, map);
186   }
187 
188   /**
189    * Creates a <code>NodeRealizer</code> that represents a class in UML. This realizer has a name label, an attribute
190    * and operation caption and a list of attributes and operation labels.
191    *
192    * @return an UML class realizer
193    * @see #CLASS_CONFIG_NAME
194    */
195   public static NodeRealizer createClassRealizer() {
196     final GenericNodeRealizer realizer = new GenericNodeRealizer();
197     realizer.setConfiguration(CLASS_CONFIG_NAME);
198     realizer.setUserData(new UmlClassModel());
199     realizer.setFillColor(COLOR_BACKGROUND);
200     realizer.setFillColor2(COLOR_FOREGROUND);
201     realizer.setLineColor(COLOR_SELECTION);
202     realizer.setLineType(LineType.LINE_2);
203     setAttributeButtonOpacity(realizer, 0);
204     setOperationButtonOpacity(realizer, 0);
205     setSelectionOpacity(realizer, 0);
206     UmlClassLabelSupport.updateAllLabels(realizer);
207     UmlClassLabelSupport.updateRealizerSize(realizer);
208     return realizer;
209   }
210 
211   /**
212    * Creates a {@link EdgeRealizer} that represents an association as defined in UML 2.0.
213    */
214   public static EdgeRealizer createAssociationRealizer() {
215     final EdgeRealizer association = new PolyLineEdgeRealizer();
216     association.setLineColor(COLOR_EDGE);
217     association.setLineType(LINE_TYPE_RELATION);
218     association.setSourceArrow(Arrow.NONE);
219     association.setTargetArrow(Arrow.NONE);
220     return association;
221   }
222 
223   /**
224    * Creates a {@link EdgeRealizer} that represents a dependency as defined in UML 2.0.
225    */
226   public static EdgeRealizer createDependencyRealizer() {
227     final EdgeRealizer dependency = new PolyLineEdgeRealizer();
228     dependency.setLineColor(COLOR_EDGE);
229     dependency.setLineType(LINE_TYPE_INHERITANCE);
230     dependency.setSourceArrow(Arrow.NONE);
231     dependency.setTargetArrow(Arrow.PLAIN);
232     return dependency;
233   }
234 
235   /**
236    * Creates a {@link EdgeRealizer} that represents a generalization as defined in UML 2.0.
237    */
238   public static EdgeRealizer createGeneralizationRealizer() {
239     final EdgeRealizer generalization = new PolyLineEdgeRealizer();
240     generalization.setLineColor(COLOR_EDGE);
241     generalization.setLineType(LINE_TYPE_RELATION);
242     generalization.setSourceArrow(Arrow.NONE);
243     generalization.setTargetArrow(Arrow.WHITE_DELTA);
244     return generalization;
245   }
246 
247   /**
248    * Creates a {@link EdgeRealizer} that represents a realization as defined in UML 2.0.
249    */
250   public static EdgeRealizer createRealizationRealizer() {
251     final EdgeRealizer realization = new PolyLineEdgeRealizer();
252     realization.setLineColor(COLOR_EDGE);
253     realization.setLineType(LINE_TYPE_INHERITANCE);
254     realization.setSourceArrow(Arrow.NONE);
255     realization.setTargetArrow(Arrow.WHITE_DELTA);
256     return realization;
257   }
258 
259   /**
260    * Creates a {@link EdgeRealizer} that represents an aggregation as defined in UML 2.0.
261    */
262   public static EdgeRealizer createAggregationRealizer() {
263     final EdgeRealizer aggregation = new PolyLineEdgeRealizer();
264     aggregation.setLineColor(COLOR_EDGE);
265     aggregation.setLineType(LINE_TYPE_RELATION);
266     aggregation.setSourceArrow(Arrow.WHITE_DIAMOND);
267     aggregation.setTargetArrow(Arrow.NONE);
268     return aggregation;
269   }
270 
271   /**
272    * Creates a {@link EdgeRealizer} that represents a composition as defined in UML 2.0.
273    */
274   public static EdgeRealizer createCompositionRealizer() {
275     final EdgeRealizer composition = new PolyLineEdgeRealizer();
276     composition.setLineColor(COLOR_EDGE);
277     composition.setLineType(LINE_TYPE_RELATION);
278     composition.setSourceArrow(Arrow.DIAMOND);
279     composition.setTargetArrow(Arrow.NONE);
280     return composition;
281   }
282 
283   /**
284    * Creates a {@link NodePort} that has minimal size.
285    */
286   public static NodePort createDummyNodePort(NodeRealizer currentRealizer, YPoint portLocation) {
287     final NodePort port = new NodePort();
288     port.setModelParameter(new NodeScaledPortLocationModel().createParameter(currentRealizer, portLocation));
289     port.setConfiguration(DUMMY_NODE_PORT);
290     return port;
291   }
292 
293   /**
294    * Checks whether or not the given {@link y.view.EdgeRealizer} visualizes a UML realization.
295    */
296   static boolean isRealization(EdgeRealizer er) {
297     return er.getTargetArrow() == Arrow.WHITE_DELTA && er.getLineType() == LINE_TYPE_RELATION;
298   }
299 
300   /**
301    * Checks whether or not the given {@link y.view.EdgeRealizer} visualizes a UML realization or generalization.
302    */
303   static boolean isInheritance(EdgeRealizer er) {
304     return er.getTargetArrow() == Arrow.WHITE_DELTA;
305   }
306 
307 
308   /**
309    * Returns the button which the mouse is currently over. There are the following buttons:
310    * <ul>
311    *   <li>{@link #BUTTON_NONE}</li>
312    *   <li>{@link #BUTTON_OPEN_CLOSE_ATTRIBUTE_SECTION}</li>
313    *   <li>{@link #BUTTON_OPEN_CLOSE_OPERATION_SECTION}</li>
314    *   <li>{@link #BUTTON_OPEN_CLOSE_CLASS_SECTIONS}</li>
315    *   <li>{@link #BUTTON_ADD_ATTRIBUTE}</li>
316    *   <li>{@link #BUTTON_ADD_OPERATION}</li>
317    *   <li>{@link #BUTTON_SUB_ATTRIBUTE}</li>
318    *   <li>{@link #BUTTON_SUB_OPERATION}</li>
319    * </ul>
320    */
321   public static int getMouseOverButton(final NodeRealizer context) {
322     final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
323     final Object button = gnr.getStyleProperty(PROPERTY_MOUSE_OVER_BUTTON);
324     return button != null ? ((Integer)button).intValue() : BUTTON_NONE;
325   }
326 
327   /**
328    * Specifies the button which the mouse is currently over. There are the following buttons:
329    * <ul>
330    *   <li>{@link #BUTTON_NONE}</li>
331    *   <li>{@link #BUTTON_OPEN_CLOSE_ATTRIBUTE_SECTION}</li>
332    *   <li>{@link #BUTTON_OPEN_CLOSE_OPERATION_SECTION}</li>
333    *   <li>{@link #BUTTON_OPEN_CLOSE_CLASS_SECTIONS}</li>
334    *   <li>{@link #BUTTON_ADD_ATTRIBUTE}</li>
335    *   <li>{@link #BUTTON_ADD_OPERATION}</li>
336    *   <li>{@link #BUTTON_SUB_ATTRIBUTE}</li>
337    *   <li>{@link #BUTTON_SUB_OPERATION}</li>
338    * </ul>
339    */
340   public static void setMouseOverButton(final NodeRealizer context, final int button) {
341     switch (button) {
342       case BUTTON_NONE:
343       case BUTTON_OPEN_CLOSE_ATTRIBUTE_SECTION:
344       case BUTTON_OPEN_CLOSE_OPERATION_SECTION:
345       case BUTTON_OPEN_CLOSE_CLASS_SECTIONS:
346       case BUTTON_ADD_ATTRIBUTE:
347       case BUTTON_ADD_OPERATION:
348       case BUTTON_SUB_ATTRIBUTE:
349       case BUTTON_SUB_OPERATION:
350         final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
351         gnr.setStyleProperty(PROPERTY_MOUSE_OVER_BUTTON, new Integer(button));
352         return;
353       default:
354         throw new IllegalArgumentException("Unknown button " + button);
355     }
356   }
357 
358   /**
359    * Returns the opacity of the attribute buttons.
360    */
361   public static float getAttributeButtonOpacity(final NodeRealizer context) {
362     final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
363     final Object opacity = gnr.getStyleProperty(PROPERTY_ATTRIBUTE_BUTTON_OPACITY);
364     return opacity != null ? ((Float)opacity).floatValue() : OPAQUE;
365   }
366 
367   /**
368    * Specifies the opacity of the attribute buttons.
369    */
370   public static void setAttributeButtonOpacity(final NodeRealizer context, final float opacity) {
371     final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
372     gnr.setStyleProperty(PROPERTY_ATTRIBUTE_BUTTON_OPACITY, new Float(opacity));
373   }
374 
375   /**
376    * Returns the opacity of the operation buttons.
377    */
378   public static float getOperationButtonOpacity(final NodeRealizer context) {
379     final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
380     final Object opacity = gnr.getStyleProperty(PROPERTY_OPERATION_BUTTON_OPACITY);
381     return opacity != null ? ((Float)opacity).floatValue() : OPAQUE;
382   }
383 
384   /**
385    * Specifies the opacity of the operation buttons.
386    */
387   public static void setOperationButtonOpacity(final NodeRealizer context, final float opacity) {
388     final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
389     gnr.setStyleProperty(PROPERTY_OPERATION_BUTTON_OPACITY, new Float(opacity));
390   }
391 
392   /**
393    * Returns the opacity of the item selection.
394    */
395   public static float getSelectionOpacity(final NodeRealizer context) {
396     final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
397     final Object opacity = gnr.getStyleProperty(PROPERTY_SELECTION_OPACITY);
398     return opacity != null ? ((Float)opacity).floatValue() : OPAQUE;
399   }
400 
401   /**
402    * Specifies the opacity of the item selection.
403    */
404   public static void setSelectionOpacity(final NodeRealizer context, final float opacity) {
405     final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
406     gnr.setStyleProperty(PROPERTY_SELECTION_OPACITY, new Float(opacity));
407   }
408 
409   /**
410    * Returns the opacity of the realizer.
411    */
412   public static float getNodeOpacity(final NodeRealizer context) {
413     final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
414     final Object opacity = gnr.getStyleProperty(PROPERTY_NODE_OPACITY);
415     return opacity != null ? ((Float) opacity).floatValue() : OPAQUE;
416   }
417 
418   /**
419    * Specifies the opacity of the realizer.
420    */
421   public static void setNodeOpacity(final NodeRealizer context, final float opacity) {
422     final GenericNodeRealizer gnr = (GenericNodeRealizer) context;
423     gnr.setStyleProperty(PROPERTY_NODE_OPACITY, new Float(opacity));
424   }
425 }
426