Graphics: fix custom Formatter after JDK8 upgrade
[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  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 package org.scilab.modules.graphic_objects.datatip;
18
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DISPLAY_COMPONENTS__;
20 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_AUTOORIENTATION__;
21 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_BOX_MODE__;
22 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DATA__;
23 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DISPLAY_FNC__;
24 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_INTERP_MODE__;
25 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_LABEL_MODE__;
26 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_ORIENTATION__;
27 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_INDEXES__;
28 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DETACHED_MODE__;
29 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_DATATIP_DETACHED_POSITION__;
30
31 import java.text.DecimalFormat;
32 import java.text.DecimalFormatSymbols;
33 import java.util.Locale;
34
35 import org.scilab.forge.scirenderer.ruler.graduations.UserDefinedFormat;
36
37 import org.scilab.modules.action_binding.InterpreterManagement;
38 import static org.scilab.modules.graphic_objects.graphicObject.ClippableProperty.ClipStateType;
39 import org.scilab.modules.graphic_objects.PolylineData;
40 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
41 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
42 import org.scilab.modules.graphic_objects.graphicObject.Visitor;
43 import org.scilab.modules.graphic_objects.textObject.Text;
44 import org.scilab.modules.localization.Messages;
45
46 public class Datatip extends Text {
47
48     /** false = datatip text box is hidden*/
49     Boolean tipBoxMode;
50     /** false = datatip label is hidden*/
51     Boolean tipLabelMode;
52     /** selects which coordinates componet to diplay*/
53     String displayComponents;
54     /** false = no interpolation between point segments*/
55     Boolean interpMode;
56     /** Displayed number format*/
57     DecimalFormat tipTextFormat;
58     /** Display function*/
59     String displayFnc;
60     /** For automatic update the datatip orientation*/
61     Boolean autoOrientation;
62     /* index of data in parent object ( polyline, plot3d, fac3d*/
63     /* size = 1 for polyline and 2 for others*/
64     Integer dataIndex;
65     Double ratio;
66
67
68     enum DatatipObjectProperty { TIP_DATA, TIP_BOX_MODE, TIP_LABEL_MODE, TIP_ORIENTATION, TIP_AUTOORIENTATION, TIP_DISPLAY_COMPONENTS,
69                                  TIP_INTERP_MODE, TIP_DISPLAY_FNC, TIP_INDEXES, TIP_DETACHED_MODE, TIP_DETACHED_POSITION
70                                };
71
72     enum TipOrientation { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT, LEFT, RIGHT, TOP, BOTTOM;
73
74                           /**
75                            * Transform a integer to a TipOrientation enum.
76                            */
77     public static TipOrientation intToEnum(Integer i) {
78         switch (i) {
79             case 0:
80                         return TipOrientation.TOP_LEFT;
81                 case 1:
82                     return TipOrientation.TOP_RIGHT;
83                 case 2:
84                     return TipOrientation.BOTTOM_LEFT;
85                 case 3:
86                     return TipOrientation.BOTTOM_RIGHT;
87                 case 4:
88                     return TipOrientation.LEFT;
89                 case 5:
90                     return TipOrientation.RIGHT;
91                 case 6:
92                     return TipOrientation.TOP;
93                 case 7:
94                     return TipOrientation.BOTTOM;
95                 default:
96                     return TipOrientation.TOP_RIGHT;
97             }
98         }
99
100                             };
101
102         TipOrientation currentOrientation;
103
104         Boolean detachedMode;
105         Double[] detachedPosition;
106
107         /**
108          * Initializes the datatip, setup format, orientation and mark.
109          */
110         public Datatip() {
111         super();
112         displayComponents = "xy";
113         autoOrientation = true;
114         setOrientationAsEnum(TipOrientation.TOP_RIGHT);
115         tipTextFormat = new DecimalFormat("%g", DecimalFormatSymbols.getInstance(Locale.US));
116
117         detachedMode = false;
118         detachedPosition = new Double[] {0.0, 0.0, 0.0};
119
120         tipBoxMode = true;
121         tipLabelMode = true;
122         interpMode = true;
123         displayFnc = "";
124         ratio = 0.;
125         dataIndex = Integer.MIN_VALUE;
126         setVisible(true);
127         setBox(true);
128         setLineMode(true);
129         setLineStyle(3);
130         setFillMode(true);
131         setBackground(-2);
132         setClipStateAsEnum(ClipStateType.OFF);
133
134         setMarkMode(true);
135         setMarkSize(8);
136         setMarkBackground(-1);
137         setMarkForeground(-1);
138         setMarkStyle(11);
139     }
140
141     @Override
142     public void accept(Visitor visitor) {
143         visitor.visit(this);
144     }
145
146     /**
147      * Convert the property name to the DatatipObjectProperty enum.
148      */
149     public Object getPropertyFromName(int propertyName) {
150         switch (propertyName) {
151             case __GO_DATATIP_DATA__:
152                 return DatatipObjectProperty.TIP_DATA;
153             case __GO_DATATIP_BOX_MODE__:
154                 return DatatipObjectProperty.TIP_BOX_MODE;
155             case __GO_DATATIP_LABEL_MODE__:
156                 return DatatipObjectProperty.TIP_LABEL_MODE;
157             case __GO_DATATIP_ORIENTATION__:
158                 return DatatipObjectProperty.TIP_ORIENTATION;
159             case __GO_DATATIP_DISPLAY_COMPONENTS__:
160                 return DatatipObjectProperty.TIP_DISPLAY_COMPONENTS;
161             case __GO_DATATIP_AUTOORIENTATION__:
162                 return DatatipObjectProperty.TIP_AUTOORIENTATION;
163             case __GO_DATATIP_INTERP_MODE__:
164                 return DatatipObjectProperty.TIP_INTERP_MODE;
165             case __GO_DATATIP_DISPLAY_FNC__:
166                 return DatatipObjectProperty.TIP_DISPLAY_FNC;
167             case __GO_DATATIP_INDEXES__ :
168                 return DatatipObjectProperty.TIP_INDEXES;
169             case __GO_DATATIP_DETACHED_MODE__:
170                 return DatatipObjectProperty.TIP_DETACHED_MODE;
171             case __GO_DATATIP_DETACHED_POSITION__:
172                 return DatatipObjectProperty.TIP_DETACHED_POSITION;
173             default:
174                 return super.getPropertyFromName(propertyName);
175         }
176     }
177
178     /**
179      * @return the datatip property
180      */
181     public Object getProperty(Object property) {
182         if (property instanceof DatatipObjectProperty) {
183             switch ((DatatipObjectProperty) property) {
184                 case TIP_DATA:
185                     return getTipData();
186                 case TIP_BOX_MODE:
187                     return getTipBoxMode();
188                 case TIP_LABEL_MODE:
189                     return getTipLabelMode();
190                 case TIP_ORIENTATION:
191                     return getOrientation();
192                 case TIP_DISPLAY_COMPONENTS:
193                     return getDisplayComponents();
194                 case TIP_AUTOORIENTATION:
195                     return isAutoOrientationEnabled();
196                 case TIP_INTERP_MODE:
197                     return getInterpMode();
198                 case TIP_DISPLAY_FNC:
199                     return getDisplayFunction();
200                 case TIP_INDEXES:
201                     return getIndexes();
202                 case TIP_DETACHED_MODE:
203                     return getDetachedMode();
204                 case TIP_DETACHED_POSITION:
205                     return getDetachedPosition();
206             }
207         }
208
209         return super.getProperty(property);
210     }
211
212     /**
213      * Set the datatip property
214      * @param property the property
215      * @param value the new property value.
216      */
217     public UpdateStatus setProperty(Object property, Object value) {
218         if (property instanceof DatatipObjectProperty) {
219             switch ((DatatipObjectProperty) property) {
220                 case TIP_BOX_MODE:
221                     return setTipBoxMode((Boolean) value);
222                 case TIP_LABEL_MODE:
223                     return setTipLabelMode((Boolean) value);
224                 case TIP_ORIENTATION:
225                     return setOrientation((Integer) value);
226                 case TIP_DISPLAY_COMPONENTS:
227                     return setDisplayComponents((String) value);
228                 case TIP_AUTOORIENTATION:
229                     return setAutoOrientation((Boolean) value);
230                 case TIP_INTERP_MODE:
231                     return setInterpMode((Boolean) value);
232                 case TIP_DISPLAY_FNC:
233                     return setDisplayFunction((String) value);
234                 case TIP_INDEXES:
235                     return setIndexes((Double[]) value);
236                 case TIP_DETACHED_MODE:
237                     return setDetachedMode((Boolean)value);
238                 case TIP_DETACHED_POSITION:
239                     return setDetachedPosition((Double[])value);
240             }
241         }
242
243         return super.setProperty(property, value);
244     }
245
246     /**
247      * Calculate the current tip data based on the given array
248      * @param data the data array
249      * @return the tip data
250      */
251     private double calcTipData(final double[] data) {
252         if (data.length < dataIndex + 2) {
253             if (data.length >= 1) {
254                 return data[data.length - 1];
255             } else {
256                 return 0.0;
257             }
258         }
259
260         //get pt0 and pt1 from polyline data
261         final double pt0 = data[dataIndex];
262         final double pt1 = data[dataIndex + 1];
263
264         return pt0 + (pt1 - pt0) * ratio;
265     }
266
267     /**
268      * Get the current tip data X
269      * @return the tip data X
270      */
271     public double getTipDataX() {
272         final double[] dataX = (double[]) PolylineData.getDataX(getParent());
273         return calcTipData(dataX);
274     }
275
276     /**
277      * Get the current tip data Y
278      * @return the tip data Y
279      */
280     public double getTipDataY() {
281         final double[] dataY = (double[]) PolylineData.getDataY(getParent());
282         return calcTipData(dataY);
283     }
284
285     /**
286      * Get the current tip data Z
287      * @return the tip data Z
288      */
289     public double getTipDataZ() {
290         final double[] dataZ = (double[]) PolylineData.getDataZ(getParent());
291         return calcTipData(dataZ);
292     }
293
294     /**
295      * Get the current tip data
296      * @return the tip data
297      */
298     public Double[] getTipData() {
299         return new Double[] {getTipDataX(), getTipDataY(), getTipDataZ()};
300     }
301
302     /**
303      * Get the current textbox orientation as an integer
304      * @return current orientation.
305      */
306     public Integer getOrientation() {
307         return getOrientationAsEnum().ordinal();
308     }
309
310     /**
311      * Get the current oriantation as a enum
312      * @return the current orientation
313      */
314     public TipOrientation getOrientationAsEnum() {
315         return currentOrientation;
316     }
317
318     /**
319      * Set the current orientation (updating the text position)
320      * @param orientation the new orientation (integer).
321      */
322     public UpdateStatus setOrientation(Integer orientation) {
323         currentOrientation = TipOrientation.intToEnum(orientation);
324         return UpdateStatus.Success;
325     }
326
327     /**
328      * Set the current orientation (updating the text position)
329      * @param orientation the new orientation (TipOrientation enum).
330      */
331     public UpdateStatus setOrientationAsEnum(TipOrientation orientation) {
332         currentOrientation = orientation;
333         return UpdateStatus.Success;
334     }
335
336     /**
337      * Get which components should be displayed.
338      * @return the string containing the coordinates to display.
339      */
340     public String getDisplayComponents() {
341         return displayComponents;
342     }
343
344     /**
345      * Checks if a given string is valid for the display components
346      * @return true if it is valid, false otherwise.
347      */
348     private boolean isValidComponent(String value) {
349         if (value.length() < 1 || value.length() > 3) {
350             return false;
351         }
352
353         boolean isXSet = false;
354         boolean isYSet = false;
355         boolean isZSet = false;
356         for (int i = 0; i < value.length(); ++i) {
357             if (value.charAt(i) == 'x' && !isXSet) {
358                 isXSet = true;
359                 continue;
360             }
361             if (value.charAt(i) == 'y' && !isYSet) {
362                 isYSet = true;
363                 continue;
364             }
365             if (value.charAt(i) == 'z' && !isZSet) {
366                 isZSet = true;
367                 continue;
368             }
369             return false;
370         }
371         return true;
372     }
373
374     /**
375      * Set which components to display if @disp is valid.
376      * @param disp The string containing which components to display
377      */
378     public UpdateStatus setDisplayComponents(String disp) {
379         if (disp == null) {
380             return UpdateStatus.Fail;
381         }
382         disp = disp.toLowerCase();
383         if (!isValidComponent(disp)) {
384             return UpdateStatus.Fail;
385         }
386         displayComponents = disp;
387         updateText();
388         return UpdateStatus.Success;
389     }
390
391
392     public Boolean isAutoOrientationEnabled() {
393         return autoOrientation;
394     }
395
396     public UpdateStatus setAutoOrientation(Boolean status) {
397         autoOrientation = status;
398         return UpdateStatus.Success;
399     }
400
401     /**
402      * Get tip formated text for the given index
403      * @param index the component index
404      * @return the formated string
405      */
406     private String getComponentFormatedText(int index) {
407         switch (displayComponents.charAt(index)) {
408             case 'x':
409                 return "X:" + tipTextFormat.format(getTipDataX());
410             case 'y':
411                 return "Y:" + tipTextFormat.format(getTipDataY());
412             case 'z':
413                 return "Z:" + tipTextFormat.format(getTipDataZ());
414             default:
415                 return "";
416         }
417     }
418
419     /**
420      * Update the text from the datatip base on current tipData value.
421      */
422     public void updateText() {
423         //if display function is empty look in parent
424         //if parent is empty too use default print
425
426         String fnc = getDisplayFunction();
427         if (fnc == null || fnc.equals("")) {
428             //look in parent
429             fnc = (String) GraphicController.getController().getProperty(getParent(), GraphicObjectProperties.__GO_DATATIP_DISPLAY_FNC__);
430             if (fnc == null || fnc.equals("")) {
431                 int numCoords = displayComponents.length();
432                 String[] textArray = new String[numCoords];
433                 for (int i = 0; i < numCoords; ++i) {
434                     textArray[i] = getComponentFormatedText(i);
435                 }
436                 Integer[] dim = new Integer[2];
437                 dim[0] = numCoords;
438                 dim[1] = 1;
439                 setTextArrayDimensions(dim);
440                 setTextStrings(textArray);
441                 return;
442             }
443         }
444
445         String errMsg =  Messages.gettext("Wrong value for '%s' property: A valid function name expected.\n");
446         errMsg = errMsg.replace("'", "''");
447         errMsg = errMsg.replace("\n", "\\n");
448         String updateCommand = "try;" +
449                                "GDZa786XBSq7899SHKp=getcallbackobject(" + getIdentifier() + ");" +
450                                "set(GDZa786XBSq7899SHKp,\"text\"," + fnc + "(GDZa786XBSq7899SHKp));" +
451                                "clear(\"GDZa786XBSq7899SHKp\");" +
452                                "catch;" +
453                                "set(GDZa786XBSq7899SHKp,\"display_function\",\"\");" +
454                                "set(GDZa786XBSq7899SHKp.parent,\"display_function\",\"\");" +
455                                "clear(\"GDZa786XBSq7899SHKp\");" +
456                                "error(msprintf(\"" + errMsg + "\", \"display_function\"));" +
457                                "end;";
458         InterpreterManagement.requestScilabExec(updateCommand);
459     }
460
461     public Boolean getTipBoxMode() {
462         return tipBoxMode;
463     }
464
465     public Boolean getTipLabelMode() {
466         return tipLabelMode;
467     }
468
469     public Boolean getInterpMode() {
470         return interpMode;
471     }
472
473     public String getDisplayFunction() {
474         return displayFnc;
475     }
476
477     public UpdateStatus setTipBoxMode(Boolean mode) {
478         tipBoxMode = mode;
479         setBox(tipBoxMode);
480         return UpdateStatus.Success;
481     }
482
483     public UpdateStatus setTipLabelMode(Boolean mode) {
484         tipLabelMode = mode;
485         return UpdateStatus.Success;
486     }
487
488     public UpdateStatus setInterpMode(Boolean mode) {
489         interpMode = mode;
490         return UpdateStatus.Success;
491     }
492
493     public UpdateStatus setDisplayFunction(String fnc) {
494         displayFnc = fnc;
495         updateText();
496         return UpdateStatus.Success;
497     }
498
499     @Override
500     public Double[] getPosition() {
501         return getTipData();
502     }
503
504     public UpdateStatus setIndexes(Double[] value) {
505         if (value[0].intValue() != dataIndex || !value[1].equals(ratio)) {
506             dataIndex = value[0].intValue();
507             ratio = new Double(value[1]);
508             updateText();
509
510             return UpdateStatus.Success;
511         }
512
513         return UpdateStatus.NoChange;
514     }
515
516     public Integer getIndexes() {
517         return dataIndex;
518     }
519
520     /**
521      * @return detached mode
522      */
523     public Boolean getDetachedMode() {
524         return detachedMode;
525     }
526
527     /**
528      * Sets the detached mode, when true datatip position
529      * is given by detachedPosition.
530      * @param status true for enable detached mode
531      */
532     public UpdateStatus setDetachedMode(Boolean status) {
533         detachedMode = status;
534         return UpdateStatus.Success;
535     }
536
537     /**
538      * Position is only used when detachedMode is true.
539      * @return datatip detached position
540      */
541     public Double[] getDetachedPosition() {
542         return detachedPosition;
543     }
544
545     /**
546      * Sets the datatip detached position
547      * @param pos detached position
548      */
549     public UpdateStatus setDetachedPosition(Double[] pos) {
550         if (pos.length != 3) {
551             return UpdateStatus.Fail;
552         }
553         for (int i = 0; i < 3; ++i) {
554             detachedPosition[i] = pos[i];
555         }
556         return UpdateStatus.Success;
557     }
558
559     /**
560      * @return Type as String
561      */
562     public Integer getType() {
563         return GraphicObjectProperties.__GO_DATATIP__;
564     }
565 }