-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.utils.strings.format;\r
-\r
-import java.io.Serializable;\r
-import java.text.DecimalFormat;\r
-import java.util.IllegalFormatConversionException;\r
-import java.util.IllegalFormatException;\r
-\r
-/**\r
- * Value metrics data\r
- * \r
- * Use 'S' Prefix to use String formatting rules http://java.sun.com/javase/6/docs/api/java/util/Formatter.html#syntax\r
- * Use 'D' Prefix to use DecimalFormat rules http://java.sun.com/javase/6/docs/api/java/text/DecimalFormat.html\r
- * \r
- * If no prefix is detected, String rules are used.\r
- * \r
- * @author Toni Kalajainen\r
- * @Author Marko Luukkainen\r
- */\r
-public class MetricsFormat implements Serializable {\r
-\r
- /**\r
- * Define serial version of this class\r
- */\r
- private static final long serialVersionUID = 8036591251300342995L;\r
-\r
- \r
- /** Presentation format */\r
- private String pattern;\r
- \r
- /** Presentation format */\r
- private String internalPattern;\r
- \r
- /** Presentation format */\r
- private String[] internalPatternDivided; \r
- \r
- /** flag if format can adjust decimals */\r
- private boolean canUseDecimals = false;\r
- \r
- /** scale */\r
- private double scale;\r
- \r
- /** name */\r
- private String name;\r
- \r
- /** hash */\r
- private int hash;\r
- \r
- /** Is double or long */\r
- private boolean isDouble = true;\r
- \r
- private boolean useDecimalFormat = false;\r
- \r
- /** Array reserved for formatter use */\r
- private Object args[] = new Object[1];\r
- \r
- \r
- public String getName() {\r
- return name;\r
- }\r
-\r
- public MetricsFormat(String pattern, double scale, String name)\r
- throws IllegalArgumentException\r
- {\r
- this.scale = scale;\r
- pattern = setPattern(pattern);\r
- this.internalPattern = formatPattern( pattern );\r
- this.internalPatternDivided = formatPatternDivided( pattern );\r
- this.name = name;\r
- this.hash = makeHash();\r
- }\r
-\r
- public MetricsFormat(String pattern, double scale) \r
- throws IllegalArgumentException\r
- {\r
- this.scale = scale;\r
- pattern = setPattern(pattern);\r
- this.internalPattern = formatPattern( pattern );\r
- this.internalPatternDivided = formatPatternDivided( pattern );\r
- this.name = "";\r
- this.hash = makeHash();\r
- }\r
- \r
- public MetricsFormat(String pattern) \r
- throws IllegalArgumentException\r
- {\r
- this.scale = 1.0f;\r
- pattern = setPattern(pattern);\r
- this.internalPattern = formatPattern( pattern );\r
- this.internalPatternDivided = formatPatternDivided( pattern );\r
- this.name = "";\r
- this.hash = makeHash();\r
- \r
- }\r
- \r
- private String setPattern(String pattern) {\r
- this.pattern = pattern;\r
- if (pattern.startsWith("D")) {\r
- pattern = pattern.substring(1);\r
- useDecimalFormat = true;\r
- } else {\r
- if (pattern.startsWith("S"))\r
- pattern = pattern.substring(1);\r
- useDecimalFormat = false;\r
- }\r
- return pattern;\r
- }\r
- \r
- /**\r
- * Replacs all % with %1$ unless % precedes with \ \r
- * \r
- * @param pattern\r
- * @return\r
- */\r
- private String formatPattern(String pattern) {\r
- int pos = 0;\r
- if (!useDecimalFormat) {\r
- while ( (pos = pattern.indexOf('%', pos)) >= 0 ) {\r
- if (pos==0 || pattern.indexOf(pos-1)!='\\') {\r
- pattern = pattern.substring(0, pos+1) + "1$" + pattern.substring(pos+1, pattern.length());\r
- pos += 3;\r
- continue;\r
- }\r
- pos++; \r
- }\r
- }\r
- \r
- double value = 0;\r
- if (useDecimalFormat) {\r
- isDouble = true;\r
- useDecimalFormat = true;\r
- canUseDecimals = false;\r
- DecimalFormat format = new DecimalFormat(pattern);\r
- format.format(value);\r
- \r
- } else {\r
- try {\r
- isDouble = true;\r
- useDecimalFormat = false;\r
- args[0] = value;\r
- String.format(pattern, args); \r
- } catch(IllegalFormatConversionException e1) {\r
- try {\r
- isDouble = false;\r
- useDecimalFormat = false;\r
- args[0] = (long)value;\r
- String.format(pattern, args); \r
- } catch (Exception e2) {\r
- throw e1;\r
- }\r
- }\r
- }\r
- \r
- return pattern;\r
- }\r
- \r
- /**\r
- * Replacs all % with %1$ unless % precedes with \ \r
- * \r
- * Divides formatString into half so that\r
- * formats precision can be adjusted with .(n)<br>\r
- * Currently only format which supports adjustable\r
- * decimals is f/F (floating point as decimal number)\r
- * \r
- * \r
- * @param pattern\r
- * @return\r
- */\r
- private String[] formatPatternDivided(String pattern) {\r
- String divPattern[] = new String[]{"",""};\r
- if (useDecimalFormat)\r
- return divPattern;\r
- int pos = 0;\r
- while ( (pos = pattern.indexOf('%', pos)) >= 0 ) {\r
- if (pos==0 || pattern.indexOf(pos-1)!='\\') {\r
- divPattern[0] = pattern.substring(0, pos+1) + "1$";\r
- divPattern[1] = pattern.substring(pos+1, pattern.length());\r
- // parse flags\r
- int pos2 = 0;\r
- while(true) {\r
- char c = divPattern[1].charAt(pos2);\r
- if (c == '-' ||\r
- c == '#' ||\r
- c == '+' ||\r
- c == ' ' ||\r
- c == '0' ||\r
- c == ',' ||\r
- c == '(' ||\r
- Character.isDigit(c))\r
- pos2++;\r
- else\r
- break;\r
- }\r
- // get rid of possible precisision setting\r
- // TODO : maybe we should let the user to set the precision\r
- // and then use user given precision instead of dynamic precision\r
- int pos3 = pos2;\r
- while(true) {\r
- char c = divPattern[1].charAt(pos3);\r
- if (c == '.' || Character.isDigit(c)) {\r
- pos3++;\r
- } else if (c == 'f'|| c == 'F') {\r
- this.canUseDecimals = true;\r
- break;\r
- } else {\r
- this.canUseDecimals = false;\r
- break;\r
- }\r
- }\r
- if (pos2 > 0 || pos3 > 0) {\r
- divPattern[0] += divPattern[1].substring(0,pos2);\r
- divPattern[1] = divPattern[1].substring(pos3, divPattern[1].length());\r
- }\r
- pos += 3;\r
- // divided patterns can have only one %\r
- break;\r
- }\r
- pos++; \r
- }\r
- \r
- double value = 0;\r
- try {\r
- // checking if format can be used\r
- args[0] = value;\r
- String.format(divPattern[0] + ".2" + divPattern[1] , args);\r
- } catch (IllegalFormatException e1) {\r
- try {\r
- pattern = formatPattern(pattern);\r
- isDouble = false;\r
- args[0] = (long)value;\r
- String.format(pattern, args); \r
- // if we get this far by not using decimals something strange has happened...\r
- divPattern[0] = null;\r
- divPattern[1] = null;\r
- canUseDecimals = false;\r
- } catch(Exception e2) {\r
- throw e1;\r
- }\r
- }\r
- \r
- return divPattern;\r
- }\r
- \r
- /**\r
- * Formats value\r
- * @param value\r
- * @return\r
- */\r
- public String formatValue(double value) {\r
- return _formatValue(internalPattern, value);\r
- }\r
- \r
- /**\r
- * Format value\r
- * Note: cannot DecimalFormatter syntax does not work with this method\r
- * @param value\r
- * @param numDecimals\r
- * @return\r
- */\r
- public String formatValue(double value, int numDecimals) {\r
- if (canUseDecimals) {\r
- if (numDecimals < 0) \r
- numDecimals = 0;\r
- return _formatValue(value, numDecimals);\r
- } else {\r
- return _formatValue(internalPattern, value);\r
- }\r
- \r
- }\r
-\r
-\r
- private String _formatValue(String pattern, double value) {\r
- //value *= scale;\r
- if (!useDecimalFormat) {\r
- if (isDouble) {\r
- args[0] = value;\r
- return String.format(pattern, args);\r
- } else {\r
- args[0] = new Long((long)value);\r
- return String.format(pattern, args); \r
- }\r
- } else {\r
- DecimalFormat format = new DecimalFormat(pattern);\r
- return format.format(value);\r
- }\r
- }\r
- \r
- private String _formatValue(double value, int decimals) {\r
- //value *= scale;\r
- args[0] = value;\r
- return String.format(internalPatternDivided[0] + "." + decimals + internalPatternDivided[1], args);\r
- \r
- }\r
-\r
- public String getPattern() {\r
- return pattern;\r
- }\r
-\r
- public double getScale() {\r
- return scale;\r
- }\r
- \r
- public String toString() {\r
- return name;\r
- }\r
- \r
- \r
- \r
- public boolean equals(Object obj) {\r
- if (this == obj) return true;\r
- if (obj == null) return false;\r
- if (!(obj instanceof MetricsFormat)) return false;\r
- MetricsFormat other = (MetricsFormat) obj;\r
- if (other.hash!=hash) return false;\r
- return other.pattern.equals(pattern) && other.scale==scale && other.name.equals(name);\r
- }\r
- \r
- private int makeHash() {\r
- long longBits = Double.doubleToLongBits(scale);\r
- int scaleHash = ((int)longBits)^(int)(longBits<<16);\r
- return pattern.hashCode() ^ scaleHash ^ name.hashCode();\r
- }\r
- \r
- public int hashCode() {\r
- return hash;\r
- }\r
-\r
- /*\r
- private void changeContent(MetricsFormat newContent) {\r
- this.name = newContent.name;\r
- this.pattern = newContent.pattern;\r
- this.scale = newContent.scale;\r
- this.internalPattern = newContent.internalPattern;\r
- this.hash = newContent.hash;\r
- }*/\r
- \r
- \r
- \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.utils.strings.format;
+
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.util.IllegalFormatConversionException;
+import java.util.IllegalFormatException;
+
+/**
+ * Value metrics data
+ *
+ * Use 'S' Prefix to use String formatting rules http://java.sun.com/javase/6/docs/api/java/util/Formatter.html#syntax
+ * Use 'D' Prefix to use DecimalFormat rules http://java.sun.com/javase/6/docs/api/java/text/DecimalFormat.html
+ *
+ * If no prefix is detected, String rules are used.
+ *
+ * @author Toni Kalajainen
+ * @Author Marko Luukkainen
+ */
+public class MetricsFormat implements Serializable {
+
+ /**
+ * Define serial version of this class
+ */
+ private static final long serialVersionUID = 8036591251300342995L;
+
+
+ /** Presentation format */
+ private String pattern;
+
+ /** Presentation format */
+ private String internalPattern;
+
+ /** Presentation format */
+ private String[] internalPatternDivided;
+
+ /** flag if format can adjust decimals */
+ private boolean canUseDecimals = false;
+
+ /** scale */
+ private double scale;
+
+ /** name */
+ private String name;
+
+ /** hash */
+ private int hash;
+
+ /** Is double or long */
+ private boolean isDouble = true;
+
+ private boolean useDecimalFormat = false;
+
+ /** Array reserved for formatter use */
+ private Object args[] = new Object[1];
+
+
+ public String getName() {
+ return name;
+ }
+
+ public MetricsFormat(String pattern, double scale, String name)
+ throws IllegalArgumentException
+ {
+ this.scale = scale;
+ pattern = setPattern(pattern);
+ this.internalPattern = formatPattern( pattern );
+ this.internalPatternDivided = formatPatternDivided( pattern );
+ this.name = name;
+ this.hash = makeHash();
+ }
+
+ public MetricsFormat(String pattern, double scale)
+ throws IllegalArgumentException
+ {
+ this.scale = scale;
+ pattern = setPattern(pattern);
+ this.internalPattern = formatPattern( pattern );
+ this.internalPatternDivided = formatPatternDivided( pattern );
+ this.name = "";
+ this.hash = makeHash();
+ }
+
+ public MetricsFormat(String pattern)
+ throws IllegalArgumentException
+ {
+ this.scale = 1.0f;
+ pattern = setPattern(pattern);
+ this.internalPattern = formatPattern( pattern );
+ this.internalPatternDivided = formatPatternDivided( pattern );
+ this.name = "";
+ this.hash = makeHash();
+
+ }
+
+ private String setPattern(String pattern) {
+ this.pattern = pattern;
+ if (pattern.startsWith("D")) {
+ pattern = pattern.substring(1);
+ useDecimalFormat = true;
+ } else {
+ if (pattern.startsWith("S"))
+ pattern = pattern.substring(1);
+ useDecimalFormat = false;
+ }
+ return pattern;
+ }
+
+ /**
+ * Replacs all % with %1$ unless % precedes with \
+ *
+ * @param pattern
+ * @return
+ */
+ private String formatPattern(String pattern) {
+ int pos = 0;
+ if (!useDecimalFormat) {
+ while ( (pos = pattern.indexOf('%', pos)) >= 0 ) {
+ if (pos==0 || pattern.indexOf(pos-1)!='\\') {
+ pattern = pattern.substring(0, pos+1) + "1$" + pattern.substring(pos+1, pattern.length());
+ pos += 3;
+ continue;
+ }
+ pos++;
+ }
+ }
+
+ double value = 0;
+ if (useDecimalFormat) {
+ isDouble = true;
+ useDecimalFormat = true;
+ canUseDecimals = false;
+ DecimalFormat format = new DecimalFormat(pattern);
+ format.format(value);
+
+ } else {
+ try {
+ isDouble = true;
+ useDecimalFormat = false;
+ args[0] = value;
+ String.format(pattern, args);
+ } catch(IllegalFormatConversionException e1) {
+ try {
+ isDouble = false;
+ useDecimalFormat = false;
+ args[0] = (long)value;
+ String.format(pattern, args);
+ } catch (Exception e2) {
+ throw e1;
+ }
+ }
+ }
+
+ return pattern;
+ }
+
+ /**
+ * Replacs all % with %1$ unless % precedes with \
+ *
+ * Divides formatString into half so that
+ * formats precision can be adjusted with .(n)<br>
+ * Currently only format which supports adjustable
+ * decimals is f/F (floating point as decimal number)
+ *
+ *
+ * @param pattern
+ * @return
+ */
+ private String[] formatPatternDivided(String pattern) {
+ String divPattern[] = new String[]{"",""};
+ if (useDecimalFormat)
+ return divPattern;
+ int pos = 0;
+ while ( (pos = pattern.indexOf('%', pos)) >= 0 ) {
+ if (pos==0 || pattern.indexOf(pos-1)!='\\') {
+ divPattern[0] = pattern.substring(0, pos+1) + "1$";
+ divPattern[1] = pattern.substring(pos+1, pattern.length());
+ // parse flags
+ int pos2 = 0;
+ while(true) {
+ char c = divPattern[1].charAt(pos2);
+ if (c == '-' ||
+ c == '#' ||
+ c == '+' ||
+ c == ' ' ||
+ c == '0' ||
+ c == ',' ||
+ c == '(' ||
+ Character.isDigit(c))
+ pos2++;
+ else
+ break;
+ }
+ // get rid of possible precisision setting
+ // TODO : maybe we should let the user to set the precision
+ // and then use user given precision instead of dynamic precision
+ int pos3 = pos2;
+ while(true) {
+ char c = divPattern[1].charAt(pos3);
+ if (c == '.' || Character.isDigit(c)) {
+ pos3++;
+ } else if (c == 'f'|| c == 'F') {
+ this.canUseDecimals = true;
+ break;
+ } else {
+ this.canUseDecimals = false;
+ break;
+ }
+ }
+ if (pos2 > 0 || pos3 > 0) {
+ divPattern[0] += divPattern[1].substring(0,pos2);
+ divPattern[1] = divPattern[1].substring(pos3, divPattern[1].length());
+ }
+ pos += 3;
+ // divided patterns can have only one %
+ break;
+ }
+ pos++;
+ }
+
+ double value = 0;
+ try {
+ // checking if format can be used
+ args[0] = value;
+ String.format(divPattern[0] + ".2" + divPattern[1] , args);
+ } catch (IllegalFormatException e1) {
+ try {
+ pattern = formatPattern(pattern);
+ isDouble = false;
+ args[0] = (long)value;
+ String.format(pattern, args);
+ // if we get this far by not using decimals something strange has happened...
+ divPattern[0] = null;
+ divPattern[1] = null;
+ canUseDecimals = false;
+ } catch(Exception e2) {
+ throw e1;
+ }
+ }
+
+ return divPattern;
+ }
+
+ /**
+ * Formats value
+ * @param value
+ * @return
+ */
+ public String formatValue(double value) {
+ return _formatValue(internalPattern, value);
+ }
+
+ /**
+ * Format value
+ * Note: cannot DecimalFormatter syntax does not work with this method
+ * @param value
+ * @param numDecimals
+ * @return
+ */
+ public String formatValue(double value, int numDecimals) {
+ if (canUseDecimals) {
+ if (numDecimals < 0)
+ numDecimals = 0;
+ return _formatValue(value, numDecimals);
+ } else {
+ return _formatValue(internalPattern, value);
+ }
+
+ }
+
+
+ private String _formatValue(String pattern, double value) {
+ //value *= scale;
+ if (!useDecimalFormat) {
+ if (isDouble) {
+ args[0] = value;
+ return String.format(pattern, args);
+ } else {
+ args[0] = new Long((long)value);
+ return String.format(pattern, args);
+ }
+ } else {
+ DecimalFormat format = new DecimalFormat(pattern);
+ return format.format(value);
+ }
+ }
+
+ private String _formatValue(double value, int decimals) {
+ //value *= scale;
+ args[0] = value;
+ return String.format(internalPatternDivided[0] + "." + decimals + internalPatternDivided[1], args);
+
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ public double getScale() {
+ return scale;
+ }
+
+ public String toString() {
+ return name;
+ }
+
+
+
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (!(obj instanceof MetricsFormat)) return false;
+ MetricsFormat other = (MetricsFormat) obj;
+ if (other.hash!=hash) return false;
+ return other.pattern.equals(pattern) && other.scale==scale && other.name.equals(name);
+ }
+
+ private int makeHash() {
+ long longBits = Double.doubleToLongBits(scale);
+ int scaleHash = ((int)longBits)^(int)(longBits<<16);
+ return pattern.hashCode() ^ scaleHash ^ name.hashCode();
+ }
+
+ public int hashCode() {
+ return hash;
+ }
+
+ /*
+ private void changeContent(MetricsFormat newContent) {
+ this.name = newContent.name;
+ this.pattern = newContent.pattern;
+ this.scale = newContent.scale;
+ this.internalPattern = newContent.internalPattern;
+ this.hash = newContent.hash;
+ }*/
+
+
+
+}