tmf: Rename "Next/Previous Event" action to "Next/Previous State Change"
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / TmfUiRefreshHandler.java
CommitLineData
9c91c317
AM
1/*******************************************************************************
2 * Copyright (c) 2014 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Alexandre Montplaisir - Initial API and implementation
aae89862 11 * Patrick Tasse - Update queue handling
9c91c317
AM
12 *******************************************************************************/
13
2bdf0193 14package org.eclipse.tracecompass.tmf.ui;
9c91c317 15
aae89862 16import java.util.LinkedHashMap;
9c91c317 17import java.util.Map;
9c91c317 18
9c91c317
AM
19import org.eclipse.swt.widgets.Display;
20
9c91c317
AM
21/**
22 * This handler offers "coalescing" of UI updates.
23 *
24 * When displaying live experiments containing a high number of traces, every
25 * trace will want to regularly update views with their new available data. This
26 * can cause a high number of threads calling {@link Display#asyncExec}
27 * repeatedly, which can really impede UI responsiveness.
28 * <p>
29 * Instead of calling {@link Display#asyncExec} directly, threads that want to
30 * queue updates to the UI can instead call
aae89862
PT
31 * {@link TmfUiRefreshHandler#queueUpdate}. If the handler is not currently
32 * executing another update it will be scheduled immediately. Otherwise the
33 * update will be queued.
34 * <p>
35 * The handler will only execute one update at a time. While it is busy, new
36 * requests received from a source that is already in the queue will replace the
37 * previous one (as we assume the latest UI update request is the most
38 * up-to-date and interesting one), preserving the previous request order. New
39 * requests received from other sources will be added to the end of the queue
40 * (keeping only the latest request from each source).
41 * <p>
42 * Once the current update is completed, the oldest request in the queue will be
43 * sent to the UI thread via one single call to {@link Display#syncExec}.
9c91c317
AM
44 *
45 * @author Alexandre Montplaisir
9c91c317
AM
46 */
47public class TmfUiRefreshHandler {
48
9c91c317
AM
49 /** Singleton instance */
50 private static TmfUiRefreshHandler fInstance = null;
51
aae89862
PT
52 private final Map<Object, Runnable> fUpdates = new LinkedHashMap<>();
53 private Thread fCurrentTask;
9c91c317
AM
54
55
56 /**
57 * Internal constructor
58 */
59 private TmfUiRefreshHandler() {
9c91c317
AM
60 fCurrentTask = null;
61 }
62
63 /**
64 * Get the handler's instance
65 *
66 * @return The singleton instance
67 */
68 public static synchronized TmfUiRefreshHandler getInstance() {
69 if (fInstance == null) {
70 fInstance = new TmfUiRefreshHandler();
71 }
72 return fInstance;
73 }
74
75 /**
76 * Cancel all current requests and dispose the handler.
77 */
78 public synchronized void dispose() {
aae89862 79 fUpdates.clear();
9c91c317 80 fCurrentTask = null;
9c91c317
AM
81 }
82
83 /**
84 * Queue a UI update. Threads that want to benefit from "UI coalescing"
85 * should send their {@link Runnable} to this method, instead of
86 * {@link Display#asyncExec(Runnable)}.
87 *
88 * @param source
aae89862
PT
89 * The source sending the request. Typically callers should use
90 * "this". When multiple requests are queued before being
91 * executed, only the latest request per source is actually sent.
9c91c317
AM
92 * @param task
93 * The {@link Runnable} to execute in the UI thread.
94 */
aae89862 95 public synchronized void queueUpdate(Object source, Runnable task) {
9c91c317
AM
96 fUpdates.put(source, task);
97 if (fCurrentTask == null) {
98 fCurrentTask = new RunAllUpdates();
aae89862 99 fCurrentTask.start();
9c91c317
AM
100 }
101 }
102
103 /**
aae89862 104 * Task to empty the update queue, and send each task to the UI thread.
9c91c317 105 */
aae89862 106 private class RunAllUpdates extends Thread {
9c91c317
AM
107 @Override
108 public void run() {
aae89862
PT
109 while (true) {
110 Runnable nextTask = null;
111 synchronized (TmfUiRefreshHandler.this) {
112 if (!fUpdates.isEmpty()) {
113 Object firstKey = fUpdates.keySet().iterator().next();
114 nextTask = fUpdates.get(firstKey);
115 fUpdates.remove(firstKey);
116 }
117 if (nextTask == null) {
118 /*
119 * No updates remaining in the queue, put fCurrentTask
120 * back to null so that a new task can be scheduled.
121 */
122 fCurrentTask = null;
123 break;
9c91c317
AM
124 }
125 }
aae89862 126 Display.getDefault().syncExec(nextTask);
9c91c317
AM
127 }
128 }
129 }
130}
This page took 0.078752 seconds and 5 git commands to generate.