Bug 13510 fixed: Datatip callback cleared 'd'
[scilab.git] / scilab / modules / graphic_objects / src / java / org / scilab / modules / graphic_objects / datatip / Datatip.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012 - Pedro Arthur dos S. Souza
4  * Copyright (C) 2012 - Caio Lucas dos S. Souza
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11  *
12  */
13
14 package org.scilab.modules.graphic_objects.datatip;
15
16 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_3COMPONENT__;
17 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_AUTOORIENTATION__;
18 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_BOX_MODE__;
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DATA__;
20 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DISPLAY_FNC__;
21 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_INTERP_MODE__;
22 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_LABEL_MODE__;
23 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_ORIENTATION__;
24 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_INDEXES__;
25
26 import java.text.DecimalFormat;
27 import java.text.DecimalFormatSymbols;
28
29 import org.scilab.forge.scirenderer.ruler.graduations.UserDefinedFormat;
30
31 import org.scilab.modules.action_binding.InterpreterManagement;
32 import org.scilab.modules.graphic_objects.PolylineData;
33 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
34 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
35 import org.scilab.modules.graphic_objects.graphicObject.Visitor;
36 import org.scilab.modules.graphic_objects.textObject.Text;
37 import org.scilab.modules.localization.Messages;
38
39 public class Datatip extends Text {
40
41     /** false = datatip text box is hidden*/
42     Boolean tipBoxMode;
43     /** false = datatip label is hidden*/
44     Boolean tipLabelMode;
45     /** false = display only (X, Y), true = display (X, Y, Z)*/
46     Boolean use3component;
47     /** false = no interpolation between point segments*/
48     Boolean interpMode;
49     /** Displayed number format*/
50     DecimalFormat tipTextFormat;
51     /** Display function*/
52     String displayFnc;
53     /** For automatic update the datatip orientation*/
54     Boolean autoOrientation;
55     /* index of data in parent object ( polyline, plot3d, fac3d*/
56     /* size = 1 for polyline and 2 for others*/
57     Integer dataIndex;
58     Double ratio;
59
60
61     enum DatatipObjectProperty { TIP_DATA, TIP_BOX_MODE, TIP_LABEL_MODE, TIP_ORIENTATION, TIP_AUTOORIENTATION, TIP_3COMPONENT, TIP_INTERP_MODE, TIP_DISPLAY_FNC, TIP_INDEXES};
62     enum TipOrientation { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT;
63
64                           /**
65                            * Transform a integer to a TipOrientation enum.
66                            */
67     public static TipOrientation intToEnum(Integer i) {
68         switch (i) {
69             case 0:
70                 return TipOrientation.TOP_LEFT;
71             case 1:
72                 return TipOrientation.TOP_RIGHT;
73             case 2:
74                 return TipOrientation.BOTTOM_LEFT;
75             case 3:
76                 return TipOrientation.BOTTOM_RIGHT;
77             default:
78                 return TipOrientation.TOP_RIGHT;
79         }
80     }
81
82                         };
83
84     TipOrientation currentOrientation;
85
86     /**
87      * Initializes the datatip, setup format, orientation and mark.
88      */
89     public Datatip() {
90         super();
91         use3component = false;
92         autoOrientation = true;
93         setOrientationAsEnum(TipOrientation.TOP_RIGHT);
94         DecimalFormat fb = new DecimalFormat("#.####E00");
95         DecimalFormatSymbols decimalFormatSymbols = fb.getDecimalFormatSymbols();
96         decimalFormatSymbols.setDecimalSeparator('.');
97         decimalFormatSymbols.setExponentSeparator("e");
98         decimalFormatSymbols.setGroupingSeparator('\u00A0');
99         fb.setDecimalFormatSymbols(decimalFormatSymbols);
100         tipTextFormat = new UserDefinedFormat(fb, "%g", 1, 0);
101
102         tipBoxMode = true;
103         tipLabelMode = true;
104         interpMode = true;
105         displayFnc = "";
106         ratio = 0.;
107         dataIndex = Integer.MIN_VALUE;
108         setVisible(true);
109         setBox(true);
110         setLineMode(true);
111         setFillMode(true);
112         setBackground(-2);
113         setClipState(1);
114
115         setMarkMode(true);
116         setMarkSize(8);
117         setMarkBackground(-1);
118         setMarkForeground(-1);
119         setMarkStyle(11);
120     }
121
122     @Override
123     public void accept(Visitor visitor) {
124         visitor.visit(this);
125     }
126
127     /**
128      * Convert the property name to the DatatipObjectProperty enum.
129      */
130     public Object getPropertyFromName(int propertyName) {
131         switch (propertyName) {
132             case __GO_DATATIP_DATA__:
133                 return DatatipObjectProperty.TIP_DATA;
134             case __GO_DATATIP_BOX_MODE__:
135                 return DatatipObjectProperty.TIP_BOX_MODE;
136             case __GO_DATATIP_LABEL_MODE__:
137                 return DatatipObjectProperty.TIP_LABEL_MODE;
138             case __GO_DATATIP_ORIENTATION__:
139                 return DatatipObjectProperty.TIP_ORIENTATION;
140             case __GO_DATATIP_3COMPONENT__:
141                 return DatatipObjectProperty.TIP_3COMPONENT;
142             case __GO_DATATIP_AUTOORIENTATION__:
143                 return DatatipObjectProperty.TIP_AUTOORIENTATION;
144             case __GO_DATATIP_INTERP_MODE__:
145                 return DatatipObjectProperty.TIP_INTERP_MODE;
146             case __GO_DATATIP_DISPLAY_FNC__:
147                 return DatatipObjectProperty.TIP_DISPLAY_FNC;
148             case __GO_DATATIP_INDEXES__ :
149                 return DatatipObjectProperty.TIP_INDEXES;
150             default:
151                 return super.getPropertyFromName(propertyName);
152         }
153     }
154
155     /**
156      * @return the datatip property
157      */
158     public Object getProperty(Object property) {
159         if (property instanceof DatatipObjectProperty) {
160             switch ((DatatipObjectProperty) property) {
161                 case TIP_DATA:
162                     return getTipData();
163                 case TIP_BOX_MODE:
164                     return getTipBoxMode();
165                 case TIP_LABEL_MODE:
166                     return getTipLabelMode();
167                 case TIP_ORIENTATION:
168                     return getOrientation();
169                 case TIP_3COMPONENT:
170                     return isUsing3Component();
171                 case TIP_AUTOORIENTATION:
172                     return isAutoOrientationEnabled();
173                 case TIP_INTERP_MODE:
174                     return getInterpMode();
175                 case TIP_DISPLAY_FNC:
176                     return getDisplayFunction();
177                 case TIP_INDEXES:
178                     return getIndexes();
179             }
180         }
181
182         return super.getProperty(property);
183     }
184
185     /**
186      * Set the datatip property
187      * @param property the property
188      * @param value the new property value.
189      */
190     public UpdateStatus setProperty(Object property, Object value) {
191         if (property instanceof DatatipObjectProperty) {
192             switch ((DatatipObjectProperty) property) {
193                 case TIP_BOX_MODE:
194                     return setTipBoxMode((Boolean) value);
195                 case TIP_LABEL_MODE:
196                     return setTipLabelMode((Boolean) value);
197                 case TIP_ORIENTATION:
198                     return setOrientation((Integer) value);
199                 case TIP_3COMPONENT:
200                     return setUse3Component((Boolean) value);
201                 case TIP_AUTOORIENTATION:
202                     return setAutoOrientation((Boolean) value);
203                 case TIP_INTERP_MODE:
204                     return setInterpMode((Boolean) value);
205                 case TIP_DISPLAY_FNC:
206                     return setDisplayFunction((String) value);
207                 case TIP_INDEXES:
208                     return setIndexes((Double[]) value);
209             }
210         }
211
212         return super.setProperty(property, value);
213     }
214
215     /**
216      * Get the current tip data
217      * @return the tip data
218      */
219     public Double[] getTipData() {
220         final double[] dataX = (double[]) PolylineData.getDataX(getParent());
221         final double[] dataY = (double[]) PolylineData.getDataY(getParent());
222
223         if (use3component) {
224             final double[] dataZ = (double[]) PolylineData.getDataZ(getParent());
225
226             if (dataX.length < dataIndex + 2 || dataY.length < dataIndex + 2 || dataZ.length < dataIndex + 2) {
227                 if (dataX.length >= 1 && dataY.length >= 1 && dataZ.length >= 1) {
228                     return new Double[] {dataX[dataX.length - 1], dataY[dataY.length - 1], dataZ[dataZ.length - 1]};
229                 } else {
230                     return new Double[] {0., 0., 0.};
231                 }
232             }
233
234             //get pt0 and pt1 from polyline data
235             final double[] pt0 = new double[] {dataX[dataIndex], dataY[dataIndex], dataZ[dataIndex]};
236             final double[] pt1 = new double[] {dataX[dataIndex + 1], dataY[dataIndex + 1], dataZ[dataIndex + 1]};
237
238             final double x = pt0[0] + (pt1[0] - pt0[0]) * ratio;
239             final double y = pt0[1] + (pt1[1] - pt0[1]) * ratio;
240             final double z = pt0[2] + (pt1[2] - pt0[2]) * ratio;
241
242             return new Double[] {x, y, z};
243         } else {
244             if (dataX.length < dataIndex + 2 || dataY.length < dataIndex + 2) {
245                 if (dataX.length >= 1 && dataY.length >= 1) {
246                     return new Double[] {dataX[dataX.length - 1], dataY[dataY.length - 1], 0.};
247                 } else {
248                     return new Double[] {0., 0., 0.};
249                 }
250             }
251
252             //get pt0 and pt1 from polyline data
253             final double[] pt0 = new double[] {dataX[dataIndex], dataY[dataIndex]};
254             final double[] pt1 = new double[] {dataX[dataIndex + 1], dataY[dataIndex + 1]};
255
256             final double x = pt0[0] + (pt1[0] - pt0[0]) * ratio;
257             final double y = pt0[1] + (pt1[1] - pt0[1]) * ratio;
258
259             return new Double[] {x, y, 0.};
260         }
261     }
262
263     /**
264      * Get the current textbox orientation as an integer
265      * @return current orientation.
266      */
267     public Integer getOrientation() {
268         return getOrientationAsEnum().ordinal();
269     }
270
271     /**
272      * Get the current oriantation as a enum
273      * @return the current orientation
274      */
275     public TipOrientation getOrientationAsEnum() {
276         return currentOrientation;
277     }
278
279     /**
280      * Set the current orientation (updating the text position)
281      * @param orientation the new orientation (integer).
282      */
283     public UpdateStatus setOrientation(Integer orientation) {
284         currentOrientation = TipOrientation.intToEnum(orientation);
285         return UpdateStatus.Success;
286     }
287
288     /**
289      * Set the current orientation (updating the text position)
290      * @param orientation the new orientation (TipOrientation enum).
291      */
292     public UpdateStatus setOrientationAsEnum(TipOrientation orientation) {
293         currentOrientation = orientation;
294         return UpdateStatus.Success;
295     }
296
297     /**
298      * @return true if the datatip is displaying the Z component, false otherwise.
299      */
300     public Boolean isUsing3Component() {
301         return use3component;
302     }
303
304     /**
305      * If true set the Z component to be displayed.
306      * @param useZ True to enable display the Z component, false to disable.
307      */
308     public UpdateStatus setUse3Component(Boolean useZ) {
309         use3component = useZ;
310         updateText();
311         return UpdateStatus.Success;
312     }
313
314
315     public Boolean isAutoOrientationEnabled() {
316         return autoOrientation;
317     }
318
319     public UpdateStatus setAutoOrientation(Boolean status) {
320         autoOrientation = status;
321         return UpdateStatus.Success;
322     }
323
324     /**
325      * Update the text from the datatip base on current tipData value.
326      */
327     public void updateText() {
328         //if display function is empty look in parent
329         //if parent is empty too use default print
330
331         String fnc = getDisplayFunction();
332         if (fnc == null || fnc.equals("")) {
333             //look in parent
334             fnc = (String) GraphicController.getController().getProperty(getParent(), GraphicObjectProperties.__GO_DATATIP_DISPLAY_FNC__);
335             if (fnc == null || fnc.equals("")) {
336                 String[] textArray = new String[] {"X:", "Y:", "Z:"};
337                 Double[] tipData = getTipData();
338                 textArray[0] += tipTextFormat.format(tipData[0]);
339                 textArray[1] += tipTextFormat.format(tipData[1]);
340                 textArray[2] += tipTextFormat.format(tipData[2]);
341
342                 Integer[] dim = new Integer[2];
343                 dim[0] = use3component ? 3 : 2;
344                 dim[1] = 1;
345                 setTextArrayDimensions(dim);
346                 setTextStrings(textArray);
347                 return;
348             }
349         }
350
351         String errMsg =  Messages.gettext("Wrong value for ''%s'' property: A valid function name expected.\n");
352         String updateCommand = "try;" +
353                                "GDZa786XBSq7899SHKp=getcallbackobject(" + getIdentifier() + ");" +
354                                "set(GDZa786XBSq7899SHKp,\"text\"," + fnc + "(GDZa786XBSq7899SHKp));" +
355                                "clear(\"GDZa786XBSq7899SHKp\");" +
356                                "catch;" +
357                                "set(GDZa786XBSq7899SHKp,\"display_function\",\"\");" +
358                                "set(GDZa786XBSq7899SHKp.parent,\"display_function\",\"\");" +
359                                "clear(\"GDZa786XBSq7899SHKp\");" +
360                                "error(msprintf(\"" + errMsg + "\", \"display_function\"));" +
361                                "end;";
362         InterpreterManagement.requestScilabExec(updateCommand);
363     }
364
365     public Boolean getTipBoxMode() {
366         return tipBoxMode;
367     }
368
369     public Boolean getTipLabelMode() {
370         return tipLabelMode;
371     }
372
373     public Boolean getInterpMode() {
374         return interpMode;
375     }
376
377     public String getDisplayFunction() {
378         return displayFnc;
379     }
380
381     public UpdateStatus setTipBoxMode(Boolean mode) {
382         tipBoxMode = mode;
383         setBox(tipBoxMode);
384         return UpdateStatus.Success;
385     }
386
387     public UpdateStatus setTipLabelMode(Boolean mode) {
388         tipLabelMode = mode;
389         return UpdateStatus.Success;
390     }
391
392     public UpdateStatus setInterpMode(Boolean mode) {
393         interpMode = mode;
394         return UpdateStatus.Success;
395     }
396
397     public UpdateStatus setDisplayFunction(String fnc) {
398         displayFnc = fnc;
399         updateText();
400         return UpdateStatus.Success;
401     }
402
403     @Override
404     public Double[] getPosition() {
405         return getTipData();
406     }
407
408     public UpdateStatus setIndexes(Double[] value) {
409         if (value[0].intValue() != dataIndex || !value[1].equals(ratio)) {
410             dataIndex = value[0].intValue();
411             ratio = new Double(value[1]);
412             updateText();
413
414             return UpdateStatus.Success;
415         }
416
417         return UpdateStatus.NoChange;
418     }
419
420     public Integer getIndexes() {
421         return dataIndex;
422     }
423
424     /**
425      * @return Type as String
426      */
427     public Integer getType() {
428         return GraphicObjectProperties.__GO_DATATIP__;
429     }
430 }