]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils/src/org/simantics/utils/strings/format/MetricsFormat.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.utils / src / org / simantics / utils / strings / format / MetricsFormat.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.utils.strings.format;\r
13 \r
14 import java.io.Serializable;\r
15 import java.text.DecimalFormat;\r
16 import java.util.IllegalFormatConversionException;\r
17 import java.util.IllegalFormatException;\r
18 \r
19 /**\r
20  * Value metrics data\r
21  * \r
22  * Use 'S' Prefix to use String formatting rules http://java.sun.com/javase/6/docs/api/java/util/Formatter.html#syntax\r
23  * Use 'D' Prefix to use DecimalFormat rules http://java.sun.com/javase/6/docs/api/java/text/DecimalFormat.html\r
24  * \r
25  * If no prefix is detected, String rules are used.\r
26  * \r
27  * @author Toni Kalajainen\r
28  * @Author Marko Luukkainen\r
29  */\r
30 public class MetricsFormat implements Serializable {\r
31 \r
32     /**\r
33      * Define serial version of this class\r
34      */\r
35     private static final long serialVersionUID = 8036591251300342995L;\r
36 \r
37     \r
38     /** Presentation format */\r
39     private String pattern;\r
40         \r
41     /** Presentation format */\r
42     private String internalPattern;\r
43     \r
44     /** Presentation format */\r
45     private String[] internalPatternDivided;   \r
46     \r
47     /** flag if format can adjust decimals */\r
48     private boolean canUseDecimals = false;\r
49         \r
50     /** scale */\r
51     private double scale;\r
52     \r
53     /** name */\r
54     private String name;\r
55     \r
56     /** hash */\r
57     private int hash;\r
58     \r
59     /** Is double or long */\r
60     private boolean isDouble = true;\r
61     \r
62     private boolean useDecimalFormat = false;\r
63     \r
64     /** Array reserved for formatter use */\r
65     private Object args[] = new Object[1];\r
66     \r
67     \r
68     public String getName() {\r
69         return name;\r
70     }\r
71 \r
72     public MetricsFormat(String pattern, double scale, String name)\r
73     throws IllegalArgumentException\r
74     {\r
75         this.scale  = scale;\r
76         pattern = setPattern(pattern);\r
77         this.internalPattern = formatPattern( pattern );\r
78         this.internalPatternDivided = formatPatternDivided( pattern );\r
79         this.name = name;\r
80         this.hash = makeHash();\r
81     }\r
82 \r
83     public MetricsFormat(String pattern, double scale) \r
84     throws IllegalArgumentException\r
85     {\r
86         this.scale  = scale;\r
87         pattern = setPattern(pattern);\r
88         this.internalPattern = formatPattern( pattern );\r
89         this.internalPatternDivided = formatPatternDivided( pattern );\r
90         this.name = "";\r
91         this.hash = makeHash();\r
92     }\r
93     \r
94     public MetricsFormat(String pattern) \r
95     throws IllegalArgumentException\r
96     {\r
97         this.scale  = 1.0f;\r
98         pattern = setPattern(pattern);\r
99         this.internalPattern = formatPattern( pattern );\r
100         this.internalPatternDivided = formatPatternDivided( pattern );\r
101         this.name = "";\r
102         this.hash = makeHash();\r
103         \r
104     }\r
105     \r
106     private String setPattern(String pattern) {\r
107         this.pattern = pattern;\r
108         if (pattern.startsWith("D")) {\r
109                 pattern = pattern.substring(1);\r
110                 useDecimalFormat = true;\r
111         } else {\r
112                 if (pattern.startsWith("S"))\r
113                         pattern = pattern.substring(1);\r
114                 useDecimalFormat = false;\r
115         }\r
116         return pattern;\r
117     }\r
118     \r
119     /**\r
120      * Replacs all % with %1$ unless % precedes with \ \r
121      * \r
122      * @param pattern\r
123      * @return\r
124      */\r
125     private String formatPattern(String pattern) {\r
126         int pos = 0;\r
127         if (!useDecimalFormat) {\r
128                 while ( (pos = pattern.indexOf('%', pos)) >= 0 ) {\r
129                 if (pos==0 || pattern.indexOf(pos-1)!='\\') {\r
130                     pattern = pattern.substring(0, pos+1) + "1$" + pattern.substring(pos+1, pattern.length());\r
131                     pos += 3;\r
132                     continue;\r
133                 }\r
134                 pos++;    \r
135             }\r
136         }\r
137                 \r
138         double value = 0;\r
139         if (useDecimalFormat) {\r
140                 isDouble = true;\r
141                 useDecimalFormat = true;\r
142                 canUseDecimals = false;\r
143                 DecimalFormat format = new DecimalFormat(pattern);\r
144                 format.format(value);\r
145             \r
146         } else {\r
147             try {\r
148                 isDouble = true;\r
149                 useDecimalFormat = false;\r
150                 args[0] = value;\r
151                 String.format(pattern, args);           \r
152             } catch(IllegalFormatConversionException e1) {\r
153                 try {\r
154                         isDouble = false;\r
155                         useDecimalFormat = false;\r
156                     args[0] = (long)value;\r
157                     String.format(pattern, args); \r
158                 } catch (Exception e2) {\r
159                         throw e1;\r
160                 }\r
161             }\r
162         }\r
163         \r
164         return pattern;\r
165     }\r
166     \r
167     /**\r
168      * Replacs all % with %1$ unless % precedes with \ \r
169      * \r
170      * Divides formatString into half so that\r
171      * formats precision can be adjusted with .(n)<br>\r
172      * Currently only format which supports adjustable\r
173      * decimals is f/F (floating point as decimal number)\r
174      * \r
175      * \r
176      * @param pattern\r
177      * @return\r
178      */\r
179     private String[] formatPatternDivided(String pattern) {\r
180         String divPattern[] = new String[]{"",""};\r
181         if (useDecimalFormat)\r
182                 return divPattern;\r
183         int pos = 0;\r
184         while ( (pos = pattern.indexOf('%', pos)) >= 0 ) {\r
185             if (pos==0 || pattern.indexOf(pos-1)!='\\') {\r
186                 divPattern[0] = pattern.substring(0, pos+1) + "1$";\r
187                 divPattern[1] =  pattern.substring(pos+1, pattern.length());\r
188                 // parse flags\r
189                 int pos2 = 0;\r
190                 while(true) {\r
191                     char c = divPattern[1].charAt(pos2);\r
192                     if (c == '-' ||\r
193                         c == '#' ||\r
194                         c == '+' ||\r
195                         c == ' ' ||\r
196                         c == '0' ||\r
197                         c == ',' ||\r
198                         c == '(' ||\r
199                         Character.isDigit(c))\r
200                         pos2++;\r
201                     else\r
202                         break;\r
203                 }\r
204                 // get rid of possible precisision setting\r
205                 // TODO : maybe we should let the user to set the precision\r
206                 // and then use user given precision instead of dynamic precision\r
207                 int pos3 = pos2;\r
208                 while(true) {\r
209                     char c = divPattern[1].charAt(pos3);\r
210                     if (c == '.' || Character.isDigit(c)) {\r
211                         pos3++;\r
212                     } else if (c == 'f'|| c == 'F') {\r
213                         this.canUseDecimals = true;\r
214                         break;\r
215                     } else {\r
216                         this.canUseDecimals = false;\r
217                         break;\r
218                     }\r
219                 }\r
220                 if (pos2 > 0 || pos3 > 0) {\r
221                     divPattern[0] += divPattern[1].substring(0,pos2);\r
222                     divPattern[1] = divPattern[1].substring(pos3, divPattern[1].length());\r
223                 }\r
224                 pos += 3;\r
225                 // divided patterns can have only one %\r
226                 break;\r
227             }\r
228             pos++;    \r
229         }\r
230                 \r
231         double value = 0;\r
232         try {\r
233             // checking if format can be used\r
234             args[0] = value;\r
235             String.format(divPattern[0] + ".2" + divPattern[1] , args);\r
236         } catch (IllegalFormatException e1) {\r
237             try {\r
238                 pattern = formatPattern(pattern);\r
239                 isDouble = false;\r
240                 args[0] = (long)value;\r
241                 String.format(pattern, args);  \r
242                 // if we get this far by not using decimals something strange has happened...\r
243                 divPattern[0] = null;\r
244                 divPattern[1] = null;\r
245                 canUseDecimals = false;\r
246             } catch(Exception e2) {\r
247                 throw e1;\r
248             }\r
249         }\r
250         \r
251         return divPattern;\r
252     }\r
253     \r
254     /**\r
255      * Formats value\r
256      * @param value\r
257      * @return\r
258      */\r
259     public String formatValue(double value) {\r
260         return _formatValue(internalPattern, value);\r
261     }\r
262     \r
263     /**\r
264      * Format value\r
265      * Note: cannot DecimalFormatter syntax does not work with this method\r
266      * @param value\r
267      * @param numDecimals\r
268      * @return\r
269      */\r
270     public String formatValue(double value, int numDecimals) {\r
271         if (canUseDecimals) {\r
272             if (numDecimals < 0) \r
273                 numDecimals = 0;\r
274             return _formatValue(value, numDecimals);\r
275         } else {\r
276             return _formatValue(internalPattern, value);\r
277         }\r
278     \r
279     }\r
280 \r
281 \r
282     private String _formatValue(String pattern, double value) {\r
283         //value *= scale;\r
284         if (!useDecimalFormat) {\r
285                 if (isDouble) {\r
286                         args[0] = value;\r
287                         return String.format(pattern, args);\r
288                 } else {\r
289                         args[0] = new Long((long)value);\r
290                         return String.format(pattern, args);                \r
291                 }\r
292         } else {\r
293                 DecimalFormat format = new DecimalFormat(pattern);\r
294                 return format.format(value);\r
295         }\r
296     }\r
297     \r
298     private String _formatValue(double value, int decimals) {\r
299         //value *= scale;\r
300         args[0] = value;\r
301         return String.format(internalPatternDivided[0] + "." + decimals + internalPatternDivided[1], args);\r
302              \r
303     }\r
304 \r
305     public String getPattern() {\r
306         return pattern;\r
307     }\r
308 \r
309     public double getScale() {\r
310         return scale;\r
311     }\r
312     \r
313     public String toString() {\r
314         return name;\r
315     }\r
316     \r
317    \r
318     \r
319     public boolean equals(Object obj) {\r
320         if (this == obj) return true;\r
321         if (obj == null) return false;\r
322         if (!(obj instanceof MetricsFormat)) return false;\r
323         MetricsFormat other = (MetricsFormat) obj;\r
324         if (other.hash!=hash) return false;\r
325         return other.pattern.equals(pattern) && other.scale==scale && other.name.equals(name);\r
326     }\r
327     \r
328     private int makeHash() {\r
329         long longBits = Double.doubleToLongBits(scale);\r
330         int scaleHash = ((int)longBits)^(int)(longBits<<16);\r
331         return pattern.hashCode() ^ scaleHash ^ name.hashCode();\r
332     }\r
333     \r
334     public int hashCode() {\r
335         return hash;\r
336     }\r
337 \r
338     /*\r
339     private void changeContent(MetricsFormat newContent) {\r
340         this.name = newContent.name;\r
341         this.pattern = newContent.pattern;\r
342         this.scale = newContent.scale;\r
343         this.internalPattern = newContent.internalPattern;\r
344         this.hash = newContent.hash;\r
345     }*/\r
346     \r
347      \r
348     \r
349 }\r