Added latency analysis feature (bug 331467)
authorBernd Hufmann <bhufmann@gmail.com>
Tue, 24 Jan 2012 16:27:45 +0000 (11:27 -0500)
committerBernd Hufmann <bhufmann@gmail.com>
Mon, 13 Feb 2012 14:05:41 +0000 (09:05 -0500)
58 files changed:
org.eclipse.linuxtools.lttng.core/META-INF/MANIFEST.MF
org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/EventMatcher.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/StackWrapper.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/EventsPair.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/Pair.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/AllLTTngUITests.java
org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/AllTests.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/LatencyGraphModelTest.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/histogram/HistogramDataModelTest.java
org.eclipse.linuxtools.lttng.ui/META-INF/MANIFEST.MF
org.eclipse.linuxtools.lttng.ui/icons/elcl16/add_button.gif [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/icons/elcl16/decreasebar_button.gif [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/icons/elcl16/delete_button.gif [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/icons/elcl16/increasebar_button.gif [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/icons/elcl16/warning.gif [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/icons/eview16/graph.gif [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/plugin.properties
org.eclipse.linuxtools.lttng.ui/plugin.xml
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/BaseDistributionData.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/DistributionData.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/HorDistributionData.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/IBaseDistributionModel.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/VerDistributionData.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/FullTraceHistogram.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Histogram.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramDataModel.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramScaledData.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramDataModel.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramModelListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeRangeHistogram.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/AbstractViewer.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/GraphViewer.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/HistogramViewer.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/LatencyView.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/Messages.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AbstractDialog.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AddDialog.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/DeleteDialog.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/ListDialog.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseTrackListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractPaintListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphMouseListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphPaintListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/HistogramPaintListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TimePointerListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TooltipListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/ZoomListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/messages.properties [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/Config.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/GraphScaledData.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphDataModel.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphModelListener.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyController.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyEventRequest.java [new file with mode: 0644]
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyGraphModel.java [new file with mode: 0644]

index a8275a04e27a2fb0f76e430c40d02e4d888dc92c..1ac8175feb1befb4c8a8a790256e7b8cbca5696e 100644 (file)
@@ -17,6 +17,7 @@ Export-Package: org.eclipse.linuxtools.lttng.core,
  org.eclipse.linuxtools.lttng.core.control,
  org.eclipse.linuxtools.lttng.core.event,
  org.eclipse.linuxtools.lttng.core.exceptions,
+ org.eclipse.linuxtools.lttng.core.latency.analyzer,
  org.eclipse.linuxtools.lttng.core.model,
  org.eclipse.linuxtools.lttng.core.request,
  org.eclipse.linuxtools.lttng.core.signal,
@@ -28,7 +29,9 @@ Export-Package: org.eclipse.linuxtools.lttng.core,
  org.eclipse.linuxtools.lttng.core.state.resource,
  org.eclipse.linuxtools.lttng.core.state.trace,
  org.eclipse.linuxtools.lttng.core.trace,
+ org.eclipse.linuxtools.lttng.core.tracecontrol,
  org.eclipse.linuxtools.lttng.core.tracecontrol.model,
  org.eclipse.linuxtools.lttng.core.tracecontrol.model.config,
- org.eclipse.linuxtools.lttng.core.tracecontrol.service
+ org.eclipse.linuxtools.lttng.core.tracecontrol.service,
+ org.eclipse.linuxtools.lttng.core.util
 Bundle-Localization: plugin
diff --git a/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/EventMatcher.java b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/EventMatcher.java
new file mode 100644 (file)
index 0000000..721efad
--- /dev/null
@@ -0,0 +1,505 @@
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse\r
+ * Public License v1.0 which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors: \r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.core.latency.analyzer;\r
+\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Map.Entry;\r
+import java.util.Set;\r
+import java.util.Stack;\r
+import java.util.Vector;\r
+\r
+import org.eclipse.linuxtools.lttng.core.event.LttngEvent;\r
+import org.eclipse.linuxtools.lttng.core.util.EventsPair;\r
+\r
+/**\r
+ * <b><u>EventMatcher</u></b>\r
+ * <p>\r
+ * Event matching class. Saves events in a list and returns the previously saved event if the currently processed one is\r
+ * its response, so that the latency can be computed by subtracting their respective timestamps.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class EventMatcher {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Class instance (Singleton pattern).\r
+     */\r
+    private static EventMatcher fInstance = null;\r
+\r
+    /**\r
+     * Stack abstraction, used to save the events in a list.\r
+     */\r
+    private StackWrapper fStack;\r
+\r
+    /**\r
+     * Match table, associates a request class to a response class.\r
+     */\r
+    private HashMap<String, String> fMatch;\r
+    /**\r
+     * Inverse match table, associates a response class to a request class.\r
+     */\r
+    private HashMap<String, String> fInverseMatch;\r
+\r
+    /**\r
+     * The number of events processed.\r
+     */\r
+    private int fProcessedEvents;\r
+    /**\r
+     * The number of events matched.\r
+     */\r
+    private int fMatchedEvents;\r
+       \r
+       /**\r
+        * Event types identification Strings.\r
+        */\r
+       @SuppressWarnings("nls")\r
+    public static String\r
+               ADD_TO_PAGE_CACHE         = "add_to_page_cache",\r
+               BIO_BACKMERGE             = "bio_backmerge",\r
+               BIO_FRONTMERGE            = "bio_frontmerge",\r
+               BIO_QUEUE                 = "bio_queue",\r
+               BUFFER_WAIT_END           = "buffer_wait_end",\r
+               BUFFER_WAIT_START         = "buffer_wait_start",\r
+               CALL                      = "call",\r
+               CLOSE                     = "close",\r
+               CORE_MARKER_FORMAT        = "core_marker_format",\r
+               CORE_MARKER_ID            = "core_marker_id",\r
+               DEV_RECEIVE               = "dev_receive",\r
+               DEV_XMIT                  = "dev_xmit",\r
+               END_COMMIT                = "end_commit",\r
+               EXEC                      = "exec",\r
+               FILE_DESCRIPTOR           = "file_descriptor",\r
+               GETRQ                     = "getrq",\r
+               GETRQ_BIO                 = "getrq_bio",\r
+               IDT_TABLE                 = "idt_table",\r
+               INTERRUPT                 = "interrupt",\r
+               IOCTL                     = "ioctl",\r
+               IRQ_ENTRY                 = "irq_entry",\r
+               IRQ_EXIT                  = "irq_exit",\r
+               LIST_MODULE               = "list_module",\r
+               LLSEEK                    = "llseek",\r
+               LSEEK                     = "lseek",\r
+               NAPI_COMPLETE             = "napi_complete",\r
+               NAPI_POLL                 = "napi_poll",\r
+               NAPI_SCHEDULE             = "napi_schedule",\r
+               NETWORK_IPV4_INTERFACE    = "network_ipv4_interface",\r
+               NETWORK_IP_INTERFACE      = "network_ip_interface",\r
+               OPEN                      = "open",\r
+               PAGE_FAULT_ENTRY          = "page_fault_entry",\r
+               PAGE_FAULT_EXIT           = "page_fault_exit",\r
+               PAGE_FAULT_GET_USER_ENTRY = "page_fault_get_user_entry",\r
+               PAGE_FAULT_GET_USER_EXIT  = "page_fault_get_user_exit",\r
+               PAGE_FREE                 = "page_free",\r
+               PLUG                      = "plug",\r
+               POLLFD                    = "pollfd",\r
+               PREAD64                   = "pread64",\r
+               PRINTF                    = "printf",\r
+               PRINTK                    = "printk",\r
+               PROCESS_EXIT              = "process_exit",\r
+               PROCESS_FORK              = "process_fork",\r
+               PROCESS_FREE              = "process_free",\r
+               PROCESS_STATE             = "process_state",\r
+               PROCESS_WAIT              = "process_wait",\r
+               READ                      = "read",\r
+               REMAP                     = "remap",\r
+               REMOVE_FROM_PAGE_CACHE    = "remove_from_page_cache",\r
+               RQ_COMPLETE_FS            = "rq_complete_fs",\r
+               RQ_COMPLETE_PC            = "rq_complete_pc",\r
+               RQ_INSERT_FS              = "rq_insert_fs",\r
+               RQ_INSERT_PC              = "rq_insert_pc",\r
+               RQ_ISSUE_FS               = "rq_issue_fs",\r
+               RQ_ISSUE_PC               = "rq_issue_pc",\r
+               RQ_REQUEUE_PC             = "rq_requeue_pc",\r
+               SCHED_MIGRATE_TASK        = "sched_migrate_task",\r
+               SCHED_SCHEDULE            = "sched_schedule",\r
+               SCHED_TRY_WAKEUP          = "sched_try_wakeup",\r
+               SCHED_WAKEUP_NEW_TASK     = "sched_wakeup_new_task",\r
+               SELECT                    = "select",\r
+               SEM_CREATE                = "sem_create",\r
+               SEND_SIGNAL               = "send_signal",\r
+               SHM_CREATE                = "shm_create",\r
+               SLEEPRQ_BIO               = "sleeprq_bio",\r
+               SOCKET_ACCEPT             = "socket_accept",\r
+               SOCKET_BIND               = "socket_bind",\r
+               SOCKET_CALL               = "socket_call",\r
+               SOCKET_CONNECT            = "socket_connect",\r
+               SOCKET_CREATE             = "socket_create",\r
+               SOCKET_GETPEERNAME        = "socket_getpeername",\r
+               SOCKET_GETSOCKNAME        = "socket_getsockname",\r
+               SOCKET_GETSOCKOPT         = "socket_getsockopt",\r
+               SOCKET_LISTEN             = "socket_listen",\r
+               SOCKET_SETSOCKOPT         = "socket_setsockopt",\r
+               SOCKET_SHUTDOWN           = "socket_shutdown",\r
+               SOCKET_SOCKETPAIR         = "socket_socketpair",\r
+               SOFTIRQ_ENTRY             = "softirq_entry",\r
+               SOFTIRQ_EXIT              = "softirq_exit",\r
+               SOFTIRQ_RAISE             = "softirq_raise",\r
+               SOFTIRQ_VEC               = "softirq_vec",\r
+               START_COMMIT              = "start_commit",\r
+               STATEDUMP_END             = "statedump_end",\r
+               SYS_CALL_TABLE            = "sys_call_table",\r
+           SYSCALL_ENTRY             = "syscall_entry",\r
+           SYSCALL_EXIT              = "syscall_exit",\r
+           TASKLET_LOW_ENTRY         = "tasklet_low_entry",\r
+           TASKLET_LOW_EXIT          = "tasklet_low_exit",\r
+           TCPV4_RCV                 = "tcpv4_rcv",\r
+           TIMER_ITIMER_EXPIRED      = "timer_itimer_expired",\r
+           TIMER_ITIMER_SET          = "timer_itimer_set",\r
+           TIMER_SET                 = "timer_set",\r
+           TIMER_TIMEOUT             = "timer_timeout",\r
+           TIMER_UPDATE_TIME         = "timer_update_time",\r
+           UDPV4_RCV                 = "udpv4_rcv",\r
+           UNPLUG_IO                 = "unplug_io",\r
+           UNPLUG_TIMER              = "unplug_timer",\r
+           VM_MAP                    = "vm_map",\r
+           VPRINTK                   = "vprintk",\r
+           WAIT_ON_PAGE_END          = "wait_on_page_end",\r
+           WAIT_ON_PAGE_START        = "wait_on_page_start",\r
+           WRITE                     = "write",\r
+           WRITEV                    = "writev";\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructor\r
+    // ------------------------------------------------------------------------\r
+       \r
+    /**\r
+     * Private constructor to defeat instantiation (Singleton pattern).\r
+     */\r
+    private EventMatcher() {\r
+        fStack = new StackWrapper();\r
+        fMatch = new HashMap<String, String>();\r
+        fInverseMatch = new HashMap<String, String>();\r
+\r
+        fProcessedEvents = 0;\r
+        fMatchedEvents = 0;\r
+\r
+        createMatchTable();\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Accessors\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Returns an instance to the EventMatcher class (Singleton pattern).\r
+     * @return An instance to the EventMatcher class (Singleton pattern).\r
+     */\r
+    public static EventMatcher getInstance() {\r
+        if (fInstance == null)\r
+            fInstance = new EventMatcher();\r
+        return fInstance;\r
+    }\r
+\r
+    /**\r
+     * Returns the number of events processed.\r
+     * @return The number of events processed.\r
+     */\r
+    public int getNBProcessedEvents() {\r
+        return fProcessedEvents;\r
+    }\r
+\r
+    /**\r
+     * Returns the number of events matched.\r
+     * @return The number of events matched.\r
+     */\r
+    public int getNBMatchedEvents() {\r
+        return fMatchedEvents;\r
+    }\r
+    \r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Releases the instance to the EventMatcher class.\r
+     */\r
+    public static void releaseInstance() {\r
+        fInstance = null;\r
+    }\r
+\r
+    /**\r
+     * Creates the event matching table, linking a response class to a request class.\r
+     */\r
+    private void createMatchTable() {\r
+        // Build the default matches\r
+        fMatch.put(PAGE_FAULT_GET_USER_EXIT, PAGE_FAULT_GET_USER_ENTRY);\r
+        fMatch.put(TASKLET_LOW_EXIT, TASKLET_LOW_ENTRY);\r
+        fMatch.put(PAGE_FAULT_EXIT, PAGE_FAULT_ENTRY);\r
+        fMatch.put(SYSCALL_EXIT, SYSCALL_ENTRY);\r
+        fMatch.put(IRQ_EXIT, IRQ_ENTRY);\r
+        fMatch.put(WRITE, READ);\r
+        fMatch.put(CLOSE, OPEN);\r
+        fMatch.put(BUFFER_WAIT_END, BUFFER_WAIT_START);\r
+        fMatch.put(END_COMMIT, START_COMMIT);\r
+        fMatch.put(WAIT_ON_PAGE_END, WAIT_ON_PAGE_START);\r
+\r
+        // Build the inverse matches based on the matches\r
+        Set<Entry<String, String>> pairs = fMatch.entrySet();\r
+        Iterator<Entry<String, String>> it = pairs.iterator();\r
+        while (it.hasNext()) {\r
+            Entry<String, String> pair = it.next();\r
+            fInverseMatch.put(pair.getValue(), pair.getKey());\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Processes an event received: if it is identified as a response, try to get its request to remove it from the\r
+     * list. If no request was saved, dismiss the current response. If it is a request, save it to the list of requests\r
+     * waiting for a response.\r
+     * @param event\r
+     *            The event to identify, and maybe process if it is a response.\r
+     * @return The request event associated with the current event (a response), or null if nothing was found (no\r
+     *         request associated with this response, or the event to identify was a request that was added to the\r
+     *         list).\r
+     */\r
+    public LttngEvent process(LttngEvent event) {\r
+        fProcessedEvents++;\r
+\r
+        String markerName = event.getMarkerName();\r
+        if (fMatch.containsKey(markerName)) {\r
+            String startEventType = fMatch.get(markerName);\r
+            Stack<LttngEvent> events = fStack.getStackOf(startEventType);\r
+            \r
+            if (events != null) {\r
+                for (int i = events.size() - 1; i >= 0; i--) {\r
+                    LttngEvent request = events.get(i);\r
+\r
+                    if (request.getCpuId() == event.getCpuId() && event.getTimestamp().getValue() > request.getTimestamp().getValue()) {\r
+                        fStack.removeEvent(startEventType, request);\r
+                        fMatchedEvents++;\r
+                        return request;\r
+                    }\r
+                }\r
+            }\r
+            return null;\r
+        } else {\r
+            // Add only if there can later be a match for this request\r
+            if (fMatch.containsValue(event.getMarkerName())) {\r
+                fStack.put(event.clone());\r
+            }\r
+            return null;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Clears the stack content.\r
+     */\r
+    public void clearStack() {\r
+        fStack.clear();\r
+\r
+        // Reset the processed and matched events counter\r
+        fProcessedEvents = 0;\r
+        fMatchedEvents = 0;\r
+    }\r
+\r
+    /**\r
+     * Resets all.\r
+     */\r
+    public void resetMatches() {\r
+        fMatch.clear();\r
+        fInverseMatch.clear();\r
+\r
+        fStack.clear();\r
+\r
+        // Reset the processed and matched events counter\r
+        fProcessedEvents = 0;\r
+        fMatchedEvents = 0;\r
+    }\r
+\r
+    /**\r
+     * Returns the list of start events.\r
+     * @return The list of start events.\r
+     */\r
+    public Collection<String> getStartEvents() {\r
+        return fMatch.values();\r
+    }\r
+\r
+    /**\r
+     * Returns the list of end events.\r
+     * @return The list of end events.\r
+     */\r
+    public Set<String> getEndEvents() {\r
+        return fMatch.keySet();\r
+    }\r
+\r
+    /**\r
+     * Returns the alphabetically-sorted list of start/end events pairs.\r
+     * @return The alphabetically-sorted list of start/end events pairs.\r
+     */\r
+    public EventsPair getEvents() {\r
+        Vector<String> start = new Vector<String>(getStartEvents());\r
+        Vector<String> end = new Vector<String>(fMatch.size());\r
+\r
+        Collections.sort(start);\r
+        for (int i = 0; i < start.size(); i++) {\r
+            end.add(fInverseMatch.get(start.get(i)));\r
+        }\r
+        return new EventsPair(start, end);\r
+    }\r
+\r
+    /**\r
+     * Adds a match to the list of events pairs.\r
+     * @param startType\r
+     *            The start event type.\r
+     * @param endType\r
+     *            The end event type.\r
+     */\r
+    public void addMatch(String startType, String endType) {\r
+        fMatch.put(endType, startType);\r
+        fInverseMatch.put(startType, endType);\r
+    }\r
+\r
+    /**\r
+     * Removes a matched pair based on the their type.\r
+     * \r
+     * <b>Note :</b> For now, only the pair's end type is used, since a type can only be either one start or one end.\r
+     * This function takes both types to account for the future, if a pairing process ever becomes more complex.\r
+     * \r
+     * @param startType\r
+     *            The type of the pair's start type.\r
+     * @param endType\r
+     *            The type of the pair's end type.\r
+     */\r
+    public void removeMatch(String startType, String endType) {\r
+        fMatch.remove(endType);\r
+        fInverseMatch.remove(startType);\r
+    }\r
+\r
+    /**\r
+     * Returns the list of all event possible types.\r
+     * @return The list of all event possible types.\r
+     */\r
+    public Vector<String> getTypeList() {\r
+        // Reserve some space for the 103 default event types.\r
+        Vector<String> eventsList = new Vector<String>(103);\r
+\r
+        eventsList.add(ADD_TO_PAGE_CACHE);\r
+        eventsList.add(BIO_BACKMERGE);\r
+        eventsList.add(BIO_FRONTMERGE);\r
+        eventsList.add(BIO_QUEUE);\r
+        eventsList.add(BUFFER_WAIT_END);\r
+        eventsList.add(BUFFER_WAIT_START);\r
+        eventsList.add(CALL);\r
+        eventsList.add(CLOSE);\r
+        eventsList.add(CORE_MARKER_FORMAT);\r
+        eventsList.add(CORE_MARKER_ID);\r
+        eventsList.add(DEV_RECEIVE);\r
+        eventsList.add(DEV_XMIT);\r
+        eventsList.add(END_COMMIT);\r
+        eventsList.add(EXEC);\r
+        eventsList.add(FILE_DESCRIPTOR);\r
+        eventsList.add(GETRQ);\r
+        eventsList.add(GETRQ_BIO);\r
+        eventsList.add(IDT_TABLE);\r
+        eventsList.add(INTERRUPT);\r
+        eventsList.add(IOCTL);\r
+        eventsList.add(IRQ_ENTRY);\r
+        eventsList.add(IRQ_EXIT);\r
+        eventsList.add(LIST_MODULE);\r
+        eventsList.add(LLSEEK);\r
+        eventsList.add(LSEEK);\r
+        eventsList.add(NAPI_COMPLETE);\r
+        eventsList.add(NAPI_POLL);\r
+        eventsList.add(NAPI_SCHEDULE);\r
+        eventsList.add(NETWORK_IPV4_INTERFACE);\r
+        eventsList.add(NETWORK_IP_INTERFACE);\r
+        eventsList.add(OPEN);\r
+        eventsList.add(PAGE_FAULT_ENTRY);\r
+        eventsList.add(PAGE_FAULT_EXIT);\r
+        eventsList.add(PAGE_FAULT_GET_USER_ENTRY);\r
+        eventsList.add(PAGE_FAULT_GET_USER_EXIT);\r
+        eventsList.add(PAGE_FREE);\r
+        eventsList.add(PLUG);\r
+        eventsList.add(POLLFD);\r
+        eventsList.add(PREAD64);\r
+        eventsList.add(PRINTF);\r
+        eventsList.add(PRINTK);\r
+        eventsList.add(PROCESS_EXIT);\r
+        eventsList.add(PROCESS_FORK);\r
+        eventsList.add(PROCESS_FREE);\r
+        eventsList.add(PROCESS_STATE);\r
+        eventsList.add(PROCESS_WAIT);\r
+        eventsList.add(READ);\r
+        eventsList.add(REMAP);\r
+        eventsList.add(REMOVE_FROM_PAGE_CACHE);\r
+        eventsList.add(RQ_COMPLETE_FS);\r
+        eventsList.add(RQ_COMPLETE_PC);\r
+        eventsList.add(RQ_INSERT_FS);\r
+        eventsList.add(RQ_INSERT_PC);\r
+        eventsList.add(RQ_ISSUE_FS);\r
+        eventsList.add(RQ_ISSUE_PC);\r
+        eventsList.add(RQ_REQUEUE_PC);\r
+        eventsList.add(SCHED_MIGRATE_TASK);\r
+        eventsList.add(SCHED_SCHEDULE);\r
+        eventsList.add(SCHED_TRY_WAKEUP);\r
+        eventsList.add(SCHED_WAKEUP_NEW_TASK);\r
+        eventsList.add(SELECT);\r
+        eventsList.add(SEM_CREATE);\r
+        eventsList.add(SEND_SIGNAL);\r
+        eventsList.add(SHM_CREATE);\r
+        eventsList.add(SLEEPRQ_BIO);\r
+        eventsList.add(SOCKET_ACCEPT);\r
+        eventsList.add(SOCKET_BIND);\r
+        eventsList.add(SOCKET_CALL);\r
+        eventsList.add(SOCKET_CONNECT);\r
+        eventsList.add(SOCKET_CREATE);\r
+        eventsList.add(SOCKET_GETPEERNAME);\r
+        eventsList.add(SOCKET_GETSOCKNAME);\r
+        eventsList.add(SOCKET_GETSOCKOPT);\r
+        eventsList.add(SOCKET_LISTEN);\r
+        eventsList.add(SOCKET_SETSOCKOPT);\r
+        eventsList.add(SOCKET_SHUTDOWN);\r
+        eventsList.add(SOCKET_SOCKETPAIR);\r
+        eventsList.add(SOFTIRQ_ENTRY);\r
+        eventsList.add(SOFTIRQ_EXIT);\r
+        eventsList.add(SOFTIRQ_RAISE);\r
+        eventsList.add(SOFTIRQ_VEC);\r
+        eventsList.add(START_COMMIT);\r
+        eventsList.add(STATEDUMP_END);\r
+        eventsList.add(SYS_CALL_TABLE);\r
+        eventsList.add(SYSCALL_ENTRY);\r
+        eventsList.add(SYSCALL_EXIT);\r
+        eventsList.add(TASKLET_LOW_ENTRY);\r
+        eventsList.add(TASKLET_LOW_EXIT);\r
+        eventsList.add(TCPV4_RCV);\r
+        eventsList.add(TIMER_ITIMER_EXPIRED);\r
+        eventsList.add(TIMER_ITIMER_SET);\r
+        eventsList.add(TIMER_SET);\r
+        eventsList.add(TIMER_TIMEOUT);\r
+        eventsList.add(TIMER_UPDATE_TIME);\r
+        eventsList.add(UDPV4_RCV);\r
+        eventsList.add(UNPLUG_IO);\r
+        eventsList.add(UNPLUG_TIMER);\r
+        eventsList.add(VM_MAP);\r
+        eventsList.add(VPRINTK);\r
+        eventsList.add(WAIT_ON_PAGE_END);\r
+        eventsList.add(WAIT_ON_PAGE_START);\r
+        eventsList.add(WRITE);\r
+        eventsList.add(WRITEV);\r
+\r
+        return eventsList;\r
+    }\r
+\r
+    /**\r
+     * Prints the stack content to the console.\r
+     */\r
+    public void print() {\r
+        fStack.printContent();\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/StackWrapper.java b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/latency/analyzer/StackWrapper.java
new file mode 100644 (file)
index 0000000..e64ccb2
--- /dev/null
@@ -0,0 +1,152 @@
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.core.latency.analyzer;\r
+\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Set;\r
+import java.util.Stack;\r
+\r
+import org.eclipse.linuxtools.lttng.core.event.LttngEvent;\r
+\r
+/**\r
+ * <b><u>StackWrapper</u></b>\r
+ * <p>\r
+ * Stack pile.\r
+ * \r
+ * TODO Change the types of the HashMaps from <String,String> to <Integer,Integer>, in order to take advantage of the\r
+ * compilation-time String.hashCode() speedup over execution-time String hash computation.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class StackWrapper {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Hash map of event stacks.\r
+     */\r
+    private HashMap<String, Stack<LttngEvent>> fStacks = null;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Constructor.\r
+     */\r
+    public StackWrapper() {\r
+        fStacks = new HashMap<String, Stack<LttngEvent>>();\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Adds an event to the list of events of the same type.\r
+     * @param event\r
+     *            The event to add to the list.\r
+     */\r
+    public void put(LttngEvent event) {\r
+        String key = event.getMarkerName();\r
+\r
+        if (fStacks.containsKey(key)) {\r
+            fStacks.get(key).add(event);\r
+        } else {\r
+            Stack<LttngEvent> newStack = new Stack<LttngEvent>();\r
+            newStack.add(event);\r
+            fStacks.put(key, newStack);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Checks if the stack contains a list of events of the given type.\r
+     * @param key\r
+     *            The type of events to check for.\r
+     * @return "true" if the stack contains events of the given type, "false" otherwise.\r
+     */\r
+    public boolean containsKey(String key) {\r
+        return fStacks.containsKey(key);\r
+    }\r
+\r
+    /**\r
+     * Returns the list of events of the given type.\r
+     * @param key\r
+     *            The type of events to return.\r
+     * @return The list of events of the given type, or null.\r
+     */\r
+    public Stack<LttngEvent> getStackOf(String key) {\r
+        return fStacks.get(key);\r
+    }\r
+\r
+    /**\r
+     * Removes the given event from the given stack list.\r
+     * @param key\r
+     *            The given stack type.\r
+     * @param event\r
+     *            The event to remove from the given stack type.\r
+     * @return "true" if the event was removed, "false" otherwise.\r
+     */\r
+    public boolean removeEvent(String key, LttngEvent event) {\r
+        Stack<LttngEvent> stack = fStacks.get(key);\r
+\r
+        boolean removed = false;\r
+\r
+        try {\r
+            /**\r
+             * TODO Correct this... Here, no matter what CPU or other content field, we always remove the last event\r
+             * added to the stack. Should be something like : return stack.remove(event);\r
+             */\r
+            stack.pop();\r
+            removed = true;\r
+        } catch (Exception e) {\r
+            e.printStackTrace();\r
+        }\r
+\r
+        // Remove the stack from the stack list if it is empty\r
+        if (stack.isEmpty()) {\r
+            fStacks.remove(key);\r
+        }\r
+\r
+        return removed;\r
+    }\r
+\r
+    /**\r
+     * Clears the stack content.\r
+     */\r
+    public void clear() {\r
+        fStacks.clear();\r
+    }\r
+\r
+    /**\r
+     * Prints the content of the stack to the console.\r
+     */\r
+    @SuppressWarnings("nls")\r
+    public void printContent() {\r
+        Collection<Stack<LttngEvent>> values = fStacks.values();\r
+        Iterator<Stack<LttngEvent>> valueIt = values.iterator();\r
+\r
+        Set<String> keys = fStacks.keySet();\r
+        Iterator<String> keyIt = keys.iterator();\r
+\r
+        while (valueIt.hasNext() && keyIt.hasNext()) {\r
+            Stack<LttngEvent> stack = valueIt.next();\r
+\r
+            System.out.println("   " + keyIt.next() + " [" + stack.size() + "] : " + stack);\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/EventsPair.java b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/EventsPair.java
new file mode 100644 (file)
index 0000000..3a13edd
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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: 
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.linuxtools.lttng.core.util;
+
+import java.util.Vector;
+
+
+/**
+ * Contains two lists of events name. The first list contains the events identified as starting request and the second list
+ * contains the events identified as ending request
+ */
+public class EventsPair extends Pair<Vector<String>, Vector<String>> {
+
+    public EventsPair() {
+        super();
+    }
+
+    public EventsPair(Vector<String> startingEvents, Vector<String> endingEvents) {
+        super(startingEvents, endingEvents);
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/Pair.java b/org.eclipse.linuxtools.lttng.core/src/org/eclipse/linuxtools/lttng/core/util/Pair.java
new file mode 100644 (file)
index 0000000..cebcf03
--- /dev/null
@@ -0,0 +1,121 @@
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.core.util;\r
+\r
+/**\r
+ * Pair utility class, encapsulates a pair of objects.\r
+ * \r
+ * @author Philippe Sawicki\r
+ * \r
+ * @param <A>\r
+ *            The type of the first object.\r
+ * @param <B>\r
+ *            The type of the second object.\r
+ */\r
+public abstract class Pair<A, B> {\r
+\r
+    /**\r
+     * A reference to the first object.\r
+     */\r
+    protected A fFirst;\r
+    /**\r
+     * A reference to the second object.\r
+     */\r
+    protected B fSecond;\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param first\r
+     *            The pair's first object.\r
+     * @param second\r
+     *            The pair's second object.\r
+     */\r
+    public Pair(A first, B second) {\r
+        fFirst = first;\r
+        fSecond = second;\r
+    }\r
+\r
+    /**\r
+     * Constructor.\r
+     */\r
+    public Pair() {\r
+        this(null, null);\r
+    }\r
+\r
+    /**\r
+     * Pair hash code.\r
+     */\r
+    @Override\r
+    public int hashCode() {\r
+        int hashFirst = fFirst != null ? fFirst.hashCode() : 0;\r
+        int hashSecond = fSecond != null ? fSecond.hashCode() : 0;\r
+\r
+        return (hashFirst + hashSecond) * hashSecond + hashFirst;\r
+    }\r
+\r
+    /**\r
+     * Object comparison.\r
+     */\r
+    @Override\r
+    @SuppressWarnings("unchecked")\r
+    public boolean equals(Object other) {\r
+        if (other instanceof Pair) {\r
+            Pair<A, B> otherPair = (Pair<A, B>) other;\r
+            return ((fFirst == otherPair.fFirst || (fFirst != null && otherPair.fFirst != null && fFirst.equals(otherPair.fFirst))) && (fSecond == otherPair.fSecond || (fSecond != null\r
+                    && otherPair.fSecond != null && fSecond.equals(otherPair.fSecond))));\r
+        }\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Object to string.\r
+     */\r
+    @Override\r
+    public String toString() {\r
+        return "(" + fFirst + ", " + fSecond + ")";  //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$\r
+    }\r
+\r
+    /**\r
+     * Returns a reference to the pair's first object.\r
+     * @return A reference to the pair's first object.\r
+     */\r
+    public A getFirst() {\r
+        return fFirst;\r
+    }\r
+\r
+    /**\r
+     * Sets the pair's first object.\r
+     * @param first\r
+     *            The pair's first object.\r
+     */\r
+    public void setFirst(A first) {\r
+        fFirst = first;\r
+    }\r
+\r
+    /**\r
+     * Returns a reference to the pair's second object.\r
+     * @return A reference to the pair's second object.\r
+     */\r
+    public B getSecond() {\r
+        return fSecond;\r
+    }\r
+\r
+    /**\r
+     * Sets the pair's second object.\r
+     * @param second\r
+     *            The pair's second object.\r
+     */\r
+    public void setSecond(B second) {\r
+        fSecond = second;\r
+    }\r
+}
\ No newline at end of file
index dcc3c10f2586fc8331fe934ce6fb6aeb3f8b5c52..ab6fe78934f204c3d5502cdc741e7322fb8d2770 100644 (file)
@@ -7,6 +7,7 @@ public class AllLTTngUITests  {
     public static Test suite() {
         TestSuite suite = new TestSuite(AllLTTngUITests.class.getName());
         //$JUnit-BEGIN$
+        suite.addTest(org.eclipse.linuxtools.lttng.ui.tests.distribution.AllTests.suite());
         suite.addTest(org.eclipse.linuxtools.lttng.ui.tests.histogram.AllTests.suite());
         //$JUnit-END$
         return suite;
diff --git a/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/AllTests.java b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/AllTests.java
new file mode 100644 (file)
index 0000000..b44a4de
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.tests.distribution;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+
+    public static Test suite() {
+        
+        TestSuite suite = new TestSuite(AllTests.class.getName());
+        //$JUnit-BEGIN$
+        suite.addTestSuite(LatencyGraphModelTest.class);
+        //$JUnit-END$
+        return suite;
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/LatencyGraphModelTest.java b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/distribution/LatencyGraphModelTest.java
new file mode 100644 (file)
index 0000000..36c382d
--- /dev/null
@@ -0,0 +1,582 @@
+package org.eclipse.linuxtools.lttng.ui.tests.distribution;
+
+import junit.framework.TestCase;
+
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config;
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.GraphScaledData;
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener;
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel;
+
+@SuppressWarnings("nls")
+public class LatencyGraphModelTest extends TestCase {
+
+    // ------------------------------------------------------------------------
+    // Test data
+    // ------------------------------------------------------------------------
+
+    // ------------------------------------------------------------------------
+    // Housekeeping
+    // ------------------------------------------------------------------------
+    
+    @Override
+    public void setUp() throws Exception {
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+    }
+
+    // ------------------------------------------------------------------------
+    // Tests
+    // ------------------------------------------------------------------------
+    
+    public void testLatencyGraphModel() {
+        LatencyGraphModel model = new LatencyGraphModel();
+        assertEquals("nbBuckets", Config.DEFAULT_NUMBER_OF_BUCKETS, model.getNbBuckets());
+        assertEquals("currentTime", Config.INVALID_EVENT_TIME, model.getCurrentEventTime());
+    }
+    
+    public void testLatencyGraphModelInt() {
+        LatencyGraphModel model = new LatencyGraphModel(100);
+        assertEquals("nbBuckets", 100, model.getNbBuckets());
+        assertEquals("currentTime", Config.INVALID_EVENT_TIME, model.getCurrentEventTime());
+    }
+
+    
+    public void testGraphModelListener() {
+        final int nbBuckets = 2000;
+        final int nbEvents = 10 * nbBuckets + 256;
+        final int[] count = new int[2];
+        count [0] = 0;
+        count [1] = 0;
+
+        // Test add listener and call of listener
+        IGraphModelListener listener = new IGraphModelListener() {
+            
+            @Override
+            public void graphModelUpdated() {
+                count[0]++;
+                
+            }
+            
+            @Override
+            public void currentEventUpdated(long currentEventTime) {
+                count[1]++;
+            }
+        };
+
+        // Test that the listener interface is called every 10000 events.
+        LatencyGraphModel model = new LatencyGraphModel(nbBuckets);
+        model.addGraphModelListener(listener);
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i+1, i, i);
+        }
+        
+        assertEquals("listener", 2, count[0]);
+
+        // Test that the listener interface is called when complete is called.
+        model.complete();
+        assertEquals("listener", 3, count[0]);
+
+        // Test that clear triggers call of listener interface
+        model.clear();
+        assertEquals("listener", 4, count[0]);
+
+        // Test that clear triggers call of listener interface
+        model.setCurrentEventNotifyListeners(100);
+        assertEquals("listener", 1, count[1]);
+        
+        // Test remove listener
+        count[0] = 0;
+        count[1] = 0;
+        model.removeGraphModelListener(listener);
+        
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i, i, i);
+        }
+        model.complete();
+        assertEquals("listener", 0, count[1]);
+        
+        // Test that clear triggers call of listener interface
+        model.setCurrentEventNotifyListeners(100);
+        assertEquals("listener", 0, count[1]);
+    }
+    
+    public void testConstructor() {
+        final int nbBuckets = 2000;
+        
+        LatencyGraphModel model = new LatencyGraphModel(nbBuckets);
+        GraphScaledData scaledData = model.scaleTo(100, 100, 1);
+        
+        // Verify model parameters
+        assertEquals("Horizontal bucket duration", 1, model.getHorBucketDuration());
+        assertEquals("Vertical bucket duration", 1, model.getVerBucketDuration());
+
+        assertEquals("Horizontal first bucket time", 0, model.getHorFirstBucketTime());
+        assertEquals("Vertical first bucket time", 0, model.getVerFirstBucketTime());
+
+        assertEquals("Horizontal last bucket ", 0, model.getHorLastBucket());
+        assertEquals("Vertical last bucket ", 0, model.getVerLastBucket());
+        
+        assertEquals("Horizontal first time", 0, model.getHorFirstEventTime());
+        assertEquals("Vertical first time", 0, model.getVerFirstEventTime());
+
+        assertEquals("Horizontal last time", 0, model.getHorLastEventTime());
+        assertEquals("Vertical last time", 0, model.getVerLastEventTime());
+        
+        assertEquals("Horizontal time limit", 2000, model.getHorTimeLimit());
+        assertEquals("Vertical time limit", 2000, model.getVerTimeLimit());
+     
+        // Verify scaled data parameters
+        scaledData = model.scaleTo(101, 100, 1);
+        
+        assertEquals("barWidth", 1, scaledData.getBarWidth());
+        assertEquals("height", 100, scaledData.getHeight());
+        assertEquals("width", 101, scaledData.getWidth());
+        
+        assertEquals(Config.INVALID_EVENT_TIME, scaledData.getCurrentEventTime());
+        
+        assertEquals("Horizontal bucket duration", 1, scaledData.getHorBucketDuration());
+        assertEquals("Vertical bucket duration", 1, scaledData.getVerBucketDuration());
+        
+        assertEquals("Horizontal bucket end time", 1, scaledData.getHorBucketEndTime(0));
+        assertEquals("Vertical bucket end time", 1, scaledData.getVerBucketEndTime(0));
+        
+        assertEquals("Horizontal bucket start time", 0, scaledData.getHorBucketStartTime(0));
+        assertEquals("Vertical bucket start time", 0, scaledData.getVerBucketStartTime(0));
+
+        assertEquals("Horizontal first time", 0, scaledData.getHorFirstEventTime());
+        assertEquals("Vertical first time", 0, scaledData.getVerFirstEventTime());
+        
+        assertEquals("Horizontal first bucket time", 0, scaledData.getHorFirstBucketTime());
+        assertEquals("Vertical first bucket time", 0, scaledData.getVerFirstBucketTime());
+
+        assertEquals("Horizontal last bucket time", 0, scaledData.getHorLastBucketTime());
+        assertEquals("Vertical last bucket time", 0, scaledData.getVerLastBucketTime());
+        
+        assertEquals("Horizontal number of buckets", 101, scaledData.getHorNbBuckets());
+        assertEquals("Vertical nubmer of buckets", 100, scaledData.getVerNbBuckets());
+        
+        assertEquals("Horizontal getIndex", 100, scaledData.getHorBucketIndex(100));
+        assertEquals("Vertical getIndex", 124, scaledData.getVerBucketIndex(124));
+        
+        assertEquals("Horizontal last bucket", 0, scaledData.getHorLastBucket());
+        assertEquals("Vertical last bucket", 0, scaledData.getVerLastBucket());
+        
+        assertEquals("Horizontal last event time", 0, scaledData.getHorLastEventTime());
+        assertEquals("Vertical last event time", 0, scaledData.getVerLastEventTime());
+    }
+    
+    public void testClear() {
+        final int nbBuckets = 2000;
+        final int nbEvents = 10 * nbBuckets + 256;
+        
+        LatencyGraphModel model = new LatencyGraphModel(nbBuckets);
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i+1, i, i);
+        }
+        // make sure that we actually counted something.
+        GraphScaledData scaledData = model.scaleTo(100, 100, 1);
+
+        assertTrue(scaledData.getHorLastBucket() > 0);
+        
+        model.clear();
+        
+        // Verify model parameters
+        assertEquals("Horizontal bucket duration", 1, model.getHorBucketDuration());
+        assertEquals("Vertical bucket duration", 1, model.getVerBucketDuration());
+
+        assertEquals("Horizontal first bucket time", 0, model.getHorFirstBucketTime());
+        assertEquals("Vertical first bucket time", 0, model.getVerFirstBucketTime());
+
+        assertEquals("Horizontal last bucket ", 0, model.getHorLastBucket());
+        assertEquals("Vertical last bucket ", 0, model.getVerLastBucket());
+        
+        assertEquals("Horizontal first time", 0, model.getHorFirstEventTime());
+        assertEquals("Vertical first time", 0, model.getVerFirstEventTime());
+
+        assertEquals("Horizontal last time", 0, model.getHorLastEventTime());
+        assertEquals("Vertical last time", 0, model.getVerLastEventTime());
+        
+        assertEquals("Horizontal time limit", 2000, model.getHorTimeLimit());
+        assertEquals("Vertical time limit", 2000, model.getVerTimeLimit());
+
+        // Verify scaled data parameters
+        scaledData = model.scaleTo(101, 100, 1);
+        
+        assertEquals("barWidth", 1, scaledData.getBarWidth());
+        assertEquals("height", 100, scaledData.getHeight());
+        assertEquals("width", 101, scaledData.getWidth());
+        
+        assertEquals(Config.INVALID_EVENT_TIME, scaledData.getCurrentEventTime());
+        
+        assertEquals("Horizontal bucket duration", 1, scaledData.getHorBucketDuration());
+        assertEquals("Vertical bucket duration", 1, scaledData.getVerBucketDuration());
+        
+        assertEquals("Horizontal bucket end time", 1, scaledData.getHorBucketEndTime(0));
+        assertEquals("Vertical bucket end time", 1, scaledData.getVerBucketEndTime(0));
+        
+        assertEquals("Horizontal bucket start time", 0, scaledData.getHorBucketStartTime(0));
+        assertEquals("Vertical bucket start time", 0, scaledData.getVerBucketStartTime(0));
+
+        assertEquals("Horizontal first time", 0, scaledData.getHorFirstEventTime());
+        assertEquals("Vertical first time", 0, scaledData.getVerFirstEventTime());
+        
+        assertEquals("Horizontal first bucket time", 0, scaledData.getHorFirstBucketTime());
+        assertEquals("Vertical first bucket time", 0, scaledData.getVerFirstBucketTime());
+
+        assertEquals("Horizontal last bucket time", 0, scaledData.getHorLastBucketTime());
+        assertEquals("Vertical last bucket time", 0, scaledData.getVerLastBucketTime());
+        
+        assertEquals("Horizontal getIndex", 100, scaledData.getHorBucketIndex(100));
+        assertEquals("Vertical getIndex", 124, scaledData.getVerBucketIndex(124));
+
+        assertEquals("Horizontal number of buckets", 101, scaledData.getHorNbBuckets());
+        assertEquals("Vertical nubmer of buckets", 100, scaledData.getVerNbBuckets());
+        
+        assertEquals("Horizontal last bucket", 0, scaledData.getHorLastBucket());
+        assertEquals("Vertical last bucket", 0, scaledData.getVerLastBucket());
+        
+        assertEquals("Horizontal last event time", 0, scaledData.getHorLastEventTime());
+        assertEquals("Vertical last event time", 0, scaledData.getVerLastEventTime());
+    }
+    
+    public void testCountEvent() {
+        final int nbBuckets = 2000;
+        final int nbEvents = 10 * nbBuckets + 256;
+        final long hOffset = 100;
+        final long vOffset = 55;
+        
+        LatencyGraphModel model = new LatencyGraphModel(nbBuckets);
+        
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i + 1, hOffset + i, vOffset + i);
+        }
+
+        // Verify model parameters
+        assertEquals("Horizontal bucket duration", 16, model.getHorBucketDuration());
+        assertEquals("Vertical bucket duration", 16, model.getVerBucketDuration());
+
+        assertEquals("Horizontal first bucket time", hOffset, model.getHorFirstBucketTime());
+        assertEquals("Vertical first bucket time", vOffset, model.getVerFirstBucketTime());
+
+        assertEquals("Horizontal last bucket ", (nbEvents - 1)/16, model.getHorLastBucket());
+        assertEquals("Vertical last bucket ", (nbEvents - 1)/16, model.getVerLastBucket());
+        
+        assertEquals("Horizontal first time", hOffset, model.getHorFirstEventTime());
+        assertEquals("Vertical first time", vOffset, model.getVerFirstEventTime());
+
+        assertEquals("Horizontal last time", nbEvents + hOffset - 1, model.getHorLastEventTime());
+        assertEquals("Vertical last time", nbEvents + vOffset - 1, model.getVerLastEventTime());
+        
+        assertEquals("Horizontal time limit", 16 * nbBuckets + hOffset, model.getHorTimeLimit());
+        assertEquals("Vertical time limit", 16 * nbBuckets + vOffset, model.getVerTimeLimit());
+
+        // Verify scaled data parameters
+        GraphScaledData scaledData = model.scaleTo(50, 100, 1);
+        
+        assertEquals("barWidth", 1, scaledData.getBarWidth());
+        assertEquals("height", 100, scaledData.getHeight());
+        assertEquals("width", 50, scaledData.getWidth());
+        
+        assertEquals(Config.INVALID_EVENT_TIME, scaledData.getCurrentEventTime());
+
+        // nbBars = width / barWidth
+        // bucketsPerBar = lastBucket/nbBars + 1
+        // scaled bucket duration = bucketsPerBar * model.bucketDuration
+        // for nbBuckets=2000 and nbEvents=20256 (means 20256 ns + offset) -> model.bucketDuration = 16
+        assertEquals("Horizontal bucket duration", 416, scaledData.getHorBucketDuration());
+        assertEquals("Vertical bucket duration", 208, scaledData.getVerBucketDuration());
+        
+        // startTime + scaledData.bucketDuration
+        assertEquals("Horizontal bucket end time", hOffset + 416, scaledData.getHorBucketEndTime(0));
+        assertEquals("Vertical bucket end time", 55 + 208, scaledData.getVerBucketEndTime(0));
+        
+        assertEquals("Horizontal bucket start time", 100, scaledData.getHorBucketStartTime(0));
+        assertEquals("Vertical bucket start time", 55, scaledData.getVerBucketStartTime(0));
+
+        assertEquals("Horizontal first time", 100, scaledData.getHorFirstEventTime());
+        assertEquals("Vertical first time", 55, scaledData.getVerFirstEventTime());
+        
+        assertEquals("Horizontal first bucket time", hOffset, scaledData.getHorFirstBucketTime());
+        assertEquals("Vertical first bucket time", 55, scaledData.getVerFirstBucketTime());
+        
+        assertEquals("Horizontal last bucket time", hOffset + 48 * 416, scaledData.getHorLastBucketTime());
+        assertEquals("Vertical last bucket time", vOffset + 97 * 208, scaledData.getVerLastBucketTime());
+        
+        assertEquals("Horizontal getIndex", 47, scaledData.getHorBucketIndex(20000));
+        assertEquals("Vertical getIndex", 47, scaledData.getVerBucketIndex(10000));
+        
+        // nb Buckets = nbBars
+        assertEquals("Horizontal number of buckets", 50, scaledData.getHorNbBuckets());
+        assertEquals("Vertical nubmer of buckets", 100, scaledData.getVerNbBuckets());
+        
+        assertEquals("Horizontal last bucket", 48, scaledData.getHorLastBucket());
+        assertEquals("Vertical last bucket", 97, scaledData.getVerLastBucket());
+        
+        // start time of last bucket
+        assertEquals("Horizontal last event time", hOffset + nbEvents - 1, scaledData.getHorLastEventTime());
+        assertEquals("Vertical last event time", vOffset + nbEvents - 1 , scaledData.getVerLastEventTime());
+    }
+
+    public void testCountEvent2() {
+
+        final int nbBuckets = 2000;
+        final int nbEvents = 10 * nbBuckets + 256;
+        final long offset = 100;
+        final int height = 100;
+        final int width = 100;
+        final int barWidth = 1;
+        
+        int[][] expectedResults = new int[width/barWidth][height/barWidth];
+        
+        int total = 0;
+        
+        // Horizontally and vertically the same data is used
+        
+        // for nbBuckets=2000 and nbEvents=20256 (means 20256 ns + offset) -> model.bucketDuration = 16
+        // nbBars = width / barWidth = 100
+        // bucketsPerBar = lastBucket/nbBars + 1 = 13
+        // scaled bucket duration = bucketsPerBar * model.bucketDuration =  13 * 16
+        boolean isFinished = false;
+        for (int i = 0; i < width/barWidth; i++) {
+            if (isFinished) {
+                break;
+            }
+            for (int j = 0; j < height/barWidth; j++) {
+                if (i == j) {
+                    int value = 13 * 16;
+                    if (total + value > nbEvents) {
+                        expectedResults[i][j] = nbEvents - total;
+                        isFinished = true;
+                        break;
+                    }
+                    else {
+                        expectedResults[i][j] = value;
+                        total += value;
+                    }
+                }
+            }
+        }
+       
+        LatencyGraphModel model = new LatencyGraphModel(nbBuckets);
+        
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i+1, offset + i, offset + i);
+        }
+
+        GraphScaledData scaledData = model.scaleTo(height, width, barWidth);
+
+        for (int i = 0; i < scaledData.getHorLastBucket(); i++) {
+            for (int j = 0; j < scaledData.getVerLastBucket(); j++) {
+                assertEquals(expectedResults[i][j], scaledData.getEventCount(i, j));
+            }
+        }
+    }
+    
+    public void testCountEvent3() {
+        // Test with barWidth > 1
+        final int nbBuckets = 2000;
+        final int nbEvents = 10 * nbBuckets + 256;
+        final long offset = 100;
+        final int height = 100;
+        final int width = 100;
+        final int barWidth = 4;
+        
+        int[][] expectedResults = new int[width/barWidth][height/barWidth];
+        
+        int total = 0;
+        
+        // Horizontally and vertically the same data is used
+        
+        // for nbBuckets=2000 and nbEvents=20256 (means 20256 ns + offset) -> model.bucketDuration = 16
+        // nbBars = width / barWidth = 25
+        // bucketsPerBar = lastBucket/nbBars + 1 = 51
+        // scaled bucket duration = bucketsPerBar * model.bucketDuration =  51 * 16
+        boolean isFinished = false;
+        for (int i = 0; i < width/barWidth; i++) {
+            if (isFinished) {
+                break;
+            }
+            for (int j = 0; j < height/barWidth; j++) {
+                if (i == j) {
+                    int value = 51 * 16;
+                    if (total + value > nbEvents) {
+                        expectedResults[i][j] = nbEvents - total;
+                        isFinished = true;
+                        break;
+                    }
+                    else {
+                        expectedResults[i][j] = value;
+                        total += value;
+                    }
+                }
+            }
+        }
+       
+        LatencyGraphModel model = new LatencyGraphModel(nbBuckets);
+        
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i+1, offset + i, offset + i);
+        }
+
+        GraphScaledData scaledData = model.scaleTo(height, width, barWidth);
+
+        for (int i = 0; i < scaledData.getHorLastBucket(); i++) {
+            for (int j = 0; j < scaledData.getVerLastBucket(); j++) {
+                assertEquals(expectedResults[i][j], scaledData.getEventCount(i, j));
+            }
+        }
+    }
+    
+    public void testCountEventReverse1() {
+        // Depending on the number of buckets and events the start buckets can be different
+        // between forward and reserve times. However, the content is correct.
+        final int nbBuckets = 100;
+        final int nbEvents = 256;
+        final long hOffset = 100;
+        final long vOffset = 55;
+        final int height = 100;
+        final int width = 50;
+        final int barWidth = 1;
+
+        LatencyGraphModel model = new LatencyGraphModel(nbBuckets);
+        
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i + 1, hOffset + i, vOffset + i);
+        }
+        
+        GraphScaledData scaledData = model.scaleTo(width, height, barWidth);
+        
+        model.clear();
+        
+        for (int i = nbEvents - 1; i >= 0; i--) {
+            model.countEvent(nbEvents - i, hOffset + i, vOffset + i);
+        }
+        
+        GraphScaledData scaledDataReverse = model.scaleTo(50, 100, 1);
+        
+        long count = 0;
+        for (int i = 0; i <= scaledData.getHorLastBucket(); i++) {
+            for (int j = 0; j <= scaledData.getVerLastBucket(); j++) {
+                count += scaledData.getEventCount(i, j);
+            }
+        }
+        
+        long revCount = 0;
+        for (int i = 0; i <= scaledDataReverse.getHorLastBucket(); i++) {
+            for (int j = 0; j <= scaledDataReverse.getVerLastBucket(); j++) {
+                revCount += scaledDataReverse.getEventCount(i, j);
+            }
+        }
+
+        assertEquals(count, revCount);
+
+        // Make sure that both scaledData have the same content
+        assertTrue("barWidth", scaledData.getBarWidth() == scaledDataReverse.getBarWidth());
+        assertTrue("height", scaledData.getHeight() == scaledDataReverse.getHeight());
+        assertTrue("width", scaledData.getWidth() == scaledDataReverse.getWidth());
+        
+        assertTrue(scaledData.getCurrentEventTime() == scaledDataReverse.getCurrentEventTime());
+
+        assertTrue("Horizontal bucket duration", scaledData.getHorBucketDuration() == scaledDataReverse.getHorBucketDuration());
+        assertTrue("Vertical bucket duration", scaledData.getVerBucketDuration() == scaledDataReverse.getVerBucketDuration());
+        
+        // startTime + scaledData.bucketDuration
+        assertTrue("Horizontal bucket end time", scaledData.getHorBucketEndTime(0) == scaledDataReverse.getHorBucketEndTime(0));
+        assertTrue("Vertical bucket end time", scaledData.getVerBucketEndTime(0) == scaledDataReverse.getVerBucketEndTime(0));
+        
+        assertTrue("Horizontal bucket start time", scaledData.getHorBucketStartTime(0) == scaledDataReverse.getHorBucketStartTime(0));
+        assertTrue("Vertical bucket start time", scaledData.getVerBucketStartTime(0) == scaledDataReverse.getVerBucketStartTime(0));
+
+        assertTrue("Horizontal first time", scaledData.getHorFirstEventTime() == scaledDataReverse.getHorFirstEventTime());
+        assertTrue("Vertical first time",  scaledData.getVerFirstEventTime() == scaledDataReverse.getVerFirstEventTime());
+        
+        assertTrue("Horizontal getIndex", scaledData.getHorBucketIndex(200) == scaledDataReverse.getHorBucketIndex(200));
+        assertTrue("Vertical getIndex", scaledData.getVerBucketIndex(100) == scaledDataReverse.getVerBucketIndex(100));
+
+        assertTrue("Horizontal last bucket", scaledData.getHorNbBuckets() == scaledDataReverse.getHorNbBuckets());
+        assertTrue("Vertical last bucket", scaledData.getVerNbBuckets() == scaledDataReverse.getVerNbBuckets());
+
+        assertTrue("Horizontal nubmer of buckets", scaledData.getHorLastBucket() == scaledDataReverse.getHorLastBucket());
+        assertTrue("Vertical nubmer of buckets", scaledData.getVerLastBucket() == scaledDataReverse.getVerLastBucket());
+        
+        // start time of last bucket
+        assertTrue("Horizontal last event time", scaledData.getHorLastEventTime() == scaledDataReverse.getHorLastEventTime());
+        assertTrue("Vertical last event time", scaledData.getVerLastEventTime() == scaledDataReverse.getVerLastEventTime());
+    }
+
+    public void testCountEventReverse2() {
+        // Depending on the number of buckets and events the start buckets can be different
+        // between forward and reserve times. However, the content is correct.
+        final int nbBuckets = 100;
+        final int nbEvents = 256;
+        final long hOffset = 100;
+        final long vOffset = 55;
+        final int height = 100;
+        final int width = 50;
+        final int barWidth = 1;
+
+        LatencyGraphModel model = new LatencyGraphModel(nbBuckets);
+        
+        for (int i = nbEvents - 1; i >= 0; i--) {
+            model.countEvent(nbEvents - i, hOffset + i, vOffset + i);
+        }
+
+        // Verify model parameters
+        int expectedBucketDuration = 4;
+        assertEquals("Horizontal bucket duration", expectedBucketDuration, model.getHorBucketDuration());
+        assertEquals("Vertical bucket duration", expectedBucketDuration, model.getVerBucketDuration());
+
+        assertEquals("Horizontal first bucket time", hOffset, model.getHorFirstBucketTime());
+        assertEquals("Vertical first bucket time", vOffset, model.getVerFirstBucketTime());
+
+        assertEquals("Horizontal last bucket", (nbEvents -1)/expectedBucketDuration, model.getHorLastBucket());
+        assertEquals("Vertical last bucket", (nbEvents -1)/expectedBucketDuration, model.getVerLastBucket());
+
+        assertEquals("Horizontal first time", hOffset, model.getHorFirstEventTime());
+        assertEquals("Vertical first time", vOffset, model.getVerFirstEventTime());
+
+        assertEquals("Horizontal last time", nbEvents + hOffset - 1, model.getHorLastEventTime());
+        assertEquals("Vertical last time", nbEvents + vOffset - 1, model.getVerLastEventTime());
+
+        assertEquals("Horizontal time limit", expectedBucketDuration * nbBuckets + hOffset, model.getHorTimeLimit());
+        assertEquals("Vertical time limit", expectedBucketDuration * nbBuckets + vOffset, model.getVerTimeLimit());
+
+        GraphScaledData scaledData = model.scaleTo(50, 100, 1);
+        
+        // Make sure that both scaledData have the same content
+        assertEquals("barWidth", barWidth, scaledData.getBarWidth());
+        assertEquals("height", height, scaledData.getHeight());
+        assertEquals("width", width, scaledData.getWidth());
+        
+        assertEquals(-1, scaledData.getCurrentEventTime()); 
+        
+        assertEquals("Horizontal bucket duration", 8, scaledData.getHorBucketDuration());
+        assertEquals("Vertical bucket duration", 4, scaledData.getVerBucketDuration());
+        
+        // startTime + scaledData.bucketDuration
+        assertEquals("Horizontal bucket end time", hOffset + 8, scaledData.getHorBucketEndTime(0));
+        assertEquals("Vertical bucket end time", vOffset + 4, scaledData.getVerBucketEndTime(0));
+        
+        assertEquals("Horizontal bucket start time", hOffset, scaledData.getHorBucketStartTime(0));
+        assertEquals("Vertical bucket start time", vOffset, scaledData.getVerBucketStartTime(0));
+
+        assertEquals("Horizontal first time", hOffset, scaledData.getHorFirstEventTime());
+        assertEquals("Vertical first time",  vOffset, scaledData.getVerFirstEventTime());
+        
+        assertEquals("Horizontal getIndex", 12, scaledData.getHorBucketIndex(200));
+        assertEquals("Vertical getIndex", 11, scaledData.getVerBucketIndex(100));
+
+        // nb Buckets = nbBars
+        assertEquals("Horizontal number of buckets", 50, scaledData.getHorNbBuckets());
+        assertEquals("Vertical number of buckets", 100, scaledData.getVerNbBuckets());
+        
+        assertEquals("Horizontal last bucket", 31, scaledData.getHorLastBucket());
+        assertEquals("Vertical last bucket", 63, scaledData.getVerLastBucket());
+        // start time of last bucket
+        assertEquals("Horizontal last event time", 355, scaledData.getHorLastEventTime());
+        assertEquals("Vertical last event time", 310, scaledData.getVerLastEventTime());
+    }
+}
index e0e0f3f9bd99159a1b26f81101eccaf414bd46de..249d34d2ef8bb81ac8334bbb6ce4f32d74219011 100644 (file)
@@ -17,6 +17,7 @@ import junit.framework.TestCase;
 
 import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramDataModel;
 import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramScaledData;
+import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramModelListener;
 
 /**
  * <b><u>HistogramDataModelTest</u></b>
@@ -55,6 +56,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbBuckets() == HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS);
         assertTrue(model.getNbEvents() == 0);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == 0);
         assertTrue(model.getTimeLimit() == HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS);
@@ -71,6 +73,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == 0);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == 0);
         assertTrue(model.getTimeLimit() == nbBuckets);
@@ -84,11 +87,12 @@ public class HistogramDataModelTest extends TestCase {
     public void testClear() {
         final int nbBuckets = 100;
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
-        model.countEvent(-1);
+        model.countEvent(0, -1);
 
         assertTrue(model.getNbEvents() == 0);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == 0);
         assertTrue(model.getTimeLimit() == nbBuckets);
@@ -102,11 +106,12 @@ public class HistogramDataModelTest extends TestCase {
     public void testCountEvent_0() {
         final int nbBuckets = 100;
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
-        model.countEvent(-1);
+        model.countEvent(0, -1);
 
         assertTrue(model.getNbEvents() == 0);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == 0);
         assertTrue(model.getTimeLimit() == nbBuckets);
@@ -118,7 +123,7 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
 
-        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight);
+        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == 0);
         }
@@ -126,6 +131,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == 0);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == 0);
         assertTrue(model.getTimeLimit() == nbBuckets);
@@ -136,9 +142,9 @@ public class HistogramDataModelTest extends TestCase {
         final int maxHeight = 10;
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
-        model.countEvent(1);
+        model.countEvent(0, 1);
 
-        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight);
+        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
         assertTrue(result.fData[0] == 1);
         for (int i = 1; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == 0);
@@ -147,6 +153,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == 1);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 1);
         assertTrue(model.getStartTime() == 1);
         assertTrue(model.getEndTime() == 1);
         assertTrue(model.getTimeLimit() == nbBuckets + 1);
@@ -158,10 +165,10 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
         for (int i = 0; i < nbBuckets; i++) {
-            model.countEvent(i);
+            model.countEvent(i, i);
         }
 
-        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight);
+        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == 1);
         }
@@ -169,6 +176,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == nbBuckets);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == nbBuckets - 1);
         assertTrue(model.getTimeLimit() == nbBuckets);
@@ -180,11 +188,11 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
         for (int i = 0; i < nbBuckets; i++) {
-            model.countEvent(i);
-            model.countEvent(i);
+            model.countEvent(i, i);
+            model.countEvent(i+1, i);
         }
 
-        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight);
+        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == 2);
         }
@@ -192,6 +200,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == 2 * nbBuckets);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == nbBuckets - 1);
         assertTrue(model.getTimeLimit() == nbBuckets);
@@ -204,10 +213,10 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
         for (int i = startTime; i < startTime + nbBuckets; i++) {
-            model.countEvent(i);
+            model.countEvent(i, i);
         }
 
-        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight);
+        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == 1);
         }
@@ -215,6 +224,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == nbBuckets);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == startTime);
         assertTrue(model.getStartTime() == startTime);
         assertTrue(model.getEndTime() == startTime + nbBuckets - 1);
         assertTrue(model.getTimeLimit() == startTime + nbBuckets);
@@ -228,15 +238,15 @@ public class HistogramDataModelTest extends TestCase {
     public void testScaleTo_0() {
         HistogramDataModel model = new HistogramDataModel(10);
         try {
-            model.scaleTo(10, 0);
+            model.scaleTo(10, 0, 1);
         }
         catch (AssertionError e1) {
             try {
-                model.scaleTo(0, 10);
+                model.scaleTo(0, 10, 1);
             }
             catch (AssertionError e2) {
                 try {
-                    model.scaleTo(0, 0);
+                    model.scaleTo(0, 0, 1);
                 }
                 catch (AssertionError e3) {
                     return;
@@ -255,10 +265,10 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
         for (int i = 0; i < nbEvents; i++) {
-            model.countEvent(i);
+            model.countEvent(i, i);
         }
 
-        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight);
+        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == expectedResult[i]);
         }
@@ -266,6 +276,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == nbEvents);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == nbEvents - 1);
         assertTrue(model.getTimeLimit() == nbBuckets);
@@ -279,10 +290,10 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
         for (int i = 0; i < nbEvents; i++) {
-            model.countEvent(i);
+            model.countEvent(i, i);
         }
 
-        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight);
+        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == expectedResult[i]);
         }
@@ -290,6 +301,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == nbEvents);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 1);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == nbEvents - 1);
         assertTrue(model.getTimeLimit() == nbBuckets);
@@ -303,10 +315,10 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
         for (int i = 0; i < nbEvents; i++) {
-            model.countEvent(i);
+            model.countEvent(i, i);
         }
 
-        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight);
+        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == expectedResult[i]);
         }
@@ -314,6 +326,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == nbEvents);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 2);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == nbEvents - 1);
         assertTrue(model.getTimeLimit() == 2 * nbBuckets);
@@ -327,10 +340,10 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
         for (int i = 0; i < nbEvents; i++) {
-            model.countEvent(i);
+            model.countEvent(i, i);
         }
 
-        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight);
+        HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == expectedResult[i]);
         }
@@ -338,6 +351,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == nbEvents);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 4);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == nbEvents - 1);
         assertTrue(model.getTimeLimit() == 4 * nbBuckets);
@@ -351,10 +365,10 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
         for (int i = 0; i < nbEvents; i++) {
-            model.countEvent(i);
+            model.countEvent(i, i);
         }
 
-        HistogramScaledData result = model.scaleTo(10, maxHeight);
+        HistogramScaledData result = model.scaleTo(10, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == expectedResult[i]);
         }
@@ -362,7 +376,7 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == nbEvents);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 2);
-        assertTrue(model.getStartTime() == 0);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getEndTime() == nbEvents - 1);
         assertTrue(model.getTimeLimit() == 2 * nbBuckets);
     }
@@ -375,10 +389,10 @@ public class HistogramDataModelTest extends TestCase {
 
         HistogramDataModel model = new HistogramDataModel(nbBuckets);
         for (int i = 0; i < nbEvents; i++) {
-            model.countEvent(i);
+            model.countEvent(i, i);
         }
 
-        HistogramScaledData result = model.scaleTo(10, maxHeight);
+        HistogramScaledData result = model.scaleTo(10, maxHeight, 1);
         for (int i = 0; i < result.fData.length; i++) {
             assertTrue(result.fData[i] == expectedResult[i]);
         }
@@ -386,9 +400,195 @@ public class HistogramDataModelTest extends TestCase {
         assertTrue(model.getNbEvents() == nbEvents);
         assertTrue(model.getNbBuckets() == nbBuckets);
         assertTrue(model.getBucketDuration() == 4);
+        assertTrue(model.getFirstBucketTime() == 0);
         assertTrue(model.getStartTime() == 0);
         assertTrue(model.getEndTime() == nbEvents - 1);
         assertTrue(model.getTimeLimit() == 4 * nbBuckets);
     }
+    
+    public void testScaleTo_7() {
+        // verify scaleTo with barWidth > 1
+        final int nbBuckets = 100;
+        final int maxHeight = 24;
+        final int width = 10;
+        final int barWidth = 4;
+        final int nbEvents = 2 * nbBuckets + 1;
+        
+        // (int)(width / barWith) = 2 
+        // -> 2 bars -> expected result needs two buckets (scaled data) 
+        // 
+        // buckets (in model) per bar = last bucket id / nbBars + 1 (plus 1 to cover all used buckets)
+        // -> buckets per bar = 50 / 2 + 1 = 26 
+        // -> first entry in expected result is 26 * 4 = 104
+        // -> second entry in expected result is 22 * 4 + 9 = 97
+        final int[] expectedResult = new int[] { 104, 97 };
+        
+        HistogramDataModel model = new HistogramDataModel(nbBuckets);
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i, i);
+        }
+
+        // verify scaled data
+        HistogramScaledData result = model.scaleTo(width, maxHeight, barWidth);
+        
+        assertEquals(4 * 26, result.fBucketDuration);
+        assertEquals(0, result.fCurrentBucket);
+        assertEquals(0, result.fFirstBucketTime);
+        assertEquals(0, result.fFirstEventTime);
+        assertEquals(1, result.fLastBucket);
+        assertEquals(104, result.fMaxValue);
+        assertEquals((double)maxHeight/104, result.fScalingFactor);
+        assertEquals(maxHeight, result.fHeight);
+        assertEquals(width, result.fWidth);
+        assertEquals(barWidth, result.fBarWidth);
+
+        for (int i = 0; i < result.fData.length; i++) {
+            assertEquals(expectedResult[i], result.fData[i]);
+        }
+        
+        // verify model
+        assertEquals(nbEvents, model.getNbEvents());
+        assertEquals(nbBuckets, model.getNbBuckets());
+        assertEquals(4, model.getBucketDuration());
+        assertEquals(0, model.getFirstBucketTime());
+        assertEquals(0, model.getStartTime());
+        assertEquals(nbEvents - 1, model.getEndTime());
+        assertEquals(4 * nbBuckets, model.getTimeLimit());
+    }
 
+    public void testScaleToReverse_1() {
+        final int nbBuckets = 100;
+        final int maxHeight = 24;
+        final int width = 10;
+        final int barWidth = 1;
+        final int nbEvents = 2 * nbBuckets + 1;
+        
+        // (int)(width / barWith) = 10 
+        // -> 10 bars -> expected result needs 10 buckets (scaled data) 
+        // 
+        // buckets in (model) per bar = last bucket id / nbBars + 1 (plus 1 to cover all used buckets)
+        // -> buckets per bar = 50 / 10 + 1 = 6 
+        final int[] expectedResult = new int[] { 21, 24, 24, 24, 24, 24, 24, 24, 12, 0 };
+        
+        HistogramDataModel model = new HistogramDataModel(nbBuckets);
+        for (int i = nbEvents - 1; i >= 0; i--) {
+            model.countEvent(i, i);
+        }
+
+        // verify scaled data
+        HistogramScaledData result = model.scaleTo(width, maxHeight, barWidth);
+        
+        assertEquals(4 * 6, result.fBucketDuration);
+        assertEquals(0, result.fCurrentBucket);
+        assertEquals(-3, result.fFirstBucketTime); // negative is correct, can happen when reverse
+        assertEquals(0, result.fFirstEventTime);
+        assertEquals(9, result.fLastBucket);
+        assertEquals(24, result.fMaxValue);
+        assertEquals((double)maxHeight/24, result.fScalingFactor);
+        assertEquals(maxHeight, result.fHeight);
+        assertEquals(width, result.fWidth);
+        assertEquals(barWidth, result.fBarWidth);
+
+        for (int i = 0; i < result.fData.length; i++) {
+            assertEquals(expectedResult[i], result.fData[i]);
+        }
+        
+        // verify model
+        assertEquals(nbEvents, model.getNbEvents());
+        assertEquals(nbBuckets, model.getNbBuckets());
+        assertEquals(4, model.getBucketDuration());
+        assertEquals(-3, model.getFirstBucketTime());
+        assertEquals(0, model.getStartTime());
+        assertEquals(nbEvents - 1, model.getEndTime());
+        assertEquals(-3 + 4 * nbBuckets, model.getTimeLimit());
+    }
+
+    
+    public void testScaleToReverse_2() { 
+        final int nbBuckets = 100;
+        final int maxHeight = 24;
+        final int width = 10;
+        final int barWidth = 1;
+        
+        final int nbEvents = 2 * nbBuckets;
+
+        HistogramDataModel model = new HistogramDataModel(nbBuckets);
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i, i);
+        }
+
+        HistogramScaledData result = model.scaleTo(width, maxHeight, barWidth);
+
+        model.clear();
+        
+        for (int i = nbEvents -1; i >= 0; i--) {
+            model.countEvent(i, i);
+        }
+        
+        HistogramScaledData revResult = model.scaleTo(width, maxHeight, barWidth);
+        
+        assertEquals(nbEvents, model.getNbEvents());
+        assertEquals(nbBuckets, model.getNbBuckets());
+        assertEquals(2, model.getBucketDuration());
+        assertEquals(0, model.getFirstBucketTime());
+        assertEquals(0, model.getStartTime());
+        assertEquals(nbEvents - 1, model.getEndTime());
+        assertEquals(2 * nbBuckets, model.getTimeLimit());
+        
+        // For the above number of events, result and revResult are exactly the same. 
+        assertEquals(result.fBucketDuration, revResult.fBucketDuration);
+        assertEquals(result.fCurrentBucket, revResult.fCurrentBucket);
+        assertEquals(result.fFirstBucketTime, revResult.fFirstBucketTime);
+        assertEquals(result.fMaxValue, revResult.fMaxValue);
+        assertEquals(result.fScalingFactor, revResult.fScalingFactor);
+        assertEquals(result.fLastBucket, revResult.fLastBucket);
+        assertEquals(result.getBucketEndTime(0), revResult.getBucketEndTime(0));
+        assertEquals(result.getBucketStartTime(0), revResult.getBucketStartTime(0));
+        
+        for (int i = 0; i < result.fData.length; i++) {
+            assertTrue(result.fData[i] == revResult.fData[i]);
+        }
+    }
+    
+    public void testModelListener() {
+        final int nbBuckets = 2000;
+        final int nbEvents = 10 * nbBuckets + 256;
+        final int[] count = new int[1];
+        count [0] = 0;
+
+        // Test add listener and call of listener
+        IHistogramModelListener listener = new IHistogramModelListener() {
+            @Override
+            public void modelUpdated() {
+                count[0]++;
+            }
+        };
+
+        // Test that the listener interface is called every 16000 events.
+        HistogramDataModel model = new HistogramDataModel(nbBuckets);
+        model.addHistogramListener(listener);
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i+1, i);
+        }
+
+        assertTrue(count[0] == 1);
+
+        // Test that the listener interface is called when complete is called.
+        model.complete();
+        assertTrue(count[0] == 2);
+
+        // Test that clear triggers call of listener interface
+        model.clear();
+        assertTrue(count[0] == 3);
+
+        // Test remove listener
+        count[0] = 0;
+        model.removeHistogramListener(listener);
+        
+        for (int i = 0; i < nbEvents; i++) {
+            model.countEvent(i, i);
+        }
+        model.complete();
+        assertTrue(count[0] == 0);
+    }
 }
index e3fe16607206349d4b02f2291beea561282ec3a9..8cf889675b57d33eb9da72d5943894a10d640dbb 100644 (file)
@@ -38,8 +38,13 @@ Export-Package: org.eclipse.linuxtools.lttng.ui;x-friends:="org.eclipse.linuxtoo
  org.eclipse.linuxtools.lttng.ui.views.controlflow;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
  org.eclipse.linuxtools.lttng.ui.views.controlflow.evProcessor;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
  org.eclipse.linuxtools.lttng.ui.views.controlflow.model;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
+ org.eclipse.linuxtools.lttng.ui.views.distribution.model,
  org.eclipse.linuxtools.lttng.ui.views.events;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
  org.eclipse.linuxtools.lttng.ui.views.histogram;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
+ org.eclipse.linuxtools.lttng.ui.views.latency;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
+ org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
+ org.eclipse.linuxtools.lttng.ui.views.latency.listeners;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
+ org.eclipse.linuxtools.lttng.ui.views.latency.model;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
  org.eclipse.linuxtools.lttng.ui.views.project;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
  org.eclipse.linuxtools.lttng.ui.views.project.dialogs;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
  org.eclipse.linuxtools.lttng.ui.views.project.handlers;x-friends:="org.eclipse.linuxtools.lttng.ui.tests",
diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/add_button.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/add_button.gif
new file mode 100644 (file)
index 0000000..ae9543c
Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/add_button.gif differ
diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/decreasebar_button.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/decreasebar_button.gif
new file mode 100644 (file)
index 0000000..3d92025
Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/decreasebar_button.gif differ
diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/delete_button.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/delete_button.gif
new file mode 100644 (file)
index 0000000..6bc0689
Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/delete_button.gif differ
diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/increasebar_button.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/increasebar_button.gif
new file mode 100644 (file)
index 0000000..aa58227
Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/increasebar_button.gif differ
diff --git a/org.eclipse.linuxtools.lttng.ui/icons/elcl16/warning.gif b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/warning.gif
new file mode 100644 (file)
index 0000000..7285660
Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/elcl16/warning.gif differ
diff --git a/org.eclipse.linuxtools.lttng.ui/icons/eview16/graph.gif b/org.eclipse.linuxtools.lttng.ui/icons/eview16/graph.gif
new file mode 100644 (file)
index 0000000..fc187dc
Binary files /dev/null and b/org.eclipse.linuxtools.lttng.ui/icons/eview16/graph.gif differ
index 5d6ea9dc3ebee63dc4216a70894b5f7c2560d1d8..2211985c6de3a76dbcf94d437d3f79a918b4cd69 100644 (file)
@@ -14,6 +14,7 @@ controlflow.view.name = Control Flow
 resources.view.name = Resources
 statistics.view.name = Statistics
 histogram.view.name = Histogram
+latency.view.name = Latency View
 
 wizard.category.name = LTTng
 project.new.wizard.name = LTTng Project
index 15bd8f1294d711bec5953146c6cf120b62dc3daa..988f3e8455d6e32638923345663c9d9273ed795c 100644 (file)
             name="%histogram.view.name"
             restorable="true">
       </view>
+      <view
+            allowMultiple="false"
+            category="org.eclipse.linuxtools.lttng.ui.views.category"
+            class="org.eclipse.linuxtools.lttng.ui.views.latency.LatencyView"
+            icon="icons/eview16/graph.gif"
+            id="org.eclipse.linuxtools.lttng.ui.views.latency"
+            name="%latency.view.name"
+            restorable="true">
+      </view>
    </extension>
    <extension
          point="org.eclipse.ui.newWizards">
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/BaseDistributionData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/BaseDistributionData.java
new file mode 100644 (file)
index 0000000..ef3ee33
--- /dev/null
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ ******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.distribution.model;
+
+
+/**
+ * <b><u>BaseDistributionData</u></b>
+ * <p>
+ */
+public class BaseDistributionData {
+
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+    public final static int OUT_OF_RANGE_BUCKET = -1;
+
+    /**
+     *  Number of buckets
+     */
+    protected final int fNbBuckets;
+    
+    /**
+     * Duration of each bucket
+     */
+    protected long fBucketDuration;
+    
+    /**
+     * Bucket index of last event time
+     */
+    protected int fLastBucket;
+
+    /**
+     * Timestamp of the first bucket. (could be negative when analyzing events with descending time!!!)
+     */
+    protected long fFirstBucketTime;
+    
+    /**
+     * Timestamp of the first event
+     */
+    protected long fFirstEventTime;
+    
+    /**
+     *  Timestamp of the last event
+     */
+    protected long fLastEventTime;
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+    public BaseDistributionData(int nbBuckets) {
+        fNbBuckets = nbBuckets;
+        clear();
+    }
+    
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+    
+    public int getNbBuckets() {
+        return fNbBuckets;
+    }
+
+    public long getBucketDuration() {
+        return fBucketDuration;
+    }
+
+    public void setBucketDuration(long bucketDuration) {
+        fBucketDuration = bucketDuration;
+    }
+
+    public int getLastBucket() {
+        return fLastBucket;
+    }
+
+    public void setLastBucket(int lastBucket) {
+        fLastBucket = lastBucket;
+    }
+
+    public long getFirstBucketTime() {
+        return fFirstBucketTime;
+    }
+
+    public void setFirstBucketTime(long firstBucketTime) {
+        fFirstBucketTime = firstBucketTime;
+    }
+
+    public long getLastBucketTime() {
+        return getBucketStartTime(fLastBucket);
+    }
+
+    public long getFirstEventTime() {
+        return fFirstEventTime;
+    }
+
+    public void setFirstEventTime(long firstEventTime) {
+        fFirstEventTime = firstEventTime;
+    }
+
+    public long getLastEventTime() {
+        return fLastEventTime;
+    }
+    
+    public void setLastEventTime(long lastEventTime) {
+        fLastEventTime = lastEventTime;
+    }
+    
+    public long getBucketStartTime(int index) {
+        return fFirstBucketTime + index * fBucketDuration;
+    }
+    
+    public long getBucketEndTime(int index) {
+        return getBucketStartTime(index) + fBucketDuration;
+    }
+    
+    public int getIndex(long time) {
+        return (int)((time - fFirstBucketTime) / fBucketDuration); 
+    }
+    
+    public boolean isIndexValid(int index) {
+        return ((index >= 0) && (index <= fNbBuckets - 1));
+    }
+    
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+    public void clear() {
+        fFirstBucketTime = 0;
+        fFirstEventTime = 0;
+        fLastEventTime = 0;
+        fLastBucket = 0;
+        fBucketDuration = 1; // 1ns
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/DistributionData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/DistributionData.java
new file mode 100644 (file)
index 0000000..75e3286
--- /dev/null
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ ******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.distribution.model;
+
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config;
+
+/**
+ * <b><u>DistributionData</u></b>
+ * <p>
+ * The algorithm is based on the algorithm for the Histogram. The difference is that
+ * it supports two dimensions. For more details about the model principle 
+ * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramDataModel 
+ * <p>
+ */
+abstract public class DistributionData extends BaseDistributionData {
+
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+
+    /**
+     * Flag to indicate if given timestamp is the first one to count 
+     */
+    protected boolean fIsFirst;
+    
+    /**
+     *  reference to fBuckets
+     */
+    protected final int [][] fBuckets;
+    
+    /**
+     * Time limit (current available longest time)
+     */
+    protected long fTimeLimit;
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+    public DistributionData(int[][] buckets) {
+        this(Config.DEFAULT_NUMBER_OF_BUCKETS, buckets);
+    }
+
+    public DistributionData(int nbBuckets, int[][] buckets) {
+        super(nbBuckets);
+        fBuckets = buckets;
+        clear();
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+   
+    public long getTimeLimit() {
+        return fTimeLimit;
+    }
+    
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.BaseDistributionData#clear()
+     */
+    @Override
+    public void clear() {
+        super.clear();
+        fIsFirst = true;
+        updateEndTime();
+    }
+
+    public boolean isFirst() {
+        return fIsFirst;
+    }
+
+    public int countEvent(long timestamp) {
+
+        // Set the start/end time if not already done
+        if (fIsFirst) {
+            fIsFirst = false;
+            fFirstBucketTime = timestamp;
+            fFirstEventTime = timestamp;
+
+            updateEndTime();
+        }
+
+        // save first event time if necessary 
+        if (timestamp < fFirstEventTime) {
+            fFirstEventTime = timestamp;
+        }
+
+        // save last event time if necessary
+        if (fLastEventTime < timestamp) {
+            fLastEventTime = timestamp;
+        }
+
+        
+        if (timestamp >= fFirstBucketTime) {
+            // Compact as needed
+            while (timestamp >= fTimeLimit) {
+                mergeBuckets();
+            }
+
+        } else {
+
+            // Get offset for buckets adjustment
+            int offset = getOffset(timestamp);
+
+            // Compact as needed
+            while (fLastBucket + offset >= fNbBuckets) {
+                mergeBuckets();
+                offset = getOffset(timestamp);
+            }
+
+            // Move buckets with offset (to right)
+            moveBuckets(offset);
+
+            // Adjust start/end time and index 
+            fLastBucket = fLastBucket + offset;
+            fFirstBucketTime = fFirstBucketTime - offset * fBucketDuration;
+            updateEndTime();
+        }
+
+        // Increment the right bucket
+        int index = (int) ((timestamp - fFirstBucketTime) / fBucketDuration);
+
+        if (fLastBucket < index) {
+            fLastBucket = index;
+        }
+
+        return index;
+    }
+
+    // ------------------------------------------------------------------------
+    // Abstract 
+    // ------------------------------------------------------------------------
+    
+    /**
+     * Moves content of buckets with the given offset in positive direction. 
+     * It has to be implemented accordingly in the relevant sub-classes for 
+     * horizontal and vertical direction.  
+     * 
+     * @param buckets - 2-dimensional array of buckets 
+     * @param offset - offset to move
+     */
+    abstract protected void moveBuckets(int offset);
+    
+    /**
+     * Merges buckets if end time is exceeded. It has to be implemented 
+     * accordingly in the relevant sub-classes for horizontal and 
+     * vertical direction.
+     * @param buckets
+     */
+    abstract protected void mergeBuckets();
+
+    // ------------------------------------------------------------------------
+    // Helper Functions
+    // ------------------------------------------------------------------------
+    protected int getOffset(long timestamp) {
+        int offset = (int) ((fFirstBucketTime - timestamp) / fBucketDuration);
+        if ((fFirstBucketTime - timestamp) % fBucketDuration != 0) {
+            offset++;
+        }
+        return offset;
+    }
+    
+    protected void updateEndTime() {
+        fTimeLimit = fFirstBucketTime + fNbBuckets * fBucketDuration;
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/HorDistributionData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/HorDistributionData.java
new file mode 100644 (file)
index 0000000..766384f
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ ******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.distribution.model;
+
+/**
+ * <b><u>HorDistributionData</u></b>
+ * <p>
+ * Implementation of DistributionData for horizontal direction.
+ */
+public class HorDistributionData extends DistributionData {
+
+    // ------------------------------------------------------------------------
+    // Constructor
+    // ------------------------------------------------------------------------
+
+    public HorDistributionData(int nbBuckets, int[][] buckets) {
+        super(nbBuckets, buckets);
+    }
+
+    // ------------------------------------------------------------------------
+    // Abstract function implementation
+    // ------------------------------------------------------------------------
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData#moveBuckets(int)
+     */
+    @Override
+    protected void moveBuckets(int offset) {
+        for (int j = 0; j < fNbBuckets; j++) {
+
+            for(int i = fNbBuckets - 1; i >= offset; i--) {
+                fBuckets[i][j] = fBuckets[i-offset][j]; 
+            }
+
+            for (int i = 0; i < offset; i++) {
+                fBuckets[i][j] = 0;
+            }
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData#mergeBuckets()
+     */
+    @Override
+    protected void mergeBuckets() {
+
+        for (int y = 0; y < fNbBuckets; y++) {
+            for (int i = 0; i < fNbBuckets / 2; i++) {
+                fBuckets[i][y] = fBuckets[2 * i][y] + fBuckets[2 * i + 1][y];
+            }
+
+            for (int i = fNbBuckets / 2; i < fNbBuckets; i++) {
+                fBuckets[i][y] = 0;
+            }
+        }
+        fBucketDuration = fBucketDuration * 2;
+        updateEndTime();
+        fLastBucket = fNbBuckets / 2 - 1;
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/IBaseDistributionModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/IBaseDistributionModel.java
new file mode 100644 (file)
index 0000000..5c61a9e
--- /dev/null
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.lttng.ui.views.distribution.model;
+
+public interface IBaseDistributionModel {
+    /**
+     * Interface to complete the model
+     */
+    public void complete();
+    
+    /**
+     * Interface to clear the model
+     */
+    public void clear();
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/VerDistributionData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/distribution/model/VerDistributionData.java
new file mode 100644 (file)
index 0000000..e44398c
--- /dev/null
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ ******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.distribution.model;
+
+/**
+ * <b><u>VerDistributionData</u></b>
+ * 
+ * Implementation of DistributionData for vertical direction. 
+ * <p>
+ */
+public class VerDistributionData extends DistributionData {
+    
+    // ------------------------------------------------------------------------
+    // Constructor
+    // ------------------------------------------------------------------------
+    public VerDistributionData(int nbBuckets, int[][] buckets) {
+        super(nbBuckets, buckets);
+    }
+
+    // ------------------------------------------------------------------------
+    // Abstract function implementation
+    // ------------------------------------------------------------------------
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData#moveBuckets(int)
+     */
+    @Override
+    protected void moveBuckets(int offset) {
+        for (int j = 0; j < fNbBuckets; j++) {
+
+            for(int i = fNbBuckets - 1; i >= offset; i--) {
+                fBuckets[j][i] = fBuckets[j][i-offset]; 
+            }
+
+            for (int i = 0; i < offset; i++) {
+                fBuckets[j][i] = 0;
+            }
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData#mergeBuckets()
+     */
+    @Override
+    protected void mergeBuckets() {
+        for (int x = 0; x < fNbBuckets; x++) {
+            for (int i = 0; i < fNbBuckets / 2; i++) {
+                fBuckets[x][i] = fBuckets[x][2 * i] + fBuckets[x][2 * i + 1];
+            }
+            for (int i = fNbBuckets / 2; i < fNbBuckets; i++) {
+                fBuckets[x][i] = 0;
+            }
+        }
+        fBucketDuration = fBucketDuration * 2;
+        updateEndTime();
+        fLastBucket = fNbBuckets / 2 - 1;
+    }
+}
index d7e0345d4dee743056cfecd05b78314445ddfb10..176cf8db6b4f0d3b29e6e987a38c366da43e5b95 100644 (file)
@@ -8,6 +8,7 @@
  * 
  * Contributors:
  *   Francois Chouinard - Initial API and implementation
+ *   Bernd Hufmann - Changed to updated histogram data model
  *******************************************************************************/
 
 package org.eclipse.linuxtools.lttng.ui.views.histogram;
@@ -75,7 +76,7 @@ public class FullTraceHistogram extends Histogram implements MouseMoveListener {
         fRangeStartTime = startTime;
         fRangeDuration = duration;
         fZoom.setNewRange(fRangeStartTime, fRangeDuration);
-        refresh();
+        fDataModel.complete();
     }
 
     @Override
@@ -131,7 +132,7 @@ public class FullTraceHistogram extends Histogram implements MouseMoveListener {
                 newStart = newEnd - fZoom.getDuration();
             }
             fRangeStartTime = newStart;
-            refresh();
+            fDataModel.complete();
         }
     }
 
@@ -166,7 +167,7 @@ public class FullTraceHistogram extends Histogram implements MouseMoveListener {
         long bucketSpan = fScaledData.fBucketDuration;
         int rangeWidth = (int) (fRangeDuration / bucketSpan);
 
-        int left = (int) ((fRangeStartTime - fDataModel.getStartTime()) / bucketSpan);
+        int left = (int) ((fRangeStartTime - fDataModel.getFirstBucketTime()) / bucketSpan);
         int right = left + rangeWidth;
         int center = (left + right) / 2;
         int height = fCanvas.getSize().y - 2;
index b7632607e33827c1647818b1ae221d26a81ea6d2..dc665aba116b54e41d7a2a3f5a4bb59ecce0e29a 100644 (file)
@@ -8,6 +8,7 @@
  * 
  * Contributors:
  *   Francois Chouinard - Initial API and implementation
+ *   Bernd Hufmann - Changed to updated histogram data model
  *******************************************************************************/
 
 package org.eclipse.linuxtools.lttng.ui.views.histogram;
@@ -69,15 +70,12 @@ import org.eclipse.swt.widgets.Text;
  * <li>number of events in that time range
  * </ul>
  */
-public abstract class Histogram implements ControlListener, PaintListener, KeyListener, MouseListener, MouseTrackListener {
+public abstract class Histogram implements ControlListener, PaintListener, KeyListener, MouseListener, MouseTrackListener, IHistogramModelListener {
 
     // ------------------------------------------------------------------------
     // Constants
     // ------------------------------------------------------------------------
 
-    // Histogram refresh frequency
-    private final static int REFRESH_FREQUENCY = HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS;
-
     // Histogram colors
     private final Color fBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
     private final Color fCurrentEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
@@ -86,6 +84,8 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
 
     // Timestamp scale (nanosecond)
     public static final byte TIME_SCALE = -9;
+    
+    public static final int HISTOGRAM_BAR_WIDTH = 1;
 
     // ------------------------------------------------------------------------
     // Attributes
@@ -118,6 +118,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
 
         createWidget(parent);
         fDataModel = new HistogramDataModel();
+        fDataModel.addHistogramListener(this);
         clear();
 
         fCanvas.addControlListener(this);
@@ -129,6 +130,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
 
     public void dispose() {
         fHistoBarColor.dispose();
+        fDataModel.removeHistogramListener(this);
     }
 
     private void createWidget(Composite parent) {
@@ -238,7 +240,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
     // ------------------------------------------------------------------------
 
     public long getStartTime() {
-        return fDataModel.getStartTime();
+        return fDataModel.getFirstBucketTime();
     }
 
     public long getEndTime() {
@@ -248,6 +250,10 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
     public long getTimeLimit() {
         return fDataModel.getTimeLimit();
     }
+    
+    public HistogramDataModel getDataModel() {
+        return fDataModel;
+    }
 
     // ------------------------------------------------------------------------
     // Operations
@@ -261,7 +267,6 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
     public void clear() {
         fDataModel.clear();
         fScaledData = null;
-        refresh();
     }
 
     /**
@@ -269,12 +274,8 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
      * 
      * @param timestamp
      */
-    public void countEvent(long timestamp) {
-        fDataModel.countEvent(timestamp);
-        if (fDataModel.getNbEvents() % REFRESH_FREQUENCY == 0) {
-            refresh();
-            refresh(); // This is intentional. Exercise left to the reader :-)
-        }
+    public void countEvent(long eventCount, long timestamp) {
+        fDataModel.countEvent(eventCount, timestamp);
     }
 
     /**
@@ -284,8 +285,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
      */
     public void setCurrentEvent(long timestamp) {
         fCurrentEventTime = (timestamp > 0) ? timestamp : 0;
-        fDataModel.setCurrentEvent(timestamp);
-        refresh();
+        fDataModel.setCurrentEventNotifyListeners(timestamp);
     }
 
     /**
@@ -297,7 +297,7 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
     public synchronized long getTimestamp(int offset) {
         assert offset > 0 && offset < fScaledData.fWidth;
         try {
-            return fDataModel.getStartTime() + fScaledData.fBucketDuration * offset;
+            return fDataModel.getFirstBucketTime() + fScaledData.fBucketDuration * offset;
         } catch (Exception e) {
             return 0; // TODO: Fix that racing condition (NPE)
         }
@@ -310,9 +310,9 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
      * @return the offset of the corresponding bucket (-1 if invalid)
      */
     public synchronized int getOffset(long timestamp) {
-        if (timestamp < fDataModel.getStartTime() || timestamp > fDataModel.getEndTime())
+        if (timestamp < fDataModel.getFirstBucketTime() || timestamp > fDataModel.getEndTime())
             return -1;
-        return (int) ((timestamp - fDataModel.getStartTime()) / fScaledData.fBucketDuration);
+        return (int) ((timestamp - fDataModel.getFirstBucketTime()) / fScaledData.fBucketDuration);
     }
 
     /**
@@ -370,7 +370,8 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
     /**
      * Refresh the histogram display
      */
-    protected void refresh() {
+    @Override
+    public void modelUpdated() {
         if (!fCanvas.isDisposed() && fCanvas.getDisplay() != null) {
             fCanvas.getDisplay().asyncExec(new Runnable() {
                 @Override
@@ -382,10 +383,10 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
                         if (canvasWidth <= 0 || canvasHeight <= 0)
                             return;
                         fDataModel.setCurrentEvent(fCurrentEventTime);
-                        fScaledData = fDataModel.scaleTo(canvasWidth, canvasHeight);
+                        fScaledData = fDataModel.scaleTo(canvasWidth, canvasHeight, HISTOGRAM_BAR_WIDTH);
                         fCanvas.redraw();
                         // Display histogram and update X-,Y-axis labels
-                        fTimeRangeStartText.setText(HistogramUtils.nanosecondsToString(fDataModel.getStartTime()));
+                        fTimeRangeStartText.setText(HistogramUtils.nanosecondsToString(fDataModel.getFirstBucketTime()));
                         fTimeRangeEndText.setText(HistogramUtils.nanosecondsToString(fDataModel.getEndTime()));
                         fMaxNbEventsText.setText(Long.toString(fScaledData.fMaxValue));
                         // The Y-axis area might need to be re-sized
@@ -540,8 +541,12 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
     }
 
     private String formatToolTipLabel(int index) {
-        long startTime = fDataModel.getStartTime() + fScaledData.fCurrentBucket * fScaledData.fBucketDuration;
-        long endTime = startTime + fScaledData.fBucketDuration;
+        long startTime = fScaledData.getBucketStartTime(fScaledData.fCurrentBucket);
+        // negative values are possible if time values came into the model in decreasing order 
+        if (startTime < 0) {
+            startTime = 0;
+        }
+        long endTime = fScaledData.getBucketEndTime(fScaledData.fCurrentBucket);
         int nbEvents = (index >= 0) ? fScaledData.fData[index] : 0;
 
         StringBuffer buffer = new StringBuffer();
@@ -561,12 +566,11 @@ public abstract class Histogram implements ControlListener, PaintListener, KeyLi
 
     @Override
     public void controlMoved(ControlEvent event) {
-        refresh();
+        fDataModel.complete();
     }
 
     @Override
     public void controlResized(ControlEvent event) {
-        refresh();
+        fDataModel.complete();
     }
-
 }
index 36c6fb748c0b749325545400c9bf1b607eedb482..28b944ecca45d774dd88cdcc55db58a73e84f225 100644 (file)
@@ -8,12 +8,15 @@
  * 
  * Contributors:
  *   Francois Chouinard - Initial API and implementation
+ *   Bernd Hufmann - Implementation of new interfaces /listeners and support for 
+ *                   time stamp in any order
  *******************************************************************************/
 
 package org.eclipse.linuxtools.lttng.ui.views.histogram;
 
 import java.util.Arrays;
 
+import org.eclipse.core.runtime.ListenerList;
 import org.eclipse.linuxtools.lttng.core.exceptions.EventOutOfSequenceException;
 import org.eclipse.linuxtools.lttng.ui.LTTngUILogger;
 
@@ -41,6 +44,15 @@ import org.eclipse.linuxtools.lttng.ui.LTTngUILogger;
  * <i>timespan</i> (<i>timespan'</i> = <i>n</i> * <i>d'</i>, where <i>d'</i> =
  * 2<i>d</i>). This compaction happens as needed as the trace is read.
  * <p>
+ * The model allows for timestamps in not increasing order. The timestamps can
+ * be fed to the model in any order. If an event has a timestamp less than the 
+ * <i>basetime</i>, the buckets will be moved to the right to account for the
+ * new smaller timestamp. The new <i>basetime</i> is a multiple of the bucket 
+ * duration smaller then the previous <i>basetime</i>. Note that the <i>basetime</i>
+ * might not be anymore a timestamp of an event. If necessary, the buckets will
+ * be compacted before moving to the right. This might be necessary to not 
+ * loose any event counts at the end of the buckets array.
+ * <p>
  * The mapping from the model to the UI is performed by the <i>scaleTo()</i>
  * method. By keeping the number of buckets <i>n</i> relatively large with
  * respect to to the number of pixels in the actual histogram, we should achieve
@@ -51,7 +63,7 @@ import org.eclipse.linuxtools.lttng.ui.LTTngUILogger;
  * <p>
  * TODO: Cut-off eccentric values? TODO: Support for going back in time?
  */
-public class HistogramDataModel {
+public class HistogramDataModel implements IHistogramDataModel {
 
     // ------------------------------------------------------------------------
     // Constants
@@ -60,6 +72,8 @@ public class HistogramDataModel {
     // The default number of buckets
     public static final int DEFAULT_NUMBER_OF_BUCKETS = 16 * 1000;
 
+    public static final int REFRESH_FREQUENCY = DEFAULT_NUMBER_OF_BUCKETS;
+    
 //    // The ratio where an eccentric value will be truncated
 //    private static final int MAX_TO_AVERAGE_CUTOFF_RATIO = 5;
 
@@ -75,15 +89,15 @@ public class HistogramDataModel {
     private int fLastBucket;
 
     // Timestamps
+    private long fFirstBucketTime; // could be negative when analyzing events with descending order!!!
     private long fFirstEventTime;
     private long fLastEventTime;
     private long fCurrentEventTime;
     private long fTimeLimit;
-
-    // ------------------------------------------------------------------------
-    // Constructors
-    // ------------------------------------------------------------------------
-
+    
+    // private listener lists
+    private final ListenerList fModelListeners;
+    
     public HistogramDataModel() {
         this(DEFAULT_NUMBER_OF_BUCKETS);
     }
@@ -91,6 +105,7 @@ public class HistogramDataModel {
     public HistogramDataModel(int nbBuckets) {
         fNbBuckets = nbBuckets;
         fBuckets = new long[nbBuckets];
+        fModelListeners = new ListenerList();
         clear();
     }
 
@@ -100,10 +115,16 @@ public class HistogramDataModel {
         fBucketDuration = other.fBucketDuration;
         fNbEvents = other.fNbEvents;
         fLastBucket = other.fLastBucket;
+        fFirstBucketTime = other.fFirstBucketTime;
         fFirstEventTime = other.fFirstEventTime;
         fLastEventTime = other.fLastEventTime;
         fCurrentEventTime = other.fCurrentEventTime;
         fTimeLimit = other.fTimeLimit;
+        fModelListeners = new ListenerList();
+        Object[] listeners = other.fModelListeners.getListeners();
+        for (Object listener : listeners) {
+            fModelListeners.add(listener);
+        }
     }
 
     // ------------------------------------------------------------------------
@@ -121,11 +142,15 @@ public class HistogramDataModel {
     public long getBucketDuration() {
         return fBucketDuration;
     }
+    
+    public long getFirstBucketTime() {
+        return fFirstBucketTime;
+    }
 
     public long getStartTime() {
         return fFirstEventTime;
     }
-
+    
     public long getEndTime() {
         return fLastEventTime;
     }
@@ -137,23 +162,55 @@ public class HistogramDataModel {
     public long getTimeLimit() {
         return fTimeLimit;
     }
+    
+    // ------------------------------------------------------------------------
+    // Listener handling
+    // ------------------------------------------------------------------------
+    
+    public void addHistogramListener(IHistogramModelListener listener) {
+        fModelListeners.add(listener);        
+    }
+    
+    public void removeHistogramListener(IHistogramModelListener listener) {
+        fModelListeners.remove(listener);
+    }
 
+    private void fireModelUpdateNotification() {
+        fireModelUpdateNotification(0);
+    }
+    
+    private void fireModelUpdateNotification(long count) {
+        if (count % REFRESH_FREQUENCY == 0) {
+            Object[] listeners = fModelListeners.getListeners();
+            for (int i = 0; i < listeners.length; i++) {
+                IHistogramModelListener listener = (IHistogramModelListener) listeners[i];
+                listener.modelUpdated();
+            }
+        }
+    }
+    
     // ------------------------------------------------------------------------
     // Operations
     // ------------------------------------------------------------------------
+    @Override
+    public void complete() {
+        fireModelUpdateNotification();
+    }
 
     /**
      * Clear the histogram model.
      */
+    @Override
     public void clear() {
         Arrays.fill(fBuckets, 0);
         fNbEvents = 0;
-        fFirstEventTime = 0;
+        fFirstBucketTime = 0;
         fLastEventTime = 0;
         fCurrentEventTime = 0;
         fLastBucket = 0;
         fBucketDuration = 1; // 1ns
         updateEndTime();
+        fireModelUpdateNotification();
     }
 
     /**
@@ -165,63 +222,108 @@ public class HistogramDataModel {
         fCurrentEventTime = timestamp;
     }
 
+    /**
+     * Sets the current event time
+     * 
+     * @param timestamp
+     */
+    public void setCurrentEventNotifyListeners(long timestamp) {
+        fCurrentEventTime = timestamp;
+        fireModelUpdateNotification();
+    }
+    
     /**
      * Add event to the correct bucket, compacting the if needed.
      * 
      * @param timestamp the timestamp of the event to count
      */
-    public void countEvent(long timestamp) {
+    @Override
+    public void countEvent(long eventCount, long timestamp) {
+        
+        // Validate
+        if (timestamp < 0) {
+            String message = "Negative time value"; //$NON-NLS-1$
+            EventOutOfSequenceException exception = new EventOutOfSequenceException(message);
+            LTTngUILogger.logError(message, exception);
+            return;
+        }
+        
         // Set the start/end time if not already done
         if (fLastBucket == 0 && fBuckets[0] == 0 && timestamp > 0) {
+            fFirstBucketTime = timestamp;
             fFirstEventTime = timestamp;
             updateEndTime();
         }
+        
+        if (timestamp < fFirstEventTime) {
+            fFirstEventTime = timestamp;
+        }
+        
         if (fLastEventTime < timestamp) {
             fLastEventTime = timestamp;
         }
+        
+        if (timestamp >= fFirstBucketTime) {
 
-        // Compact as needed
-        while (timestamp >= fTimeLimit) {
-            mergeBuckets();
-        }
+            // Compact as needed
+            while (timestamp >= fTimeLimit) {
+                mergeBuckets();
+            }
 
-        // Validate
-        if (timestamp < fFirstEventTime) {
-            String message = "Out of order timestamp. Going back in time?"; //$NON-NLS-1$
-            EventOutOfSequenceException exception = new EventOutOfSequenceException(message);
-            LTTngUILogger.logError(message, exception);
-            return;
-        }
+        } else {
+            
+            // get offset for adjustment
+            int offset = getOffset(timestamp);
+
+            // Compact as needed
+            while(fLastBucket + offset >= fNbBuckets) {
+                mergeBuckets();
+                offset = getOffset(timestamp);
+            }
+            
+            moveBuckets(offset);
+
+            fLastBucket = fLastBucket + offset;
 
+            fFirstBucketTime = fFirstBucketTime - offset*fBucketDuration;
+            updateEndTime();
+        }
+        
         // Increment the right bucket
-        int index = (int) ((timestamp - fFirstEventTime) / fBucketDuration);
+        int index = (int) ((timestamp - fFirstBucketTime) / fBucketDuration);
         fBuckets[index]++;
         fNbEvents++;
         if (fLastBucket < index)
             fLastBucket = index;
+        
+        fireModelUpdateNotification(eventCount);
     }
 
     /**
-     * Scale the model data to the width and height requested.
+     * Scale the model data to the width, height and bar width requested.
      * 
      * @param width
      * @param height
+     * @param bar width
      * @return the result array of size [width] and where the highest value
      *         doesn't exceed [height]
      */
-    public HistogramScaledData scaleTo(int width, int height) {
+    @Override
+    public HistogramScaledData scaleTo(int width, int height, int barWidth) {
         // Basic validation
-        if (width <= 0 ||  height <= 0)
-            throw new AssertionError("Invalid histogram dimensions (" + width + "x" + height + ")");
+        if (width <= 0 ||  height <= 0 || barWidth <= 0)
+            throw new AssertionError("Invalid histogram dimensions (" + width + "x" + height + ", barWidth=" + barWidth + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 
         // The result structure
-        HistogramScaledData result = new HistogramScaledData(width, height);
+        HistogramScaledData result = new HistogramScaledData(width, height, barWidth);
 
         // Scale horizontally
         result.fMaxValue = 0;
-        int bucketsPerBar = fLastBucket / width + 1;
+        
+        int nbBars = width / barWidth;
+        int bucketsPerBar = fLastBucket / nbBars + 1;
         result.fBucketDuration = bucketsPerBar * fBucketDuration;
-        for (int i = 0; i < width; i++) {
+        for (int i = 0; i < nbBars; i++) {
             int count = 0;
             for (int j = i * bucketsPerBar; j < (i + 1) * bucketsPerBar; j++) {
                 if (fNbBuckets <= j)
@@ -240,11 +342,13 @@ public class HistogramDataModel {
         }
 
         // Set the current event index in the scaled histogram
-        if (fCurrentEventTime >= fFirstEventTime && fCurrentEventTime <= fLastEventTime)
-            result.fCurrentBucket = (int) ((fCurrentEventTime - fFirstEventTime) / fBucketDuration) / bucketsPerBar;
+        if (fCurrentEventTime >= fFirstBucketTime && fCurrentEventTime <= fLastEventTime)
+            result.fCurrentBucket = (int) ((fCurrentEventTime - fFirstBucketTime) / fBucketDuration) / bucketsPerBar;
         else
             result.fCurrentBucket = HistogramScaledData.OUT_OF_RANGE_BUCKET;
 
+        result.fFirstBucketTime = fFirstBucketTime;
+        result.fFirstEventTime = fFirstEventTime;
         return result;
     }
 
@@ -253,7 +357,7 @@ public class HistogramDataModel {
     // ------------------------------------------------------------------------
 
     private void updateEndTime() {
-        fTimeLimit = fFirstEventTime + fNbBuckets * fBucketDuration;
+        fTimeLimit = fFirstBucketTime + fNbBuckets * fBucketDuration;
     }
 
     private void mergeBuckets() {
@@ -265,5 +369,23 @@ public class HistogramDataModel {
         updateEndTime();
         fLastBucket = fNbBuckets / 2 - 1;
     }
+    
+    private void moveBuckets(int offset) {
+        for(int i = fNbBuckets - 1; i >= offset; i--) {
+            fBuckets[i] = fBuckets[i-offset]; 
+        }
+
+        for (int i = 0; i < offset; i++) {
+            fBuckets[i] = 0;
+        }
+    }
+
+    private int getOffset(long timestamp) {
+        int offset = (int) ((fFirstBucketTime - timestamp) / fBucketDuration);
+        if ((fFirstBucketTime - timestamp) % fBucketDuration != 0) {
+            offset++;
+        }
+        return offset;
+    }
 
 }
index 2b88329570eabb9bade5ffd75ecc725bf35c8357..120d243298998bc6276abfd1b1657c5322594b5f 100644 (file)
@@ -30,22 +30,22 @@ public class HistogramRequest extends TmfEventRequest<LttngEvent> {
     // Attributes
     // ------------------------------------------------------------------------
 
-    private final Histogram fHistogram;
+    protected final HistogramDataModel fHistogram;
 
     // ------------------------------------------------------------------------
     // Constructor
     // ------------------------------------------------------------------------
 
-    public HistogramRequest(Histogram histogram, TmfTimeRange range, int rank, int nbEvents, ITmfDataRequest.ExecutionType execType) {
+    public HistogramRequest(HistogramDataModel histogram, TmfTimeRange range, int rank, int nbEvents, ITmfDataRequest.ExecutionType execType) {
         super(LttngEvent.class, range, rank, nbEvents, LttngConstants.DEFAULT_BLOCK_SIZE, execType);
         fHistogram = histogram;
     }
 
-    public HistogramRequest(Histogram histogram, TmfTimeRange range, ITmfDataRequest.ExecutionType execType) {
+    public HistogramRequest(HistogramDataModel histogram, TmfTimeRange range, ITmfDataRequest.ExecutionType execType) {
         this(histogram, range, 0, ALL_DATA, execType);
     }
 
-    public HistogramRequest(Histogram histogram, TmfTimeRange range, int rank, ITmfDataRequest.ExecutionType execType) {
+    public HistogramRequest(HistogramDataModel histogram, TmfTimeRange range, int rank, ITmfDataRequest.ExecutionType execType) {
         this(histogram, range, rank, ALL_DATA, execType);
     }
 
@@ -58,19 +58,19 @@ public class HistogramRequest extends TmfEventRequest<LttngEvent> {
         super.handleData(event);
         if (event != null) {
             long timestamp = event.getTimestamp().getValue();
-            fHistogram.countEvent(timestamp);
+            fHistogram.countEvent(getNbRead(), timestamp);
         }
     }
 
     @Override
     public void handleCompleted() {
-        fHistogram.refresh();
+        fHistogram.complete();
         super.handleCompleted();
     }
 
     @Override
     public void handleCancel() {
-        fHistogram.refresh();
+        fHistogram.clear();
         super.handleCancel();
     }
 
index 8260b4fb595068857bfc2b7caeafeb88e2850c8f..b1e6a1fe5e1523f8cd2ba539909e94bf7294a61f 100644 (file)
@@ -8,6 +8,7 @@
  * 
  * Contributors:
  *   Francois Chouinard - Initial API and implementation
+ *   Bernd Hufmann - Added setter and getter
  *******************************************************************************/
 
 package org.eclipse.linuxtools.lttng.ui.views.histogram;
@@ -33,38 +34,67 @@ public class HistogramScaledData {
 
     public int fWidth;
     public int fHeight;
+    public int fBarWidth;
     public int[] fData;
     public long fBucketDuration;
     public long fMaxValue;
     public int fCurrentBucket;
     public int fLastBucket;
     public double fScalingFactor;
+    public long fFirstBucketTime;
+    public long fFirstEventTime;
 
     // ------------------------------------------------------------------------
     // Constructor
     // ------------------------------------------------------------------------
 
-    public HistogramScaledData(int width, int height) {
+    public HistogramScaledData(int width, int height, int barWidth) {
         fWidth = width;
         fHeight = height;
-        fData = new int[width];
+        fBarWidth = barWidth;
+        fData = new int[width/fBarWidth];
         Arrays.fill(fData, 0);
         fBucketDuration = 1;
         fMaxValue = 0;
         fCurrentBucket = 0;
         fLastBucket = 0;
         fScalingFactor = 1;
+        fFirstBucketTime = 0;
     }
 
     public HistogramScaledData(HistogramScaledData other) {
         fWidth = other.fWidth;
         fHeight = other.fHeight;
+        fBarWidth = other.fBarWidth;
         fData = Arrays.copyOf(other.fData, fWidth);
         fBucketDuration = other.fBucketDuration;
         fMaxValue = other.fMaxValue;
         fCurrentBucket = other.fCurrentBucket;
         fLastBucket = other.fLastBucket;
         fScalingFactor = other.fScalingFactor;
+        fFirstBucketTime = other.fFirstBucketTime;
+    }
+    
+    // ------------------------------------------------------------------------
+    // Setter and Getter
+    // ------------------------------------------------------------------------
+    public long getFirstBucketTime() {
+        return fFirstBucketTime;
     }
 
+    public void setFirstBucketTime(long firstEventTime) {
+        fFirstBucketTime = firstEventTime;
+    }
+    
+    public long getLastBucketTime() {
+        return getBucketStartTime(fLastBucket);
+    }
+    
+    public long getBucketStartTime(int index) {
+        return fFirstBucketTime + index * fBucketDuration;
+    }
+    
+    public long getBucketEndTime(int index) {
+        return getBucketStartTime(index) + fBucketDuration;
+    }
 }
\ No newline at end of file
index 32f9dc11bfcc0bd17610699b52abd59c34253633..62bc9573effca2d0cfce224f2602a81f96790c8f 100644 (file)
@@ -265,8 +265,7 @@ public class HistogramView extends TmfView {
     public void updateCurrentEventTime(long newTime) {
         if (fCurrentExperiment != null) {
             TmfTimeRange timeRange = new TmfTimeRange(new TmfTimestamp(newTime, TIME_SCALE), TmfTimestamp.BigCrunch);
-            HistogramRequest request = new HistogramRequest(fTimeRangeHistogram, timeRange, 0, 1,
-                    ExecutionType.FOREGROUND) {
+            HistogramRequest request = new HistogramRequest(fTimeRangeHistogram.getDataModel(), timeRange, 0, 1, ExecutionType.FOREGROUND) {
                 @Override
                 public void handleData(LttngEvent event) {
                     if (event != null) {
@@ -445,7 +444,7 @@ public class HistogramView extends TmfView {
 
         fTimeRangeHistogram.clear();
         fTimeRangeHistogram.setTimeRange(startTime, endTime - startTime);
-        fTimeRangeRequest = new HistogramRequest(fTimeRangeHistogram, timeRange, ExecutionType.FOREGROUND);
+        fTimeRangeRequest = new HistogramRequest(fTimeRangeHistogram.getDataModel(), timeRange, ExecutionType.FOREGROUND);
         fCurrentExperiment.sendRequest(fTimeRangeRequest);
     }
 
@@ -453,8 +452,8 @@ public class HistogramView extends TmfView {
         if (fFullTraceRequest != null && !fFullTraceRequest.isCompleted()) {
             fFullTraceRequest.cancel();
         }
-        fFullTraceRequest = new HistogramRequest(fFullTraceHistogram, fullRange,
-                (int) fFullTraceHistogram.fDataModel.getNbEvents(), ExecutionType.BACKGROUND);
+        fFullTraceRequest = new HistogramRequest(fFullTraceHistogram.getDataModel(), fullRange, (int) fFullTraceHistogram.fDataModel.getNbEvents(),
+                ExecutionType.BACKGROUND);
         fCurrentExperiment.sendRequest(fFullTraceRequest);
     }
 
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramDataModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramDataModel.java
new file mode 100644 (file)
index 0000000..35606f3
--- /dev/null
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.histogram;
+
+/**
+ * <b><u>IHistogramDataModel</u></b>
+ * <p>
+ */
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDistributionModel;
+
+public interface IHistogramDataModel extends IBaseDistributionModel {
+    /**
+     * Add event to the correct bucket, compacting the if needed.
+     * 
+     * @param timestamp the timestamp of the event to count
+     */
+    public void countEvent(long eventCount, long timestamp);
+    
+    /**
+     * Scale the model data to the width, height and bar width requested.
+     * 
+     * @param width
+     * @param height
+     * @param bar width
+     * @return the result array of size [width] and where the highest value
+     *         doesn't exceed [height] considering the bar width [barWidth]
+     */
+    public HistogramScaledData scaleTo(int width, int height, int barWidth);
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramModelListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/IHistogramModelListener.java
new file mode 100644 (file)
index 0000000..d980a17
--- /dev/null
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.histogram;
+
+/**
+ * <b><u>IHistogramModelListener</u></b>
+ * <p>
+ */
+public interface IHistogramModelListener {
+    /**
+     * Method to notify listeners about model updates 
+     */
+    public void modelUpdated();
+}
index 1ed5f7ef5b7ffc91f13d95ff5030108cd4881415..85a00612e46855049740b8d140aa58f1265f38a9 100644 (file)
@@ -1,6 +1,6 @@
 /*******************************************************************************
- * Copyright (c) 2011 Ericsson
  * 
+ * Copyright (c) 2011 Ericsson
  * 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
@@ -8,6 +8,7 @@
  * 
  * Contributors:
  *   Francois Chouinard - Initial API and implementation
+ *   Bernd Hufmann - Changed to updated histogram data model   
  *******************************************************************************/
 
 package org.eclipse.linuxtools.lttng.ui.views.histogram;
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/AbstractViewer.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/AbstractViewer.java
new file mode 100644 (file)
index 0000000..75597d6
--- /dev/null
@@ -0,0 +1,255 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new model-view-controller design\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDistributionModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseTrackListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.ZoomListener;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.SWTException;\r
+import org.eclipse.swt.widgets.Canvas;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Display;\r
+\r
+/**\r
+ * <b><u>AbstractViewer</u></b>\r
+ * <p>\r
+ * Abstract viewer.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public abstract class AbstractViewer extends Canvas {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Parent composite node.\r
+     */\r
+    protected Composite fParent;\r
+\r
+    /**\r
+     * Paint listener.\r
+     */\r
+    protected AbstractPaintListener fPaintListener;\r
+\r
+    /**\r
+     * Zoom listener, to zoom in and out of a graph using the scroll wheel.\r
+     */\r
+    protected ZoomListener fZoomListener;\r
+\r
+    /**\r
+     * Tool tip listener.\r
+     */\r
+    protected AbstractMouseTrackListener fMouseTraceListener;\r
+\r
+    /**\r
+     * Mouse listener\r
+     */\r
+    protected AbstractMouseListener fMouseListener;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructor\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Constructor.\r
+     * @param parent\r
+     *            The parent composite node.\r
+     * @param style\r
+     *            The SWT style to use to render the view.\r
+     */\r
+    public AbstractViewer(Composite parent, int style) {\r
+        super(parent, style);\r
+\r
+        fParent = parent;\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Abstract interface\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Clears the view.\r
+     */\r
+    abstract public void clear();\r
+\r
+    /**\r
+     * Clears the background of the view but keeps min and max values.\r
+     */\r
+    abstract public void clearBackground();\r
+\r
+    /**\r
+     * Method to increase bar width\r
+     */\r
+    abstract public void increaseBarWidth();\r
+    \r
+    /**\r
+     * Method to decrease bar width\r
+     */\r
+    abstract public void decreaseBarWidth();\r
+\r
+    /**\r
+     * Return data model\r
+     */\r
+    abstract public IBaseDistributionModel getModel();\r
+    \r
+    \r
+    // ------------------------------------------------------------------------\r
+    // Accessors\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Returns the zoom factor for the canvas.\r
+     * @return The zoom factor for the canvas.\r
+     */\r
+    public int getZoomFactor() {\r
+        if (fZoomListener != null) {\r
+            return fZoomListener.getZoomFactor();\r
+        } else {\r
+            return 1;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns the zoom increment for the canvas.\r
+     * @return The zoom increment for the canvas.\r
+     */\r
+    public int getZoomIncrement() {\r
+        if (fZoomListener != null) {\r
+            return fZoomListener.getZoomIncrement();\r
+        } else {\r
+            return 1;\r
+        }\r
+    }\r
+\r
+    \r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Draw horizontal label each "nbTicks" ticks.\r
+     * @param nbTicks\r
+     *            The draw interval.\r
+     */\r
+    public void setDrawLabelEachNTicks(int nbTicks) {\r
+        fPaintListener.setDrawLabelEachNTicks(nbTicks);\r
+    }\r
+\r
+    /**\r
+     * Sets the title of the graph.\r
+     * @param graphTitle\r
+     *            The title of the graph.\r
+     */\r
+    public void setGraphTitle(String graphTitle) {\r
+        fPaintListener.setGraphTitle(graphTitle);\r
+    }\r
+\r
+    /**\r
+     * Sets the horizontal axis label.\r
+     * @param xLabel\r
+     *            The horizontal axis label.\r
+     * @param offset\r
+     *            The horizontal axis draw offset (in pixels).\r
+     */\r
+    public void setXAxisLabel(String xLabel, int offset) {\r
+        fPaintListener.setXAxisLabel(xLabel, offset);\r
+    }\r
+\r
+    /**\r
+     * Sets the vertical axis label.\r
+     * @param yLabel\r
+     *            The vertical axis label.\r
+     */\r
+    public void setYAxisLabel(String yLabel) {\r
+        fPaintListener.setYAxisLabel(yLabel);\r
+    }\r
+\r
+    /**\r
+     * Asks for the view to be redrawn, synchronously or asynchronously.\r
+     * @param asyncRedraw\r
+     *            If "true", the view will be redrawn asynchronously, otherwise it will be redraw synchronously.\r
+     */\r
+    public void askForRedraw(boolean asyncRedraw) {\r
+        if (asyncRedraw == true) {\r
+            Display.getDefault().asyncExec(new Runnable() {\r
+                @Override\r
+                public void run() {\r
+                    try {\r
+                        redraw();\r
+                    } catch (SWTException e) {\r
+                        // ...\r
+                    }\r
+                }\r
+            });\r
+        } else {\r
+            Display.getDefault().syncExec(new Runnable() {\r
+                @Override\r
+                public void run() {\r
+                    try {\r
+                        redraw();\r
+                    } catch (SWTException e) {\r
+                        // ...\r
+                    }\r
+                }\r
+            });\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Asks for the view to be redrawn (asynchronously).\r
+     */\r
+    public void askForRedraw() {\r
+        askForRedraw(true);\r
+    }\r
+\r
+    /**\r
+     * Redraws the title after a zoom to display the new zoom factor.\r
+     */\r
+    public void redrawTitle() {\r
+        fPaintListener.paintGraphTitle();\r
+    }\r
+\r
+    /**\r
+     * Removes the view's listeners before disposing of it.\r
+     */\r
+    @Override\r
+    public void dispose() {\r
+        try {\r
+            if (fPaintListener != null) {\r
+                removePaintListener(fPaintListener);\r
+                fPaintListener = null;\r
+            }\r
+            if (fZoomListener != null) {\r
+                removeListener(SWT.MouseWheel, fZoomListener);\r
+                fZoomListener = null;\r
+            }\r
+            if (fMouseTraceListener != null) {\r
+                removeListener(SWT.MouseMove, fMouseTraceListener);\r
+                fMouseTraceListener = null;\r
+            }\r
+        } catch (SWTException e) {\r
+            // This exception will be thrown if the user closes the view\r
+            // while it is receiving data from the Analyzer.\r
+\r
+            // ...\r
+        }\r
+\r
+        super.dispose();\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/GraphViewer.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/GraphViewer.java
new file mode 100644 (file)
index 0000000..2598543
--- /dev/null
@@ -0,0 +1,158 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new model-view-controller design\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.GraphMouseListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.GraphPaintListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.TimePointerListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel;\r
+import org.eclipse.swt.widgets.Composite;\r
+\r
+/**\r
+ * <b><u>GraphViewer</u></b>\r
+ * <p>\r
+ * Graph viewer.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class GraphViewer extends AbstractViewer implements IGraphModelListener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Latency graph model\r
+     */\r
+    private LatencyGraphModel fModel;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+\r
+       /**\r
+        * Constructor.\r
+        * @param parent The parent composite node.\r
+        * @param style The SWT style to use to render the view.\r
+        */\r
+       public GraphViewer(Composite parent, int style) {\r
+               super(parent, style);\r
+\r
+               // Register the paint listener\r
+               fPaintListener = new GraphPaintListener(this);\r
+               addPaintListener(fPaintListener);\r
+\r
+               // Register the mouse track listener\r
+               fMouseTraceListener = new TimePointerListener(this, (GraphPaintListener)fPaintListener);\r
+               addMouseTrackListener(fMouseTraceListener);\r
+\r
+               // Register mouse listener\r
+               fMouseListener = new GraphMouseListener(this, (GraphPaintListener)fPaintListener);\r
+               addMouseListener(fMouseListener);\r
+\r
+               fModel = new LatencyGraphModel();\r
+        fModel.addGraphModelListener(this);\r
+       }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#dispose()\r
+        */\r
+       @Override\r
+       public void dispose() {\r
+           fModel.removeGraphModelListener(this);\r
+           fPaintListener.dispose();\r
+           super.dispose();\r
+       }\r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clear()\r
+        */\r
+       @Override\r
+       public void clear() {\r
+               fPaintListener.clear();\r
+       }\r
+       \r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clearBackground()\r
+        */\r
+       @Override\r
+       public void clearBackground() {\r
+               fPaintListener.clear();\r
+       }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#increaseBarWidth()\r
+     */\r
+    @Override\r
+    public void increaseBarWidth() {\r
+        fPaintListener.increaseBarWitdh();\r
+        graphModelUpdated();\r
+    }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#decreaseBarWidth()\r
+     */\r
+    @Override\r
+    public void decreaseBarWidth() {\r
+        fPaintListener.decreaseBarWitdh();\r
+        graphModelUpdated();\r
+    }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#getModel()\r
+     */\r
+    @Override\r
+    public IGraphDataModel getModel() {\r
+        return fModel;\r
+    }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#graphModelUpdated()\r
+     */\r
+    @Override\r
+    public void graphModelUpdated() {\r
+        if (!isDisposed() && getDisplay() != null) {\r
+            getDisplay().asyncExec(new Runnable() {\r
+                @Override\r
+                public void run() {\r
+                    if (!isDisposed()) {\r
+                        redraw();\r
+                    }\r
+                }\r
+            });\r
+        }\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#currentEventUpdated()\r
+     */\r
+    @Override\r
+    public void currentEventUpdated(long currentEventTime) {\r
+        graphModelUpdated();\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/HistogramViewer.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/HistogramViewer.java
new file mode 100644 (file)
index 0000000..96860d3
--- /dev/null
@@ -0,0 +1,157 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new model-view-controller design\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramDataModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramDataModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramModelListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.HistogramPaintListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.TooltipListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.listeners.ZoomListener;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.widgets.Composite;\r
+\r
+/**\r
+ * <b><u>HistogramViewer</u></b>\r
+ * <p>\r
+ * \r
+ * Histogram viewer.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class HistogramViewer extends AbstractViewer implements IHistogramModelListener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+       /**\r
+        * Usable width for data plotting.\r
+        */\r
+       protected int fUsableWidth;\r
+\r
+       /**\r
+        * Latency histogram model.\r
+        */\r
+       private HistogramDataModel fModel;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+\r
+       /**\r
+        * Constructor.\r
+        * @param parent The parent composite node.\r
+        * @param style The SWT style to use to render the view.\r
+        */\r
+       public HistogramViewer(Composite parent, int style) {\r
+               super(parent, style);\r
+               \r
+               // Register the paint listener\r
+               fPaintListener = new HistogramPaintListener(this);\r
+               addPaintListener(fPaintListener);\r
+               \r
+               // Register the zoom listener\r
+               fZoomListener = new ZoomListener(this);\r
+               addListener(SWT.MouseWheel, fZoomListener);\r
+               \r
+               // Register the mouse click listener\r
+               fMouseTraceListener = new TooltipListener(this, (HistogramPaintListener)fPaintListener);\r
+               addMouseTrackListener(fMouseTraceListener);\r
+               \r
+               fModel = new HistogramDataModel();\r
+               fModel.addHistogramListener(this);\r
+       }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#dispose()\r
+        */\r
+       @Override\r
+       public void dispose() {\r
+           fModel.removeHistogramListener(this);\r
+           fPaintListener.dispose();\r
+           super.dispose();\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clear()\r
+        */\r
+       @Override\r
+       public void clear() {\r
+               fPaintListener.clear();\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#clearBackground()\r
+        */\r
+       @Override\r
+       public void clearBackground() {\r
+               fPaintListener.clear();\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#increaseBarWidth()\r
+        */\r
+       @Override\r
+    public void increaseBarWidth() {\r
+           fPaintListener.increaseBarWitdh();\r
+           modelUpdated();\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#decreaseBarWidth()\r
+        */\r
+       @Override\r
+    public void decreaseBarWidth() {\r
+           fPaintListener.decreaseBarWitdh();\r
+           modelUpdated();\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer#getModel()\r
+        */\r
+       @Override\r
+    public IHistogramDataModel getModel() {\r
+        return fModel;\r
+    }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramModelListener#modelUpdated()\r
+        */\r
+    @Override\r
+    public void modelUpdated() {\r
+        \r
+        if (!isDisposed() && getDisplay() != null) {\r
+            getDisplay().asyncExec(new Runnable() {\r
+                @Override\r
+                public void run() {\r
+                    if (!isDisposed()) {\r
+                        redraw();\r
+                    }\r
+                }\r
+            });\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/LatencyView.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/LatencyView.java
new file mode 100644 (file)
index 0000000..dcb227e
--- /dev/null
@@ -0,0 +1,477 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new model-view-controller design\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.jface.action.Action;\r
+import org.eclipse.jface.action.IMenuManager;\r
+import org.eclipse.jface.action.IToolBarManager;\r
+import org.eclipse.jface.action.Separator;\r
+import org.eclipse.linuxtools.lttng.core.event.LttngEvent;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AddDialog;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.DeleteDialog;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.ListDialog;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyController;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel;\r
+import org.eclipse.linuxtools.tmf.core.event.TmfEvent;\r
+import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;\r
+import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;\r
+import org.eclipse.linuxtools.tmf.core.experiment.TmfExperiment;\r
+import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;\r
+import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentDisposedSignal;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;\r
+import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;\r
+import org.eclipse.linuxtools.tmf.ui.views.TmfView;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.ControlEvent;\r
+import org.eclipse.swt.events.ControlListener;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.ui.IActionBars;\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+\r
+/**\r
+ * <b><u>LatencyView</u></b>\r
+ * <p>\r
+ * TmfView displaying the latency views (i.e. the two latency charts).\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class LatencyView extends TmfView implements IGraphModelListener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+    \r
+    // The initial window span (in nanoseconds)\r
+    public static long INITIAL_WINDOW_SPAN = (1L * 100 * 1000 * 1000); // .1sec\r
+\r
+    /**\r
+     * The view's unique ID.\r
+     */\r
+    public static final String ID = "org.eclipse.linuxtools.lttng.ui.views.latency.LatencyView"; //$NON-NLS-1$\r
+\r
+    /**\r
+     * A reference to the currently selected experiment.\r
+     */\r
+    protected TmfExperiment<LttngEvent> fExperiment = null;\r
+\r
+    /**\r
+     * Parent composite.\r
+     */\r
+    protected Composite fParent;\r
+\r
+    /**\r
+     * Graph view.\r
+     */\r
+    protected GraphViewer fGraphViewer;\r
+    \r
+    /**\r
+     * Histogram view.\r
+     */\r
+    protected HistogramViewer fHistogramViewer;\r
+\r
+    /**\r
+     * Action executed when the user wants to see the list of matching events.\r
+     */\r
+    protected Action fListMatchingEvents;\r
+    \r
+    /**\r
+     * Action executed when the user wants to add matching events.\r
+     */\r
+    protected Action fAddMatchingEvents;\r
+    \r
+    /**\r
+     * Action executed when the user wants to delete matching events.\r
+     */\r
+    protected Action fDeleteMatchingEvents;\r
+    \r
+    /**\r
+     * Action executed when the user wants to increase the width of the histogram bars.\r
+     */\r
+    protected Action fIncreaseBarWidth;\r
+    \r
+    /**\r
+     * Action executed when the user wants to decrease the width of the histogram bars.\r
+     */\r
+    protected Action fDecreaseBarWidth;\r
+\r
+    /**\r
+     * The current histogram window time range.\r
+     */\r
+    protected TmfTimeRange fTimeRange = null;\r
+\r
+    /**\r
+     * Controller of the latency model which is responsible to retrieve data from the trace\r
+     */\r
+    final private LatencyController fController;\r
+\r
+    /**\r
+     * Flag to notify that TimeSyncSignal was received and is being processed.\r
+     */\r
+    private boolean fSyncSignalReceived = false;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructor\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Constructor.\r
+     */\r
+    public LatencyView() {\r
+        super(Messages.LatencyView_ViewName);\r
+        fController = LatencyController.getInstance();\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Create the UI controls of this view.\r
+     * \r
+     * @param parent\r
+     *            The composite parent of this view.\r
+     */\r
+    @Override\r
+    public void createPartControl(Composite parent) {\r
+        // Save the parent\r
+        fParent = parent;\r
+\r
+        makeActions();\r
+        contributeToActionBars();\r
+\r
+        // Add a control listener to handle the view resize events (to redraw the canvas)\r
+        fParent.addControlListener(new ControlListener() {\r
+            @Override\r
+            public void controlMoved(ControlEvent event) {\r
+                fHistogramViewer.clearBackground();\r
+                fGraphViewer.clearBackground();\r
+                fController.handleCompleted();\r
+            }\r
+\r
+            @Override\r
+            public void controlResized(ControlEvent event) {\r
+                fHistogramViewer.clearBackground();\r
+                fGraphViewer.clearBackground();\r
+                fController.handleCompleted();\r
+            }\r
+        });\r
+\r
+        // ///////////////////////////////////////////////////////////////////////////////////\r
+        // Layout for the whole view, other elements will be in a child composite of this one\r
+        // Contains :\r
+        // Composite layoutSelectionWindow\r
+        // Composite layoutTimesSpinner\r
+        // Composite layoutExperimentHistogram\r
+        // ///////////////////////////////////////////////////////////////////////////////////\r
+        Composite layoutFullView = new Composite(fParent, SWT.FILL);\r
+        FillLayout gridFullView = new FillLayout();\r
+        gridFullView.marginHeight = 0;\r
+        gridFullView.marginWidth = 0;\r
+        layoutFullView.setLayout(gridFullView);\r
+\r
+        // Create the graph views\r
+        fGraphViewer = new GraphViewer(layoutFullView, SWT.DOUBLE_BUFFERED);\r
+        fGraphViewer.setDrawLabelEachNTicks(2);\r
+        fGraphViewer.setGraphTitle(Messages.LatencyView_Graphs_Graph_Title);\r
+        fGraphViewer.setXAxisLabel(Messages.LatencyView_Graphs_Graph_XAxisLabel, 40);\r
+        fGraphViewer.setYAxisLabel(Messages.LatencyView_Graphs_Graph_YAxisLabel);\r
+\r
+        fHistogramViewer = new HistogramViewer(layoutFullView, SWT.DOUBLE_BUFFERED);\r
+        fHistogramViewer.setDrawLabelEachNTicks(2);\r
+        fHistogramViewer.setGraphTitle(Messages.LatencyView_Graphs_Histogram_Title);\r
+        fHistogramViewer.setXAxisLabel(Messages.LatencyView_Graphs_Histogram_XAxisLabel, 55);\r
+        fHistogramViewer.setYAxisLabel(Messages.LatencyView_Graphs_Histogram_YAxisLabel);\r
+\r
+        fController.registerModel(fGraphViewer.getModel());\r
+        fController.registerModel(fHistogramViewer.getModel());\r
+        \r
+        ((LatencyGraphModel)fGraphViewer.getModel()).addGraphModelListener(this);\r
+        \r
+        @SuppressWarnings("unchecked")\r
+        TmfExperiment<TmfEvent> experiment = (TmfExperiment<TmfEvent>) TmfExperiment.getCurrentExperiment();\r
+        if (experiment != null) {\r
+\r
+            TmfTimeRange experimentTRange = experiment.getTimeRange();\r
+\r
+            if (experimentTRange != TmfTimeRange.Null) {\r
+                TmfExperimentSelectedSignal<TmfEvent> signal = new TmfExperimentSelectedSignal<TmfEvent>(this, experiment);\r
+                experimentSelected(signal);\r
+            }\r
+        }\r
+    }\r
+\r
+    @SuppressWarnings("nls")\r
+    @Override\r
+    public String toString() {\r
+        return "["+ Messages.LatencyView_ViewName+"]";\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Signal handlers\r
+    // ------------------------------------------------------------------------\r
+\r
+    @SuppressWarnings("unchecked")\r
+    @TmfSignalHandler\r
+    public void experimentSelected(TmfExperimentSelectedSignal<TmfEvent> signal) {\r
+        // Clear the views\r
+        fGraphViewer.clear();\r
+        fHistogramViewer.clear();\r
+\r
+        if (fParent != null) {\r
+            // Update the trace reference\r
+            fExperiment = (TmfExperiment<LttngEvent>) signal.getExperiment();\r
+\r
+            fTimeRange = TmfTimeRange.Null;\r
+            TmfTimeRange experimentTRange = fExperiment.getTimeRange();\r
+\r
+            if (!experimentTRange.equals(TmfTimeRange.Null)) {\r
+                fTimeRange = new TmfTimeRange(experimentTRange.getStartTime(), \r
+                        new TmfTimestamp(experimentTRange.getStartTime().getValue() + INITIAL_WINDOW_SPAN, experimentTRange.getStartTime().getScale(), experimentTRange.getStartTime().getPrecision()));\r
+                fController.refreshModels(fExperiment, fTimeRange);\r
+            }\r
+        }\r
+    }    \r
+    @TmfSignalHandler\r
+    public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal) {\r
+        if (fTimeRange == TmfTimeRange.Null && signal.getExperiment().equals(fExperiment)) {\r
+            TmfTimeRange experimentTRange = signal.getRange();\r
+\r
+            if (experimentTRange != TmfTimeRange.Null) {\r
+                fTimeRange = new TmfTimeRange(experimentTRange.getStartTime(), \r
+                        new TmfTimestamp(experimentTRange.getStartTime().getValue() + INITIAL_WINDOW_SPAN, experimentTRange.getStartTime().getScale(), experimentTRange.getStartTime().getPrecision()));\r
+                fController.refreshModels(fExperiment, fTimeRange);\r
+            }\r
+        }\r
+    }\r
+    \r
+    @TmfSignalHandler\r
+    public void experimentDisposed(TmfExperimentDisposedSignal<TmfEvent> signal) {\r
+        fTimeRange = TmfTimeRange.Null;\r
+        fExperiment = null;\r
+        fController.clear();\r
+    }\r
+\r
+    /**\r
+     * Called when the LatencyView is closed: disposes of the canvas and unregisters models from views.\r
+     */\r
+    @Override\r
+    public void dispose() {\r
+        fController.dispose();\r
+        fController.deregisterModel(fGraphViewer.getModel());\r
+        fController.deregisterModel(fHistogramViewer.getModel());\r
+        ((LatencyGraphModel)fGraphViewer.getModel()).removeGraphModelListener(this);\r
+\r
+        fGraphViewer.dispose();\r
+        fHistogramViewer.dispose();\r
+\r
+        super.dispose();\r
+    }\r
+\r
+    /**\r
+     * Method called when synchronization is active and that the user select an event.\r
+     * \r
+     * The models will be updated with the new current selected time.\r
+     * \r
+     * @param signal\r
+     *            Signal received from the framework. Contain the event.\r
+     */\r
+    @TmfSignalHandler\r
+    public void currentTimeUpdated(TmfTimeSynchSignal signal) {\r
+        if (signal.getSource() != this) {\r
+            fSyncSignalReceived = true;\r
+            fController.setCurrentEventTime(signal.getCurrentTime().getValue());\r
+            fSyncSignalReceived = false;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Method called when synchronization is active and that the user changed the current time range.\r
+\r
+     * The models will be updated with the new time range.\r
+     * \r
+     * @param signal\r
+     *            Signal received from the framework. Contain the new time range.\r
+     */\r
+    @TmfSignalHandler\r
+    public void synchToTimeRange(TmfRangeSynchSignal signal) {\r
+        if (signal.getSource() != this) {\r
+            // Erase the graph views\r
+            fGraphViewer.clear();\r
+            fHistogramViewer.clear();\r
+            \r
+            TmfTimestamp startTime = signal.getCurrentRange().getStartTime();\r
+            TmfTimestamp endTime = signal.getCurrentRange().getEndTime();\r
+            fTimeRange = new TmfTimeRange(startTime, endTime);\r
+\r
+            fController.refreshModels(fExperiment, fTimeRange);\r
+        }\r
+    }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#graphModelUpdated()\r
+     */\r
+    @Override\r
+    public void graphModelUpdated() {\r
+        // Nothing to do - update of viewers will be done in the viewers\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphModelListener#currentEventUpdated(long)\r
+     */\r
+    @Override\r
+    public void currentEventUpdated(final long currentEventTime) {\r
+        if (fExperiment != null && \r
+                !fSyncSignalReceived && // Don't broadcast the current time that was received just before with a time sync signal\r
+                currentEventTime != Config.INVALID_EVENT_TIME) {\r
+\r
+            // Queue update in the event request queue \r
+            TmfTimeRange timeRange = new TmfTimeRange(new TmfTimestamp(currentEventTime, Config.TIME_SCALE), TmfTimestamp.BigCrunch);\r
+            TmfEventRequest<LttngEvent> request = new TmfEventRequest<LttngEvent>(LttngEvent.class, timeRange, 0, 1, ExecutionType.FOREGROUND) {\r
+                @Override\r
+                public void handleCompleted() {\r
+                    broadcast(new TmfTimeSynchSignal(this, new TmfTimestamp(currentEventTime, Config.TIME_SCALE)));\r
+                }\r
+            };\r
+            fExperiment.sendRequest(request);\r
+        }\r
+    }\r
+    \r
+    // ------------------------------------------------------------------------\r
+    // Helper functions\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Fills the local pull down menu.\r
+     * @param manager\r
+     *            The menu manager.\r
+     */\r
+    private void fillLocalPullDown(IMenuManager manager) {\r
+        manager.add(new Separator());\r
+        manager.add(fIncreaseBarWidth);\r
+        manager.add(fDecreaseBarWidth);\r
+        manager.add(new Separator());\r
+        manager.add(fListMatchingEvents);\r
+        manager.add(fAddMatchingEvents);\r
+        manager.add(fDeleteMatchingEvents);\r
+        manager.add(new Separator());\r
+    }\r
+\r
+    /**\r
+     * Fills the local toolbar.\r
+     * @param manager\r
+     *            The toolbar manager\r
+     */\r
+    private void fillLocalToolBar(IToolBarManager manager) {\r
+        manager.add(new Separator());\r
+        manager.add(fIncreaseBarWidth);\r
+        manager.add(fDecreaseBarWidth);\r
+        manager.add(new Separator());\r
+        manager.add(fListMatchingEvents);\r
+        manager.add(fAddMatchingEvents);\r
+        manager.add(fDeleteMatchingEvents);\r
+        manager.add(new Separator());\r
+    }\r
+\r
+    /**\r
+     * Creates the actions required by the dialog events.\r
+     */\r
+    private void makeActions() {\r
+        // Increase the histogram bar width\r
+        fIncreaseBarWidth = new Action() {\r
+            @Override\r
+            public void run() {\r
+                fHistogramViewer.increaseBarWidth();\r
+                fGraphViewer.increaseBarWidth();\r
+            }\r
+        };\r
+        String tooltipText = Messages.LatencyView_Action_IncreaseBarWidth_Tooltip;\r
+        fIncreaseBarWidth.setText(tooltipText);\r
+        fIncreaseBarWidth.setToolTipText(tooltipText);\r
+        fIncreaseBarWidth.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/increasebar_button.gif")); //$NON-NLS-1$\r
+\r
+        // Decrease the histogram bar width\r
+        fDecreaseBarWidth = new Action() {\r
+            @Override\r
+            public void run() {\r
+                fHistogramViewer.decreaseBarWidth();\r
+                fGraphViewer.decreaseBarWidth();\r
+            }\r
+        };\r
+        tooltipText = Messages.LatencyView_Action_DecreaseBarWidth_Tooltip;\r
+        fDecreaseBarWidth.setText(tooltipText);\r
+        fDecreaseBarWidth.setToolTipText(tooltipText);\r
+        fDecreaseBarWidth.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/decreasebar_button.gif")); //$NON-NLS-1$\r
+\r
+        // List matching events dialog\r
+        fListMatchingEvents = new Action() {\r
+            @Override\r
+            public void run() {\r
+                ListDialog listDialog = new ListDialog(fParent.getShell(), Messages.LatencyView_Dialogs_ListEvents_Title, Messages.LatencyView_Dialogs_ListEvents_Message);\r
+                listDialog.create();\r
+                listDialog.open();\r
+            }\r
+        };\r
+        tooltipText = Messages.LatencyView_Action_ListEvents_Tooltip;\r
+        fListMatchingEvents.setText(tooltipText);\r
+        fListMatchingEvents.setToolTipText(tooltipText);\r
+        fListMatchingEvents.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/eview16/events_view.gif")); //$NON-NLS-1$\r
+\r
+        // Add matching events dialog\r
+        fAddMatchingEvents = new Action() {\r
+            @Override\r
+            public void run() {\r
+                AddDialog addDialog = new AddDialog(fParent.getShell(), Messages.LatencyView_Dialogs_AddEvents_Title, Messages.LatencyView_Dialogs_AddEvents_Message);\r
+                addDialog.create();\r
+                addDialog.open();\r
+            }\r
+        };\r
+        tooltipText = Messages.LatencyView_Action_AddEvents_Tooltip;\r
+        fAddMatchingEvents.setText(tooltipText);\r
+        fAddMatchingEvents.setToolTipText(tooltipText);\r
+        fAddMatchingEvents.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/add_button.gif")); //$NON-NLS-1$\r
+\r
+        // Remove matching events dialog\r
+        fDeleteMatchingEvents = new Action() {\r
+            @Override\r
+            public void run() {\r
+                DeleteDialog deleteDialog = new DeleteDialog(fParent.getShell(), Messages.LatencyView_Dialogs_DeleteEvents_Title,\r
+                        Messages.LatencyView_Dialogs_DeleteEvents_Message);\r
+                deleteDialog.create();\r
+                deleteDialog.open();\r
+            }\r
+        };\r
+        tooltipText = Messages.LatencyView_Action_DeleteEvents_Tooltip;\r
+        fDeleteMatchingEvents.setText(tooltipText);\r
+        fDeleteMatchingEvents.setToolTipText(tooltipText);\r
+        fDeleteMatchingEvents.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/delete_button.gif")); //$NON-NLS-1$\r
+    }\r
+\r
+    /**\r
+     * Build the toolbar and menu by adding action buttons for dialogs.\r
+     */\r
+    private void contributeToActionBars() {\r
+        IActionBars bars = getViewSite().getActionBars();\r
+        fillLocalPullDown(bars.getMenuManager());\r
+        fillLocalToolBar(bars.getToolBarManager());\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/Messages.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/Messages.java
new file mode 100644 (file)
index 0000000..85cffa9
--- /dev/null
@@ -0,0 +1,85 @@
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Updated    \r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency;\r
+\r
+import org.eclipse.osgi.util.NLS;\r
+\r
+/**\r
+ * Returns localized strings from the resource bundle (i.e. "messages.properties").\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class Messages {\r
+\r
+    public static String LatencyView_ViewName;\r
+    public static String LatencyView_Action_IncreaseBarWidth_Tooltip;\r
+    public static String LatencyView_Action_DecreaseBarWidth_Tooltip;\r
+    public static String LatencyView_Action_AddEvents_Tooltip;\r
+    public static String LatencyView_Action_DeleteEvents_Tooltip;\r
+    public static String LatencyView_Action_ListEvents_Tooltip;\r
+    public static String LatencyView_Dialogs_AddEvents_Title;\r
+    public static String LatencyView_Dialogs_AddEvents_Message;\r
+    public static String LatencyView_Dialogs_AddEvents_Buttons_Add;\r
+    public static String LatencyView_Dialogs_AddEvents_Buttons_Close;\r
+    public static String LatencyView_Dialogs_AddEvents_Columns_Start;\r
+    public static String LatencyView_Dialogs_AddEvents_Columns_End;\r
+    public static String LatencyView_Dialogs_AddEvents_Columns_List_Trigger;\r
+    public static String LatencyView_Dialogs_AddEvents_Columns_List_End;\r
+    public static String LatencyView_Dialogs_AddEvents_Errors_NoSelection;\r
+    public static String LatencyView_Dialogs_AddEvents_Errors_StartNotSelected;\r
+    public static String LatencyView_Dialogs_AddEvents_Errors_EndNotSelected;\r
+    public static String LatencyView_Dialogs_AddEvents_Errors_SameSelected;\r
+    public static String LatencyView_Dialogs_AddEvents_Errors_AlreadyMatched;\r
+    public static String LatencyView_Dialogs_AddEvents_Errors_StartAlreadyMatched;\r
+    public static String LatencyView_Dialogs_AddEvents_Errors_EndAlreadyMatched;\r
+    public static String LatencyView_Dialogs_AddEvents_Errors_StartAsEnd;\r
+    public static String LatencyView_Dialogs_AddEvents_Errors_EndAsStart;\r
+    public static String LatencyView_Dialogs_DeleteEvents_Title;\r
+    public static String LatencyView_Dialogs_DeleteEvents_Message;\r
+    public static String LatencyView_Dialogs_DeleteEvents_Buttons_Close;\r
+    public static String LatencyView_Dialogs_DeleteEvents_Buttons_Delete;\r
+    public static String LatencyView_Dialogs_DeleteEvents_Confirm_Title;\r
+    public static String LatencyView_Dialogs_DeleteEvents_Confirm_Message;\r
+    public static String LatencyView_Dialogs_ListEvents_Title;\r
+    public static String LatencyView_Dialogs_ListEvents_Message;\r
+    public static String LatencyView_Dialogs_ListEvents_Buttons_Close;\r
+    public static String LatencyView_Dialogs_ListEvents_Buttons_Reset;\r
+    public static String LatencyView_Dialogs_ListEvents_Columns_Trigger;\r
+    public static String LatencyView_Dialogs_ListEvents_Columns_End;\r
+    public static String LatencyView_Dialogs_ListEvents_Confirm_Title;\r
+    public static String LatencyView_Dialogs_ListEvents_Confirm_Message;\r
+    public static String LatencyView_Graphs_Graph_Title;\r
+    public static String LatencyView_Graphs_Graph_XAxisLabel;\r
+    public static String LatencyView_Graphs_Graph_YAxisLabel;\r
+    public static String LatencyView_Graphs_Histogram_Title;\r
+    public static String LatencyView_Graphs_Histogram_XAxisLabel;\r
+    public static String LatencyView_Graphs_Histogram_YAxisLabel;\r
+    public static String LatencyView_msgSlogan;\r
+    public static String LatencyView_tmf_UI;\r
+    public static String LatencyView_ClippingWarning;\r
+    \r
+\r
+    /**\r
+     * Bundle name.\r
+     */\r
+    private static final String BUNDLE_NAME = "org.eclipse.linuxtools.lttng.ui.views.latency.messages"; //$NON-NLS-1$\r
+\r
+    static {\r
+        // initialize resource bundle\r
+        NLS.initializeMessages(BUNDLE_NAME, Messages.class);\r
+    }\r
+\r
+    private Messages() {\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AbstractDialog.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AbstractDialog.java
new file mode 100644 (file)
index 0000000..2551eae
--- /dev/null
@@ -0,0 +1,240 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new messages file, fixed warnings\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;\r
+\r
+import java.util.Vector;\r
+\r
+import org.eclipse.jface.dialogs.IDialogSettings;\r
+import org.eclipse.jface.dialogs.IMessageProvider;\r
+import org.eclipse.jface.dialogs.TitleAreaDialog;\r
+import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher;\r
+import org.eclipse.linuxtools.lttng.core.util.EventsPair;\r
+import org.eclipse.linuxtools.lttng.ui.LTTngUiPlugin;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyController;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.swt.widgets.Shell;\r
+\r
+/**\r
+ * <b><u>AbstractDialog</u></b>\r
+ * <p> \r
+ * Includes the main functions shared by all the different dialogs.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public abstract class AbstractDialog extends TitleAreaDialog {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * The dialog window title.\r
+     */\r
+    protected String fDialogTitle;\r
+    /**\r
+     * The dialog window message.\r
+     */\r
+    protected String fDialogMessage;\r
+\r
+    /**\r
+     * The code returned by the dialog when the user closes the "Add" dialog.\r
+     */\r
+    public static final int ADD = 53445;\r
+    /**\r
+     * The code returned by the dialog when the user closes the "Delete" dialog.\r
+     */\r
+    public static final int DELETE = ADD + 1;\r
+    /**\r
+     * The code returned by the dialog when the user resets the latency pair to default.\r
+     */\r
+    public static final int RESET = DELETE + 1;\r
+\r
+    /**\r
+     * String ID of the number of pairs saved in the settings file.\r
+     */\r
+    protected static final String LATENCY_NB_MATCH_PAIRS = "NB_LATENCY_MATCH_PAIRS"; //$NON-NLS-1$\r
+    /**\r
+     * String ID of the start event pairs saved in the settings file.\r
+     */\r
+    protected static final String LATENCY_PAIRS_START = "LATENCY_PAIRS_START"; //$NON-NLS-1$\r
+    /**\r
+     * String ID of the end event pairs saved in the settings file.\r
+     */\r
+    protected static final String LATENCY_PAIRS_END = "LATENCY_PAIRS_END"; //$NON-NLS-1$\r
+\r
+    /**\r
+     * Dialog settings, saves the event pairs across sessions.\r
+     */\r
+    protected IDialogSettings fSettings;\r
+\r
+    /**\r
+     * Do the graphs canvas need to be redrawn due to latency pairs changes ?\r
+     */\r
+    protected boolean fRedrawGraphs = false;\r
+    \r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param parentShell\r
+     *            The parent shell.\r
+     * @param title\r
+     *            The dialog window's title.\r
+     * @param message\r
+     *            The dialog window's message.\r
+     */\r
+    public AbstractDialog(Shell parentShell, String title, String message) {\r
+        super(parentShell);\r
+        fDialogTitle = title;\r
+        fDialogMessage = message;\r
+\r
+        fSettings = LTTngUiPlugin.getDefault().getDialogSettings();\r
+    }\r
+\r
+    /**\r
+     * Constructor\r
+     * @param parentShell\r
+     *            The parent shell.\r
+     * @param title\r
+     *            The dialog window's title.\r
+     */\r
+    @SuppressWarnings("nls")\r
+    public AbstractDialog(Shell parentShell, String title) {\r
+        this(parentShell, title, "");\r
+    }\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param parentShell\r
+     *            The parent shell.\r
+     */\r
+    @SuppressWarnings("nls")\r
+    public AbstractDialog(Shell parentShell) {\r
+        this(parentShell, "", "");\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Creates the dialog.\r
+     * \r
+     * <b>Note :</b> Since there is an issue with the table's vertical scroll bar, this dialog "resize" is necessary to\r
+     * ensure a minimal height for the window.\r
+     */\r
+    @Override\r
+    public void create() {\r
+        super.create();\r
+        // Set the title\r
+        setTitle(fDialogTitle);\r
+        // Set the message\r
+        setMessage(fDialogMessage, IMessageProvider.INFORMATION);\r
+\r
+        // Position the dialog at the center of the screen\r
+        int windowWidth = Display.getCurrent().getPrimaryMonitor().getBounds().width;\r
+        int windowHeight = Display.getCurrent().getPrimaryMonitor().getBounds().height;\r
+        int dialogWidth = getShell().getSize().x;\r
+        int dialogHeight = windowHeight / 2;\r
+\r
+        int x = (windowWidth - dialogWidth) / 2;\r
+        int y = (windowHeight - dialogHeight) / 2;\r
+\r
+        getShell().setSize(getShell().getSize().x, dialogHeight);\r
+        getShell().setLocation(x, y);\r
+    }\r
+\r
+    /**\r
+     * Formats the "#" of the event in the table by adding "00" before it.\r
+     * @param number\r
+     *            The number to format.\r
+     * @param max\r
+     *            The maximum number of event pairs in the list.\r
+     * @return The formatted string.\r
+     */\r
+    @SuppressWarnings("nls")\r
+    protected String formatListNumber(int number, int max) {\r
+        return String.format("%0" + max + "d", number);\r
+    }\r
+\r
+    /**\r
+     * Returns the match pairs saved in the settings file.\r
+     * @return The match pairs saved in the settings file.\r
+     */\r
+    protected EventsPair getMatchPairs() {\r
+        try {\r
+            // Check if the settings file has already some data (i.e. try provoking an exception)\r
+            fSettings.getInt(LATENCY_NB_MATCH_PAIRS);\r
+\r
+            String[] starts = fSettings.getArray(LATENCY_PAIRS_START);\r
+            String[] ends = fSettings.getArray(LATENCY_PAIRS_END);\r
+\r
+            EventMatcher.getInstance().resetMatches();\r
+            for (int i = 0; i < starts.length; i++) {\r
+                EventMatcher.getInstance().addMatch(starts[i], ends[i]);\r
+            }\r
+\r
+            return EventMatcher.getInstance().getEvents();\r
+        } catch (NumberFormatException e) {\r
+            return EventMatcher.getInstance().getEvents();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Saves the event match pairs to a settings file.\r
+     * @param start\r
+     *            The start event types.\r
+     * @param end\r
+     *            The end event types.\r
+     */\r
+    protected void saveMatchPairs(Vector<String> start, Vector<String> end) {\r
+        fSettings.put(LATENCY_NB_MATCH_PAIRS, start.size());\r
+        fSettings.put(LATENCY_PAIRS_START, start.toArray(new String[] {}));\r
+        fSettings.put(LATENCY_PAIRS_END, end.toArray(new String[] {}));\r
+    }\r
+\r
+    /**\r
+     * Ask the LatencyView to send a new analysis request to the views, so that they can be redrawn.\r
+     */\r
+    protected void redrawGraphs() {\r
+        LatencyController.getInstance().refreshModels();\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite)\r
+     */\r
+    @Override\r
+    protected abstract Control createDialogArea(Composite parent);\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)\r
+     */\r
+    @Override\r
+    protected abstract void createButtonsForButtonBar(Composite parent);\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.jface.dialogs.Dialog#isResizable()\r
+     */\r
+    @Override\r
+    protected boolean isResizable() {\r
+        return true;\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AddDialog.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/AddDialog.java
new file mode 100644 (file)
index 0000000..aee1ef9
--- /dev/null
@@ -0,0 +1,488 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new messages file, fixed warnings\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;\r
+\r
+import java.util.Vector;\r
+\r
+import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher;\r
+import org.eclipse.linuxtools.lttng.core.util.EventsPair;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Listener;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Table;\r
+import org.eclipse.swt.widgets.TableColumn;\r
+import org.eclipse.swt.widgets.TableItem;\r
+\r
+/**\r
+ * <b><u>AddDialog</u></b>\r
+ * <p>\r
+ * Add dialog, lets the user add custom start/end event pairs.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class AddDialog extends AbstractDialog {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * The dialog's start table.\r
+     */\r
+    protected Table fStartTable;\r
+\r
+    /**\r
+     * The dialog's end table.\r
+     */\r
+    protected Table fEndTable;\r
+\r
+    /**\r
+     * The dialog's list table.\r
+     */\r
+    protected Table fListTable;\r
+\r
+    /**\r
+     * Start table columns.\r
+     */\r
+    protected TableColumn[] fStartColumns;\r
+\r
+    /**\r
+     * End table columns.\r
+     */\r
+    protected TableColumn[] fEndColumns;\r
+\r
+    /**\r
+     * List table columns.\r
+     */\r
+    protected TableColumn[] fListColumns;\r
+\r
+    /**\r
+     * Start table column names (header titles).\r
+     */\r
+    protected static final String[] START_COLUMN_NAMES = { "", Messages.LatencyView_Dialogs_AddEvents_Columns_Start }; //$NON-NLS-1$\r
+\r
+    /**\r
+     * End table column names (header titles).\r
+     */\r
+    protected static final String[] END_COLUMN_NAMES = { "", Messages.LatencyView_Dialogs_AddEvents_Columns_End }; //$NON-NLS-1$\r
+\r
+    /**\r
+     * List table column names (header titles).\r
+     */\r
+    protected static final String[] LIST_COLUMN_NAMES = {\r
+            "#", //$NON-NLS-1$\r
+            Messages.LatencyView_Dialogs_AddEvents_Columns_List_Trigger,\r
+            Messages.LatencyView_Dialogs_AddEvents_Columns_List_End };\r
+\r
+    /**\r
+     * Column widths.\r
+     */\r
+    protected static final int[] COLUMN_WIDTHS = { 25, 250, 250 };\r
+\r
+    /**\r
+     * Possible event types.\r
+     */\r
+    protected Vector<String> fEventTypes = new Vector<String>();\r
+\r
+    /**\r
+     * Start event types.\r
+     */\r
+    protected Vector<String> fEventStartTypes;\r
+\r
+    /**\r
+     * End event types.\r
+     */\r
+    protected Vector<String> fEventEndTypes;\r
+\r
+    /**\r
+     * Selected start type.\r
+     */\r
+    protected String fStartType;\r
+\r
+    /**\r
+     * Selected end type.\r
+     */\r
+    protected String fEndType;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param parentShell\r
+     *            The parent shell.\r
+     * @param title\r
+     *            The dialog's window title.\r
+     * @param message\r
+     *            The dialog's window message.\r
+     */\r
+    public AddDialog(Shell parentShell, String title, String message) {\r
+        super(parentShell, title, message);\r
+\r
+        // Get the possible events from the list\r
+        fEventTypes = EventMatcher.getInstance().getTypeList();\r
+\r
+        // Get the list of start and end types from the EventMatcher\r
+        EventsPair pair = getMatchPairs();\r
+        fEventStartTypes = pair.getFirst();\r
+        fEventEndTypes = pair.getSecond();\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Creates the start table's columns (i.e. the table header).\r
+     */\r
+    protected void createStartColumns() {\r
+        fStartColumns = new TableColumn[START_COLUMN_NAMES.length];\r
+        for (int i = 0; i < START_COLUMN_NAMES.length; i++) {\r
+            fStartColumns[i] = new TableColumn(fStartTable, SWT.LEFT);\r
+            fStartColumns[i].setText(START_COLUMN_NAMES[i]);\r
+            fStartColumns[i].setWidth(COLUMN_WIDTHS[i]);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Creates the end table's columns (i.e. the table header).\r
+     */\r
+    protected void createEndColumns() {\r
+        fEndColumns = new TableColumn[END_COLUMN_NAMES.length];\r
+        for (int i = 0; i < END_COLUMN_NAMES.length; i++) {\r
+            fEndColumns[i] = new TableColumn(fEndTable, SWT.LEFT);\r
+            fEndColumns[i].setText(END_COLUMN_NAMES[i]);\r
+            fEndColumns[i].setWidth(COLUMN_WIDTHS[i]);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Creates the list table's columns (i.e. the table header).\r
+     */\r
+    protected void createListColumns() {\r
+        fListColumns = new TableColumn[LIST_COLUMN_NAMES.length];\r
+        for (int i = 0; i < LIST_COLUMN_NAMES.length; i++) {\r
+            fListColumns[i] = new TableColumn(fListTable, SWT.LEFT);\r
+            fListColumns[i].setText(LIST_COLUMN_NAMES[i]);\r
+            fListColumns[i].setWidth(COLUMN_WIDTHS[i]);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Creates the start column list.\r
+     * @param parent\r
+     *            The parent composite.\r
+     */\r
+    protected void createStartColumn(Composite parent) {\r
+        final int style = SWT.SINGLE | SWT.CHECK | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+        GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);\r
+        fStartTable = new Table(parent, style);\r
+        fStartTable.setLayoutData(layoutData);\r
+\r
+        // Some cosmetic enhancements\r
+        fStartTable.setHeaderVisible(true);\r
+        fStartTable.setLinesVisible(true);\r
+\r
+        createStartColumns();\r
+\r
+        for (int i = 0; i < fEventTypes.size(); i++) {\r
+            TableItem item = new TableItem(fStartTable, SWT.RIGHT);\r
+\r
+            String[] columns = { fEventTypes.get(i), fEventTypes.get(i) };\r
+\r
+            item.setText(columns);\r
+        }\r
+\r
+        fStartTable.setItemCount(fEventTypes.size());\r
+\r
+        fStartTable.addListener(SWT.Selection, new Listener() {\r
+            @Override\r
+            public void handleEvent(Event event) {\r
+                if (event.detail == SWT.CHECK) {\r
+                    TableItem[] items = fStartTable.getItems();\r
+                    for (TableItem item : items) {\r
+                        if (item != event.item) {\r
+                            item.setChecked(false);\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        });\r
+    }\r
+\r
+    /**\r
+     * Creates the end column list.\r
+     * @param parent\r
+     *            The parent composite.\r
+     */\r
+    protected void createEndColumn(Composite parent) {\r
+        final int style = SWT.SINGLE | SWT.CHECK | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+        GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);\r
+        fEndTable = new Table(parent, style);\r
+        fEndTable.setLayoutData(layoutData);\r
+\r
+        // Some cosmetic enhancements\r
+        fEndTable.setHeaderVisible(true);\r
+        fEndTable.setLinesVisible(true);\r
+\r
+        createEndColumns();\r
+\r
+        for (int i = 0; i < fEventTypes.size(); i++) {\r
+            TableItem item = new TableItem(fEndTable, SWT.RIGHT);\r
+\r
+            String[] columns = { fEventTypes.get(i), fEventTypes.get(i) };\r
+\r
+            item.setText(columns);\r
+        }\r
+\r
+        fEndTable.setItemCount(fEventTypes.size());\r
+\r
+        fEndTable.addListener(SWT.Selection, new Listener() {\r
+            @Override\r
+            public void handleEvent(Event event) {\r
+                if (event.detail == SWT.CHECK) {\r
+                    TableItem[] items = fEndTable.getItems();\r
+                    for (TableItem item : items) {\r
+                        if (item != event.item) {\r
+                            item.setChecked(false);\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        });\r
+    }\r
+\r
+    /**\r
+     * Creates the list column for already existing event pairs.\r
+     * @param parent\r
+     *            The parent composite.\r
+     */\r
+    protected void createListColumn(Composite parent) {\r
+        final int style = SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+        GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);\r
+        layoutData.horizontalSpan = 2;\r
+        fListTable = new Table(parent, style);\r
+        fListTable.setLayoutData(layoutData);\r
+\r
+        // Some cosmetic enhancements\r
+        fListTable.setHeaderVisible(true);\r
+        fListTable.setLinesVisible(true);\r
+\r
+        createListColumns();\r
+\r
+        for (int i = 0; i < fEventStartTypes.size(); i++) {\r
+            TableItem item = new TableItem(fListTable, SWT.RIGHT);\r
+\r
+            String max = String.valueOf(fEventStartTypes.size());\r
+            String number = formatListNumber(i + 1, max.length());\r
+\r
+            String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+            item.setText(columns);\r
+        }\r
+\r
+        fListTable.setItemCount(103);\r
+        fListTable.remove(fEventTypes.size(), 103 - 1);\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createDialogArea(org.eclipse.swt.widgets.Composite)\r
+     */\r
+    @Override\r
+    protected Control createDialogArea(Composite parent) {\r
+        GridLayout layout = new GridLayout(2, true);\r
+        parent.setLayout(layout);\r
+\r
+        createStartColumn(parent);\r
+        createEndColumn(parent);\r
+        createListColumn(parent);\r
+\r
+        return parent;\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)\r
+     */\r
+    @Override\r
+    protected void createButtonsForButtonBar(Composite parent) {\r
+        GridData gridData = new GridData();\r
+        gridData.verticalAlignment = GridData.FILL;\r
+        gridData.horizontalSpan = 1;\r
+        gridData.grabExcessHorizontalSpace = true;\r
+        gridData.grabExcessVerticalSpace = true;\r
+        gridData.horizontalAlignment = SWT.RIGHT;\r
+\r
+        parent.setLayoutData(gridData);\r
+\r
+        // Create the "Add" button\r
+        Button addButton = createButton(parent, ADD, Messages.LatencyView_Dialogs_AddEvents_Buttons_Add, false);\r
+        addButton.addListener(SWT.Selection, new Listener() {\r
+            @Override\r
+            public void handleEvent(Event event) {\r
+                if (isValidInput()) {\r
+                    // Add the event pair to the EventMatcher and save the pairs\r
+                    EventMatcher.getInstance().addMatch(fStartType, fEndType);\r
+                    fEventStartTypes.add(fStartType);\r
+                    fEventEndTypes.add(fEndType);\r
+                    saveMatchPairs(fEventStartTypes, fEventEndTypes);\r
+\r
+                    EventsPair pairs = EventMatcher.getInstance().getEvents();\r
+                    fEventStartTypes = pairs.getFirst();\r
+                    fEventEndTypes = pairs.getSecond();\r
+\r
+                    fListTable.removeAll();\r
+\r
+                    for (int i = 0; i < fEventStartTypes.size(); i++) {\r
+                        TableItem item = new TableItem(fListTable, SWT.RIGHT);\r
+\r
+                        String max = String.valueOf(fEventStartTypes.size());\r
+                        String number = formatListNumber(i + 1, max.length());\r
+\r
+                        String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+                        item.setText(columns);\r
+                    }\r
+\r
+                    saveMatchPairs(fEventStartTypes, fEventEndTypes);\r
+                }\r
+\r
+                fRedrawGraphs = true;\r
+            }\r
+        });\r
+\r
+        // Create the "Close" button\r
+        Button closeButton = createButton(parent, CANCEL, Messages.LatencyView_Dialogs_AddEvents_Buttons_Close, false);\r
+        closeButton.addListener(SWT.Selection, new Listener() {\r
+            @Override\r
+            public void handleEvent(Event event) {\r
+                setReturnCode(CANCEL);\r
+\r
+                if (fRedrawGraphs == true)\r
+                    redrawGraphs();\r
+\r
+                close();\r
+            }\r
+        });\r
+    }\r
+\r
+    /**\r
+     * Validate the list before adding event pairs.\r
+     * @return "true" if the input is valid, "false" otherwise.\r
+     */\r
+    protected boolean isValidInput() {\r
+        // Remove the previous error message\r
+        setErrorMessage(null);\r
+\r
+        boolean valid = true;\r
+\r
+        // Check if an item from the start list is selected\r
+        TableItem[] items = fStartTable.getItems();\r
+        fStartType = null;\r
+        boolean startHasSelectedItem = false;\r
+        for (int i = 0; i < items.length && !startHasSelectedItem; i++) {\r
+            if (items[i].getChecked() == true) {\r
+                fStartType = items[i].getText();\r
+                startHasSelectedItem = true;\r
+            }\r
+        }\r
+\r
+        // Check if an item from the end list is selected\r
+        items = fEndTable.getItems();\r
+        fEndType = null;\r
+        boolean endHasSelectedItem = false;\r
+        for (int i = 0; i < items.length && !endHasSelectedItem; i++) {\r
+            if (items[i].getChecked() == true) {\r
+                fEndType = items[i].getText();\r
+                endHasSelectedItem = true;\r
+            }\r
+        }\r
+\r
+        // Print error message if needed.\r
+        if (!startHasSelectedItem && !endHasSelectedItem) {\r
+            setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_NoSelection);\r
+            valid = false;\r
+        } else if (!startHasSelectedItem) {\r
+            setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_StartNotSelected);\r
+            valid = false;\r
+        } else if (!endHasSelectedItem) {\r
+            setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_EndNotSelected);\r
+            valid = false;\r
+        }\r
+\r
+        // Check if the same item is selected in both lists\r
+        if (startHasSelectedItem && endHasSelectedItem) {\r
+            if (fStartType.equalsIgnoreCase(fEndType)) {\r
+                setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_SameSelected);\r
+                valid = false;\r
+            }\r
+        }\r
+\r
+        // Check if the selected item is already in the list\r
+        if (startHasSelectedItem && endHasSelectedItem) {\r
+            EventsPair pairs = getMatchPairs();\r
+            Vector<String> startEvents = pairs.getFirst();\r
+            Vector<String> endEvents = pairs.getSecond();\r
+\r
+            boolean startAlreadyUsed = false;\r
+            boolean endAlreadyUsed = false;\r
+            boolean startAsEndAlreadyUsed = false;\r
+            boolean endAsStartAlreadyUsed = false;\r
+\r
+            if (startEvents.contains(fStartType)) {\r
+                startAlreadyUsed = true;\r
+            }\r
+            if (endEvents.contains(fEndType)) {\r
+                endAlreadyUsed = true;\r
+            }\r
+            if (startEvents.contains(fEndType)) {\r
+                endAsStartAlreadyUsed = true;\r
+            }\r
+            if (endEvents.contains(fStartType)) {\r
+                startAsEndAlreadyUsed = true;\r
+            }\r
+\r
+            if (startAlreadyUsed && endAlreadyUsed) {\r
+                setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_AlreadyMatched);\r
+                valid = false;\r
+            } else if (startAlreadyUsed) {\r
+                setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_StartAlreadyMatched);\r
+                valid = false;\r
+            } else if (endAlreadyUsed) {\r
+                setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_EndAlreadyMatched);\r
+                valid = false;\r
+            }\r
+\r
+            if (startAsEndAlreadyUsed) {\r
+                setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_StartAsEnd);\r
+                valid = false;\r
+            }\r
+            if (endAsStartAlreadyUsed) {\r
+                setErrorMessage(Messages.LatencyView_Dialogs_AddEvents_Errors_EndAsStart);\r
+                valid = false;\r
+            }\r
+        }\r
+\r
+        return valid;\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/DeleteDialog.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/DeleteDialog.java
new file mode 100644 (file)
index 0000000..c975688
--- /dev/null
@@ -0,0 +1,155 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new messages file, fixed warnings\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;\r
+\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Listener;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.TableItem;\r
+\r
+/**\r
+ * <b><u>DeleteDialog</u></b>\r
+ * <p>\r
+ * Remove dialog, lets the user remove start/end event pairs.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class DeleteDialog extends ListDialog {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param parentShell\r
+     *            The parent shell.\r
+     * @param title\r
+     *            The dialog's window title.\r
+     * @param message\r
+     *            The dialog's window message.\r
+     */\r
+    public DeleteDialog(Shell parentShell, String title, String message) {\r
+        super(parentShell, title, message);\r
+\r
+        // Set the table style\r
+        fStyle = SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.ListDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)\r
+     */\r
+    @Override\r
+    protected void createButtonsForButtonBar(Composite parent) {\r
+        GridData gridData = new GridData();\r
+        gridData.verticalAlignment = GridData.FILL;\r
+        gridData.horizontalSpan = 1;\r
+        gridData.grabExcessHorizontalSpace = true;\r
+        gridData.grabExcessVerticalSpace = true;\r
+        gridData.horizontalAlignment = SWT.RIGHT;\r
+\r
+        parent.setLayoutData(gridData);\r
+\r
+        // Create the "Delete" button\r
+        Button deleteButton = createButton(parent, DELETE, Messages.LatencyView_Dialogs_DeleteEvents_Buttons_Delete, false);\r
+        deleteButton.addListener(SWT.Selection, new Listener() {\r
+            @Override\r
+            public void handleEvent(Event event) {\r
+                TableItem selectedItem = fTable.getSelection()[0];\r
+                if (selectedItem == null)\r
+                    return;\r
+\r
+                int[] selectedIndices = fTable.getSelectionIndices();\r
+\r
+                String deletePairs = ""; //$NON-NLS-1$\r
+                for (int i = 0; i < selectedIndices.length; i++) {\r
+                    int index = selectedIndices[i];\r
+                    deletePairs += "\t* " + fEventStartTypes.get(index) + " / " + fEventEndTypes.get(index); //$NON-NLS-1$ //$NON-NLS-2$\r
+\r
+                    if (i < selectedIndices.length - 1) {\r
+                        deletePairs += "\n"; //$NON-NLS-1$\r
+                    }\r
+                }\r
+\r
+                boolean confirmDeletion = MessageDialog.openQuestion(getShell(), Messages.LatencyView_Dialogs_DeleteEvents_Confirm_Title,\r
+                        Messages.LatencyView_Dialogs_DeleteEvents_Confirm_Message + "\n\n" + deletePairs); //$NON-NLS-1$\r
+\r
+                if (confirmDeletion) {\r
+                    // Remove the events starting from the end of the list, otherwise the TableItem elements will lose\r
+                    // their index from the table and may trigger an exception when removing an index that is no longer\r
+                    // valid.\r
+                    for (int i = selectedIndices.length - 1; i >= 0; i--) {\r
+                        int selectedIndex = selectedIndices[i];\r
+                        EventMatcher.getInstance().removeMatch(fEventStartTypes.get(selectedIndex), fEventEndTypes.get(selectedIndex));\r
+\r
+                        fTable.remove(selectedIndex);\r
+\r
+                        // Update the list of events\r
+                        fEventStartTypes.remove(selectedIndex);\r
+                        fEventEndTypes.remove(selectedIndex);\r
+                    }\r
+\r
+                    // Save the events pairs in the settings file so it can be retrieved in the next session\r
+                    saveMatchPairs(fEventStartTypes, fEventEndTypes);\r
+\r
+                    fTable.setItemCount(fEventStartTypes.size());\r
+\r
+                    TableItem[] newItems = fTable.getItems();\r
+                    fTable.removeAll();\r
+                    for (int i = 0; i < newItems.length; i++) {\r
+                        TableItem item = new TableItem(fTable, SWT.RIGHT);\r
+\r
+                        String max = String.valueOf(fEventStartTypes.size());\r
+                        String number = formatListNumber(i + 1, max.length());\r
+\r
+                        String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+                        item.setText(columns);\r
+                    }\r
+\r
+                    fRedrawGraphs = true;\r
+                }\r
+            }\r
+        });\r
+\r
+        // Create the "Close" button\r
+        Button closeButton = createButton(parent, CANCEL, Messages.LatencyView_Dialogs_AddEvents_Buttons_Close, false);\r
+        closeButton.addListener(SWT.Selection, new Listener() {\r
+            @Override\r
+            public void handleEvent(Event event) {\r
+                // Remember the user's list\r
+                saveMatchPairs(fEventStartTypes, fEventEndTypes);\r
+\r
+                setReturnCode(CANCEL);\r
+\r
+                if (fRedrawGraphs == true)\r
+                    redrawGraphs();\r
+\r
+                close();\r
+            }\r
+        });\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/ListDialog.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/dialogs/ListDialog.java
new file mode 100644 (file)
index 0000000..fd99352
--- /dev/null
@@ -0,0 +1,252 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new messages file, fixed warnings\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.dialogs;\r
+\r
+import java.util.Vector;\r
+\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher;\r
+import org.eclipse.linuxtools.lttng.core.util.EventsPair;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Listener;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Table;\r
+import org.eclipse.swt.widgets.TableColumn;\r
+import org.eclipse.swt.widgets.TableItem;\r
+\r
+/**\r
+ * <b><u>ListDialog</u></b>\r
+ * <p>\r
+ * List dialog, shows the list of start/end event pairs.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class ListDialog extends AbstractDialog {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * The dialog's table.\r
+     */\r
+    protected Table fTable;\r
+\r
+    /**\r
+     * Start event types.\r
+     */\r
+    protected Vector<String> fEventStartTypes;\r
+\r
+    /**\r
+     * End event types.\r
+     */\r
+    protected Vector<String> fEventEndTypes;\r
+\r
+    /**\r
+     * Table columns\r
+     */\r
+    protected TableColumn[] fColumns;\r
+\r
+    /**\r
+     * Column names (header titles).\r
+     */\r
+    protected static final String[] COLUMN_NAMES = { "#", Messages.LatencyView_Dialogs_ListEvents_Columns_Trigger, Messages.LatencyView_Dialogs_ListEvents_Columns_End }; //$NON-NLS-1$\r
+\r
+    /**\r
+     * Column widths.\r
+     */\r
+    protected static final int[] COLUMN_WIDTHS = { 25, 250, 250 };\r
+\r
+    /**\r
+     * The table style.\r
+     */\r
+    protected int fStyle;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructor\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param parentShell\r
+     *            The parent shell.\r
+     * @param title\r
+     *            The dialog's window title.\r
+     * @param message\r
+     *            The dialog's window message.\r
+     */\r
+    public ListDialog(Shell parentShell, String title, String message) {\r
+        super(parentShell, title, message);\r
+\r
+        // Set the table style\r
+        fStyle = SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL;\r
+\r
+        // Get the list of start and end types from the EventMatcher\r
+        EventsPair pair = getMatchPairs();\r
+        fEventStartTypes = pair.getFirst();\r
+        fEventEndTypes = pair.getSecond();\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Creates the table's column (i.e. the table header).\r
+     */\r
+    protected void createColumns() {\r
+        fColumns = new TableColumn[COLUMN_NAMES.length];\r
+        for (int i = 0; i < COLUMN_NAMES.length; i++) {\r
+            fColumns[i] = new TableColumn(fTable, SWT.LEFT);\r
+            fColumns[i].setText(COLUMN_NAMES[i]);\r
+            fColumns[i].setWidth(COLUMN_WIDTHS[i]);\r
+        }\r
+    }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createDialogArea(org.eclipse.swt.widgets.Composite)\r
+     */\r
+    @Override\r
+    protected Control createDialogArea(Composite parent) {\r
+        GridLayout layout = new GridLayout(1, true);\r
+        parent.setLayout(layout);\r
+\r
+        GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);\r
+        fTable = new Table(parent, fStyle);\r
+        fTable.setLayoutData(layoutData);\r
+\r
+        // Some cosmetic enhancements\r
+        fTable.setHeaderVisible(true);\r
+        fTable.setLinesVisible(true);\r
+\r
+        createColumns();\r
+\r
+        for (int i = 0; i < fEventStartTypes.size(); i++) {\r
+            TableItem item = new TableItem(fTable, SWT.RIGHT);\r
+\r
+            String max = String.valueOf(fEventStartTypes.size());\r
+            String number = formatListNumber(i + 1, max.length());\r
+\r
+            String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+            item.setText(columns);\r
+        }\r
+\r
+        return parent;\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.dialogs.AbstractDialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)\r
+     */\r
+    @Override\r
+    protected void createButtonsForButtonBar(Composite parent) {\r
+        GridData gridData = new GridData();\r
+        gridData.verticalAlignment = GridData.FILL;\r
+        gridData.horizontalSpan = 1;\r
+        gridData.grabExcessHorizontalSpace = true;\r
+        gridData.grabExcessVerticalSpace = true;\r
+        gridData.horizontalAlignment = SWT.RIGHT;\r
+\r
+        parent.setLayoutData(gridData);\r
+\r
+        // Create the "Reset" button\r
+        Button resetButton = createButton(parent, RESET, Messages.LatencyView_Dialogs_ListEvents_Buttons_Reset, false);\r
+        resetButton.addListener(SWT.Selection, new Listener() {\r
+            @Override\r
+            public void handleEvent(Event event) {\r
+                boolean confirmDeletion = MessageDialog.openQuestion(getShell(), Messages.LatencyView_Dialogs_ListEvents_Confirm_Title,\r
+                        Messages.LatencyView_Dialogs_ListEvents_Confirm_Message);\r
+\r
+                if (confirmDeletion) {\r
+                    EventMatcher.getInstance().resetMatches();\r
+\r
+                    fTable.removeAll();\r
+\r
+                    Vector<String> defaultStarts = new Vector<String>();\r
+                    Vector<String> defaultEnds = new Vector<String>();\r
+\r
+                    defaultStarts.add(EventMatcher.PAGE_FAULT_GET_USER_ENTRY);\r
+                    defaultEnds.add(EventMatcher.PAGE_FAULT_GET_USER_EXIT);\r
+                    defaultStarts.add(EventMatcher.TASKLET_LOW_ENTRY);\r
+                    defaultEnds.add(EventMatcher.TASKLET_LOW_EXIT);\r
+                    defaultStarts.add(EventMatcher.PAGE_FAULT_ENTRY);\r
+                    defaultEnds.add(EventMatcher.PAGE_FAULT_EXIT);\r
+                    defaultStarts.add(EventMatcher.SYSCALL_ENTRY);\r
+                    defaultEnds.add(EventMatcher.SYSCALL_EXIT);\r
+                    defaultStarts.add(EventMatcher.IRQ_ENTRY);\r
+                    defaultEnds.add(EventMatcher.IRQ_EXIT);\r
+                    defaultStarts.add(EventMatcher.READ);\r
+                    defaultEnds.add(EventMatcher.WRITE);\r
+                    defaultStarts.add(EventMatcher.OPEN);\r
+                    defaultEnds.add(EventMatcher.CLOSE);\r
+                    defaultStarts.add(EventMatcher.BUFFER_WAIT_START);\r
+                    defaultEnds.add(EventMatcher.BUFFER_WAIT_END);\r
+                    defaultStarts.add(EventMatcher.START_COMMIT);\r
+                    defaultEnds.add(EventMatcher.END_COMMIT);\r
+                    defaultStarts.add(EventMatcher.WAIT_ON_PAGE_START);\r
+                    defaultEnds.add(EventMatcher.WAIT_ON_PAGE_END);\r
+\r
+                    saveMatchPairs(defaultStarts, defaultEnds);\r
+\r
+                    for (int i = 0; i < defaultStarts.size(); i++) {\r
+                        EventMatcher.getInstance().addMatch(defaultStarts.get(i), defaultEnds.get(i));\r
+                    }\r
+\r
+                    // Get the list of start and end types from the EventMatcher\r
+                    EventsPair pair = getMatchPairs();\r
+                    fEventStartTypes = pair.getFirst();\r
+                    fEventEndTypes = pair.getSecond();\r
+\r
+                    for (int i = 0; i < fEventStartTypes.size(); i++) {\r
+                        TableItem item = new TableItem(fTable, SWT.RIGHT);\r
+\r
+                        String max = String.valueOf(fEventStartTypes.size());\r
+                        String number = formatListNumber(i + 1, max.length());\r
+\r
+                        String[] columns = { number, fEventStartTypes.get(i), fEventEndTypes.get(i) };\r
+\r
+                        item.setText(columns);\r
+                    }\r
+\r
+                    fTable.setItemCount(fEventStartTypes.size());\r
+\r
+                    fRedrawGraphs = true;\r
+                }\r
+            }\r
+        });\r
+\r
+        // Create the "Close" button\r
+        Button closeButton = createButton(parent, CANCEL, Messages.LatencyView_Dialogs_ListEvents_Buttons_Close, false);\r
+        closeButton.addListener(SWT.Selection, new Listener() {\r
+            @Override\r
+            public void handleEvent(Event event) {\r
+                setReturnCode(CANCEL);\r
+\r
+                if (fRedrawGraphs == true)\r
+                    redrawGraphs();\r
+\r
+                close();\r
+            }\r
+        });\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseListener.java
new file mode 100644 (file)
index 0000000..3d3b1a0
--- /dev/null
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;
+
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+
+/**
+ * <b><u>AbstractMouseListener</u></b>
+ * <p>
+ */
+public abstract class AbstractMouseListener implements MouseListener {
+
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+
+    /**
+     * Mouse x-coordinate.
+     */
+    protected int fMouseX;
+    
+    /**
+     * Mouse y-coordinate.
+     */
+    protected int fMouseY;
+
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+    
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
+     */
+    @Override
+    public void mouseDoubleClick(MouseEvent e) {
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
+     */
+    @Override
+    public void mouseDown(MouseEvent e) {
+        fMouseX = e.x;
+        fMouseY = e.y;
+        display();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
+     */
+    @Override
+    public void mouseUp(MouseEvent e) {
+    }
+    
+    /**
+     * Callback to display information at the current x-y position
+     */
+    protected abstract void display();
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseTrackListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractMouseTrackListener.java
new file mode 100644 (file)
index 0000000..b4e53fe
--- /dev/null
@@ -0,0 +1,77 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors: \r
+ * Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation \r
+ * Mathieu Denis (mathieu.denis55@gmail.com) - Refactored code\r
+ * Bernd Hufmann - Changed implemented interface to MouseTraceListener\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.swt.events.MouseEvent;\r
+import org.eclipse.swt.events.MouseTrackListener;\r
+\r
+/**\r
+ *  <b><u>AbstractMouseListener</u></b>\r
+ * <p>\r
+ * AbstractMouseListener, base class for the canvas mouse listener.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public abstract class AbstractMouseTrackListener implements MouseTrackListener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Mouse x-coordinate.\r
+     */\r
+    protected int fMouseX;\r
+    /**\r
+     * Mouse y-coordinate.\r
+     */\r
+    protected int fMouseY;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.swt.events.MouseTrackListener#mouseEnter(org.eclipse.swt.events.MouseEvent)\r
+     */\r
+    @Override\r
+    public void mouseEnter(MouseEvent event) {\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.swt.events.MouseTrackListener#mouseExit(org.eclipse.swt.events.MouseEvent)\r
+     */\r
+    @Override\r
+    public void mouseExit(MouseEvent event) {\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.swt.events.MouseTrackListener#mouseHover(org.eclipse.swt.events.MouseEvent)\r
+     */\r
+    @Override\r
+    public void mouseHover(MouseEvent event) {\r
+        fMouseX = event.x;\r
+        fMouseY = event.y;\r
+        display();\r
+    }\r
+\r
+    /**\r
+     * Tooltip display callback.\r
+     */\r
+    protected abstract void display();\r
+\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractPaintListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/AbstractPaintListener.java
new file mode 100644 (file)
index 0000000..ae7be22
--- /dev/null
@@ -0,0 +1,735 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new model-view-controller design, display improvements\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.PaintEvent;\r
+import org.eclipse.swt.events.PaintListener;\r
+import org.eclipse.swt.graphics.Color;\r
+import org.eclipse.swt.graphics.Font;\r
+import org.eclipse.swt.graphics.GC;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.graphics.Rectangle;\r
+import org.eclipse.swt.widgets.Display;\r
+\r
+/**\r
+ * <b><u>AbstractPaintListener</u></b>\r
+ * <p> \r
+ * Abstract paint listener. Draws the graphs on the view canvas.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public abstract class AbstractPaintListener implements PaintListener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     *  Default colors and fonts\r
+     */\r
+    protected final Color DEFAULT_DATA_COLOR = new Color(Display.getDefault(), 74, 112, 139);\r
+    protected final static Color DEFAULT_LABEL_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK);\r
+    protected final static Color DEFAULT_TEXT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY);\r
+    protected final static Color DEFAULT_DATA_BACKGROUND_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);\r
+    protected final static Color DEFAULT_CURRENT_EVENT_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_RED);\r
+\r
+    protected final Font DEFAULT_TITLE_FONT = new Font(Display.getDefault(), "Arial", 10, SWT.BOLD); //$NON-NLS-1$\r
+    protected final Font DEFAULT_VALUES_FONT = new Font(Display.getDefault(), "Arial", 7, SWT.NORMAL); //$NON-NLS-1$\r
+    protected final Font DEFAULT_LABEL_FONT = new Font(Display.getDefault(), "Arial", 8, SWT.NORMAL); //$NON-NLS-1$\r
+    \r
+    /**\r
+     * A reference to the listener's view.\r
+     */\r
+    protected AbstractViewer fViewer;\r
+\r
+    /**\r
+     * Graph title\r
+     */\r
+    protected String fGraphTitle;\r
+\r
+    /**\r
+     * X-axis label.\r
+     */\r
+    protected String fXAxisLabel;\r
+    \r
+    /**\r
+     * Y-axis label.\r
+     */\r
+    protected String fYAxisLabel;\r
+\r
+    /**\r
+     * Horizontal offset for the x-axis label.\r
+     */\r
+    protected int fXAxisLabelOffset;\r
+\r
+    /**\r
+     * Vertical offset for the horizontal axis offset.\r
+     */\r
+    protected int fHorizontalAxisYOffset = 20;\r
+\r
+    /**\r
+     * Graph padding.\r
+     */\r
+    protected int fPadding = Config.GRAPH_PADDING;\r
+\r
+    /**\r
+     * Graph client area.\r
+     */\r
+    protected Rectangle fClientArea = new Rectangle(0, 0, 1, 1);\r
+\r
+    /**\r
+     * Foreground color.\r
+     */\r
+    protected Color fForegroundColor;\r
+    \r
+    /**\r
+     * Background color.\r
+     */\r
+    protected Color fBackgroundColor;\r
+    \r
+    /**\r
+     * Data plotting color.\r
+     */\r
+    protected Color fDataColor;\r
+    \r
+    /**\r
+     * Axis label color.\r
+     */\r
+    protected Color fLabelColor;\r
+    \r
+    /**\r
+     * Text color.\r
+     */\r
+    protected Color fTextColor;\r
+    \r
+    /**\r
+     * Data background color.\r
+     */\r
+    protected Color fDataBackgroundColor;\r
+\r
+    /**\r
+     * Color for current event time line.\r
+     */\r
+    protected Color fCurrentEventColor;\r
+\r
+    /**\r
+     * Original canvas font.\r
+     */\r
+    protected Font fOriginalFont;\r
+\r
+    /**\r
+     * Font for the title of the graph.\r
+     */\r
+    protected Font fTitleFont;\r
+\r
+    /**\r
+     * Font for the values on the horizontal and vertical axis.\r
+     */\r
+    protected Font fValuesFont;\r
+\r
+    /**\r
+     * Font for the horizontal and vertical labels.\r
+     */\r
+    protected Font fLabelFont;\r
+\r
+    /**\r
+     * Horizontal offset for the axis arrow.\r
+     */\r
+    protected final int ARROW_DELTA_X = 10;\r
+\r
+    /**\r
+     * Vertical offset for the axis arrow.\r
+     */\r
+    protected final int ARROW_DELTA_Y = 4;\r
+\r
+    /**\r
+     * Max horizontal distance between ticks.\r
+     */\r
+    protected final int MAX_WIDTH_BETWEEN_TICKS = 40;\r
+\r
+    /**\r
+     * Max vertical distance between ticks.\r
+     */\r
+    protected final int MAX_HEIGHT_BETWEEN_TICKS = 30;\r
+\r
+    /**\r
+     * Max characters that can be displayed on the vertical axis.\r
+     */\r
+    protected final int MAX_CHAR_VERTICAL_DISPLAY = 5;\r
+\r
+    /**\r
+     * Draw label each "drawLabelEachNTicks_" ticks.\r
+     */\r
+    protected int fDrawLabelEachNTicks = 1;\r
+\r
+    /**\r
+     * Image drawn on the canvas.\r
+     */\r
+    protected Image fImage;\r
+\r
+    /**\r
+     * Paint canvas, where the values are plotted.\r
+     */\r
+    protected GC fAxisImage;\r
+\r
+    /**\r
+     * Is the paint listener initialized ?\r
+     */\r
+    protected boolean fInitialized = false;\r
+\r
+    /**\r
+     * Draw area.\r
+     */\r
+    protected Rectangle fDrawArea;\r
+\r
+    /**\r
+     * Right padding (in pixels).\r
+     */\r
+    protected int fPaddingRight = Config.GRAPH_PADDING;\r
+\r
+    /**\r
+     * Top padding (in pixels).\r
+     */\r
+    protected int fPaddingTop = Config.GRAPH_PADDING;\r
+\r
+    /**\r
+     * Vertical axis offset (in pixels).\r
+     */\r
+    protected int fVerticalAxisOffset = 2 * Config.GRAPH_PADDING;\r
+\r
+    /**\r
+     * Vertical axis factor for values (10^delta). When values larger than MAX_CHAR_VERTICAL_DISPLAY.\r
+     */\r
+    protected int fDelta = 0;\r
+\r
+    /**\r
+     * The barWidth of a bar\r
+     */\r
+    protected int fBarWith = Config.DEFAULT_HISTOGRAM_BAR_WIDTH;\r
+\r
+    /**\r
+     * Minimum value on horizontal axis\r
+     */\r
+    protected long fXMin = -1;\r
+\r
+    /**\r
+     * Maximum value on horizontal axis\r
+     */\r
+    protected long fXMax = -1;\r
+\r
+    /**\r
+     * Minimum value on vertical axis\r
+     */\r
+    protected long fYMin = -1;\r
+\r
+    /**\r
+     * Maximum value on vertical axis\r
+     */\r
+    protected long fYMax = -1;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Constructor.\r
+     * @param view\r
+     *            A reference to the listener's view.\r
+     */\r
+    public AbstractPaintListener(AbstractViewer view) {\r
+        fViewer = view;\r
+        fDataColor = DEFAULT_DATA_COLOR;\r
+        fLabelColor = DEFAULT_LABEL_COLOR;\r
+        fTextColor = DEFAULT_TEXT_COLOR;\r
+        fDataBackgroundColor = DEFAULT_DATA_BACKGROUND_COLOR;\r
+        fCurrentEventColor = DEFAULT_CURRENT_EVENT_COLOR;\r
+        \r
+        fTitleFont = DEFAULT_TITLE_FONT;\r
+        fValuesFont = DEFAULT_VALUES_FONT;\r
+        fLabelFont = DEFAULT_LABEL_FONT;\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Accessors\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Returns the draw area height.\r
+     * @return The draw area height.\r
+     */\r
+    public double getHeight() {\r
+        return (fClientArea.height - 2.0 * fPadding - fHorizontalAxisYOffset - fPaddingTop);\r
+    }\r
+\r
+    /**\r
+     * Returns the histogram's draw area width.\r
+     * @return The histogram's draw area width.\r
+     */\r
+    public double getWidth() {\r
+        return (fClientArea.width - 2.0 * fPadding - fVerticalAxisOffset - fPaddingRight);  // width of the plot area;\r
+    }\r
+\r
+    /**\r
+     * Returns the histogram's draw area padding.\r
+     * @return The histogram's draw area padding.\r
+     */\r
+    public int getPadding() {\r
+        return fPadding;\r
+    }\r
+\r
+    /**\r
+     * Returns the histogram's draw area top padding.\r
+     * @return The histogram's draw area top padding.\r
+     */\r
+    public int getPaddingTop() {\r
+        return fPaddingTop;\r
+    }\r
+\r
+    /**\r
+     * Returns the histogram's vertical axis offset.\r
+     * @return The histogram's vertical axis offset.\r
+     */\r
+    public int getVerticalAxisOffset() {\r
+        return fVerticalAxisOffset;\r
+    }\r
+\r
+    /**\r
+     * Returns the histogram's horizontal axis offset.\r
+     * @return The histogram's horizontal axis offset.\r
+     */\r
+    public int getHorizontalAxisYOffset() {\r
+        return fHorizontalAxisYOffset;\r
+    }\r
+\r
+    /**\r
+     *  Returns the horizontal minimum value\r
+     *  @return The horizontal minimum value.\r
+     */\r
+    public long getXMin() {\r
+        return fXMin;\r
+    }\r
+\r
+    /**\r
+     *  Returns the horizontal maximum value\r
+     *  @return The horizontal maximum value.\r
+     */\r
+    public long getXMax() {\r
+        return fXMax;\r
+    }\r
+\r
+    /**\r
+     *  Returns the horizontal minimum value\r
+     *  @return The horizontal minimum value.\r
+     */\r
+    public long getYMin() {\r
+        return fYMin;\r
+    }\r
+\r
+    /**\r
+     *  Returns the vertical maximum value\r
+     *  @return The vertical maximum value.\r
+     */\r
+    public long getYMax() {\r
+        return fYMax;\r
+    }\r
+    \r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Disposes local resources (e.g. colors or fonts)\r
+     */\r
+    public void dispose() {\r
+        DEFAULT_DATA_COLOR.dispose();\r
+        DEFAULT_TITLE_FONT.dispose();\r
+        DEFAULT_VALUES_FONT.dispose();\r
+        DEFAULT_LABEL_FONT.dispose();\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)\r
+     */\r
+    @Override\r
+    public void paintControl(PaintEvent e) {\r
+        fClientArea = fViewer.getClientArea();\r
+\r
+        fForegroundColor = e.gc.getForeground();\r
+        fBackgroundColor = e.gc.getBackground();\r
+        fOriginalFont = e.gc.getFont();\r
+\r
+        scale();\r
+        \r
+        if (!fInitialized) {\r
+            fImage = new Image(Display.getDefault(), fViewer.getBounds());\r
+\r
+            fAxisImage = new GC(fImage);\r
+\r
+            fAxisImage.setForeground(fForegroundColor);\r
+            fAxisImage.setBackground(fBackgroundColor);\r
+            fAxisImage.fillRectangle(fImage.getBounds());\r
+\r
+            fInitialized = true;\r
+        }\r
+        \r
+        paintGraphTitle();\r
+        paintBackground();     \r
+        paintHorizontalAxis();\r
+        paintVerticalAxis();\r
+        paintContent();\r
+\r
+        e.gc.drawImage(fImage, 0, 0);\r
+    }\r
+\r
+    /**\r
+     * Paints the title of the graph.\r
+     */\r
+    public void paintGraphTitle() {\r
+        if (fGraphTitle != null) {\r
+            fAxisImage.setFont(fTitleFont);\r
+            fAxisImage.setForeground(fLabelColor);\r
+            fAxisImage.setBackground(fBackgroundColor);\r
+\r
+            int zoomFactor = fViewer.getZoomFactor() / fViewer.getZoomIncrement() + 1;\r
+            int labelWidth = fAxisImage.stringExtent(fGraphTitle).x;\r
+            // Draws the zoom factor in the title only if there is one\r
+            if (fViewer.getZoomFactor() > 1)\r
+                fAxisImage.drawText(fGraphTitle + " (" + zoomFactor + "x)", (fViewer.getBounds().width - fPadding - labelWidth) / 2, 0); //$NON-NLS-1$ //$NON-NLS-2$\r
+            else\r
+                fAxisImage.drawText(fGraphTitle, (fViewer.getBounds().width - fPadding - labelWidth) / 2, 0);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Paints the background of the draw area.\r
+     */\r
+    public void paintBackground() {\r
+        fAxisImage.setBackground(fDataBackgroundColor);\r
+\r
+        fAxisImage.fillRectangle(fPadding + fVerticalAxisOffset, fPadding + fPaddingTop, (int)getWidth() + 1, (int)getHeight());\r
+    }\r
+\r
+    /**\r
+     * Paints the horizontal axis.\r
+     */\r
+    public void paintHorizontalAxis() {\r
+        fAxisImage.setForeground(fForegroundColor);\r
+\r
+        int y = fClientArea.height - fPadding - fHorizontalAxisYOffset;\r
+\r
+        fAxisImage.drawLine(fClientArea.x + fPadding + fVerticalAxisOffset, y, fClientArea.width - fPadding, y);\r
+\r
+        paintHorizontalArrow(fClientArea.width - fPadding, y);\r
+        // Draw the axis graphic details only if there are some data points (i.e. do not draw the axis graphic details\r
+        // if the window timerange is so small that no latency can be computed, or if there are no matching events in\r
+        // the timerange (for example, when an experiment has many traces with a large time gap between the logged\r
+        // events sets).\r
+        if (fXMin != Long.MAX_VALUE && fXMax != Long.MIN_VALUE && fXMin != fXMax) {\r
+            paintHorizontalTicks(y);\r
+            paintHorizontalAxisValues(y + 30);\r
+        }\r
+        paintHorizontalAxisLabel(y + fHorizontalAxisYOffset - 5);\r
+    }\r
+\r
+    /**\r
+     * Paints the vertical axis.\r
+     */\r
+    public void paintVerticalAxis() {\r
+        fAxisImage.setForeground(fForegroundColor);\r
+\r
+        int x = fClientArea.x + fPadding + fVerticalAxisOffset;\r
+\r
+        fAxisImage.drawLine(x, fPadding, x, fClientArea.height - fPadding - fHorizontalAxisYOffset);\r
+\r
+        paintVerticalArrow(x, fClientArea.y + fPadding);\r
+        // Draw the axis graphic details only if there are some data points (i.e. do not draw the axis graphic details\r
+        // if the window timerange is so small that no latency can be computed, or if there are no matching events in\r
+        // the timerange (for example, when an experiment has many traces with a large time gap between the logged\r
+        // events sets).\r
+        if (fXMin != Long.MAX_VALUE && fXMax != Long.MIN_VALUE && fXMin != fXMax) {\r
+            paintVerticalTicks(x);\r
+            paintVerticalAxisValues(x);\r
+        }\r
+        paintVerticalAxisLabel(x);\r
+    }\r
+\r
+    /**\r
+     * Paints the arrow on the horizontal axis.\r
+     * @param x\r
+     *            The x-coordinate of the point where the arrow points.\r
+     * @param y\r
+     *            The y-coordinate of the point where the arrow points.\r
+     */\r
+    public void paintHorizontalArrow(int x, int y) {\r
+        // Arrow top line\r
+        fAxisImage.drawLine(x - ARROW_DELTA_X, y - ARROW_DELTA_Y, x, y);\r
+        // Arrow bottom line\r
+        fAxisImage.drawLine(x - ARROW_DELTA_X, y + ARROW_DELTA_Y, x, y);\r
+    }\r
+\r
+    /**\r
+     * Paints the arrow on the vertical axis.\r
+     * @param x\r
+     *            The x-coordinate of the point where the arrow points.\r
+     * @param y\r
+     *            The y-coordinate of the point where the arrow points.\r
+     */\r
+    public void paintVerticalArrow(int x, int y) {\r
+        // Arrow left line\r
+        fAxisImage.drawLine(x - ARROW_DELTA_Y, y + ARROW_DELTA_X, x, y);\r
+        // Arrow right line\r
+        fAxisImage.drawLine(x + ARROW_DELTA_Y, y + ARROW_DELTA_X, x, y);\r
+    }\r
+\r
+    /**\r
+     * Paints the horizontal ticks.\r
+     * @param y\r
+     *            The y coordinate where to draw the axis.\r
+     */\r
+    public void paintHorizontalTicks(int y) {\r
+        if (fXMin >= 0L && fXMin >= 0L) {\r
+            int nbTicks = (int)(getWidth()) / MAX_WIDTH_BETWEEN_TICKS + 1;\r
+\r
+            for (int i = 0; i < nbTicks; i++) {\r
+                if (i % fDrawLabelEachNTicks == 0) {\r
+                    int x = i * MAX_WIDTH_BETWEEN_TICKS + fPadding + fVerticalAxisOffset;\r
+                    fAxisImage.drawLine(x, y, x, y + 3);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Paints the horizontal axis values.\r
+     * @param y\r
+     *            The y coordinate where to draw the axis.\r
+     */\r
+    public void paintHorizontalAxisValues(int y) {\r
+        if (fXMin >= 0L && fXMax >= 0L) {\r
+            fAxisImage.setForeground(fTextColor);\r
+            fAxisImage.setBackground(fBackgroundColor);\r
+\r
+            double width = getWidth();\r
+            int nbTicks = ((int)getWidth()) / MAX_WIDTH_BETWEEN_TICKS + 1;\r
+\r
+            for (int i = 0; i < nbTicks; i++) {\r
+                if (i % fDrawLabelEachNTicks == 0) {\r
+                    int x = i * MAX_WIDTH_BETWEEN_TICKS + fPadding + fVerticalAxisOffset;\r
+                    \r
+                    long currentValue = (i * MAX_WIDTH_BETWEEN_TICKS)* (long)((fXMax - fXMin) / width) + fXMin;\r
+                    String currentLabel = formatStringForHorizontalAxis(currentValue);\r
+\r
+                    fAxisImage.setFont(fValuesFont);\r
+                    fAxisImage.drawText(currentLabel, x, y - 24);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Paints the horizontal axis label.\r
+     * @param y\r
+     *            The y-coordinate where to draw the label.\r
+     */\r
+    public void paintHorizontalAxisLabel(int y) {\r
+        if (fXAxisLabel != null) {\r
+            fAxisImage.setFont(fLabelFont);\r
+            fAxisImage.setForeground(fLabelColor);\r
+\r
+            int labelWidth = fAxisImage.stringExtent(fXAxisLabel).x;\r
+\r
+            fAxisImage.drawText(fXAxisLabel, fClientArea.width - fPadding - labelWidth, y);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Paints the vertical axis ticks.\r
+     * @param x\r
+     *            The x-coordinate where to draw the ticks.\r
+     */\r
+    public void paintVerticalTicks(int x) {\r
+        if (fYMin != 0L && fYMin != 0L) {\r
+            int nbTicks = (int)(getHeight() / MAX_HEIGHT_BETWEEN_TICKS + 1);\r
+\r
+            for (int i = 0; i < nbTicks; i++) {\r
+                int y = fClientArea.height - fPadding - fHorizontalAxisYOffset - i * MAX_HEIGHT_BETWEEN_TICKS;\r
+                fAxisImage.drawLine(x - 3, y, x, y);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Paints the vertical axis values.\r
+     * @param x\r
+     *            The x-coordinate where to draw the values.\r
+     */\r
+    public void paintVerticalAxisValues(int x) {\r
+        if (fYMin >= 0L && fYMax >= 0L) {\r
+            fAxisImage.setForeground(fTextColor);\r
+            fAxisImage.setBackground(fBackgroundColor);\r
+\r
+            double height = getHeight();\r
+            int nbTicks = (int)(height / MAX_HEIGHT_BETWEEN_TICKS + 1);\r
+\r
+            // System.out.println("nbTicks = " + nbTicks);\r
+\r
+            for (int i = 0; i < nbTicks; i++) {\r
+                int y = fClientArea.height - fPadding - fHorizontalAxisYOffset - i * MAX_HEIGHT_BETWEEN_TICKS;\r
+\r
+                long currentValue = (i * MAX_HEIGHT_BETWEEN_TICKS)* (long)((fYMax - fYMin) / height) + fYMin;\r
+                String currentLabel = formatStringForVerticalAxis(currentValue);\r
+\r
+                fAxisImage.setFont(fValuesFont);\r
+\r
+                Point textDimensions = fAxisImage.stringExtent(currentLabel);\r
+                fAxisImage.drawText(currentLabel, x - textDimensions.x - 5, y - textDimensions.y / 2);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Increases the bar width. \r
+     */\r
+    public void increaseBarWitdh() {\r
+        fBarWith = fBarWith << 1;\r
+        if (fBarWith > Config.MAX_HISTOGRAM_BAR_WIDTH) {\r
+            fBarWith = Config.MAX_HISTOGRAM_BAR_WIDTH;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Decreases the bar width. \r
+     */\r
+    public void decreaseBarWitdh() {\r
+        fBarWith = fBarWith >> 1;\r
+        if (fBarWith < Config.MIN_HISTOGRAM_BAR_WIDTH) {\r
+            fBarWith = Config.MIN_HISTOGRAM_BAR_WIDTH; \r
+        }\r
+    }\r
+\r
+    \r
+    /**\r
+     * Paints the vertical axis label.\r
+     * @param x\r
+     *            The x-coordinate where to draw the label.\r
+     */\r
+    public void paintVerticalAxisLabel(int x) {\r
+        if (fYAxisLabel != null) {\r
+            fAxisImage.setFont(fLabelFont);\r
+            fAxisImage.setForeground(fLabelColor);\r
+            fAxisImage.setBackground(fBackgroundColor);\r
+\r
+            if (fDelta >= 1)\r
+                fAxisImage.drawText(fYAxisLabel + " (x10^" + fDelta + ")", x + 10, fHorizontalAxisYOffset - 5);  //$NON-NLS-1$//$NON-NLS-2$\r
+            else\r
+                fAxisImage.drawText(fYAxisLabel, x + 10, fPadding);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Adds points to the graph and draws them to the canvas.\r
+     * @param points\r
+     *            The buffer of points to draw.\r
+     * @param nbPoints\r
+     *            The number of points in the buffer.\r
+     */\r
+    abstract public String formatToolTipLabel(int x, int y);\r
+\r
+    /**\r
+     * Method to be implemented to scale the model data to the actual screen size.\r
+     */\r
+    abstract public void scale();\r
+    \r
+    /**\r
+     * Called for drawing elements after points are added to the graph.\r
+     */\r
+    abstract public void paintContent();\r
+\r
+    /**\r
+     * Clears the image and prepares it for redrawing.\r
+     */\r
+    public void clear() {\r
+        fInitialized = false;\r
+        fXMin = -1;\r
+        fXMax = -1;\r
+        fYMin = -1;\r
+        fYMax = -1;\r
+    }\r
+    \r
+    /**\r
+     * Draw horizontal label each "nbTicks" ticks.\r
+     * @param nbTicks\r
+     *            The draw interval.\r
+     */\r
+    public void setDrawLabelEachNTicks(int nbTicks) {\r
+        fDrawLabelEachNTicks = nbTicks;\r
+    }\r
+\r
+    /**\r
+     * Sets the title of the graph.\r
+     * @param graphTitle\r
+     *            The title of the graph.\r
+     */\r
+    public void setGraphTitle(String graphTitle) {\r
+        fGraphTitle = graphTitle;\r
+    }\r
+\r
+    /**\r
+     * Sets the horizontal axis label.\r
+     * @param xAxisLabel\r
+     *            The horizontal axis label.\r
+     * @param offset\r
+     *            The horizontal axis draw offset (in pixels).\r
+     */\r
+    public void setXAxisLabel(String xAxisLabel, int offset) {\r
+        fXAxisLabel = xAxisLabel;\r
+        fXAxisLabelOffset = offset;\r
+    }\r
+\r
+    /**\r
+     * Sets the vertical axis label.\r
+     * @param yAxisLabel\r
+     *            The vertical axis label.\r
+     */\r
+    public void setYAxisLabel(String yAxisLabel) {\r
+        fYAxisLabel = yAxisLabel;\r
+    }\r
+\r
+    /**\r
+     * Returns a string representing the given value. \r
+     * \r
+     * @param value\r
+     *            The numeric value to convert to String.\r
+     * @return The String-formatted value.\r
+     */\r
+    public String formatStringForHorizontalAxis(long value) {\r
+        return String.valueOf(value);\r
+    }\r
+\r
+    /**\r
+     * Returns a string representing the given value. \r
+     * \r
+     * @param value\r
+     *            The numeric value to convert to String.\r
+     * @return The String-formatted value.\r
+     */\r
+    public String formatStringForVerticalAxis(long value) {\r
+        return String.valueOf(value);\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphMouseListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphMouseListener.java
new file mode 100644 (file)
index 0000000..5d6cb75
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;
+
+import org.eclipse.linuxtools.lttng.ui.views.latency.GraphViewer;
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.LatencyGraphModel;
+
+/**
+ * <b><u>GraphMouseListener</u></b>
+ * <p>
+ */
+public class GraphMouseListener extends AbstractMouseListener {
+    
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+
+    /**
+     * A reference to the observed view.
+     */
+    protected GraphViewer fView;
+
+    /**
+     * A reference to the HistogramPaintListener.
+     */
+    protected GraphPaintListener fGraph;
+
+    // ------------------------------------------------------------------------
+    // Constructor
+    // ------------------------------------------------------------------------
+    
+    /**
+     * Constructor.
+     * @param view
+     *            A reference to the observed view.
+     * @param histogramPaintListener
+     *            A reference to the histogram's paintListener.
+     */
+    public GraphMouseListener(GraphViewer view, GraphPaintListener graphPaintListener) {
+        fView = view;
+        fGraph = graphPaintListener;
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseListener#display()
+     */
+    @Override
+    protected void display() {
+        long currentTime = fGraph.getCurrentTimeFromHorizontalValue(fMouseX);
+        ((LatencyGraphModel)fView.getModel()).setCurrentEventNotifyListeners(currentTime);
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphPaintListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/GraphPaintListener.java
new file mode 100644 (file)
index 0000000..a6732c2
--- /dev/null
@@ -0,0 +1,227 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new model-view-controller design, display improvements\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import java.text.DecimalFormat;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.BaseDistributionData;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramUtils;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.GraphViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.Config;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.GraphScaledData;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel;\r
+\r
+/**\r
+ * <b><u>GraphPaintListener</u></b>\r
+ * <p>\r
+ * Graph paint listener.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class GraphPaintListener extends AbstractPaintListener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Scaled data from data model\r
+     */\r
+    protected GraphScaledData fScaledData;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param viewer\r
+     *            A reference to the listener's viewer.\r
+     */\r
+    public GraphPaintListener(AbstractViewer view) {\r
+        super(view);\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#scale()\r
+     */\r
+    @Override\r
+    public void scale() {\r
+         \r
+         // width of the plot area\r
+         double width = getWidth();\r
+         // height of the plot area\r
+         double height = getHeight();\r
+\r
+         IGraphDataModel model = ((GraphViewer)fViewer).getModel();\r
+         fScaledData = model.scaleTo((int)width, (int)height, fBarWith);\r
+\r
+         fXMin = fScaledData.getHorFirstBucketTime() > 0 ? fScaledData.getHorFirstBucketTime() : 0;\r
+         fXMax = 0;\r
+         if (fScaledData.getHorLastBucket() > 0) {\r
+             fXMax = fScaledData.getHorBucketEndTime(fScaledData.getHorNbBuckets() - 1);\r
+         }\r
+         \r
+         fYMin = fScaledData.getVerFirstBucketTime() > 0 ? fScaledData.getVerFirstBucketTime() : 0;\r
+         fYMax = 0;\r
+         if (fScaledData.getVerLastBucket() > 0) {\r
+             fYMax = fScaledData.getVerBucketEndTime(fScaledData.getVerNbBuckets() - 1);\r
+         }\r
+     }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintContent()\r
+     */\r
+    @Override\r
+    public void paintContent() {\r
+        if (fXMin >= 0 && fXMax >= 0 && fYMin >= 0 && fYMax >= 0 && fScaledData != null) {\r
+            \r
+            fAxisImage.setForeground(fDataColor);\r
+            fAxisImage.setBackground(fDataColor);\r
+\r
+            double height = getHeight();\r
+\r
+            int xLen = fScaledData.getHorNbBuckets();\r
+            int yLen = fScaledData.getVerNbBuckets();\r
+\r
+            int barWidth = fScaledData.getBarWidth();\r
+            \r
+            for (int i = 0; i < xLen; i++) {\r
+                for (int j = 0; j < yLen; j++) {\r
+                    if (fScaledData.getEventCount(i, j) > 0) {\r
+\r
+                        double x = fPadding + i * barWidth + fVerticalAxisOffset + 1;\r
+                        double y = fPadding + fPaddingTop + height - j * barWidth;\r
+\r
+                        // Avoid over-drawing background area\r
+                        int yBarWidth = fBarWith;\r
+                        if (y - yBarWidth < fPadding + fPaddingTop) {\r
+                            yBarWidth = (int) (y - fPadding - fPaddingTop);\r
+                        }\r
+                        int xBarWidth = fBarWith;\r
+                        if(x + xBarWidth > fClientArea.width - fPadding - fPaddingRight) {\r
+                            xBarWidth =  (int)(fClientArea.width - fPadding - fPaddingRight - x);    \r
+                        }\r
+                        fAxisImage.fillRectangle((int) x, (int) y - (int) yBarWidth, (int) xBarWidth, (int) yBarWidth);\r
+                    }\r
+                }\r
+            }\r
+            \r
+            if (fScaledData.isCurrentEventTimeValid()) {\r
+                // Draw vertical line\r
+                int index = fScaledData.getHorBucketIndex(fScaledData.getCurrentEventTime());\r
+\r
+                int x = fPadding + index * barWidth + fVerticalAxisOffset + 1;\r
+                fAxisImage.setForeground(fCurrentEventColor);\r
+                fAxisImage.setBackground(fCurrentEventColor);\r
+                fAxisImage.drawLine(x, fPadding + fPaddingTop, x, fClientArea.height - fPadding - fHorizontalAxisYOffset);\r
+            }\r
+        }\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatStringForVerticalAxis(long)\r
+     */\r
+    @Override\r
+    public String formatStringForVerticalAxis(long value) {\r
+        DecimalFormat formatter = new DecimalFormat("0.0E0"); //$NON-NLS-1$\r
+        return formatter.format(value);\r
+    }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatStringForHorizontalAxis(long)\r
+     */\r
+    @Override\r
+    public String formatStringForHorizontalAxis(long value) {\r
+        return HistogramUtils.nanosecondsToString(value);\r
+    }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatToolTipLabel(int, int)\r
+     */\r
+    @Override\r
+    public String formatToolTipLabel(int x, int y) {\r
+\r
+        int index = getIndexFromHorizontalValue(x);\r
+        int yIndex = getIndexFromVerticalValue(y);\r
+\r
+        if (index != BaseDistributionData.OUT_OF_RANGE_BUCKET && yIndex != BaseDistributionData.OUT_OF_RANGE_BUCKET) {\r
+            if (fScaledData.getEventCount(index, yIndex) > 0) {\r
+                StringBuffer buffer = new StringBuffer();\r
+                buffer.append("Time Range in s = ["); //$NON-NLS-1$\r
+                // TODO change Utility\r
+                long startTime = fScaledData.getHorBucketStartTime(index) > 0 ? fScaledData.getHorBucketStartTime(index) : 0;\r
+                buffer.append(HistogramUtils.nanosecondsToString(startTime));\r
+                buffer.append(","); //$NON-NLS-1$\r
+                buffer.append(HistogramUtils.nanosecondsToString(fScaledData.getHorBucketEndTime(index)));\r
+                buffer.append("]\n"); //$NON-NLS-1$\r
+                buffer.append("Latency Range in s = ["); //$NON-NLS-1$\r
+                long yStartTime = fScaledData.getVerBucketStartTime(yIndex) > 0 ? fScaledData.getVerBucketStartTime(yIndex) : 0;\r
+                buffer.append(HistogramUtils.nanosecondsToString(yStartTime));\r
+                buffer.append(","); //$NON-NLS-1$\r
+                buffer.append(HistogramUtils.nanosecondsToString(fScaledData.getVerBucketEndTime(yIndex)));\r
+                buffer.append("]\n"); //$NON-NLS-1$\r
+                buffer.append("Latency count = "); //$NON-NLS-1$\r
+                buffer.append(fScaledData.getEventCount(index, yIndex));\r
+                return buffer.toString();\r
+            }\r
+        }\r
+        return ""; //$NON-NLS-1$\r
+    }\r
+    \r
+    public int getIndexFromHorizontalValue(int x) {\r
+        if (fScaledData != null) {\r
+            double barWidth = fScaledData.getBarWidth();\r
+            \r
+            int index = (int) ((x - fPadding - fVerticalAxisOffset - 1) / barWidth);\r
+            if ((index >= 0) && (fScaledData.getHorNbBuckets() > index)) {\r
+                return index;\r
+            }\r
+        }\r
+        return BaseDistributionData.OUT_OF_RANGE_BUCKET;\r
+    }\r
+    \r
+    public int getIndexFromVerticalValue(int y) {\r
+        if (fScaledData != null) {\r
+            double barWidth = fScaledData.getBarWidth();\r
+            double height = getHeight();     // height of the plot area\r
+            \r
+            int index = (int) ((height - (y - fPadding - fPaddingTop)) / barWidth);\r
+            if (index >= 0 && fScaledData.getVerNbBuckets() > index) {\r
+                return index;\r
+            }\r
+        }\r
+        return BaseDistributionData.OUT_OF_RANGE_BUCKET;\r
+    }\r
+\r
+    public long getCurrentTimeFromHorizontalValue(int x) {\r
+        if (fXMin >= 0 && fXMax >= 0) {\r
+            int index = getIndexFromHorizontalValue(x);\r
+            if (index != BaseDistributionData.OUT_OF_RANGE_BUCKET) {\r
+                return fScaledData.getHorBucketStartTime(index);\r
+            }\r
+        }\r
+        return Config.INVALID_EVENT_TIME;\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/HistogramPaintListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/HistogramPaintListener.java
new file mode 100644 (file)
index 0000000..0241f64
--- /dev/null
@@ -0,0 +1,355 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Adapted to new model-view-controller design, display improvements\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import java.text.DecimalFormat;\r
+import java.util.Collections;\r
+import java.util.Vector;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramScaledData;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramUtils;\r
+import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramDataModel;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.HistogramViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.widgets.Display;\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+\r
+/**\r
+ * <b><u>HistogramPaintListener</u></b>\r
+ * <p>\r
+ * Histogram paint listener.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class HistogramPaintListener extends AbstractPaintListener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Is a histogram bar so high that it is clipped from the draw area ?\r
+     */\r
+    private boolean fBarIsClipped = false;\r
+\r
+    /**\r
+     * Scaled data from data model\r
+     */\r
+    protected HistogramScaledData fScaledData;\r
+\r
+    /**\r
+     * Warning Image\r
+     */\r
+    protected Image fWarningImage;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Constructor.\r
+     * @param view\r
+     *            A reference to the listener's viewer.\r
+     */\r
+    public HistogramPaintListener(AbstractViewer viewer) {\r
+        super(viewer);\r
+        fWarningImage = AbstractUIPlugin.imageDescriptorFromPlugin(Messages.LatencyView_tmf_UI, "icons/elcl16/warning.gif").createImage(Display.getCurrent()); //$NON-NLS-1$\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Accessors\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Returns the histogram's bar Width.\r
+     * @return The histogram's bar Width.\r
+     */\r
+    public int getBarWidth() {\r
+        return fBarWith;\r
+    }\r
+    \r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#dispose()\r
+     */\r
+    @Override\r
+    public void dispose() {\r
+        fWarningImage.dispose();\r
+        super.dispose();\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#scale()\r
+     */\r
+    @Override\r
+    public void scale() {\r
+        // width of the plot area\r
+        double width = getWidth();\r
+        // height of the plot area\r
+        double height = getHeight();\r
+\r
+        int barWidth = getBarWidth();\r
+\r
+        IHistogramDataModel model = ((HistogramViewer)fViewer).getModel();\r
+        fScaledData = model.scaleTo((int)width, (int)height, barWidth);\r
+\r
+        fYMin = 0;\r
+        fYMax = fScaledData.fMaxValue;\r
+\r
+        fXMin = fScaledData.getFirstBucketTime();\r
+        fXMin = fXMin > 0 ? fXMin : 0; \r
+        fXMax = fScaledData.getBucketEndTime(fScaledData.fLastBucket - 1);\r
+\r
+        // No data to display - set end time to 0 \r
+        if (fYMax == 0) {\r
+            fXMax = 0;\r
+        }\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintVerticalTicks(int)\r
+     */\r
+    @Override\r
+    public void paintVerticalTicks(int x) {\r
+        // done in method paintVerticalAxisValues()\r
+    }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintVerticalAxisValues(int)\r
+     */\r
+    @Override\r
+    public void paintVerticalAxisValues(int x) {\r
+        int zoomFactor = 1;\r
+\r
+        zoomFactor = fViewer.getZoomFactor();\r
+\r
+        if (fYMin >= 0L && fYMax != 0L) {\r
+            fAxisImage.setForeground(fTextColor);\r
+            fAxisImage.setBackground(fBackgroundColor);\r
+\r
+            // Apply the zoom to the max value of the graph for the next calculations\r
+            long yMax = fYMax / zoomFactor;\r
+\r
+            int nbTicks = ((int)getHeight()) / MAX_HEIGHT_BETWEEN_TICKS + 1;\r
+\r
+            Vector<Integer> values = new Vector<Integer>();\r
+            boolean multipleSameValues = true;\r
+            while (multipleSameValues) {\r
+                double valueStep = (double) (yMax - fYMin) / (double) (nbTicks);\r
+\r
+                for (int i = 0; i < nbTicks; i++) {\r
+                    double currentValue = (double) (fYMin + i * valueStep) / (Math.pow(10, fDelta));\r
+\r
+                    values.add((int) currentValue);\r
+                }\r
+\r
+                Collections.sort(values);\r
+                boolean hasRepetition = false;\r
+                for (int i = 1; i < values.size(); i++) {\r
+                    if (values.get(i) == values.get(i - 1)) {\r
+                        hasRepetition = true;\r
+                        break;\r
+                    }\r
+                }\r
+\r
+                if (hasRepetition) {\r
+                    nbTicks--;\r
+                    values.clear();\r
+                } else {\r
+                    multipleSameValues = false;\r
+\r
+                    // Draw rectangle over the old values\r
+                    int height = fViewer.getBounds().height - 2 * fPadding - fPaddingTop - fHorizontalAxisYOffset;\r
+                    fAxisImage.fillRectangle(0, fPadding + fPaddingTop, fPadding + fVerticalAxisOffset, height);\r
+\r
+                    double pixelStep = (getHeight()) / values.size() + 1;\r
+\r
+                    for (int i = 0; i < values.size(); i++) {\r
+                        double currentValue = values.get(i);\r
+\r
+                        int y = (int)  (fClientArea.height - fPadding - fHorizontalAxisYOffset -  i * pixelStep);\r
+                        String currentLabel = formatStringForVerticalAxis((long) currentValue);\r
+\r
+                        fAxisImage.setFont(fValuesFont);\r
+\r
+                        Point textDimensions = fAxisImage.stringExtent(currentLabel);\r
+                        fAxisImage.drawText(currentLabel, x - textDimensions.x - 5, y - textDimensions.y / 2);\r
+                        fAxisImage.drawLine(x - 3, y, x, y);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#paintContent()\r
+     */\r
+    @Override\r
+    public void paintContent() {\r
+        double zoomFactor = fViewer.getZoomFactor();\r
+\r
+        // Calculate the vertical axis factor and see if it has changed\r
+        double tmpDelta = fDelta;\r
+        fDelta = 0;\r
+        if (Long.toString(fYMax / (long) zoomFactor).length() > MAX_CHAR_VERTICAL_DISPLAY) {\r
+            fDelta = Long.toString(fYMax / (long) zoomFactor).length() - MAX_CHAR_VERTICAL_DISPLAY;\r
+        }\r
+        if (tmpDelta != fDelta) {\r
+            fViewer.clearBackground();\r
+        }\r
+\r
+        paintBackground();\r
+        paintVerticalAxis();\r
+        paintHorizontalAxis();\r
+\r
+        fAxisImage.setForeground(fDataColor);\r
+        fAxisImage.setBackground(fDataColor);\r
+\r
+        // height of the plot area\r
+        double height = getHeight();\r
+\r
+        int barWidth = getBarWidth();\r
+        \r
+        // axisImage_.setBackground(backgroundColor_);\r
+        // 1.a Iterate over the points, from 0 to nbPoints\r
+        // 1.b Find the max counter value\r
+        // 2. Assign the max value to the "yMax_" class attribute\r
+        // 3. Draw the histogram bars using "axisImage_.fillRectangle(...)"\r
+        boolean oneBarIsClipped = false;\r
+\r
+        for (int i = 0; i < fScaledData.fData.length; i++) {\r
+            double pointY = fScaledData.fData[i];\r
+\r
+            // in pixels\r
+            double x = fPadding + i * barWidth + fVerticalAxisOffset + 1;\r
+\r
+            if (i == fScaledData.fData.length - 1)\r
+                x -= 1.0;\r
+            double barHeight = zoomFactor * ((double)(pointY - fYMin) / (double)(fYMax - fYMin)) * height;\r
+\r
+            if (barHeight > height + 1) {\r
+                barHeight = height;\r
+                oneBarIsClipped = true;\r
+\r
+                fAxisImage.drawImage(fWarningImage, 5, 3);\r
+            }\r
+\r
+            // Only draw the bars that have a barHeight of more than 1 pixel\r
+            if (barHeight > 0) {\r
+                double y = fPadding + fPaddingTop + height - barHeight;\r
+                fAxisImage.setBackground(fDataColor);\r
+\r
+                if (barHeight > height - 1) {\r
+                    fAxisImage.fillRectangle((int) x, (int) y, (int) barWidth, (int) (barHeight + 1));\r
+                } else {\r
+                    fAxisImage.fillRectangle((int) x, (int) y, (int) barWidth, (int) (barHeight + 2));\r
+                }\r
+            }\r
+        }\r
+\r
+        if (oneBarIsClipped)\r
+            fBarIsClipped = true;\r
+        else\r
+            fBarIsClipped = false;\r
+    }\r
+    \r
+    /**\r
+     * Paints the histogram horizontal axis values in engineering notation in which the exponent is a multiple of three.\r
+     * @param value\r
+     *            The numeric value to convert to engineering notation.\r
+     * @return The given value formatted according to the engineering notation.\r
+     */\r
+    @Override\r
+    public String formatStringForHorizontalAxis(long value) {\r
+        DecimalFormat formatter = new DecimalFormat("##0.#E0"); //$NON-NLS-1$\r
+        return formatter.format(value);\r
+    }\r
+\r
+    /**\r
+     * Sets the bar width.\r
+     * @param barWidth \r
+     *            bar width to set\r
+     */\r
+    public void setBarWidth(int barWidth) {\r
+        fBarWith = barWidth;\r
+    }\r
+    \r
+    /**\r
+     * Returns "true" if a histogram bar is so high that it cannot be drawn in the draw area, "false" otherwise.\r
+     * @return "true" if a histogram bar is so high that it cannot be drawn in the draw area, "false" otherwise.\r
+     */\r
+    public boolean barIsClipped() {\r
+        return fBarIsClipped;\r
+    }\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractPaintListener#formatToolTipLabel(int, int)\r
+     */\r
+    @Override\r
+    public String formatToolTipLabel(int x, int y) {\r
+        if (fScaledData != null) {\r
+\r
+            double barWidth = getBarWidth();\r
+            double height = getHeight();     // height of the plot area\r
+            \r
+            double zoomFactor = fViewer.getZoomFactor();\r
+\r
+            int index = (int) ((x - fPadding - fVerticalAxisOffset - 1) / barWidth);\r
+\r
+            double barHeight = 0.0;\r
+            if (index >= 0 && index <= fScaledData.fLastBucket) {\r
+                barHeight = (zoomFactor * height * (fScaledData.fData[index] - fYMin) / (fYMax - fYMin));\r
+            }\r
+\r
+            long fMouseY = (long) (height - (y - fPadding - fPaddingTop));\r
+\r
+            // Verifying mouse pointer is over histogram bar\r
+            if (index >= 0 && fScaledData.fLastBucket >= index && fMouseY >= 0 && fMouseY < barHeight && fMouseY < height && x >= (fVerticalAxisOffset + fPadding)) {\r
+\r
+                fScaledData.fCurrentBucket = index;\r
+\r
+                long startTime = fScaledData.getBucketStartTime(index);\r
+                // negative values are possible if time values came into the model in decreasing order\r
+                if (startTime < 0) {\r
+                    startTime = 0;\r
+                }\r
+                long endTime = fScaledData.getBucketEndTime(index);\r
+                int nbEvents = fScaledData.fData[index];\r
+\r
+                StringBuffer buffer = new StringBuffer();\r
+                buffer.append("Latency Range in s = ["); //$NON-NLS-1$\r
+                buffer.append(HistogramUtils.nanosecondsToString(startTime));\r
+                buffer.append(","); //$NON-NLS-1$\r
+                buffer.append(HistogramUtils.nanosecondsToString(endTime));\r
+                buffer.append("]\n"); //$NON-NLS-1$\r
+                buffer.append("Latency count = "); //$NON-NLS-1$\r
+                buffer.append(nbEvents);\r
+                return buffer.toString();\r
+            }\r
+        }\r
+        return ""; //$NON-NLS-1$\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TimePointerListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TimePointerListener.java
new file mode 100644 (file)
index 0000000..31027ca
--- /dev/null
@@ -0,0 +1,69 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *   Bernd Hufmann - Changed display interface implementation \r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+\r
+/**\r
+ * <b><u>TimePointerListener</u></b>\r
+ * <p>\r
+ * Displays a tooltip showing the approximate values of the point under the mouse cursor.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class TimePointerListener extends AbstractMouseTrackListener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * A reference to the observed view.\r
+     */\r
+    protected AbstractViewer fView;\r
+\r
+    /**\r
+     * A reference to the HistogramPaintListener.\r
+     */\r
+    protected GraphPaintListener fGraph;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Constructor.\r
+     * @param view\r
+     *            A reference to the observed view.\r
+     * @param histogramPaintListener\r
+     *            A reference to the histogram's paintListener.\r
+     */\r
+    public TimePointerListener(AbstractViewer view, GraphPaintListener graphPaintListener) {\r
+        fView = view;\r
+        fGraph = graphPaintListener;\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseTrackListener#display()\r
+     */\r
+    @Override\r
+    protected void display() {\r
+        fView.setToolTipText(fGraph.formatToolTipLabel(fMouseX, fMouseY));\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TooltipListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/TooltipListener.java
new file mode 100644 (file)
index 0000000..ccb8bc2
--- /dev/null
@@ -0,0 +1,100 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com) - Initial API and implementation\r
+ *   Bernd Hufmann - Changed display interface implementation\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.Messages;\r
+\r
+/**\r
+ * <b><u>TooltipListener</u></b>\r
+ * <p>\r
+ * Tooltip listener, displays the event count for each latency selected by the mouse click area on histogram.\r
+ * \r
+ * @author Ali Jawhar\r
+ */\r
+public class TooltipListener extends AbstractMouseTrackListener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * A reference to the observed view.\r
+     */\r
+    protected AbstractViewer fView;\r
+\r
+    /**\r
+     * A reference to the HistogramPaintListener.\r
+     */\r
+    protected HistogramPaintListener fHistogram;\r
+\r
+    /**\r
+     * Is the mouse over the warning icon, indicating that a bar is higher than the draw area due to zooming ?\r
+     */\r
+    protected boolean fDisplayWarning = false;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Constructor.\r
+     * @param view\r
+     *            A reference to the observed view.\r
+     * @param histogramPaintListener\r
+     *            A reference to the histogram's paintListener.\r
+     */\r
+    public TooltipListener(AbstractViewer view, HistogramPaintListener histogramPaintListener) {\r
+        fView = view;\r
+        fHistogram = histogramPaintListener;\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.listeners.AbstractMouseTrackListener#display()\r
+     */\r
+    @Override\r
+    protected void display() {\r
+        displayWarningTooltip();\r
+        displayTooltip();\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Helper Functions\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /**\r
+     * Displays a tooltip if the mouse is over the warning icon indication that a bar cannot be draw entirely due to the\r
+     * zoom factor.\r
+     */\r
+    protected void displayWarningTooltip() {\r
+        if (fHistogram.barIsClipped() && fMouseX > 5 && fMouseX < 21 && fMouseY > 3 && fMouseY < 18) {\r
+            fView.setToolTipText(Messages.LatencyView_ClippingWarning);\r
+            fDisplayWarning = true;\r
+        } else {\r
+            fDisplayWarning = false;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Displays the tooltip showing the details of the histogram bar pointed by the mouse.\r
+     */\r
+    protected void displayTooltip() {\r
+        if (!fDisplayWarning)\r
+            fView.setToolTipText(fHistogram.formatToolTipLabel(fMouseX, fMouseY));\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/ZoomListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/listeners/ZoomListener.java
new file mode 100644 (file)
index 0000000..266f926
--- /dev/null
@@ -0,0 +1,134 @@
+/*******************************************************************************\r
+ * Copyright (c) 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactored code\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.listeners;\r
+\r
+import org.eclipse.linuxtools.lttng.ui.views.latency.AbstractViewer;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.widgets.Canvas;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Listener;\r
+\r
+/**\r
+ * <b><u>ZoomListener</u></b>\r
+ * <p>\r
+ * \r
+ * Canvas zoom listener.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class ZoomListener implements Listener {\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Attributes\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * A reference to the observed view.\r
+     */\r
+    protected AbstractViewer fView;\r
+    /**\r
+     * Default zoom factor.\r
+     */\r
+    protected int fZoomFactor;\r
+    /**\r
+     * Zoom increment.\r
+     */\r
+    protected int fZoomIncrement = 30;\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Constructors\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param view\r
+     *            A reference to the observed view.\r
+     * @param defaultZoomFactor\r
+     *            Default zoom factor.\r
+     */\r
+    public ZoomListener(AbstractViewer view, int defaultZoomFactor) {\r
+        fView = view;\r
+        fZoomFactor = defaultZoomFactor;\r
+    }\r
+\r
+    /**\r
+     * Constructor.\r
+     * @param view\r
+     *            A reference to the observed view.\r
+     */\r
+    public ZoomListener(AbstractViewer view) {\r
+        this(view, 1);\r
+    }\r
+\r
+    // ------------------------------------------------------------------------\r
+    // Accessors\r
+    // ------------------------------------------------------------------------\r
+\r
+    /**\r
+     * Returns the zoom factor.\r
+     * @return The zoom factor.\r
+     */\r
+    public int getZoomFactor() {\r
+        if (fZoomFactor < 1)\r
+            return 1;\r
+        else\r
+            return fZoomFactor;\r
+    }\r
+\r
+    /**\r
+     * Returns the zoom increment.\r
+     * @return The zoom increment.\r
+     */\r
+    public int getZoomIncrement() {\r
+        return fZoomIncrement;\r
+    }\r
+    \r
+    // ------------------------------------------------------------------------\r
+    // Operations\r
+    // ------------------------------------------------------------------------\r
+    \r
+    /*\r
+     * (non-Javadoc)\r
+     * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event)\r
+     */\r
+    @Override\r
+    public void handleEvent(Event event) {\r
+        switch (event.type) {\r
+            case SWT.MouseWheel:\r
+                boolean scrollDown = (event.count == 0 ? false : (event.count > 0 ? false : true));\r
+                int zoomStep = fZoomIncrement;\r
+                if (scrollDown)\r
+                    zoomStep = -fZoomIncrement;\r
+                fZoomFactor = Math.max(0, fZoomFactor + zoomStep);\r
+\r
+                Canvas canvas = (Canvas) event.widget;\r
+                if (fView != null) {\r
+                    // clear the background to allow redraw of values of the vertical axis.\r
+                    fView.clearBackground();\r
+                    fView.redrawTitle();\r
+                    fView.askForRedraw();\r
+                }\r
+                canvas.redraw();\r
+                break;\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Sets the zoom increment.\r
+     * @param zoomIncrement\r
+     *            The new zoom increment.\r
+     */\r
+    public void setZoomIncrement(int zoomIncrement) {\r
+        fZoomIncrement = zoomIncrement;\r
+    }\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/messages.properties b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/messages.properties
new file mode 100644 (file)
index 0000000..cf907c0
--- /dev/null
@@ -0,0 +1,59 @@
+#*******************************************************************************\r
+# Copyright (c) 2011 Ericsson\r
+#  \r
+# All rights reserved. This program and the accompanying materials are\r
+# made available under the terms of the Eclipse Public License v1.0 which\r
+# accompanies this distribution, and is available at\r
+# http://www.eclipse.org/legal/epl-v10.html\r
+#  \r
+# Contributors:\r
+#   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+#   Bernd Hufmann - Updated and added properties    \r
+# *******************************************************************************/\r
+\r
+LatencyView_ViewName=LatencyView\r
+LatencyView_Action_IncreaseBarWidth_Tooltip=Increase bar width/height\r
+LatencyView_Action_DecreaseBarWidth_Tooltip=Decrease bar width/height\r
+LatencyView_Action_AddEvents_Tooltip=Add matching events\r
+LatencyView_Action_DeleteEvents_Tooltip=Delete matching events\r
+LatencyView_Action_ListEvents_Tooltip=List matching events\r
+LatencyView_Dialogs_AddEvents_Title=Add event pairs\r
+LatencyView_Dialogs_AddEvents_Message=Select a pair of events to add it to the match list :\r
+LatencyView_Dialogs_AddEvents_Buttons_Add=Add\r
+LatencyView_Dialogs_AddEvents_Buttons_Close=Close\r
+LatencyView_Dialogs_AddEvents_Columns_Start=Start event types\r
+LatencyView_Dialogs_AddEvents_Columns_End=End event types\r
+LatencyView_Dialogs_AddEvents_Columns_List_Trigger=Trigger event type\r
+LatencyView_Dialogs_AddEvents_Columns_List_End=End event type\r
+LatencyView_Dialogs_AddEvents_Errors_NoSelection=You must select one item from both lists_\r
+LatencyView_Dialogs_AddEvents_Errors_StartNotSelected=You must select one item from the start event list_\r
+LatencyView_Dialogs_AddEvents_Errors_EndNotSelected=You must select one item from the end event list_\r
+LatencyView_Dialogs_AddEvents_Errors_SameSelected=The same event cannot be selected in both list at the same time_\r
+LatencyView_Dialogs_AddEvents_Errors_AlreadyMatched=The start and end events are already matched_\r
+LatencyView_Dialogs_AddEvents_Errors_StartAlreadyMatched=The start event is already matched_\r
+LatencyView_Dialogs_AddEvents_Errors_EndAlreadyMatched=The end event is already matched_\r
+LatencyView_Dialogs_AddEvents_Errors_StartAsEnd=The start event is already matched as an end event_\r
+LatencyView_Dialogs_AddEvents_Errors_EndAsStart=The end event is already matched as a start event_\r
+LatencyView_Dialogs_DeleteEvents_Title=Delete event pairs\r
+LatencyView_Dialogs_DeleteEvents_Message=Select a pair of matched events to remove it from the list :\r
+LatencyView_Dialogs_DeleteEvents_Buttons_Close=Close\r
+LatencyView_Dialogs_DeleteEvents_Buttons_Delete=Delete\r
+LatencyView_Dialogs_DeleteEvents_Confirm_Title=Confirm event deletion\r
+LatencyView_Dialogs_DeleteEvents_Confirm_Message=Are you sure you want to delete these event pairs?\r
+LatencyView_Dialogs_ListEvents_Title=Matched events list\r
+LatencyView_Dialogs_ListEvents_Message=List of matched events for latency computation :\r
+LatencyView_Dialogs_ListEvents_Buttons_Close=Close\r
+LatencyView_Dialogs_ListEvents_Buttons_Reset=Reset to default pairs\r
+LatencyView_Dialogs_ListEvents_Columns_Trigger=Trigger event type\r
+LatencyView_Dialogs_ListEvents_Columns_End=End event type\r
+LatencyView_Dialogs_ListEvents_Confirm_Title=Confirm pairs reset\r
+LatencyView_Dialogs_ListEvents_Confirm_Message=Are you sure you want to reset the event pairs to their default values?\r
+LatencyView_Graphs_Graph_Title=Latency vs Time\r
+LatencyView_Graphs_Graph_XAxisLabel=time (s)\r
+LatencyView_Graphs_Graph_YAxisLabel=latency (ms)\r
+LatencyView_Graphs_Histogram_Title=Latency Distribution\r
+LatencyView_Graphs_Histogram_XAxisLabel=latency (ms)\r
+LatencyView_Graphs_Histogram_YAxisLabel=# events\r
+LatencyView_msgSlogan=Latency View\r
+LatencyView_tmf_UI=org.eclipse.linuxtools.lttng.ui\r
+LatencyView_ClippingWarning=One or more bars are higher than the drawing area due to zooming
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/Config.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/Config.java
new file mode 100644 (file)
index 0000000..e2d77ea
--- /dev/null
@@ -0,0 +1,76 @@
+/*******************************************************************************\r
+ * Copyright (c) 2010, 2011 Ericsson\r
+ * \r
+ * All rights reserved. This program and the accompanying materials are\r
+ * made available under the terms of the Eclipse Public License v1.0 which\r
+ * accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ * \r
+ * Contributors:\r
+ *   Philippe Sawicki (INF4990.A2010@gmail.com)   - Initial API and implementation\r
+ *   Mathieu Denis    (mathieu.denis55@gmail.com) - Refactor code\r
+ *   Bernd Hufmann - Added and updated constants\r
+ *******************************************************************************/\r
+package org.eclipse.linuxtools.lttng.ui.views.latency.model;\r
+\r
+/**\r
+ * <b><u>Config</u></b>\r
+ * <p>\r
+ * Configuration class, holds some application constants.\r
+ * \r
+ * @author Philippe Sawicki\r
+ */\r
+public class Config {\r
+\r
+    /**\r
+     * Private constructor to defeat instantiation.\r
+     */\r
+    private Config() {\r
+    }\r
+\r
+    /**\r
+     * Time scale for TMF events;\r
+     */\r
+    public static byte TIME_SCALE = -9;\r
+    \r
+    /**\r
+     * Size of the point buffer holding point values before sending them to the view.\r
+     */\r
+    public static final int POINT_BUFFER_SIZE = 10000;\r
+\r
+    /**\r
+     * Histogram bar width.\r
+     */\r
+    public static final int DEFAULT_HISTOGRAM_BAR_WIDTH = 2;\r
+    \r
+    /**\r
+     * Histogram bar width increase step.\r
+     */\r
+    public static final int MIN_HISTOGRAM_BAR_WIDTH = 1;\r
+\r
+    /**\r
+     * Histogram bar width increase step.\r
+     */\r
+    public static final int MAX_HISTOGRAM_BAR_WIDTH = 16;\r
+\r
+    \r
+    /**\r
+     * Diameter of a point drawn on the chart (in pixels).\r
+     */\r
+    public static final int GRAPH_POINT_DIAMETER = 1;\r
+\r
+    /**\r
+     * Graph padding.\r
+     */\r
+    public static final int GRAPH_PADDING = 10;\r
+\r
+    /**\r
+     * Default number of buckets used in data models\r
+     */\r
+    public static final int DEFAULT_NUMBER_OF_BUCKETS = 2 * 1000;\r
+    \r
+    /**\r
+     * Invalid event time\r
+     */\r
+    public static final long INVALID_EVENT_TIME = -1;\r
+}
\ No newline at end of file
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/GraphScaledData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/GraphScaledData.java
new file mode 100644 (file)
index 0000000..d41e684
--- /dev/null
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.latency.model;
+
+/**
+ * <b><u>GraphScaledData</u></b>
+ * Convenience class for scaled distribution data.  
+ * <p>
+ */
+import java.util.Arrays;
+
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.BaseDistributionData;
+
+public class GraphScaledData {
+
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+
+    private int fWidth;
+    private int fHeight;
+    private int fBarWidth;
+    private int[][] fData;
+    private BaseDistributionData fHorDistributionData;
+    private BaseDistributionData fVerDistributionData;
+    private long fCurrentEventTime;
+
+    // ------------------------------------------------------------------------
+    // Constructor
+    // ------------------------------------------------------------------------
+
+    public GraphScaledData(int width, int height, int barWidth) {
+        fWidth = width;
+        fHeight = height;
+        fBarWidth = barWidth;
+        int horNbBuckets = (int)width/barWidth;
+        int verNbBuckets = (int)height/barWidth; 
+        fData = new int[horNbBuckets][verNbBuckets];
+        for (int[] row : fData) {
+            Arrays.fill(row, 0);    
+        }
+        fHorDistributionData = new BaseDistributionData(horNbBuckets);
+        fHorDistributionData.clear();
+        
+        fVerDistributionData = new BaseDistributionData(verNbBuckets);
+        fVerDistributionData.clear();
+        
+        fCurrentEventTime = Config.INVALID_EVENT_TIME;
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+
+    public int getWidth() {
+        return fWidth;
+    }
+
+    public int getHeight() {
+        return fHeight;
+    }
+
+    public int getBarWidth() {
+        return fBarWidth;
+    }
+
+    public int[][] getData() {
+        return fData;
+    }
+
+    public int getHorNbBuckets() {
+        return fHorDistributionData.getNbBuckets();
+    }
+    
+    public int getVerNbBuckets() {
+        return fVerDistributionData.getNbBuckets();
+    }
+
+    public long getHorFirstBucketTime() {
+        return fHorDistributionData.getFirstBucketTime();
+    }
+
+    public long getVerFirstBucketTime() {
+        return fVerDistributionData.getFirstBucketTime();
+    }
+
+    public long getHorLastBucketTime() {
+        return fHorDistributionData.getLastBucketTime();
+    }
+
+    public long getVerLastBucketTime() {
+        return fVerDistributionData.getLastBucketTime();
+    }
+    
+    public long getHorFirstEventTime() {
+        return fHorDistributionData.getFirstEventTime();
+    }
+
+    public long getVerFirstEventTime() {
+        return fVerDistributionData.getFirstEventTime();
+    }
+
+    public long getHorLastEventTime() {
+        return fHorDistributionData.getLastEventTime();
+    }
+
+    public long getVerLastEventTime() {
+        return fVerDistributionData.getLastEventTime();
+    }
+    
+    public long getHorBucketDuration() {
+        return fHorDistributionData.getBucketDuration();
+    }
+
+    public long getVerBucketDuration() {
+        return fVerDistributionData.getBucketDuration();
+    }
+
+    public int getHorLastBucket() {
+        return fHorDistributionData.getLastBucket();
+    }
+
+    public int getVerLastBucket() {
+        return fVerDistributionData.getLastBucket();
+    }
+
+    public long getHorBucketStartTime(int index) {
+        return  fHorDistributionData.getBucketStartTime(index);
+    }
+    
+    public long getHorBucketEndTime(int index) {
+        return fHorDistributionData.getBucketEndTime(index);
+    }
+    
+    public long getVerBucketStartTime(int index) {
+        return  fVerDistributionData.getBucketStartTime(index);
+    }
+    
+    public long getVerBucketEndTime(int index) {
+        return fVerDistributionData.getBucketEndTime(index);
+    }
+    
+    public int getEventCount(int horIndex, int verIndex) {
+        return fData[horIndex][verIndex];
+    }
+    
+    public long getCurrentEventTime() {
+        return fCurrentEventTime;
+    }
+
+    public boolean isCurrentEventTimeValid() {
+        if (fCurrentEventTime == Config.INVALID_EVENT_TIME || fCurrentEventTime < getHorFirstEventTime() || fCurrentEventTime > getHorLastEventTime()) {
+            return false;
+        }
+        return true;
+    }
+    
+    public int getHorBucketIndex(long time) {
+         return fHorDistributionData.getIndex(time);
+    }
+    
+    public int getVerBucketIndex(long time) {
+        return fVerDistributionData.getIndex(time);
+    }
+    
+    public boolean isHorIndexValid(int index) {
+        return fHorDistributionData.isIndexValid(index);
+    }
+    
+    public boolean isVerIndexValid(int index) {
+        return fVerDistributionData.isIndexValid(index);
+    }
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    public void setWidth(int width) {
+        fWidth = width;
+    }
+
+    public void setHeight(int height) {
+        fHeight = height;
+    }
+    
+    public void setBarWidth(int barWidth) {
+        fBarWidth = barWidth;
+    }
+
+    public void setData(int[][] data) {
+        fData = data;
+    }
+
+    public void setHorFirstBucketTime(long firstBucketTime) {
+        fHorDistributionData.setFirstBucketTime(firstBucketTime);
+    }
+
+    public void setVerFirstBucketTime(long firstBucketTime) {
+        fVerDistributionData.setFirstBucketTime(firstBucketTime);
+    }
+
+    public void setHorFirstEventTime(long firstEventTime) {
+        fHorDistributionData.setFirstEventTime(firstEventTime);
+    }
+
+    public void setVerFirstEventTime(long firstEventTime) {
+        fVerDistributionData.setFirstEventTime(firstEventTime);
+    }
+
+    public void setHorLastEventTime(long lastEventTime) {
+        fHorDistributionData.setLastEventTime(lastEventTime);
+    }
+
+    public void setVerLastEventTime(long lastEventTime) {
+        fVerDistributionData.setLastEventTime(lastEventTime);
+    }
+
+    public void setHorBucketDuration(long bucketDuration) {
+        fHorDistributionData.setBucketDuration(bucketDuration);
+    }
+
+    public void setVerBucketDuration(long bucketDuration) {
+        fVerDistributionData.setBucketDuration(bucketDuration);
+    }
+
+    public void setHorLastBucket(int lastBucket) {
+        fHorDistributionData.setLastBucket(lastBucket);
+    }
+
+    public void setVerLastBucket(int lastBucket) {
+        fVerDistributionData.setLastBucket(lastBucket);
+    }
+
+    public void setCurrentEventTime(long currentEventTime) {
+        fCurrentEventTime = currentEventTime;
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphDataModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphDataModel.java
new file mode 100644 (file)
index 0000000..182004b
--- /dev/null
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.linuxtools.lttng.ui.views.latency.model;
+
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDistributionModel;
+
+/**
+ * <b><u>IGraphDataModel</u></b>
+ * <p>
+ */
+public interface IGraphDataModel extends IBaseDistributionModel {
+
+    /**
+     * Add event to the correct bucket, compacting the if needed.
+     * 
+     * @param eventCount - the event count
+     * @param timestamp - the timestamp (x-coordinate) of the event to count
+     * @param time - the time (y-coordinate) of the event to count
+     */
+    public void countEvent(int eventCount, long timestamp, long time);
+    
+    /**
+     * Scale the model data to the width and height requested.
+     * 
+     * @param width - width of graph
+     * @param height - height of graph
+     * @param barWidth - width of bar
+     * @return the result array of size [width] and where the highest value
+     *         doesn't exceed [height]
+     */
+    public GraphScaledData scaleTo(int width, int height, int barWidth);
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphModelListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/IGraphModelListener.java
new file mode 100644 (file)
index 0000000..b664399
--- /dev/null
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.lttng.ui.views.latency.model;
+
+/**
+ * <b><u>IGraphModelListener</u></b>
+ * <p>
+ */
+public interface IGraphModelListener {
+    
+    /**
+     * Method to notify listeners about model updates 
+     */
+    public void graphModelUpdated();
+
+    /**
+     * Method to inform listeners about current time updates 
+     */
+    public void currentEventUpdated(long currentEventTime);
+
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyController.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyController.java
new file mode 100644 (file)
index 0000000..fa212d3
--- /dev/null
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.lttng.ui.views.latency.model;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDistributionModel;
+import org.eclipse.linuxtools.lttng.ui.views.histogram.IHistogramDataModel;
+import org.eclipse.linuxtools.tmf.core.component.TmfEventProvider;
+import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
+import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType;
+
+/**
+ * <b><u>LatencyController</u></b>
+ * <p>
+ */
+public class LatencyController {
+   
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+
+    private static LatencyController fInstance = null;
+    
+    private LatencyEventRequest fEventRequest;
+    
+    private TmfEventProvider<?> fProvider;
+    
+    private final ListenerList fModels;
+
+    // ------------------------------------------------------------------------
+    // Constructor
+    // ------------------------------------------------------------------------
+
+    private LatencyController() {
+        fModels = new ListenerList();
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+    public static LatencyController getInstance() {
+        if (fInstance == null) {
+            fInstance = new LatencyController();
+        }
+        return fInstance;
+    }
+    
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    /**
+     * Refresh all registered models
+     * 
+     * @param provider - TmfEventProvider to request data from
+     * @param timeRange - time range of request
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public void refreshModels(TmfEventProvider<?> provider, TmfTimeRange timeRange) {
+        // save provider
+        fProvider = provider;
+        if (fProvider != null) {
+            if (fEventRequest != null && !fEventRequest.isCompleted()) {
+                fEventRequest.cancel();
+            }
+            clear();
+            fEventRequest = new LatencyEventRequest(this, timeRange, ExecutionType.FOREGROUND);
+            fProvider.sendRequest((TmfDataRequest)fEventRequest);
+        }
+    }
+
+    /**
+     * Refreshes registered models by re-sending previous request to saved provider
+     */
+    public void refreshModels() {
+        if (fProvider != null && fEventRequest != null) {
+            refreshModels(fProvider, fEventRequest.getRange());
+        }
+    }
+
+    /**
+     * Clear all models
+     */
+    public void clear() {
+        Object models[] = fModels.getListeners();
+        
+        for (int i = 0; i < models.length; i++) {
+            ((IBaseDistributionModel)models[i]).clear();
+        }
+    }
+    
+    /**
+     * Dispose of controller
+     */
+    public void dispose() {
+        if (fEventRequest != null && !fEventRequest.isCompleted()) {
+            fEventRequest.cancel();
+        }
+        fProvider = null;
+    }
+    
+    /**
+     * Register given model.
+     * @param model - model to register
+     */
+    public void registerModel(IBaseDistributionModel model) {
+        fModels.add(model);
+    }
+    
+    /**
+     * Deregister given model.
+     * 
+     * @param model - model to deregister
+     */
+    public void deregisterModel(IBaseDistributionModel model) {
+        fModels.remove(model);
+    }
+    
+    /**
+     * Handle data of event request and pass it information to the registered models
+     * 
+     * @param eventCount - event count
+     * @param timestamp - start timestamp of latency calculation
+     * @param latency - latency value (startTimestamp - endTimestamp)
+     */
+    public void handleData(int eventCount, long timestamp, long latency) {
+        Object[] models = fModels.getListeners();
+        for (int i = 0; i < models.length; i++) {
+            IBaseDistributionModel model = (IBaseDistributionModel)models[i];
+            if (model instanceof IHistogramDataModel) {
+                ((IHistogramDataModel)model).countEvent(eventCount, latency);
+            } else if (model instanceof IGraphDataModel) {
+                ((IGraphDataModel)model).countEvent(eventCount, timestamp, latency);
+            }
+        }
+    }
+
+    /**
+     * Handle complete indication from request.
+     */
+    public void handleCompleted() {
+        Object[] models = fModels.getListeners();
+        for (int i = 0; i < models.length; i++) {
+            ((IBaseDistributionModel)models[i]).complete();
+        }
+    }
+
+    /**
+     * Handle cancel indication from request.
+     */
+    public void handleCancel() {
+        clear();
+    }
+    
+    /**
+     * Set event provider for refresh.
+     * 
+     * @param provider
+     */
+    public void setEventProvider(TmfEventProvider<?> provider) {
+        fProvider = provider;
+    }
+    
+    /**
+     * Set current event time in model(s).
+     * 
+     * @param timestamp
+     */
+    public void setCurrentEventTime(long timestamp) {
+        Object[] models = fModels.getListeners();
+        for (int i = 0; i < models.length; i++) {
+            IBaseDistributionModel model = (IBaseDistributionModel)models[i];
+            if (model instanceof LatencyGraphModel) {
+                ((LatencyGraphModel)model).setCurrentEventNotifyListeners(timestamp);
+            }
+        }
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyEventRequest.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyEventRequest.java
new file mode 100644 (file)
index 0000000..d871ecb
--- /dev/null
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.lttng.ui.views.latency.model;
+
+import org.eclipse.linuxtools.lttng.core.LttngConstants;
+import org.eclipse.linuxtools.lttng.core.event.LttngEvent;
+import org.eclipse.linuxtools.lttng.core.latency.analyzer.EventMatcher;
+import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
+import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest;
+import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;
+
+/**
+ * <b><u>LatencyEventRequest</u></b>
+ * <p>
+ */
+public class LatencyEventRequest extends TmfEventRequest<LttngEvent> {
+
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+    final private LatencyController fController;
+    
+    // ------------------------------------------------------------------------
+    // Constructor
+    // ------------------------------------------------------------------------
+
+    public LatencyEventRequest(LatencyController controller, TmfTimeRange range, int rank, int nbEvents, ITmfDataRequest.ExecutionType execType) {
+        super(LttngEvent.class, range, rank, nbEvents, LttngConstants.DEFAULT_BLOCK_SIZE, execType);
+        fController = controller;
+        EventMatcher.getInstance().clearStack();
+    }
+
+    public LatencyEventRequest(LatencyController controller, TmfTimeRange range, ITmfDataRequest.ExecutionType execType) {
+        this(controller, range, 0, ALL_DATA, execType);
+    }
+
+    public LatencyEventRequest(LatencyController controller, TmfTimeRange range, int rank, ITmfDataRequest.ExecutionType execType) {
+        this(controller, range, rank, ALL_DATA, execType);
+    }
+
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.tmf.request.TmfDataRequest#handleData(org.eclipse.linuxtools.tmf.event.TmfData)
+     */
+    @Override
+    public void handleData(LttngEvent event) {
+        super.handleData(event);
+        
+        LttngEvent startEvent = EventMatcher.getInstance().process(event);
+
+        if (startEvent != null) {
+            long latency = event.getTimestamp().getValue() - startEvent.getTimestamp().getValue(); 
+            fController.handleData(getNbRead(), startEvent.getTimestamp().getValue(), latency);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.tmf.request.TmfDataRequest#handleCompleted()
+     */
+    @Override
+    public void handleCompleted() {
+        fController.handleCompleted();
+        super.handleCompleted();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.tmf.request.TmfDataRequest#handleCancel()
+     */
+    @Override
+    public void handleCancel() {
+        EventMatcher.getInstance().clearStack();
+        fController.handleCancel();
+        super.handleCancel();
+    }
+}
diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyGraphModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/latency/model/LatencyGraphModel.java
new file mode 100644 (file)
index 0000000..399379f
--- /dev/null
@@ -0,0 +1,380 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Ericsson
+ * 
+ * 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:
+ *   Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.linuxtools.lttng.ui.views.latency.model;
+
+import java.util.Arrays;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.DistributionData;
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.HorDistributionData;
+import org.eclipse.linuxtools.lttng.ui.views.distribution.model.VerDistributionData;
+
+/**
+ * <b><u>LatencyGraphModel</u></b>
+ * <p>
+ */
+public class LatencyGraphModel implements IGraphDataModel {
+
+    // ------------------------------------------------------------------------
+    // Attributes
+    // ------------------------------------------------------------------------
+    private final int fNbBuckets;
+    private final int [][] fBuckets;
+    private final DistributionData fHorDistributionData;
+    private final DistributionData fVerDistributionData;
+    private long fCurrentEventTime;
+    
+    // private listener lists
+    private final ListenerList fModelListeners;
+
+    private final ReentrantLock fLock;
+    
+    // ------------------------------------------------------------------------
+    // Constructors
+    // ------------------------------------------------------------------------
+    public LatencyGraphModel() {
+        this(Config.DEFAULT_NUMBER_OF_BUCKETS);
+    }
+
+    public LatencyGraphModel(int nbBuckets) {
+        fNbBuckets = nbBuckets;
+        fBuckets = new int[nbBuckets][nbBuckets];
+        fHorDistributionData = new HorDistributionData(nbBuckets, fBuckets);
+        fVerDistributionData = new VerDistributionData(nbBuckets, fBuckets);
+        fCurrentEventTime = Config.INVALID_EVENT_TIME;
+       
+        fModelListeners = new ListenerList();
+        fLock = new ReentrantLock();
+        clear();
+    }
+
+    // ------------------------------------------------------------------------
+    // Accessors
+    // ------------------------------------------------------------------------
+    
+    public int getNbBuckets() {
+        return fNbBuckets;
+    }
+    
+    public long getHorBucketDuration() {
+        fLock.lock(); 
+        try {
+            return fHorDistributionData.getBucketDuration();
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    public long getVerBucketDuration() {
+        fLock.lock(); 
+        try {
+            return fVerDistributionData.getBucketDuration();
+        } finally {
+            fLock.unlock();
+        }
+    }
+    
+    public long getHorFirstBucketTime() {
+        fLock.lock(); 
+        try {
+            return fHorDistributionData.getFirstBucketTime();
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    public long getVerFirstBucketTime() {
+        fLock.lock(); 
+        try {
+            return fVerDistributionData.getFirstBucketTime();
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    public long getHorFirstEventTime() {
+        fLock.lock(); 
+        try {
+            return fHorDistributionData.getFirstEventTime();
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    public long getVerFirstEventTime() {
+        fLock.lock(); 
+        try {
+            return fVerDistributionData.getFirstEventTime();
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    public long getHorLastEventTime() {
+        fLock.lock(); 
+        try {
+            return fHorDistributionData.getLastEventTime();
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    public long getVerLastEventTime() {
+        fLock.lock(); 
+        try {
+            return fVerDistributionData.getLastEventTime();
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    public long getHorTimeLimit() {
+        fLock.lock(); 
+        try {
+            return fHorDistributionData.getTimeLimit();
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    public long getVerTimeLimit() {
+        fLock.lock(); 
+        try {
+            return fVerDistributionData.getTimeLimit();
+        } finally {
+            fLock.unlock();
+        }
+    }
+    
+    public int getHorLastBucket() {
+        fLock.lock(); 
+        try {
+            return fHorDistributionData.getLastBucket();
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    public int getVerLastBucket() {
+        fLock.lock(); 
+        try {
+            return fVerDistributionData.getLastBucket();
+        } finally {
+            fLock.unlock();
+        }
+    }
+    
+    public long getCurrentEventTime() {
+        fLock.lock();
+        try {
+            return fCurrentEventTime;
+        } finally {
+            fLock.unlock();
+        }
+    }
+
+    // ------------------------------------------------------------------------
+    // Listener interface
+    // ------------------------------------------------------------------------
+    public void addGraphModelListener(IGraphModelListener listener) {
+        fModelListeners.add(listener);        
+    }
+    
+    public void removeGraphModelListener(IGraphModelListener listener) {
+        fModelListeners.remove(listener);
+    }
+    // ------------------------------------------------------------------------
+    // Operations
+    // ------------------------------------------------------------------------
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDataModel#clear()
+     */
+    @Override
+    public void clear() {
+        fLock.lock();
+        try {
+            for (int[] row : fBuckets) {
+                Arrays.fill(row, 0, fNbBuckets, 0);
+            }
+            fHorDistributionData.clear();
+            fVerDistributionData.clear();
+        } finally {
+            fLock.unlock();
+        }
+        fireModelUpdateNotification();
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel#countEvent(int, long, long)
+     */
+    @Override
+    public void countEvent(int eventCount, long timestamp, long time) {
+        fLock.lock();
+        try {
+            int horIndex = fHorDistributionData.countEvent(timestamp);
+            int verIndex = fVerDistributionData.countEvent(time);
+
+            fBuckets[horIndex][verIndex]++;
+        } finally {
+            fLock.unlock();
+        }
+
+        fireModelUpdateNotification(eventCount);
+    }
+    
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.latency.model.IGraphDataModel#scaleTo(int, int, int)
+     */
+    @Override
+    public GraphScaledData scaleTo(int width, int height, int barWidth) {
+        GraphScaledData scaledData = new GraphScaledData(width, height, barWidth);
+        fLock.lock();
+        try {
+            if (!fHorDistributionData.isFirst() && !fVerDistributionData.isFirst() ) {
+
+                // Basic validation
+                if (width <= 0 ||  height <= 0 || barWidth <= 0)
+                    throw new AssertionError("Invalid histogram dimensions (" + width + "x" + height + ", barWidth=" + barWidth + ")");   //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$
+
+                // Scale horizontally
+                int nbBars = width / barWidth;
+                int bucketsPerBar = fHorDistributionData.getLastBucket() / nbBars + 1;
+
+                int horData[][] = new int[nbBars][fNbBuckets];  
+                for (int y = 0; y < fNbBuckets; y++) {
+                    for (int i = 0; i < nbBars; i++) {
+                        int count = 0;
+                        for (int j = i * bucketsPerBar; j < (i + 1) * bucketsPerBar; j++) {
+                            if (fNbBuckets <= j)
+                                break;
+                            count += fBuckets[j][y];
+                        }
+                        horData[i][y] = count;
+                    }
+                }
+
+                // Scale vertically
+                int nbVerBars = height / barWidth;
+                int bucketsPerVerBar = fVerDistributionData.getLastBucket() / nbVerBars + 1;
+
+                int verData[][] = new int[nbBars][nbVerBars];  
+                for (int x = 0; x < nbBars; x++) {
+                    for (int i = 0; i < nbVerBars; i++) {
+                        int count = 0;
+                        for (int j = i * bucketsPerVerBar; j < (i + 1) * bucketsPerVerBar; j++) {
+                            if (fNbBuckets <= j)
+                                break;
+                            count += horData[x][j];
+                        }
+                        verData[x][i] = count;
+                    }
+                }
+
+                scaledData.setData(verData);
+                scaledData.setHorFirstBucketTime(fHorDistributionData.getFirstBucketTime());
+                scaledData.setVerFirstBucketTime(fVerDistributionData.getFirstBucketTime());
+                scaledData.setHorFirstEventTime(fHorDistributionData.getFirstEventTime());
+                scaledData.setVerFirstEventTime(fVerDistributionData.getFirstEventTime());
+                scaledData.setHorLastEventTime(fHorDistributionData.getLastEventTime());
+                scaledData.setVerLastEventTime(fVerDistributionData.getLastEventTime());
+                scaledData.setHorBucketDuration(bucketsPerBar * fHorDistributionData.getBucketDuration());
+                scaledData.setVerBucketDuration(bucketsPerVerBar * fVerDistributionData.getBucketDuration());
+                scaledData.setHorLastBucket(fHorDistributionData.getLastBucket() / bucketsPerBar);
+                scaledData.setVerLastBucket(fVerDistributionData.getLastBucket() / bucketsPerVerBar);
+                scaledData.setCurrentEventTime(fCurrentEventTime);
+            }
+        } finally {
+            fLock.unlock();
+        }
+
+        return scaledData;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see org.eclipse.linuxtools.lttng.ui.views.distribution.model.IBaseDataModel#complete()
+     */
+    @Override
+    public void complete() {
+        fireModelUpdateNotification();
+    }
+
+    /**
+     * Sets the current event time but don't notify listeners.
+     * 
+     * @param timestamp
+     */
+    public void setCurrentEvent(long timestamp) {
+        fLock.lock();
+        try {
+            fCurrentEventTime = timestamp;
+        } finally {
+            fLock.unlock();
+        }   
+    }
+
+    /**
+     * Sets the current event time and notify listeners.
+     * 
+     * @param timestamp
+     */
+    public void setCurrentEventNotifyListeners(long timestamp) {
+        fLock.lock();
+        try {
+            fCurrentEventTime = timestamp;
+        } finally {
+            fLock.unlock();
+        }
+        fireCurrentEventUpdateNotification();
+    }
+   
+    // ------------------------------------------------------------------------
+    // Helper functions
+    // ------------------------------------------------------------------------
+
+    /*
+     * Notify listeners immediately
+     */
+    private void fireModelUpdateNotification() {
+        fireModelUpdateNotification(0);
+    }
+    
+    /*
+     * Notify listeners with certain refresh rate.
+     */
+    private void fireModelUpdateNotification(int count) {
+        if (count % Config.POINT_BUFFER_SIZE == 0) {
+            Object[] listeners = fModelListeners.getListeners();
+            for (int i = 0; i < listeners.length; i++) {
+                IGraphModelListener listener = (IGraphModelListener) listeners[i];
+                listener.graphModelUpdated();
+            }
+        }
+    }
+
+    /*
+     * Notify listeners immediately
+     */
+    private void fireCurrentEventUpdateNotification() {
+        Object[] listeners = fModelListeners.getListeners();
+        for (int i = 0; i < listeners.length; i++) {
+            IGraphModelListener listener = (IGraphModelListener) listeners[i];
+            listener.currentEventUpdated(fCurrentEventTime);
+        }
+    }
+}
This page took 0.195792 seconds and 5 git commands to generate.