analysis.lami: correctly handle Number (double, long etc.) type graphing
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Tue, 10 May 2016 22:42:14 +0000 (18:42 -0400)
committerAlexandre Montplaisir <alexmonthy@efficios.com>
Tue, 31 May 2016 22:54:05 +0000 (18:54 -0400)
LTTng analysis return mostly long values either for the time stamps or
actual measurements. SWTChart, on the other hand, deals only with
"double" numerical values. Casting long to double causes a loss of
precision for big long value (e.g time stamps).

E.g: Loss of precision occurs when time ranges with a big minimal value
(2^62) but with little delta (1 ns) between events exist. Graphs
generated from such time ranges as an axis would result in a single dot
which is a clear problem.

The presented solution uses linear mapping to preserve resolution and
precision when possible.

The linear mapping requires two ranges: the internal range and the
external range.

Each graph is responsible to provide an internal LamiGraphRange. This
range is the internal representation in double in which all raw
(external) value are to be mapped. For now the default internal range is
0 to 1.

The external range [raw values range] is generated by finding the
minimal value and maximal values of aspects to be plotted.

Each point is then mapped to a corresponding value from the internal
range:

eV = external value
eR = external range
iV = internal value
iR = internal range

iV = (( eV - eR.minimum ) * ( iR.delta / eR.delta )) + iR.minimum

Since the default internal range is from 0 to 1 all raw values are
mapped to a value from 0 to 1.

On graph tick generation axis formatter transforms internal
representation to external representation and formats the result.

Other change:
- Aspects now return their numerical values via resolveNumber to ensure
  no casting is done.
- Move axis formatter to ui plugin.

Bug: 493941

Change-Id: I289180e10a7f1cbf6ecdd1beba93549b8fbe4c23
Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Alexandre Montplaisir <alexmonthy@efficios.com>
Reviewed-on: https://git.eclipse.org/r/73239
Reviewed-by: Patrick Tasse <patrick.tasse@gmail.com>
Tested-by: Patrick Tasse <patrick.tasse@gmail.com>
Reviewed-by: Hudson CI
28 files changed:
analysis/org.eclipse.tracecompass.analysis.lami.core.tests/src/org/eclipse/tracecompass/analysis/lami/core/tests/LamiJsonParserTest.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiDurationAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiEmptyAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiGenericAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiIRQNameAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiIRQNumberAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiIRQTypeAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiMixedAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiProcessNameAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiProcessPIDAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiProcessTIDAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiTableEntryAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiTimeRangeBeginAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiTimeRangeDurationAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiTimeRangeEndAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/aspect/LamiTimestampAspect.java
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiLabelFormat.java [deleted file]
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiTimeStampFormat.java [deleted file]
analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/types/LamiIRQ.java
analysis/org.eclipse.tracecompass.analysis.lami.ui/META-INF/MANIFEST.MF
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/LamiDecimalUnitFormat.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/LamiLabelFormat.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/LamiTimeStampFormat.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/package-info.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/viewers/LamiBarChartViewer.java
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/viewers/LamiGraphRange.java [new file with mode: 0644]
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/viewers/LamiScatterViewer.java
analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/viewers/LamiXYChartViewer.java

index 0f50cd5e281db83e0a43f75f8ba3e51185425cc2..577aeb0c35cbfe665a201ae3a2dc075b1a25cac6 100644 (file)
@@ -201,12 +201,12 @@ public class LamiJsonParserTest {
         List<LamiTableEntryAspect> aspects = perSyscallClass.getAspects();
 
         assertEquals("read()", aspects.get(0).resolveString(readEntry));
-        assertEquals(2398123.0, checkNotNull(aspects.get(1).resolveDouble(readEntry)).doubleValue(), DELTA);
-        assertEquals(8123982.0, checkNotNull(aspects.get(2).resolveDouble(readEntry)).doubleValue(), DELTA);
-        assertEquals(223232.0, checkNotNull(aspects.get(3).resolveDouble(readEntry)).doubleValue(), DELTA);
-        assertEquals(98233.0, checkNotNull(aspects.get(4).resolveDouble(readEntry)).doubleValue(), DELTA);
-        assertEquals(1293828.0, checkNotNull(aspects.get(5).resolveDouble(readEntry)).doubleValue(), DELTA);
-        assertEquals(1195595.0, checkNotNull(aspects.get(6).resolveDouble(readEntry)).doubleValue(), DELTA);
+        assertEquals(2398123.0, checkNotNull(aspects.get(1).resolveNumber(readEntry)).doubleValue(), DELTA);
+        assertEquals(8123982.0, checkNotNull(aspects.get(2).resolveNumber(readEntry)).doubleValue(), DELTA);
+        assertEquals(223232.0, checkNotNull(aspects.get(3).resolveNumber(readEntry)).doubleValue(), DELTA);
+        assertEquals(98233.0, checkNotNull(aspects.get(4).resolveNumber(readEntry)).doubleValue(), DELTA);
+        assertEquals(1293828.0, checkNotNull(aspects.get(5).resolveNumber(readEntry)).doubleValue(), DELTA);
+        assertEquals(1195595.0, checkNotNull(aspects.get(6).resolveNumber(readEntry)).doubleValue(), DELTA);
         assertNull(aspects.get(7).resolveString(readEntry));
     }
 
