]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.utils/src/org/simantics/utils/strings/format/MetricsFormat.java b/bundles/org.simantics.utils/src/org/simantics/utils/strings/format/MetricsFormat.java
new file mode 100644 (file)
index 0000000..c675f6d
--- /dev/null
@@ -0,0 +1,349 @@
+/*******************************************************************************\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