Commit | Line | Data |
---|---|---|
6e512b93 ASL |
1 | /******************************************************************************* |
2 | * Copyright (c) 2009 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 | * Francois Chouinard - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | ||
13 | package org.eclipse.linuxtools.lttng.ui.views.timeframe; | |
14 | ||
4df4581d | 15 | import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp; |
6c13869b FC |
16 | import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange; |
17 | import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp; | |
6e512b93 ASL |
18 | import org.eclipse.swt.SWT; |
19 | import org.eclipse.swt.events.ModifyEvent; | |
20 | import org.eclipse.swt.events.ModifyListener; | |
21 | import org.eclipse.swt.layout.GridData; | |
22 | import org.eclipse.swt.widgets.Composite; | |
23 | import org.eclipse.swt.widgets.Group; | |
24 | import org.eclipse.swt.widgets.Label; | |
25 | import org.eclipse.swt.widgets.Spinner; | |
26 | ||
27 | // ======================================================================== | |
28 | // SpinnerGroup | |
29 | // ======================================================================== | |
30 | ||
31 | /** | |
32 | * <b><u>SpinnerGroup</u></b> | |
33 | * <p> | |
34 | * A SpinnerGroup holds two coordinated spinners (for seconds and | |
35 | * nanoseconds) representing the current time within the trace. | |
36 | * <p> | |
37 | * The current time can take any value anything within the time range (start | |
38 | * and end time). | |
39 | */ | |
40 | public class SpinnerGroup { | |
41 | ||
42 | // The nanosecond scale (10^9) | |
8d2e2848 FC |
43 | private static final int NS_PER_SECOND = 1000 * 1000 * 1000; |
44 | private static final byte NS_SCALING_FACTOR = -9; | |
6e512b93 | 45 | |
62d1696a | 46 | // Labels |
9c4eb5f7 FC |
47 | private static final String SECONDS_LABEL = "sec"; //$NON-NLS-1$ |
48 | private static final String NANOSEC_LABEL = "ns"; //$NON-NLS-1$ | |
62d1696a | 49 | |
6e512b93 ASL |
50 | // Widgets |
51 | private Group group; | |
52 | private Spinner seconds; | |
53 | private Spinner nanosec; | |
54 | ||
55 | // The valid time range - start time | |
4df4581d | 56 | private ITmfTimestamp startTime; |
6e512b93 ASL |
57 | private int startSeconds; |
58 | private int startNanosec; | |
59 | ||
60 | // The valid time range - end time | |
4df4581d | 61 | private ITmfTimestamp endTime; |
6e512b93 ASL |
62 | private int endSeconds; |
63 | private int endNanosec; | |
64 | ||
65 | // The current time value | |
4df4581d | 66 | private ITmfTimestamp currentTime; |
6e512b93 ASL |
67 | private int currentSeconds; |
68 | private int currentNanosec; | |
69 | ||
6e512b93 ASL |
70 | /** |
71 | * <b><u>Constructor</u></b> | |
72 | * <p> | |
73 | * <li>Creates the display group and formats it for the grid cell | |
74 | * <li>Sets the initial values for Start/End/Current time | |
75 | * </li> | |
76 | * <p> | |
77 | * @param parent - the parent Composite | |
78 | * @param groupName - the group name | |
79 | * @param range - the valid time range (start/end time) | |
80 | * @param current - the current time | |
81 | */ | |
4df4581d | 82 | public SpinnerGroup(TimeFrameView owner, Composite parent, String groupName, TmfTimeRange range, ITmfTimestamp current) { |
6e512b93 | 83 | |
6e512b93 ASL |
84 | // Create the group |
85 | group = new Group(parent, SWT.BORDER); | |
86 | group.setText(groupName); | |
87 | ||
88 | // Make it use the whole grid cell | |
89 | GridData gridData = new GridData(SWT.LEFT, SWT.TOP, true, false); | |
90 | gridData.horizontalAlignment = SWT.FILL; | |
91 | group.setLayoutData(gridData); | |
92 | ||
93 | // Create and position the widgets | |
94 | seconds = new Spinner(group, SWT.BORDER); | |
95 | seconds.addModifyListener(new ModifyListener() { | |
d4011df2 FC |
96 | @Override |
97 | public void modifyText(ModifyEvent e) { | |
6e512b93 ASL |
98 | currentSeconds = seconds.getSelection(); |
99 | refreshCurrentTime(); | |
100 | } | |
101 | }); | |
102 | seconds.setBounds(5, 25, 110, 25); | |
103 | ||
104 | Label label = new Label(group, SWT.LEFT); | |
62d1696a | 105 | label.setText(SECONDS_LABEL); |
6e512b93 ASL |
106 | label.setBounds(120, 28, 25, 22); |
107 | ||
108 | nanosec = new Spinner(group, SWT.BORDER); | |
109 | nanosec.addModifyListener(new ModifyListener() { | |
d4011df2 FC |
110 | @Override |
111 | public void modifyText(ModifyEvent e) { | |
6e512b93 ASL |
112 | currentNanosec = nanosec.getSelection(); |
113 | // Correct for nanosec underflow | |
114 | if (currentNanosec < 0) { | |
115 | currentSeconds--; | |
8d2e2848 | 116 | currentNanosec = NS_PER_SECOND - 1; |
6e512b93 ASL |
117 | } |
118 | // Correct for nanosec overflow | |
8d2e2848 | 119 | if (currentNanosec >= NS_PER_SECOND) { |
6e512b93 ASL |
120 | currentSeconds++; |
121 | currentNanosec = 0; | |
122 | } | |
123 | refreshCurrentTime(); | |
124 | } | |
125 | }); | |
126 | nanosec.setBounds(150, 25, 110, 25); | |
127 | ||
128 | label = new Label(group, SWT.LEFT); | |
62d1696a | 129 | label.setText(NANOSEC_LABEL); |
6e512b93 ASL |
130 | label.setBounds(265, 28, 25, 22); |
131 | ||
132 | setContent(range, current); | |
133 | } | |
134 | ||
135 | private void refreshCurrentTime() { | |
8d2e2848 FC |
136 | long newCurrentTime = ((long) currentSeconds) * NS_PER_SECOND + currentNanosec; |
137 | TmfTimestamp ts = new TmfTimestamp(newCurrentTime, NS_SCALING_FACTOR, 0); | |
6e512b93 | 138 | currentTime = ts; |
09acd610 | 139 | // fOwner.synchTimeFrameWidgets(this); |
6e512b93 ASL |
140 | } |
141 | ||
142 | // ==================================================================== | |
143 | // Get/Set | |
144 | // ==================================================================== | |
145 | ||
4df4581d | 146 | public ITmfTimestamp getStartTime() { |
6e512b93 ASL |
147 | return startTime; |
148 | } | |
149 | ||
4df4581d | 150 | public ITmfTimestamp getEndTime() { |
6e512b93 ASL |
151 | return endTime; |
152 | } | |
153 | ||
4df4581d | 154 | public ITmfTimestamp getCurrentTime() { |
6e512b93 ASL |
155 | return currentTime; |
156 | } | |
157 | ||
158 | public TmfTimestamp getSpan() { | |
5179fc01 | 159 | TmfTimestamp span = (TmfTimestamp) startTime.getDelta(endTime); |
6e512b93 ASL |
160 | return span; |
161 | } | |
162 | ||
163 | public TmfTimeRange getTimeRange() { | |
164 | TmfTimeRange range = new TmfTimeRange(startTime, endTime); | |
165 | return range; | |
166 | } | |
167 | ||
4df4581d | 168 | public void setStartTime(ITmfTimestamp ts) { |
62d1696a | 169 | try { |
5179fc01 | 170 | startTime = (TmfTimestamp) ts.getDelta(new TmfTimestamp(0, NS_SCALING_FACTOR)); |
8d2e2848 FC |
171 | startSeconds = (int) (startTime.getValue() / NS_PER_SECOND); |
172 | startNanosec = (int) (startTime.getValue() % NS_PER_SECOND); | |
62d1696a FC |
173 | } |
174 | catch (ArithmeticException e) { | |
175 | } | |
6e512b93 ASL |
176 | } |
177 | ||
4df4581d | 178 | public void setEndTime(ITmfTimestamp ts) { |
62d1696a | 179 | try { |
5179fc01 | 180 | endTime = (TmfTimestamp) ts.getDelta(new TmfTimestamp(0, NS_SCALING_FACTOR)); |
8d2e2848 FC |
181 | endSeconds = (int) (endTime.getValue() / NS_PER_SECOND); |
182 | endNanosec = (int) (endTime.getValue() % NS_PER_SECOND); | |
62d1696a FC |
183 | } |
184 | catch (ArithmeticException e) { | |
185 | } | |
6e512b93 ASL |
186 | } |
187 | ||
4df4581d | 188 | public void setCurrentTime(ITmfTimestamp ts) { |
62d1696a | 189 | try { |
5179fc01 | 190 | currentTime = (TmfTimestamp) ts.getDelta(new TmfTimestamp(0, NS_SCALING_FACTOR)); |
8d2e2848 FC |
191 | currentSeconds = (int) (currentTime.getValue() / NS_PER_SECOND); |
192 | currentNanosec = (int) (currentTime.getValue() % NS_PER_SECOND); | |
62d1696a FC |
193 | } |
194 | catch (ArithmeticException e) { | |
195 | } | |
6e512b93 ASL |
196 | } |
197 | ||
198 | // ==================================================================== | |
199 | // Operators | |
200 | // ==================================================================== | |
201 | ||
202 | /** | |
203 | * <b><u>setContent</u></b> | |
204 | * <p> | |
205 | * <li>validates that [startTime <= currentTime <= endTime] is respected | |
206 | * <li>sets the start/current/end time and update the spinners | |
207 | * </li> | |
208 | * <p> | |
209 | * | |
210 | * @param range | |
211 | * @param current | |
212 | */ | |
4df4581d | 213 | public void setContent(TmfTimeRange range, ITmfTimestamp current) { |
6e512b93 ASL |
214 | |
215 | if (range != null) { | |
216 | // Extract the time range | |
4df4581d | 217 | ITmfTimestamp start = range.getStartTime(); |
218 | ITmfTimestamp end = range.getEndTime(); | |
6e512b93 ASL |
219 | |
220 | // Assume start time is OK | |
221 | setStartTime(start); | |
222 | ||
223 | // Make sure end time >= start time | |
224 | if (end.compareTo(start, false) < 0) { | |
225 | end = start; | |
226 | } | |
227 | setEndTime(end); | |
228 | ||
229 | // Make sure [start time <= current time <= end time] | |
230 | // If not: current = min(max(start, current), end); | |
231 | if (current.compareTo(start, false) < 0) { | |
232 | current = start; | |
233 | } | |
234 | if (current.compareTo(end, false) > 0) { | |
235 | current = end; | |
236 | } | |
237 | } | |
238 | setCurrentTime(current); | |
239 | ||
240 | // And configure the spinners | |
241 | updateSpinners(); | |
242 | } | |
243 | ||
244 | /** | |
245 | * <b><u>setValue</u></b> | |
246 | * <p> | |
247 | * <li>validates that [startTime <= currentTime <= endTime] is respected | |
248 | * <li>sets the current time and the spinners | |
249 | * </li> | |
250 | * <p> | |
251 | * | |
252 | * @param range | |
253 | * @param current | |
254 | */ | |
4df4581d | 255 | public void setValue(ITmfTimestamp current) { |
6e512b93 ASL |
256 | |
257 | // Make sure [start time <= current time <= end time] | |
258 | // If not: current = min(max(start, current), end); | |
259 | if (current.compareTo(startTime, false) < 0) { | |
260 | current = startTime; | |
261 | } | |
262 | if (current.compareTo(endTime, false) > 0) { | |
263 | current = endTime; | |
264 | } | |
265 | setCurrentTime(current); | |
266 | ||
267 | // And configure the spinners | |
268 | updateSpinners(); | |
269 | } | |
270 | ||
271 | /** | |
272 | * Update the spinners with the new current time value | |
273 | * Perform the update on the UI thread | |
274 | */ | |
275 | public void updateSpinners() { | |
db1ea19b FC |
276 | // Ignore update if disposed |
277 | if (seconds.isDisposed()) return; | |
278 | ||
6e512b93 | 279 | seconds.getDisplay().asyncExec(new Runnable() { |
d4011df2 | 280 | @Override |
6e512b93 ASL |
281 | public void run() { |
282 | if (!seconds.isDisposed() && !nanosec.isDisposed()) { | |
283 | // If we are on the start second, ensure that [currentNS >= startNS] | |
284 | // If the currentSeconds > startSeconds, set startns to -1 so we can | |
285 | // "underflow" | |
286 | int startns = -1; | |
287 | if (currentSeconds <= startSeconds) { | |
288 | currentSeconds = startSeconds; | |
289 | startns = startNanosec; | |
290 | if (currentNanosec < startns) { | |
291 | currentNanosec = startns; | |
292 | } | |
293 | } | |
294 | ||
295 | // If we are on the end second, ensure that [currentNS <= endNS] | |
296 | // If the currentSeconds < endSeconds, set endns to MAX so we can | |
297 | // "overflow" | |
8d2e2848 | 298 | int endns = NS_PER_SECOND; |
6e512b93 ASL |
299 | if (currentSeconds >= endSeconds) { |
300 | currentSeconds = endSeconds; | |
301 | endns = endNanosec; | |
302 | if (currentNanosec > endns) { | |
303 | currentNanosec = endns; | |
304 | } | |
305 | } | |
306 | ||
307 | // Refresh the spinners (value, range, increments, ...) | |
308 | // To ensure that the spinners are properly set, the range has to be > 0 | |
09acd610 FC |
309 | // seconds.setValues(currentSeconds, startSeconds - 1, endSeconds + 1, 0, 1, 10); |
310 | // nanosec.setValues(currentNanosec, startns - 1, endns + 1, 0, 1, 1000000); | |
311 | seconds.setValues(currentSeconds, startSeconds, endSeconds, 0, 1, 10); | |
312 | nanosec.setValues(currentNanosec, startns, endns, 0, 100000, 10000000); | |
6e512b93 ASL |
313 | |
314 | // If start == end (i.e. no range), disable the spinner | |
315 | // (if start == end, the spinner widget range is set to [0..100] by default) | |
316 | seconds.setEnabled(startSeconds != endSeconds); | |
317 | nanosec.setEnabled(startns != endns); | |
318 | } | |
319 | } | |
320 | }); | |
321 | } | |
bf5aa8e4 | 322 | } |