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.entityrelationship.painters;
29  import y.base.YList;
30  import y.geom.OrientedRectangle;
31  import y.geom.YDimension;
32  import y.geom.YRectangle;
33  import y.io.graphml.NamespaceConstants;
34  import y.io.graphml.input.DeserializationEvent;
35  import y.io.graphml.input.DeserializationHandler;
36  import y.io.graphml.input.GraphMLParseException;
37  import y.io.graphml.output.GraphMLWriteException;
38  import y.io.graphml.output.SerializationEvent;
39  import y.io.graphml.output.SerializationHandler;
40  import y.io.graphml.output.XmlWriter;
41  import y.layout.NodeLabelCandidate;
42  import y.layout.NodeLabelLayout;
43  import y.layout.NodeLabelModel;
44  import y.layout.NodeLayout;
45  import y.view.NodeLabel;
46  import y.view.NodeRealizer;
47  
48  /**
49   * This label model computes the size and placement information for the
50   * attributes label of an ERD entity node.
51   * The area of the attributes label starts at the separator line and fills
52   * the whole lower compartment.
53   */
54  public class ErdAttributesNodeLabelModel implements NodeLabelModel {
55  
56    /** The horizontal distance of the label to the border of the node */
57    private static final double OFFSET_X = 2;
58    /** The minimal vertical distance of the label to the separator line */
59    private static final double MIN_OFFSET_Y = 2;
60    /**
61     *  The model parameter that contains information about a specific label.
62     *  In this case it is an empty class because there is only one possible position
63     *  for the attributes label.
64     */
65    private static final ErdAttributesNodeLabelModelParameter PARAMETER =
66            new ErdAttributesNodeLabelModelParameter();
67  
68    /**
69     * Returns the default parameter of this label model.
70     * @return the default parameter
71     */
72    public Object getDefaultParameter() {
73      return PARAMETER;
74    }
75  
76    /**
77     * Returns the oriented label position and bounds encoded by the given model
78     * parameter.
79     *
80     * @param labelSize The size of the label that should be placed.
81     * @param nodeLayout The layout of the node to which the label belongs.
82     * @param param The model parameter that describes the abstract position of
83     * the label within this model. The parameter must have been generated by
84     * this model.
85     *
86     * @return the oriented label position and bounds.
87     */
88    public OrientedRectangle getLabelPlacement(
89            final YDimension labelSize,
90            final NodeLayout nodeLayout,
91            final Object param
92    ) {
93      final YRectangle tmp1 = getLabelBox(labelSize, nodeLayout);
94      return new OrientedRectangle(tmp1);
95    }
96  
97    /**
98     * Returns a list of candidate positions for the specified node and label data.
99     *
100    * @param nl The label layout for which candidates should be generated.
101    * @param nodeLayout The layout of the node to which the label belongs.
102    * @return a list of candidate positions for the specified node and label data.
103    */
104   public YList getLabelCandidates(
105           final NodeLabelLayout nl,
106           final NodeLayout nodeLayout
107   ) {
108     final YList candidates = new YList();
109     final YRectangle box = getLabelBox(nl.getBox(), nodeLayout);
110     candidates.add(new NodeLabelCandidate(
111             box.getLocation(),
112             box,
113             PARAMETER,
114             nl,
115             true));
116     return candidates;
117   }
118 
119   /**
120    * Creates a model parameter that represents the given node label context best
121    * within this model.
122    * The created model parameter represents the closest parameter representation
123    * of the given oriented label bounds that can be achieved within this model.
124    *
125    * @param labelBounds
126    * The bounds of the label for which a parameter representation is sought.
127    * @param nodeLayout
128    * The layout of the node to which the label belongs.
129    *
130    * @return  the default parameter
131    */
132   public Object createModelParameter(
133           final OrientedRectangle labelBounds,
134           final NodeLayout nodeLayout
135   ) {
136     return PARAMETER;
137   }
138 
139 
140   /**
141    * Computes the size and position of the attributes label.
142    * @param labelSize The size of the label
143    * @param nodeLayout The layout of the node
144    * @return a <code>YRectangle</code> that defines the area of the label box
145    */
146   private static YRectangle getLabelBox(
147           final YDimension labelSize,
148           final NodeLayout nodeLayout
149   ) {
150     if (nodeLayout instanceof NodeRealizer) {
151       //if ERD style is used, compute the borders of the area under the separator
152       final NodeRealizer nr = (NodeRealizer) nodeLayout;
153       if (ErdNodePainter.useErdStyle(nr)) {
154         final NodeLabel nl = nr.getLabel();
155         final double sy = ErdNodePainter.separator(nl);
156 
157         final double offsetY = Math.max(MIN_OFFSET_Y, nl.getDistance());
158 
159         final double x = nr.getX();
160 
161         final double minX = x + OFFSET_X;
162         final double minY = sy + offsetY;
163 
164         return new YRectangle(
165                 minX,
166                 minY,
167                 Math.max(labelSize.width, x + nr.getWidth() - OFFSET_X - minX),
168                 Math.max(labelSize.height, nr.getY() + nr.getHeight() - offsetY - minY));
169       }
170     }
171 
172     // if no ERD style is used return a default box
173     return getDefaultBox(labelSize, nodeLayout);
174   }
175 
176   /**
177    * Computes a default size and position for the label.
178    * @param labelSize the size of the label
179    * @param nodeLayout the layout of the node
180    * @return a <code>YRectangle</code> that defines the area of the label box
181    */
182   private static YRectangle getDefaultBox(
183           final YDimension labelSize,
184           final NodeLayout nodeLayout
185   ) {
186     final double w = labelSize.width;
187     final double h = labelSize.height;
188     return new YRectangle(
189             nodeLayout.getX() + (nodeLayout.getWidth() - w) * 0.5,
190             nodeLayout.getY() + (nodeLayout.getHeight() - h) * 0.5,
191             w,
192             h);
193   }
194 
195   /**
196    * This parameter is used to provide information for a specific label.
197    * As the attributes label always fills the whole lower compartment of the
198    * entity node, this parameter has no function. However, it is needed to proper
199    * serialization/deserialization.
200    */
201   private static final class ErdAttributesNodeLabelModelParameter {
202   }
203 
204 
205   /**
206    * This handler provides a serialization/deserialization functionality for the
207    * nodes in ERD style.
208    *
209    * It makes sure that the attributes label can be loaded/stored from/to GraphML properly.
210    */
211   public static final class Handler
212           implements SerializationHandler, DeserializationHandler {
213 
214     /** The GraphML element name for the ERD label model */
215     private static final String MODEL_NAME = "ErdAttributesNodeLabelModel";
216     /** The GraphML element name for the parameter of the ERD label model */
217     private static final String PARAM_NAME = "ErdAttributesNodeLabelModelParameter";
218 
219     /**
220      * Handles the deserialization of the ERD attributes label.
221      * @param event an event that contains all data that is needed for deserialization.
222      * @throws GraphMLParseException
223      */
224     public void onHandleDeserialization(
225             final DeserializationEvent event
226     ) throws GraphMLParseException {
227       final org.w3c.dom.Node node = event.getXmlNode();
228       if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE &&
229           NamespaceConstants.YFILES_JAVA_NS.equals(node.getNamespaceURI())) {
230         final String ln = node.getLocalName();
231         if (MODEL_NAME.equals(ln)) {
232           event.setResult(new ErdAttributesNodeLabelModel());
233         } else if (PARAM_NAME.equals(ln)) {
234           event.setResult(PARAMETER);
235         }
236       }
237     }
238 
239     /**
240      * Handles the serialization of the ERD attributes label.
241      * @param event an event that contains all data that is needed for serialization.
242      * @throws GraphMLWriteException
243      */
244     public void onHandleSerialization(
245             final SerializationEvent event
246     ) throws GraphMLWriteException {
247       final Object item = event.getItem();
248       if (item instanceof ErdAttributesNodeLabelModel) {
249         final XmlWriter writer = event.getWriter();
250         writer.writeStartElement(MODEL_NAME, NamespaceConstants.YFILES_JAVA_NS);
251         writer.writeEndElement();
252         event.setHandled(true);
253       } else if (item == PARAMETER) {
254         final XmlWriter writer = event.getWriter();
255         writer.writeStartElement(PARAM_NAME, NamespaceConstants.YFILES_JAVA_NS);
256         writer.writeEndElement();
257         event.setHandled(true);
258       }
259     }
260   }
261 }
262