index 069b8f7b5e9c07b7a4fa00bbf7d5583fa3bf04d0..bfdf3261d9c5c65108ff201e124d627f7d012834 100644 (file)
@@ -65,11 +65,11 @@ public class LamiDurationAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(@NonNull LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(@NonNull LamiTableEntry entry) {
         LamiData data = entry.getValue(fColIndex);
         if (data instanceof LamiDuration) {
             LamiDuration range = (LamiDuration) data;
-            return Double.valueOf(range.getValue());
+            return range.getValue();
         }
         return null;
     }
@@ -77,13 +77,21 @@ public class LamiDurationAspect extends LamiTableEntryAspect {
     @Override
     public @NonNull Comparator<@NonNull LamiTableEntry> getComparator() {
         return (o1, o2) -> {
-            Double dO1 = resolveDouble(o1);
-            Double dO2 = resolveDouble(o2);
-            if (dO1 == null || dO2 == null) {
+            Number d1 = resolveNumber(o1);
+            Number d2 = resolveNumber(o2);
+
+            if (d1 == null && d2 == null) {
                 return 0;
             }
+            if (d1 == null) {
+                return 1;
+            }
+
+            if (d2 == null) {
+                return -1;
+            }
 
-            return dO1.compareTo(dO2);
+            return Long.compare(d1.longValue(), d2.longValue());
         };
     }
 
index 49004a71773664f3559de16c8c83d362f22fd885..444df6d87c2886cd1e83ca68238620d4a6b65b27 100644 (file)
@@ -46,7 +46,7 @@ public class LamiEmptyAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(@NonNull LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(@NonNull LamiTableEntry entry) {
         return null;
     }
 
index 075bdccb08fe8c184454fbc6e172c32b25ef847b..d1db60823b03623dffbf14b4e57d3215678edd9a 100644 (file)
@@ -63,7 +63,7 @@ public class LamiGenericAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(@NonNull LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(@NonNull LamiTableEntry entry) {
         if (fIsContinuous) {
             try {
                 if (entry.getValue(fColIndex).toString() != null) {
@@ -80,13 +80,21 @@ public class LamiGenericAspect extends LamiTableEntryAspect {
     public Comparator<LamiTableEntry> getComparator() {
         if (isContinuous()) {
             return (o1, o2) -> {
-                Double dO1 = resolveDouble(o1);
-                Double dO2 = resolveDouble(o2);
-                if (dO1 == null || dO2 == null) {
+                Number d1 = resolveNumber(o1);
+                Number d2 = resolveNumber(o2);
+
+                if (d1 == null && d2 == null) {
                     return 0;
                 }
+                if (d1 == null) {
+                    return 1;
+                }
+
+                if (d2 == null) {
+                    return -1;
+                }
 
-                return dO1.compareTo(dO2);
+                return Double.compare(d1.doubleValue(), d2.doubleValue());
             };
         }
 
@@ -95,9 +103,16 @@ public class LamiGenericAspect extends LamiTableEntryAspect {
             String s1 = resolveString(o1);
             String s2 = resolveString(o2);
 
-            if (s1 == null || s2 == null) {
+            if (s1 == null && s2 == null) {
                 return 0;
             }
+            if (s1 == null) {
+                return 1;
+            }
+
+            if (s2 == null) {
+                return -1;
+            }
 
             return s1.compareTo(s2);
         };
index f4dc2016c8f58a789334e9a7ee5d8a15e1283ba3..7a470efe13c2ace3332c547bd7d51be438fa9d40 100644 (file)
@@ -62,7 +62,7 @@ public class LamiIRQNameAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(LamiTableEntry entry) {
         return null;
     }
 
@@ -72,9 +72,16 @@ public class LamiIRQNameAspect extends LamiTableEntryAspect {
             String s1 = resolveString(o1);
             String s2 = resolveString(o2);
 
-            if (s1 == null || s2 == null) {
+            if (s1 == null && s2 == null) {
                 return 0;
             }
+            if (s1 == null) {
+                return 1;
+            }
+
+            if (s2 == null) {
+                return -1;
+            }
 
             return s1.compareTo(s2);
         };
index 81da9b361d7b936959def4b75b9d081a4c804747..88a97991067a50cc2a41ae63335a7b216631d1a3 100644 (file)
@@ -61,10 +61,10 @@ public class LamiIRQNumberAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(LamiTableEntry entry) {
         LamiData data = entry.getValue(fColIndex);
         if (data instanceof LamiIRQ) {
-            return Double.valueOf(((LamiIRQ) data).getNumber());
+            return (((LamiIRQ) data).getNumber());
         }
 
         return null;
@@ -73,13 +73,21 @@ public class LamiIRQNumberAspect extends LamiTableEntryAspect {
     @Override
     public Comparator<LamiTableEntry> getComparator() {
         return (o1, o2) -> {
-            Double dO1 = resolveDouble(o1);
-            Double dO2 = resolveDouble(o2);
-            if (dO1 == null || dO2 == null) {
+            Number d1 = resolveNumber(o1);
+            Number d2 = resolveNumber(o2);
+
+            if (d1 == null && d2 == null) {
                 return 0;
             }
+            if (d1 == null) {
+                return 1;
+            }
+
+            if (d2 == null) {
+                return -1;
+            }
 
-            return dO1.compareTo(dO2);
+            return Integer.compare(d1.intValue(), d2.intValue());
         };
     }
 
index dbd6fcb63ff2935cc3b5db2cc0904e72efcfd25f..375e7ee600e8862013d3be55f61d9c708c5bc5f5 100644 (file)
@@ -70,7 +70,7 @@ public class LamiIRQTypeAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(LamiTableEntry entry) {
         return null;
     }
 
@@ -80,9 +80,16 @@ public class LamiIRQTypeAspect extends LamiTableEntryAspect {
             String s1 = resolveString(o1);
             String s2 = resolveString(o2);
 
-            if (s1 == null || s2 == null) {
+            if (s1 == null && s2 == null) {
                 return 0;
             }
+            if (s1 == null) {
+                return 1;
+            }
+
+            if (s2 == null) {
+                return -1;
+            }
 
             return s1.compareTo(s2);
         };
index 07b745b31ded5b480b8672b97c4fb9dd5fdc4e45..ed61b96084810b8552340489306e3c22b95d691a 100644 (file)
@@ -71,7 +71,7 @@ public class LamiMixedAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(LamiTableEntry entry) {
         return null;
     }
 
@@ -81,9 +81,16 @@ public class LamiMixedAspect extends LamiTableEntryAspect {
             String s1 = resolveString(o1);
             String s2 = resolveString(o2);
 
-            if (s1 == null || s2 == null) {
+            if (s1 == null && s2 == null) {
                 return 0;
             }
+            if (s1 == null) {
+                return 1;
+            }
+
+            if (s2 == null) {
+                return -1;
+            }
 
             return s1.compareTo(s2);
         };
index c9278b31110bd32423b82b6e5d3653b0114319c5..0335a41b16edb36a11354466fe584997e766013d 100644 (file)
@@ -59,7 +59,7 @@ public class LamiProcessNameAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(LamiTableEntry entry) {
         return null;
     }
 
@@ -69,9 +69,16 @@ public class LamiProcessNameAspect extends LamiTableEntryAspect {
             String s1 = resolveString(o1);
             String s2 = resolveString(o2);
 
-            if (s1 == null || s2 == null) {
+            if (s1 == null && s2 == null) {
                 return 0;
             }
+            if (s1 == null) {
+                return 1;
+            }
+
+            if (s2 == null) {
+                return -1;
+            }
 
             return s1.compareTo(s2);
         };
index b242fa5400f0fbfafc61763b93b19579cd6f944e..1b8d0e737c1ad3e8b88e37b9d0737a857bb90765 100644 (file)
@@ -65,16 +65,11 @@ public class LamiProcessPIDAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(LamiTableEntry entry) {
         LamiData data = entry.getValue(fColIndex);
         if (data instanceof LamiProcess) {
             Long pid = ((LamiProcess) data).getPID();
-
-            if (pid == null) {
-                return null;
-            }
-
-            return Double.valueOf(pid);
+            return pid;
         }
 
         return null;
@@ -83,13 +78,21 @@ public class LamiProcessPIDAspect extends LamiTableEntryAspect {
     @Override
     public Comparator<LamiTableEntry> getComparator() {
         return (o1, o2) -> {
-            Double dO1 = resolveDouble(o1);
-            Double dO2 = resolveDouble(o2);
-            if (dO1 == null || dO2 == null) {
+            Number d1 = resolveNumber(o1);
+            Number d2 = resolveNumber(o2);
+
+            if (d1 == null && d2 == null) {
                 return 0;
             }
+            if (d1 == null) {
+                return 1;
+            }
+
+            if (d2 == null) {
+                return -1;
+            }
 
-            return dO1.compareTo(dO2);
+            return Long.compare(d1.longValue(), d2.longValue());
         };
     }
 }
index 5fea94a78b565eb4b7c13f91398b6e190cd704f6..74c38b369cbda1714a603fe21b4c14fddb06abd7 100644 (file)
@@ -65,16 +65,11 @@ public class LamiProcessTIDAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double  resolveDouble(LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(LamiTableEntry entry) {
         LamiData data = entry.getValue(fColIndex);
         if (data instanceof LamiProcess) {
             Long tid = ((LamiProcess) data).getTID();
-
-            if (tid == null) {
-                return null;
-            }
-
-            return Double.valueOf(tid);
+            return tid;
         }
 
         return null;
@@ -83,13 +78,21 @@ public class LamiProcessTIDAspect extends LamiTableEntryAspect {
     @Override
     public Comparator<LamiTableEntry> getComparator() {
         return (o1, o2) -> {
-            Double dO1 = resolveDouble(o1);
-            Double dO2 = resolveDouble(o2);
-            if (dO1 == null || dO2 == null) {
+            Number d1 = resolveNumber(o1);
+            Number d2 = resolveNumber(o2);
+
+            if (d1 == null && d2 == null) {
                 return 0;
             }
+            if (d1 == null) {
+                return 1;
+            }
+
+            if (d2 == null) {
+                return -1;
+            }
 
-            return dO1.compareTo(dO2);
+            return Long.compare(d1.longValue(), d2.longValue());
         };
     }
 }
index a0705625f79162fbe9ef3c719eb93f4250b1b257..6db4ca770bf99169e867c072282d36ff766a6b2d 100644 (file)
@@ -117,7 +117,7 @@ public abstract class LamiTableEntryAspect {
      *            The table row
      * @return The double value for the given cell
      */
-    public abstract @Nullable Double resolveDouble(LamiTableEntry entry);
+    public abstract @Nullable Number resolveNumber(LamiTableEntry entry);
 
     /**
      * Get the comparator that should be used to compare this entry (or table
index abb160e4969bcef59550e895297847add10095b5..29a384cc75bc420c4a6076f7de82d7517a963dfd 100644 (file)
@@ -64,11 +64,11 @@ public class LamiTimeRangeBeginAspect extends LamiTableEntryAspect {
 
 
     @Override
-    public @Nullable Double resolveDouble(@NonNull LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(@NonNull LamiTableEntry entry) {
         LamiData data = entry.getValue(fColIndex);
         if (data instanceof LamiTimeRange) {
             LamiTimeRange range = (LamiTimeRange) data;
-            return Double.valueOf(range.getStart());
+            return range.getStart();
         }
         return null;
     }
@@ -76,13 +76,21 @@ public class LamiTimeRangeBeginAspect extends LamiTableEntryAspect {
     @Override
     public Comparator<LamiTableEntry> getComparator() {
         return (o1, o2) -> {
-            Double dO1 = resolveDouble(o1);
-            Double dO2 = resolveDouble(o2);
-            if (dO1 == null || dO2 == null) {
+            Number d1 = resolveNumber(o1);
+            Number d2 = resolveNumber(o2);
+
+            if (d1 == null && d2 == null) {
                 return 0;
             }
+            if (d1 == null) {
+                return 1;
+            }
+
+            if (d2 == null) {
+                return -1;
+            }
 
-            return dO1.compareTo(dO2);
+            return Long.compare(d1.longValue(), d2.longValue());
         };
     }
 
index 6b1fe35c32eec15d88a4ef009cc7b1be4355190b..f70448eb6b1099f08e0ea7dcd6423f35ba86a323 100644 (file)
@@ -65,11 +65,11 @@ public class LamiTimeRangeDurationAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(@NonNull LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(@NonNull LamiTableEntry entry) {
         LamiData data = entry.getValue(fColIndex);
         if (data instanceof LamiTimeRange) {
             LamiTimeRange range = (LamiTimeRange) data;
-            return Double.valueOf(range.getDuration());
+            return Long.valueOf(range.getDuration());
         }
         return null;
     }
@@ -77,13 +77,21 @@ public class LamiTimeRangeDurationAspect extends LamiTableEntryAspect {
     @Override
     public Comparator<LamiTableEntry> getComparator() {
         return (o1, o2) -> {
-            Double dO1 = resolveDouble(o1);
-            Double dO2 = resolveDouble(o2);
-            if (dO1 == null || dO2 == null) {
+            Number d1 = resolveNumber(o1);
+            Number d2 = resolveNumber(o2);
+
+            if (d1 == null && d2 == null) {
                 return 0;
             }
+            if (d1 == null) {
+                return 1;
+            }
+
+            if (d2 == null) {
+                return -1;
+            }
 
-            return dO1.compareTo(dO2);
+            return Long.compare(d1.longValue(), d2.longValue());
         };
     }
 
index 997989a3db5a3e6fb7e0363133514b366cec25c2..3705314847e2304ac1e55f82e45a011fadd1423f 100644 (file)
@@ -61,11 +61,11 @@ public class LamiTimeRangeEndAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(@NonNull LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(@NonNull LamiTableEntry entry) {
         LamiData data = entry.getValue(fColIndex);
         if (data instanceof LamiTimeRange) {
             LamiTimeRange range = (LamiTimeRange) data;
-            return Double.valueOf(range.getEnd());
+            return Long.valueOf(range.getEnd());
         }
         return null;
     }
@@ -73,13 +73,21 @@ public class LamiTimeRangeEndAspect extends LamiTableEntryAspect {
     @Override
     public Comparator<LamiTableEntry> getComparator() {
         return (o1, o2) -> {
-            Double dO1 = resolveDouble(o1);
-            Double dO2 = resolveDouble(o2);
-            if (dO1 == null || dO2 == null) {
+            Number d1 = resolveNumber(o1);
+            Number d2 = resolveNumber(o2);
+
+            if (d1 == null && d2 == null) {
                 return 0;
             }
+            if (d1 == null) {
+                return 1;
+            }
+
+            if (d2 == null) {
+                return -1;
+            }
 
-            return dO1.compareTo(dO2);
+            return Long.compare(d1.longValue(), d2.longValue());
         };
     }
 
index 6f41e48977e015f01c77c216d9ab10b91315d922..31acda91fe4d73ea1151061fdc1e402f068b5fbb 100644 (file)
@@ -61,11 +61,11 @@ public class LamiTimestampAspect extends LamiTableEntryAspect {
     }
 
     @Override
-    public @Nullable Double resolveDouble(@NonNull LamiTableEntry entry) {
+    public @Nullable Number resolveNumber(@NonNull LamiTableEntry entry) {
         LamiData data = entry.getValue(fColIndex);
         if (data instanceof LamiInteger) {
             LamiInteger range = (LamiInteger) data;
-            return Double.valueOf(range.getValue());
+            return Long.valueOf(range.getValue());
         }
         return null;
     }
@@ -73,13 +73,21 @@ public class LamiTimestampAspect extends LamiTableEntryAspect {
     @Override
     public Comparator<LamiTableEntry> getComparator() {
         return (o1, o2) -> {
-            Double dO1 = resolveDouble(o1);
-            Double dO2 = resolveDouble(o2);
-            if (dO1 == null || dO2 == null) {
+            Number d1 = resolveNumber(o1);
+            Number d2 = resolveNumber(o2);
+
+            if (d1 == null && d2 == null) {
                 return 0;
             }
+            if (d1 == null) {
+                return 1;
+            }
+
+            if (d2 == null) {
+                return -1;
+            }
 
-            return dO1.compareTo(dO2);
+            return Long.compare(d1.longValue(), d2.longValue());
         };
     }
 
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiLabelFormat.java b/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiLabelFormat.java
deleted file mode 100644 (file)
index 11d8be1..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 EfficiOS Inc., Jonathan Rajotte-Julien
- *
- * 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
- *******************************************************************************/
-
-package org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module;
-
-import java.text.FieldPosition;
-import java.text.Format;
-import java.text.ParsePosition;
-import java.util.Map.Entry;
-
-
-import org.eclipse.jdt.annotation.Nullable;
-
-import com.google.common.collect.BiMap;
-
-/**
- * Format label based on a given Map<String, Integer>
- *
- * @author Jonathan Rajotte-Julien
- */
-public class LamiLabelFormat extends Format {
-
-    private static final long serialVersionUID = 4939553034329681316L;
-
-    private static final String SWTCHART_EMPTY_LABEL = " "; //$NON-NLS-1$
-    private static final String UNKNOWN_REPRESENTATION = "?"; //$NON-NLS-1$
-    private final BiMap<@Nullable String, Integer> fMap;
-
-    /**
-     * Constructor
-     *
-     * @param map
-     *            Map of indices to labels
-     */
-    public LamiLabelFormat(BiMap<@Nullable String, Integer> map) {
-        super();
-        fMap = map;
-    }
-
-    @Override
-    public @Nullable StringBuffer format(@Nullable Object obj, @Nullable StringBuffer toAppendTo, @Nullable FieldPosition pos) {
-        if (obj == null || toAppendTo == null) {
-            return new StringBuffer(SWTCHART_EMPTY_LABEL);
-        }
-
-        Double doubleObj = (Double) obj;
-
-        /*
-         * Return a string buffer with a space in it since SWT does not like to
-         * draw empty strings.
-         */
-        if ((doubleObj % 1 != 0) || !fMap.containsValue((doubleObj.intValue()))) {
-            return new StringBuffer(SWTCHART_EMPTY_LABEL);
-        }
-
-        for (Entry<@Nullable String, Integer> entry : fMap.entrySet()) {
-            /*
-             * FIXME: Find if the elements are the same, based on their double
-             * value, because SWTChart uses double values so we do the same
-             * check. The loss of precision could lead to false positives.
-             */
-            if (Double.compare(entry.getValue().doubleValue(), doubleObj.doubleValue()) == 0) {
-                if (entry.getKey() == null) {
-                    return new StringBuffer(UNKNOWN_REPRESENTATION);
-                }
-                return toAppendTo.append(entry.getKey());
-            }
-        }
-        return new StringBuffer(SWTCHART_EMPTY_LABEL);
-    }
-
-    @Override
-    public @Nullable Object parseObject(@Nullable String source, @Nullable ParsePosition pos) {
-        return fMap.get(source);
-    }
-
-}
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiTimeStampFormat.java b/analysis/org.eclipse.tracecompass.analysis.lami.core/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/core/module/LamiTimeStampFormat.java
deleted file mode 100644 (file)
index 49c13a8..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015, 2016 EfficiOS Inc. and others
- *
- * 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
- *******************************************************************************/
-
-package org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module;
-
-import java.text.FieldPosition;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat;
-
-/**
- * Formatter for time stamps
- */
-public class LamiTimeStampFormat extends SimpleDateFormat {
-
-    private static final long serialVersionUID = 4285447886537779762L;
-
-    private final TmfTimestampFormat fFormat;
-
-    // ------------------------------------------------------------------------
-    // Constructors
-    // ------------------------------------------------------------------------
-
-    /**
-     * The default constructor (uses the default time format)
-     */
-    public LamiTimeStampFormat() {
-        fFormat = TmfTimestampFormat.getDefaulTimeFormat();
-    }
-
-    /**
-     * The normal constructor
-     *
-     * @param pattern the format pattern
-     */
-    public LamiTimeStampFormat(String pattern) {
-        fFormat = new TmfTimestampFormat(pattern);
-    }
-
-    // ------------------------------------------------------------------------
-    // Operations
-    // ------------------------------------------------------------------------
-
-    @Override
-    public StringBuffer format(@Nullable Date date, @Nullable StringBuffer toAppendTo,
-            @Nullable FieldPosition fieldPosition) {
-        if (date != null && toAppendTo != null) {
-            long time = date.getTime();
-            toAppendTo.append(fFormat.format(time));
-            return toAppendTo;
-        }
-        return new StringBuffer();
-    }
-}
index ce71dc0dda9898e0cbff0829bcd59cfeca0ce18e..2fdacceaa4aa5448de2d12af64593860cb91c2a6 100644 (file)
@@ -71,7 +71,7 @@ public class LamiIRQ extends LamiData {
      *
      * @return The IRQ number
      */
-    public int getNumber() {
+    public Integer getNumber() {
         return fNumber;
     }
 
index a7603e5a8d456a53d1285caa124f0006b067321c..2f91a965bf1ae6880c2abb41175cea7da21d1b1d 100644 (file)
@@ -17,6 +17,7 @@ Require-Bundle: org.eclipse.ui,
  org.eclipse.tracecompass.tmf.ui,
  org.eclipse.tracecompass.analysis.lami.core
 Export-Package: org.eclipse.tracecompass.internal.analysis.lami.ui;x-internal:=true,
+ org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.format;x-internal:=true,
  org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.handler;x-internal:=true,
  org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.signals;x-internal:=true,
  org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.viewers;x-internal:=true,
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/LamiDecimalUnitFormat.java b/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/LamiDecimalUnitFormat.java
new file mode 100644 (file)
index 0000000..c3bd73d
--- /dev/null
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Jonathan Rajotte-Julien
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.format;
+
+import java.math.BigDecimal;
+import java.text.FieldPosition;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.common.core.format.DecimalUnitFormat;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.viewers.LamiGraphRange;
+
+/**
+ * Decimal formatter for Lami graph
+ *
+ * Since the graph use normalized internal value the initial (external)
+ * representation needs to be obtained. Subsequent formatting is done based on a
+ * Double. Loss of precision could occurs based on the size. For now, loss of
+ * precision for decimal values is not a big concern. If it ever become one the
+ * use of Long while formatting might come in handy.
+ *
+ * @author Jonathan Rajotte-Julien
+ */
+public class LamiDecimalUnitFormat extends DecimalUnitFormat {
+
+    /** Maximum amount of digits that can be represented into a double */
+    private static final int BIG_DECIMAL_DIVISION_SCALE = 22;
+
+    private static final long serialVersionUID = 977671266270661188L;
+
+    private @Nullable LamiGraphRange fInternalRange = null;
+    private @Nullable LamiGraphRange fExternalRange = null;
+
+    /**
+     * Default constructor
+     */
+    public LamiDecimalUnitFormat() {
+        super();
+    }
+
+    /**
+     * Constructor with internal and external LamiRange for scale transformation
+     *
+     * @param internalRange
+     *            The internal range used for graph representation
+     *
+     * @param externalRange
+     *            The external (real value) range shown to the user
+     */
+    public LamiDecimalUnitFormat(LamiGraphRange internalRange, LamiGraphRange externalRange) {
+        super();
+        fInternalRange = internalRange;
+        fExternalRange = externalRange;
+    }
+
+    /**
+     * Constructor with multiplication factor.
+     *
+     * @param factor
+     *            Multiplication factor to apply to the value
+     */
+    public LamiDecimalUnitFormat(double factor) {
+        super(factor);
+    }
+
+    /**
+     * Constructor with multiplication factor and internal and external
+     * LamiRange for scale transformation.
+     *
+     * @param factor
+     *            Multiplication factor to apply to the value
+     * @param internalRange
+     *            The internal range used for graph representation
+     * @param externalRange
+     *            The external (real value) range shown to the user
+     */
+    public LamiDecimalUnitFormat(double factor, LamiGraphRange internalRange, LamiGraphRange externalRange) {
+        super(factor);
+        fInternalRange = internalRange;
+        fExternalRange = externalRange;
+    }
+
+    /**
+     * @return the internal range definition
+     */
+    public @Nullable LamiGraphRange getInternalRange() {
+        return fInternalRange;
+    }
+
+    /**
+     * @param internalRange
+     *            The internal range definition to be used by the formatter
+     */
+    public void setInternalRange(@Nullable LamiGraphRange internalRange) {
+        fInternalRange = internalRange;
+    }
+
+    /**
+     * @return the external range definition
+     */
+    public @Nullable LamiGraphRange getExternalRange() {
+        return fExternalRange;
+    }
+
+    /**
+     * @param externalRange
+     *            The external range definition to be used by the formatter
+     */
+    public void setExternalRange(@Nullable LamiGraphRange externalRange) {
+        fExternalRange = externalRange;
+    }
+
+    @Override
+    public StringBuffer format(@Nullable Object obj, @Nullable StringBuffer toAppendTo, @Nullable FieldPosition pos) {
+        if (!(obj instanceof Number) || toAppendTo == null) {
+            throw new IllegalArgumentException("Cannot format given Object as a Number: " + obj); //$NON-NLS-1$
+        }
+
+        @Nullable LamiGraphRange internalRange = fInternalRange;
+        @Nullable LamiGraphRange externalRange = fExternalRange;
+        if (internalRange == null || externalRange == null) {
+            StringBuffer buffer = super.format(obj, toAppendTo, pos);
+            return (buffer == null ? new StringBuffer() : buffer);
+        }
+
+        if (internalRange.getDelta().compareTo(BigDecimal.ZERO) == 0) {
+            StringBuffer buffer = super.format(externalRange.getMinimum().doubleValue(), toAppendTo, pos);
+            return (buffer == null ? new StringBuffer() : buffer);
+        }
+
+        if (externalRange.getDelta().compareTo(BigDecimal.ZERO) == 0) {
+            StringBuffer buffer = super.format(externalRange.getMinimum().doubleValue(), toAppendTo, pos);
+            return (buffer == null ? new StringBuffer() : buffer);
+        }
+
+        /* Find external value before formatting */
+        BigDecimal externalValue = (new BigDecimal(obj.toString()))
+                .subtract(internalRange.getMinimum())
+                .multiply(externalRange.getDelta())
+                .divide(internalRange.getDelta(), BIG_DECIMAL_DIVISION_SCALE, BigDecimal.ROUND_DOWN)
+                .add(externalRange.getMinimum());
+
+        Double value = externalValue.doubleValue();
+        StringBuffer buffer = super.format(value, toAppendTo, pos);
+        return (buffer == null ? new StringBuffer() : buffer);
+    }
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/LamiLabelFormat.java b/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/LamiLabelFormat.java
new file mode 100644 (file)
index 0000000..9574789
--- /dev/null
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Jonathan Rajotte-Julien
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.format;
+
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+import java.util.Map.Entry;
+
+
+import org.eclipse.jdt.annotation.Nullable;
+
+import com.google.common.collect.BiMap;
+
+/**
+ * Format label based on a given Map<String, Integer>
+ *
+ * @author Jonathan Rajotte-Julien
+ */
+public class LamiLabelFormat extends Format {
+
+    private static final long serialVersionUID = 4939553034329681316L;
+
+    private static final String SWTCHART_EMPTY_LABEL = " "; //$NON-NLS-1$
+    private static final String UNKNOWN_REPRESENTATION = "?"; //$NON-NLS-1$
+    private final BiMap<@Nullable String, Integer> fMap;
+
+    /**
+     * Constructor
+     *
+     * @param map
+     *            Map of indices to labels
+     */
+    public LamiLabelFormat(BiMap<@Nullable String, Integer> map) {
+        super();
+        fMap = map;
+    }
+
+    @Override
+    public @Nullable StringBuffer format(@Nullable Object obj, @Nullable StringBuffer toAppendTo, @Nullable FieldPosition pos) {
+        if (obj == null || toAppendTo == null) {
+            return new StringBuffer(SWTCHART_EMPTY_LABEL);
+        }
+
+        Double doubleObj = (Double) obj;
+
+        /*
+         * Return a string buffer with a space in it since SWT does not like to
+         * draw empty strings.
+         */
+        if ((doubleObj % 1 != 0) || !fMap.containsValue((doubleObj.intValue()))) {
+            return new StringBuffer(SWTCHART_EMPTY_LABEL);
+        }
+
+        for (Entry<@Nullable String, Integer> entry : fMap.entrySet()) {
+            /*
+             * FIXME: Find if the elements are the same, based on their double
+             * value, because SWTChart uses double values so we do the same
+             * check. The loss of precision could lead to false positives.
+             */
+            if (Double.compare(entry.getValue().doubleValue(), doubleObj.doubleValue()) == 0) {
+                if (entry.getKey() == null) {
+                    return new StringBuffer(UNKNOWN_REPRESENTATION);
+                }
+                return toAppendTo.append(entry.getKey());
+            }
+        }
+        return new StringBuffer(SWTCHART_EMPTY_LABEL);
+    }
+
+    @Override
+    public @Nullable Object parseObject(@Nullable String source, @Nullable ParsePosition pos) {
+        return fMap.get(source);
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/LamiTimeStampFormat.java b/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/LamiTimeStampFormat.java
new file mode 100644 (file)
index 0000000..87c607b
--- /dev/null
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 EfficiOS Inc. and others
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.format;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.math.BigDecimal;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.viewers.LamiGraphRange;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat;
+
+/**
+ * Formatter for time stamps
+ */
+public class LamiTimeStampFormat extends Format {
+
+    private static final int BIG_DECIMAL_DIVISION_SCALE = 22;
+
+    private static final long serialVersionUID = 4285447886537779762L;
+
+    private final TmfTimestampFormat fFormat;
+
+    private @Nullable LamiGraphRange fInternalRange = null;
+    private @Nullable LamiGraphRange fExternalRange = null;
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+
+    /**
+     * The default constructor
+     */
+    public LamiTimeStampFormat() {
+        fFormat = checkNotNull(TmfTimestampFormat.getDefaulTimeFormat());
+    }
+
+    /**
+     * The base constructor
+     *
+     * @param internalRange
+     *            The internal range used for graph representation
+     * @param externalRange
+     *            The external (real value) range shown to the user
+     */
+    public LamiTimeStampFormat(LamiGraphRange internalRange, LamiGraphRange externalRange) {
+        fFormat = checkNotNull(TmfTimestampFormat.getDefaulTimeFormat());
+        fInternalRange = internalRange;
+        fExternalRange = externalRange;
+    }
+
+    /**
+     * The normal constructor
+     *
+     * @param pattern
+     *            The format pattern
+     */
+    public LamiTimeStampFormat(String pattern) {
+        fFormat = new TmfTimestampFormat(pattern);
+    }
+
+    /**
+     * The normal constructor
+     *
+     * @param pattern
+     *            the format pattern
+     * @param internalRange
+     *            The internal range used for graph representation
+     * @param externalRange
+     *            The external (real value) range shown to the user
+     */
+    public LamiTimeStampFormat(String pattern, LamiGraphRange internalRange, LamiGraphRange externalRange) {
+        fFormat = new TmfTimestampFormat(pattern);
+        fInternalRange = internalRange;
+        fExternalRange = externalRange;
+    }
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    /**
+     * @return the internal range definition
+     */
+    public @Nullable LamiGraphRange getInternalRange() {
+        return fInternalRange;
+    }
+
+    /**
+     * @param internalRange
+     *            The internal range definition to be used by the formatter
+     */
+    public void setInternalRange(@Nullable LamiGraphRange internalRange) {
+        fInternalRange = internalRange;
+    }
+
+    /**
+     * @return the external range definition
+     */
+    public @Nullable LamiGraphRange getExternalRange() {
+        return fExternalRange;
+    }
+
+    /**
+     * @param externalRange
+     *            The external range definition to be used by the formatter
+     */
+    public void setExternalRange(@Nullable LamiGraphRange externalRange) {
+        fExternalRange = externalRange;
+    }
+
+
+    @Override
+    public StringBuffer format(@Nullable Object obj, @Nullable StringBuffer toAppendTo, @Nullable FieldPosition pos) {
+        if (obj != null && obj instanceof Number && toAppendTo != null) {
+            @Nullable LamiGraphRange internalRange = fInternalRange;
+            @Nullable LamiGraphRange externalRange = fExternalRange;
+            if (internalRange == null || externalRange == null) {
+                long time = ((Number)obj).longValue();
+                return checkNotNull(toAppendTo.append(fFormat.format(time)));
+            }
+
+            if (internalRange.getDelta().compareTo(BigDecimal.ZERO) == 0) {
+                return checkNotNull(toAppendTo.append(fFormat.format(externalRange.getMinimum().doubleValue())));
+            }
+
+            if (externalRange.getDelta().compareTo(BigDecimal.ZERO) == 0) {
+                return checkNotNull(toAppendTo.append(fFormat.format(externalRange.getMinimum().doubleValue())));
+            }
+
+            /* Find external value before formatting */
+            BigDecimal externalValue = (new BigDecimal(obj.toString()))
+                    .subtract(internalRange.getMinimum())
+                    .multiply(externalRange.getDelta())
+                    .divide(internalRange.getDelta(), BIG_DECIMAL_DIVISION_SCALE, BigDecimal.ROUND_DOWN)
+                    .add(externalRange.getMinimum());
+
+            return checkNotNull(toAppendTo.append(fFormat.format(externalValue.longValue())));
+        }
+        return new StringBuffer();
+    }
+
+    @Override
+    public @Nullable Object parseObject(@Nullable String source, @Nullable ParsePosition pos) {
+        return null;
+    }
+
+}
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/package-info.java b/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/format/package-info.java
new file mode 100644 (file)
index 0000000..c91e0f0
--- /dev/null
@@ -0,0 +1,11 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Jonathan Rajotte-Julien
+ *
+ * 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
+ *******************************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.format;
\ No newline at end of file
index bd48497410e701f49d3906381d6147ed01798bdb..0795713fea5121611ecfa628d6afe261e40f8122 100644 (file)
@@ -11,6 +11,7 @@ package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.viewers;
 
 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -82,6 +83,10 @@ public class LamiBarChartViewer extends LamiXYChartViewer {
     private final Map<ISeries, List<Mapping>> fIndexPerSeriesMapping;
     private final Map<LamiTableEntry, Mapping> fEntryToCategoriesMap;
 
+    private LamiGraphRange fYInternalRange = new LamiGraphRange(checkNotNull(BigDecimal.ZERO), checkNotNull(BigDecimal.ONE));
+    private LamiGraphRange fYExternalRange;
+
+
     /**
      * Creates a bar chart Viewer instance based on SWTChart.
      *
@@ -127,6 +132,10 @@ public class LamiBarChartViewer extends LamiXYChartViewer {
         }
         fCategories = xCategories.toArray(new String[0]);
 
+        /* The y values range */
+        /* Clamp minimum to zero or negative value */
+        fYExternalRange = getRange(yAxisAspects, true);
+
         /*
          * Log scale magic course 101:
          *
@@ -141,14 +150,18 @@ public class LamiBarChartViewer extends LamiXYChartViewer {
          */
         double min = Double.MAX_VALUE;
         double max = Double.MIN_VALUE;
-        double logScaleEpsilon = ZERO;
+        double logScaleEpsilon = ZERO_DOUBLE;
         if (logscale) {
 
-            /* Find minimum and maximum values */
+            /* Find minimum and maximum values excluding <= 0 values */
             for (LamiTableEntryAspect aspect : yAxisAspects) {
                 for (LamiTableEntry entry : entries) {
-                    Double value = aspect.resolveDouble(entry);
-                    if (value == null || value <= 0) {
+                    Number externalValue = aspect.resolveNumber(entry);
+                    if (externalValue == null) {
+                        continue;
+                    }
+                    Double value = getInternalDoubleValue(externalValue, fYInternalRange, fYExternalRange);
+                    if (value <= 0) {
                         continue;
                     }
                     min = Math.min(min, value);
@@ -156,6 +169,11 @@ public class LamiBarChartViewer extends LamiXYChartViewer {
                 }
             }
 
+            if (min == Double.MAX_VALUE) {
+                /* Series are empty in log scale*/
+                return;
+            }
+
             double delta = max - min;
             logScaleEpsilon = min - ((min * delta) / (LOGSCALE_EPSILON_FACTOR * max));
         }
@@ -172,21 +190,26 @@ public class LamiBarChartViewer extends LamiXYChartViewer {
 
             for (int i = 0; i < entries.size(); i++) {
                 Integer categoryIndex = checkNotNull(fEntryToCategoriesMap.get(checkNotNull(entries.get(i)))).fInternalValue;
-                Double yValue = yAxisAspect.resolveDouble(entries.get(i));
+
                 if (categoryIndex == null) {
                     /* Invalid value do not show */
                     continue;
                 }
 
-                if (yValue == null) {
+                Double yValue = ZERO_DOUBLE;
+                @Nullable Number number = yAxisAspect.resolveNumber(entries.get(i));
+
+                if (number == null) {
                     /*
                      * Null value for y is the same as zero since this is a bar
                      * chart
                      */
-                    yValue = Double.valueOf(ZERO);
+                    yValue = ZERO_DOUBLE;
+                } else {
+                    yValue = getInternalDoubleValue(number, fYInternalRange, fYExternalRange);
                 }
 
-                if (logscale && yValue <= ZERO) {
+                if (logscale && yValue <= ZERO_DOUBLE) {
                     /*
                      * Less or equal to 0 values can't be plotted on a log
                      * scale. We map them to the mean of the >=0 minimal value
@@ -220,12 +243,27 @@ public class LamiBarChartViewer extends LamiXYChartViewer {
 
         /* Set the formatter on the Y axis */
         IAxisTick yTick = getChart().getAxisSet().getYAxis(0).getTick();
-        yTick.setFormat(getContinuousAxisFormatter(yAxisAspects, entries));
+        yTick.setFormat(getContinuousAxisFormatter(yAxisAspects, entries, fYInternalRange, fYExternalRange));
+
+        /*
+         * SWTChart workaround: SWTChart fiddles with tick mark visibility based
+         * on the fact that it can parse the label to double or not.
+         *
+         * If the label happens to be a double, it checks for the presence of
+         * that value in its own tick labels to decide if it should add it or
+         * not. If it happens that the parsed value is already present in its
+         * map, the tick gets a visibility of false.
+         *
+         * The X axis does not have this problem since SWTCHART checks on label
+         * angle, and if it is != 0 simply does no logic regarding visibility.
+         * So simply set a label angle of 1 to the axis.
+         */
         yTick.setTickLabelAngle(1);
 
         /* Adjust the chart range */
         getChart().getAxisSet().adjustRange();
-        if (logscale) {
+
+        if (logscale && logScaleEpsilon != max) {
             getChart().getAxisSet().getYAxis(0).setRange(new Range(logScaleEpsilon, max));
         }
 
diff --git a/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/viewers/LamiGraphRange.java b/analysis/org.eclipse.tracecompass.analysis.lami.ui/src/org/eclipse/tracecompass/internal/provisional/analysis/lami/ui/viewers/LamiGraphRange.java
new file mode 100644 (file)
index 0000000..62287aa
--- /dev/null
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc., Jonathan Rajotte-Julien
+ *
+ * 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
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.viewers;
+
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
+import java.math.BigDecimal;
+
+/**
+ * BigDecimal based range representation
+ *
+ * @author Jonathan Rajotte-Julien
+ */
+public class LamiGraphRange {
+
+    private final BigDecimal fMinimum;
+    private final BigDecimal fMaximum;
+    private final BigDecimal fRange;
+
+    /**
+     * Constructor
+     *
+     * @param minimum
+     *            The minimum value of the range
+     * @param maximum
+     *            The maximum value of the range
+     */
+    public LamiGraphRange(BigDecimal minimum, BigDecimal maximum) {
+        fMinimum = minimum;
+        fMaximum = maximum;
+        fRange = checkNotNull(maximum.subtract(minimum));
+    }
+
+    /**
+     * @return the minimum value of the range
+     */
+    public BigDecimal getMinimum() {
+        return fMinimum;
+    }
+
+    /**
+     * @return the maximum value of the range
+     */
+    public BigDecimal getMaximum() {
+        return fMaximum;
+    }
+
+    /**
+     * @return the range delta
+     */
+    public BigDecimal getDelta() {
+        return fRange;
+    }
+}
\ No newline at end of file
index 20ba7b3b8932af29817ca02644d2e6145fc1ccff..ea3869c2d43d35d042b800e5303403dfc92fc7f7 100644 (file)
@@ -11,6 +11,7 @@ package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.viewers;
 
 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -41,9 +42,9 @@ import org.eclipse.swt.widgets.Listener;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.aspect.LamiTableEntryAspect;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiChartModel;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiChartModel.ChartType;
-import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiLabelFormat;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiResultTable;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiTableEntry;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.format.LamiLabelFormat;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.signals.LamiSelectionUpdateSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
 import org.swtchart.IAxisTick;
@@ -68,6 +69,13 @@ public class LamiScatterViewer extends LamiXYChartViewer {
 
     private final Map<ISeries, List<Integer>> fIndexMapping;
 
+    /* Use a scale from 0 to 1 internally for both axes */
+    private LamiGraphRange fXInternalRange = new LamiGraphRange(checkNotNull(BigDecimal.ZERO), checkNotNull(BigDecimal.ONE));
+    private LamiGraphRange fYInternalRange = new LamiGraphRange(checkNotNull(BigDecimal.ZERO), checkNotNull(BigDecimal.ONE));
+
+    private @Nullable LamiGraphRange fXExternalRange = null;
+    private @Nullable LamiGraphRange fYExternalRange = null;
+
     /* The current data point for the hovering cross */
     private Point fHoveringCrossDataPoint;
 
@@ -121,6 +129,15 @@ public class LamiScatterViewer extends LamiXYChartViewer {
          */
         if (!areXAspectsContinuous) {
             generateLabelMap(xAxisAspects, checkNotNull(xMap));
+        } else {
+            /*
+             * Always clamp the range to min and max
+             *
+             * TODO: in the future this could be based on the result of the
+             * delta between max and min multiplied by a ratio like it is done in
+             * LibreOffice Calc
+             */
+            fXExternalRange = getRange(xAxisAspects, false);
         }
 
         /*
@@ -148,12 +165,18 @@ public class LamiScatterViewer extends LamiXYChartViewer {
          */
         if (!areYAspectsContinuous) {
             generateLabelMap(yAxisAspects, yMap);
+        } else {
+            /*
+             * Only clamp the range to the minimum value if it is a time stamp since
+             * plotting from 1970 would make little sense.
+             */
+            fYExternalRange = getRange(yAxisAspects, areYAspectsTimeStamp);
         }
 
         /* Plot the series */
         int index = 0;
         for (LamiTableEntryAspect yAspect : getYAxisAspects()) {
-            String name = ""; //$NON-NLS-1$
+            String name;
             LamiTableEntryAspect xAspect;
             if (xAxisAspects.size() == 1) {
                 /* Always map to the same x series */
@@ -164,35 +187,53 @@ public class LamiScatterViewer extends LamiXYChartViewer {
                 name = (yAspect.getName() + ' ' + Messages.LamiScatterViewer_by + ' ' + xAspect.getName());
             }
 
-            List<@Nullable Double> xDoubleSeries = new ArrayList<>();
-            List<@Nullable Double> yDoubleSeries = new ArrayList<>();
+            List<@Nullable Double> xDoubleSeries;
+            List<@Nullable Double> yDoubleSeries;
 
             if (xAspect.isContinuous()) {
-                xDoubleSeries = getResultTable().getEntries().stream().map((entry -> xAspect.resolveDouble(entry))).collect(Collectors.toList());
+                xDoubleSeries = getResultTable().getEntries().stream()
+                        .map(entry -> {
+                            Number number = xAspect.resolveNumber(entry);
+                            if (number != null && fXExternalRange != null) {
+                                return getInternalDoubleValue(number, fXInternalRange, fXExternalRange);
+                            }
+                            return null;
+                        })
+                        .collect(Collectors.toList());
             } else {
-                xDoubleSeries = getResultTable().getEntries().stream().map(entry -> {
-                    String string = xAspect.resolveString(entry);
-                    Integer value = xMap.get(string);
-                    if (value != null) {
-                        return Double.valueOf(value.doubleValue());
-                    }
-                    return null;
-
-                }).collect(Collectors.toList());
+                xDoubleSeries = getResultTable().getEntries().stream()
+                        .map(entry -> {
+                            String string = xAspect.resolveString(entry);
+                            Integer value = xMap.get(string);
+                            if (value != null) {
+                                return Double.valueOf(value.doubleValue());
+                            }
+                            return null;
+                        })
+                        .collect(Collectors.toList());
             }
 
             if (yAspect.isContinuous()) {
-                yDoubleSeries = getResultTable().getEntries().stream().map((entry -> yAspect.resolveDouble(entry))).collect(Collectors.toList());
+                yDoubleSeries = getResultTable().getEntries().stream()
+                        .map(entry -> {
+                            Number number = yAspect.resolveNumber(entry);
+                            if (number != null && fYExternalRange != null) {
+                                return getInternalDoubleValue(number, fYInternalRange, fYExternalRange);
+                            }
+                            return null;
+                        })
+                        .collect(Collectors.toList());
             } else {
-                yDoubleSeries = getResultTable().getEntries().stream().map(entry -> {
-                    String string = yAspect.resolveString(entry);
-                    Integer value = yMap.get(string);
-                    if (value != null) {
-                        return Double.valueOf(value.doubleValue());
-                    }
-                    return null;
-
-                }).collect(Collectors.toList());
+                yDoubleSeries = getResultTable().getEntries().stream()
+                        .map(entry -> {
+                            String string = yAspect.resolveString(entry);
+                            Integer value = yMap.get(string);
+                            if (value != null) {
+                                return Double.valueOf(value.doubleValue());
+                            }
+                            return null;
+                        })
+                        .collect(Collectors.toList());
             }
 
             List<@Nullable Double> validXDoubleSeries = new ArrayList<>();
@@ -211,7 +252,7 @@ public class LamiScatterViewer extends LamiXYChartViewer {
                     /* Reject this tuple */
                     continue;
                 }
-                if ((xIsLog && xValue <= ZERO) || (yIsLog && yValue <= ZERO)) {
+                if ((xIsLog && xValue <= ZERO_DOUBLE) || (yIsLog && yValue <= ZERO_DOUBLE)) {
                     /*
                      * Equal or less than 0 values can't be plotted on log scale
                      */
@@ -242,7 +283,7 @@ public class LamiScatterViewer extends LamiXYChartViewer {
         /* Modify x axis related chart styling */
         IAxisTick xTick = getChart().getAxisSet().getXAxis(0).getTick();
         if (areXAspectsContinuous) {
-            xTick.setFormat(getContinuousAxisFormatter(xAxisAspects, getResultTable().getEntries()));
+            xTick.setFormat(getContinuousAxisFormatter(xAxisAspects, getResultTable().getEntries(), fXInternalRange, fXExternalRange));
         } else {
             xTick.setFormat(new LamiLabelFormat(checkNotNull(xMap)));
             updateTickMark(checkNotNull(xMap), xTick, getChart().getPlotArea().getSize().x);
@@ -254,7 +295,7 @@ public class LamiScatterViewer extends LamiXYChartViewer {
         /* Modify Y axis related chart styling */
         IAxisTick yTick = getChart().getAxisSet().getYAxis(0).getTick();
         if (areYAspectsContinuous) {
-            yTick.setFormat(getContinuousAxisFormatter(yAxisAspects, getResultTable().getEntries()));
+            yTick.setFormat(getContinuousAxisFormatter(yAxisAspects, getResultTable().getEntries(), fYInternalRange, fYExternalRange));
         } else {
             yTick.setFormat(new LamiLabelFormat(checkNotNull(yMap)));
             updateTickMark(checkNotNull(yMap), yTick, getChart().getPlotArea().getSize().y);
index 874e3b5a35b675a7cea993638e75f410e60e1118..a958302ff23f5f8f579514b5094b145ffa1aa7e0 100644 (file)
@@ -12,6 +12,7 @@ package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.viewers;
 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
 import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
 
+import java.math.BigDecimal;
 import java.text.Format;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -43,7 +44,8 @@ import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.aspect.L
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiChartModel;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiResultTable;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiTableEntry;
-import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiTimeStampFormat;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.format.LamiDecimalUnitFormat;
+import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.format.LamiTimeStampFormat;
 import org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.signals.LamiSelectionUpdateSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
 import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer;
@@ -71,14 +73,10 @@ public abstract class LamiXYChartViewer extends TmfViewer implements ILamiViewer
      */
     protected static final String UNKNOWN = "?"; //$NON-NLS-1$
 
-    /** Zero value */
-    protected static final double ZERO = 0.0;
-
-    /** Symbol for seconds (used in the custom ns -> s conversion) */
-    private static final String SECONDS_SYMBOL = "s"; //$NON-NLS-1$
-
-    /** Symbol for nanoseconds (used in the custom ns -> s conversion) */
-    private static final String NANOSECONDS_SYMBOL = "ns"; //$NON-NLS-1$
+    /** Zero long value */
+    protected static final long ZERO_LONG = 0L;
+    /** Zero double value */
+    protected static final double ZERO_DOUBLE = 0.0;
 
     /**
      * Function to use to map Strings read from the data table to doubles for
@@ -86,7 +84,7 @@ public abstract class LamiXYChartViewer extends TmfViewer implements ILamiViewer
      */
     protected static final ToDoubleFunction<@Nullable String> DOUBLE_MAPPER = str -> {
         if (str == null || str.equals(UNKNOWN)) {
-            return ZERO;
+            return ZERO_LONG;
         }
         return Double.parseDouble(str);
     };
@@ -143,12 +141,21 @@ public abstract class LamiXYChartViewer extends TmfViewer implements ILamiViewer
     /**
      * Decimal formatter to display nanoseconds as seconds.
      */
-    protected static final DecimalUnitFormat NANO_TO_SECS_FORMATTER = new DecimalUnitFormat(0.000000001);
+    protected static final DecimalUnitFormat NANO_TO_SECS_FORMATTER = new LamiDecimalUnitFormat(0.000000001);
 
     /**
      * Default decimal formatter.
      */
-    protected static final DecimalUnitFormat DECIMAL_FORMATTER = new DecimalUnitFormat();
+    protected static final DecimalUnitFormat DECIMAL_FORMATTER = new LamiDecimalUnitFormat();
+
+    /** Symbol for seconds (used in the custom ns -> s conversion) */
+    private static final String SECONDS_SYMBOL = "s"; //$NON-NLS-1$
+
+    /** Symbol for nanoseconds (used in the custom ns -> s conversion) */
+    private static final String NANOSECONDS_SYMBOL = "ns"; //$NON-NLS-1$
+
+    /** Maximum amount of digits that can be represented into a double */
+    private static final int BIG_DECIMAL_DIVISION_SCALE = 22;
 
     private final Listener fResizeListener = event -> {
         /* Refresh the titles to fit the current chart size */
@@ -360,45 +367,64 @@ public abstract class LamiXYChartViewer extends TmfViewer implements ILamiViewer
      *            The list of aspects of the axis.
      * @param entries
      *            The list of entries of the chart.
+     * @param internalRange
+     *            The internal range for value transformation
+     * @param externalRange
+     *            The external range for value transformation
      * @return a formatter for the axis.
      */
-    protected static Format getContinuousAxisFormatter(List<LamiTableEntryAspect> axisAspects, List<LamiTableEntry> entries) {
+    protected static Format getContinuousAxisFormatter(List<LamiTableEntryAspect> axisAspects, List<LamiTableEntry> entries , @Nullable LamiGraphRange internalRange, @Nullable LamiGraphRange externalRange) {
+
+        Format formatter = DECIMAL_FORMATTER;
 
         if (areAspectsTimeStamp(axisAspects)) {
             /* Set a TimeStamp formatter depending on the duration between the first and last value */
-            double max = Double.MIN_VALUE;
-            double min = Double.MAX_VALUE;
+            BigDecimal max = new BigDecimal(Long.MIN_VALUE);
+            BigDecimal min = new BigDecimal(Long.MAX_VALUE);
 
             for (LamiTableEntry entry : entries) {
                 for (LamiTableEntryAspect aspect : axisAspects) {
-                    Double current = aspect.resolveDouble(entry);
-                    if (current != null) {
-                        max = Math.max(max, current);
-                        min = Math.min(min, current);
+                    @Nullable Number number = aspect.resolveNumber(entry);
+                    if (number != null) {
+                        BigDecimal current = new BigDecimal(number.toString());
+                        max = current.max(max);
+                        min = current.min(min);
                     }
                 }
             }
-            long duration = (long) max - (long) min;
 
+            long duration = max.subtract(min).longValue();
             if (duration > TimeUnit.DAYS.toNanos(1)) {
-                return DAYS_FORMATTER;
+                formatter = DAYS_FORMATTER;
             } else if (duration > TimeUnit.HOURS.toNanos(1)) {
-                return HOURS_FORMATTER;
+                formatter = HOURS_FORMATTER;
             } else if (duration > TimeUnit.MINUTES.toNanos(1)) {
-                return MINUTES_FORMATTER;
+                formatter = MINUTES_FORMATTER;
             } else if (duration > TimeUnit.SECONDS.toNanos(15)) {
-                return SECONDS_FORMATTER;
+                formatter = SECONDS_FORMATTER;
             } else {
-                return MILLISECONDS_FORMATTER;
+                formatter = MILLISECONDS_FORMATTER;
             }
+            ((LamiTimeStampFormat) formatter).setInternalRange(internalRange);
+            ((LamiTimeStampFormat) formatter).setExternalRange(externalRange);
+
         } else if (areAspectsTimeDuration(axisAspects)) {
-            /* Set the time duration formatter */
-            return NANO_TO_SECS_FORMATTER;
+            /* Set the time duration formatter. */
+            formatter = NANO_TO_SECS_FORMATTER;
+            ((LamiDecimalUnitFormat) formatter).setInternalRange(internalRange);
+            ((LamiDecimalUnitFormat) formatter).setExternalRange(externalRange);
 
         } else {
-            /* For other numeric aspects, use the default decimal unit formatter */
-            return DECIMAL_FORMATTER;
+            /*
+             * For other numeric aspects, use the default lami decimal unit
+             * formatter.
+             */
+            formatter = DECIMAL_FORMATTER;
+            ((LamiDecimalUnitFormat) formatter).setInternalRange(internalRange);
+            ((LamiDecimalUnitFormat) formatter).setExternalRange(externalRange);
         }
+
+        return formatter;
     }
 
     /**
@@ -715,4 +741,81 @@ public abstract class LamiXYChartViewer extends TmfViewer implements ILamiViewer
 
         return toolBar;
     }
+
+    /**
+     * Get a {@link LamiGraphRange} that covers all data points in the result
+     * table.
+     * <p>
+     * The returned range will be the minimum and maximum of the resolved values
+     * of the passed aspects for all result entries. If <code>clampToZero</code>
+     * is true, a positive minimum value will be clamped down to zero.
+     *
+     * @param aspects
+     *            The aspects that the range will represent
+     * @param clampToZero
+     *            If true, a positive minimum value will be clamped down to zero
+     * @return the range
+     */
+    protected LamiGraphRange getRange(List<LamiTableEntryAspect> aspects, boolean clampToZero) {
+        /* Find the minimum and maximum values */
+        BigDecimal min = new BigDecimal(Long.MAX_VALUE);
+        BigDecimal max = new BigDecimal(Long.MIN_VALUE);
+        for (LamiTableEntryAspect lamiTableEntryAspect : aspects) {
+            for (LamiTableEntry entry : getResultTable().getEntries()) {
+                @Nullable Number number = lamiTableEntryAspect.resolveNumber(entry);
+                if (number != null) {
+                    BigDecimal current = new BigDecimal(number.toString());
+                    min = current.min(min);
+                    max = current.max(max);
+                }
+            }
+        }
+
+        if (clampToZero) {
+            min.min(BigDecimal.ZERO);
+        }
+
+        /* Do not allow a range with a zero delta default to 1 */
+        if (max.equals(min)) {
+            max = min.add(BigDecimal.ONE);
+        }
+
+        return new LamiGraphRange(checkNotNull(min), checkNotNull(max));
+    }
+
+    /**
+     * Transform an external value into an internal value. Since SWTChart only
+     * support Double and Lami can pass Long values, loss of precision might
+     * happen. To minimize this, transform the raw values to an internal
+     * representation based on a linear transformation.
+     *
+     * The internal value =
+     *
+     * ((rawValue - rawMinimum) * (internalRangeDelta/rawRangeDelta)) +
+     * internalMinimum
+     *
+     * @param number
+     *            The number to transform
+     * @param internalRange
+     *            The internal range definition to be used
+     * @param externalRange
+     *            The external range definition to be used
+     * @return the transformed value in Double comprised inside the internal
+     *         range
+     */
+    protected static double getInternalDoubleValue(Number number, LamiGraphRange internalRange, LamiGraphRange externalRange) {
+        BigDecimal value = new BigDecimal(number.toString());
+
+        if (externalRange.getDelta().compareTo(BigDecimal.ZERO) == 0) {
+            return internalRange.getMinimum().doubleValue();
+        }
+
+        BigDecimal internalValue = value
+                .subtract(externalRange.getMinimum())
+                .multiply(internalRange.getDelta())
+                .divide(externalRange.getDelta(), BIG_DECIMAL_DIVISION_SCALE, BigDecimal.ROUND_DOWN)
+                .add(internalRange.getMinimum());
+
+        return internalValue.doubleValue();
+    }
 }
This page took 0.050385 seconds and 5 git commands to generate.