a9f9b828abfd807702b01f6ce37fafaed9ec8948
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / block / AfficheBlock.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
4  * Copyright (C) 2011-2015 - Scilab Enterprises - Clement DAVID
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 package org.scilab.modules.xcos.block;
17
18 import com.mxgraph.model.mxGeometry;
19 import java.awt.GraphicsEnvironment;
20 import java.awt.event.ActionEvent;
21 import java.awt.event.ActionListener;
22 import java.beans.PropertyChangeEvent;
23 import java.beans.PropertyChangeListener;
24 import java.io.Serializable;
25 import java.util.Formatter;
26 import java.util.Iterator;
27 import java.util.Locale;
28 import java.util.Map.Entry;
29 import java.util.TreeMap;
30 import java.util.logging.Logger;
31
32 import javax.swing.Timer;
33
34 import org.scilab.modules.graph.utils.ScilabExported;
35 import org.scilab.modules.graph.utils.StyleMap;
36 import org.scilab.modules.types.ScilabString;
37 import org.scilab.modules.xcos.JavaController;
38 import org.scilab.modules.xcos.Kind;
39
40 /**
41  * Implement the AFFICH_m block
42  */
43 public final class AfficheBlock extends BasicBlock {
44     /**
45      * Default refresh rate used on the simulation to update block.
46      */
47     private static final int DEFAULT_TIMER_RATE = 200;
48
49     private static final Logger LOG = Logger.getLogger(AfficheBlock.class.getName());
50     private static final String EXPRS = "exprs";
51     private static final int PRECISION_INDEX = 4;
52     private static final String NEW_LINE = System.getProperty("line.separator");
53     private static final String SPACE = "  ";
54
55     private static final TreeMap<String, String[][]> values = new TreeMap<String, String[][]>();
56     private static final UpdateValueListener updateAction = new UpdateValueListener();
57     private static final Timer printTimer = new Timer(DEFAULT_TIMER_RATE, updateAction);
58
59     /**
60      * Update the value of the associated block
61      */
62     @SuppressWarnings(value = { "serial" })
63     private static class UpdateValueListener implements ActionListener, Serializable {
64         /**
65          * Default constructor
66          */
67         public UpdateValueListener() {
68         }
69
70         /**
71          * Calculate an print the new String value.
72          *
73          * @param e
74          *            the current event
75          * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
76          */
77         @Override
78         public void actionPerformed(ActionEvent e) {
79             synchronized (values) {
80                 for (Iterator<Entry<String, String[][]>> it = values.entrySet().iterator(); it.hasNext();) {
81                     final Entry<String, String[][]> entry = it.next();
82
83                     update(entry.getKey(), entry.getValue());
84
85                     it.remove();
86                 }
87             }
88         }
89
90         /**
91          * Update and refresh the values
92          */
93         private void update(String uid, String[][] data) {
94             // FIXME re-implement this sheet
95             //            final Object cell = Xcos.getInstance().lookupForCell(new String[] { uid });
96             //            if (cell != null) {
97             //                final XcosDiagram diag = Xcos.findParent(cell);
98             //                final String value = getText(data);
99             //
100             //                diag.getModel().setValue(cell, value);
101             //
102             //                final mxCellState state = diag.getView().getState(cell);
103             //                if (state != null) {
104             //                    state.setLabel(value);
105             //                }
106             //
107             //                diag.getAsComponent().redraw(state);
108             //            }
109         }
110
111         /**
112          * Construct a String representation of the values.
113          */
114         private final String getText(final String[][] data) {
115             final StringBuilder blockResult = new StringBuilder();
116             final int iRows = data.length;
117             final int iCols = data[0].length;
118
119             for (int i = 0; i < iRows; i++) {
120                 for (int j = 0; j < iCols; j++) {
121                     if (iCols != 0) {
122                         blockResult.append(SPACE);
123                     }
124
125                     blockResult.append(data[i][j]);
126                 }
127                 blockResult.append(NEW_LINE);
128             }
129
130             return blockResult.toString();
131         }
132     }
133
134     /**
135      * Update the style according to the values of the expression
136      *
137      * @SuppressWarnings(value = { "serial" })
138      */
139     private static final class UpdateStyle implements PropertyChangeListener, Serializable {
140         /**
141          *
142          */
143         private static final String OPENING_BRACKET = "[";
144         private static transient UpdateStyle instance;
145
146         /**
147          * Default constructor.
148          */
149         private UpdateStyle() {
150         }
151
152         /**
153          * @return the instance
154          */
155         public static UpdateStyle getInstance() {
156             if (instance == null) {
157                 instance = new UpdateStyle();
158             }
159             return instance;
160         }
161
162         /**
163          * Update the style of the block according to the expression value
164          *
165          * @param evt
166          *            the evnt
167          * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
168          */
169         @Override
170         public void propertyChange(PropertyChangeEvent evt) {
171             // Pre-condition
172             final String property = evt.getPropertyName();
173             if (evt.getSource() == null || !property.equals(EXPRS)) {
174                 LOG.severe("Unable to update the style");
175             }
176
177             final AfficheBlock src = (AfficheBlock) evt.getSource();
178             final String[][] data = ((ScilabString) evt.getNewValue()).getData();
179
180             updateValue(src, data);
181             updateStyle(src, data);
182
183             /*
184              * Refresh
185              */
186             // FIXME
187             //            if (src.getParentDiagram() != null) {
188             //                final XcosDiagram parent = src.getParentDiagram();
189             //                final mxRectangle rect = parent.getPreferredSizeForCell(src);
190             //
191             //                parent.getModel().setGeometry(src, new mxGeometry(src.getGeometry().getX(), src.getGeometry().getY(), rect.getWidth(), rect.getHeight()));
192             //            }
193         }
194
195         /**
196          * Update the value according to the data (matrix size and precision)
197          *
198          * @param src
199          *            the src block
200          * @param data
201          *            the "exprs" data
202          */
203         private void updateValue(AfficheBlock src, String[][] data) {
204             /*
205              * Getting the first parameter for the matrix size
206              */
207             final int[] size;
208             int[] index = new int[] { 0, 0 };
209             final String data00 = data[index[0]][index[1]];
210             if (data00.startsWith(OPENING_BRACKET)) {
211                 final String[] strSize = data00.split("[\\[\\],]");
212                 try {
213                     size = new int[] { Integer.parseInt(strSize[1]), Integer.parseInt(strSize[2]) };
214                 } catch (NumberFormatException e) {
215                     LOG.severe(e.toString());
216                     return;
217                 }
218             } else {
219                 size = new int[] { 1, 1 };
220             }
221
222             index = new int[] { PRECISION_INDEX, 0 };
223             final String width = data[index[0]][index[1]];
224
225             //            AbstractElement.incrementIndexes(index, true);
226             final String rational = data[index[0]][index[1]];
227
228             final String format = "%" + width + "." + rational + "f";
229             final StringBuilder value = new StringBuilder();
230             for (int i = 0; i < size[0]; i++) {
231                 for (int j = 0; j < size[1]; j++) {
232                     value.append(new Formatter(Locale.US).format(format, Double.valueOf(0.0)).toString());
233                     value.append(SPACE);
234                 }
235                 value.append(NEW_LINE);
236             }
237
238             src.setValue(value.toString());
239         }
240
241         /**
242          * Update the style of the block according to the data.
243          *
244          * @param src
245          *            the block
246          * @param data
247          *            the "exprs" data
248          */
249         private void updateStyle(final AfficheBlock src, final String[][] data) {
250             /*
251              * Getting the first index to handle Affich_f and Affich_m
252              */
253             int[] index = new int[] { 0, 0 };
254             final String data00 = data[index[0]][index[1]];
255             //            if (data00.startsWith(OPENING_BRACKET)) {
256             //                AbstractElement.incrementIndexes(index, true);
257             //            }
258
259             /*
260              * Apply style
261              */
262             final StyleMap style = new StyleMap(src.getStyle());
263
264             //            try {
265             //                final int parsedFontInt = Integer.parseInt(data[index[0]][index[1]]);
266             //                style.put(mxConstants.STYLE_FONTFAMILY, Font.getFont(parsedFontInt).getName());
267             //
268             //                AbstractElement.incrementIndexes(index, true);
269             //                final int parsedFontSizeInt = Integer.parseInt(data[index[0]][index[1]]);
270             //                style.put(mxConstants.STYLE_FONTSIZE, Integer.toString(Font.getSize(parsedFontSizeInt)));
271             //
272             //                AbstractElement.incrementIndexes(index, true);
273             //                final int parsedFontColorInt = Integer.parseInt(data[index[0]][index[1]]);
274             //                String color = "#" + Integer.toHexString(Font.getColor(parsedFontColorInt).getRGB());
275             //                style.put(mxConstants.STYLE_FONTCOLOR, color);
276             //            } catch (NumberFormatException e) {
277             //                LOG.severe(e.toString());
278             //                return;
279             //            }
280
281             src.setStyle(style.toString());
282         }
283     }
284
285     public AfficheBlock(JavaController controller, long uid, Kind kind, Object value, mxGeometry geometry, String style, String id) {
286         super(controller, uid, kind, value, geometry, style, id);
287     }
288
289
290     /**
291      * Assign a value to an AfficheBlock instance
292      *
293      * @param uid
294      *            the block id
295      * @param value
296      *            the value to set.
297      */
298     @ScilabExported(module = "scicos_blocks", filename = "Blocks.giws.xml")
299     public static void setValue(final String uid, final String[][] value) {
300         if (value.length == 0 || value[0].length == 0) {
301             throw new IllegalArgumentException("value is not a non-empty String matrix (String[][])");
302         }
303
304         // update nothing in case of a headless env.
305         if (GraphicsEnvironment.isHeadless()) {
306             return;
307         }
308
309         synchronized (values) {
310             values.put(uid, value);
311
312             if (!printTimer.isRunning()) {
313                 printTimer.start();
314             }
315         }
316     }
317 }