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 | * William Bourque - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | package org.eclipse.linuxtools.lttng.ui.views.histogram; | |
13 | ||
14 | import org.eclipse.linuxtools.lttng.event.LttngEvent; | |
15 | import org.eclipse.linuxtools.lttng.event.LttngTimestamp; | |
9aae0442 ASL |
16 | import org.eclipse.linuxtools.tmf.component.ITmfDataProvider.ExecutionType; |
17 | import org.eclipse.linuxtools.tmf.event.TmfEvent; | |
6e512b93 ASL |
18 | import org.eclipse.linuxtools.tmf.event.TmfTimeRange; |
19 | import org.eclipse.linuxtools.tmf.event.TmfTimestamp; | |
20 | import org.eclipse.linuxtools.tmf.experiment.TmfExperiment; | |
21 | import org.eclipse.linuxtools.tmf.signal.TmfExperimentSelectedSignal; | |
22 | import org.eclipse.linuxtools.tmf.signal.TmfExperimentUpdatedSignal; | |
23 | import org.eclipse.linuxtools.tmf.signal.TmfRangeSynchSignal; | |
24 | import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler; | |
25 | import org.eclipse.linuxtools.tmf.signal.TmfTimeSynchSignal; | |
9aae0442 ASL |
26 | import org.eclipse.linuxtools.tmf.trace.ITmfTrace; |
27 | import org.eclipse.linuxtools.tmf.trace.TmfContext; | |
6e512b93 ASL |
28 | import org.eclipse.linuxtools.tmf.ui.views.TmfView; |
29 | import org.eclipse.swt.SWT; | |
30 | import org.eclipse.swt.events.ControlEvent; | |
31 | import org.eclipse.swt.events.ControlListener; | |
32 | import org.eclipse.swt.graphics.Font; | |
33 | import org.eclipse.swt.graphics.FontData; | |
34 | import org.eclipse.swt.layout.GridData; | |
35 | import org.eclipse.swt.layout.GridLayout; | |
36 | import org.eclipse.swt.widgets.Composite; | |
37 | import org.eclipse.swt.widgets.Text; | |
38 | ||
39 | /** | |
40 | * <b><u>HistogramView</u></b> | |
41 | * <p> | |
42 | * View that contain an visual approach to the window that control the request. | |
43 | * This is intended to replace the TimeFrameView | |
44 | * <p> | |
45 | * This view is composed of 2 canvas, one for the whole experiment and one for the selectionned window in the experiment. | |
46 | * It also contain a certain number of controls to print or change informations about the experiment. | |
47 | */ | |
48 | public class HistogramView extends TmfView implements ControlListener { | |
49 | ||
50 | // *** TODO *** | |
51 | // Here is what's left to do in this view | |
52 | // | |
53 | // 1- Make sure the interval time is small enought on very big trace (bug 311930) | |
54 | // The interval time of the content is dynamically assigned from the screen width and trace duration. | |
55 | // However, on very big trace (more than 1 hour), we could end up with time interval that are > 1 seconds, | |
56 | // which is not very precise. | |
57 | // An algorithm need to be implemented to make sure we "increase" the number of interval in the content if | |
58 | // their precision is getting too bad. | |
59 | // | |
60 | // 2- Make sure all control are thread safe (bug 309348) | |
61 | // Right now, all the basic controls (i.e. Text and Label) are sensible to "Thread Access Exception" if | |
62 | // updated from different threads; we need to carefully decide when/where to redraw them. | |
63 | // This is a real problem since there is a lot of thread going on in this view. | |
64 | // All basic control should be subclassed to offer "Asynchronous" functions. | |
65 | // | |
66 | // 3- Implement a "preferences view" for the HistogramView (bug 311935) | |
67 | // There is a lot of ajustable preferences in the view, however there is no way to ajust them right now | |
68 | // at run time. There should be a view of some kind of "menu" to allow the user to change them while executing. | |
69 | // Most of the pertinent values are in HistogramConstant.java or in this file. | |
70 | ||
71 | public static final String ID = "org.eclipse.linuxtools.lttng.ui.views.histogram"; | |
72 | ||
73 | // "Minimum" screen width size. On smaller screen, we will apply several space saving technique | |
74 | private static final int SCREEN_SMALL_IF_SMALLER_THAN = 1600; | |
75 | ||
76 | // Size of the "fulll trace" canvas | |
77 | private static final int FULL_TRACE_CANVAS_HEIGHT = 25; | |
78 | private static final int FULL_TRACE_BAR_WIDTH = 1; | |
79 | private static final double FULL_TRACE_DIFFERENCE_TO_AVERAGE = 1.5; | |
80 | ||
81 | // Size of the "Selected Window" canvas | |
82 | private static final int SELECTED_WINDOW_CANVAS_WIDTH = 300; | |
83 | private static final int SMALL_SELECTED_WINDOW_CANVAS_WIDTH = 200; | |
84 | private static final int SELECTED_WINDOW_CANVAS_HEIGHT = 60; | |
85 | private static final int SELECTED_WINDOW_BAR_WIDTH = 1; | |
86 | private static final double SELECTED_WINDOW_DIFFERENCE_TO_AVERAGE = 10.0; | |
87 | ||
88 | // For the two "events" label (Max and min number of events in the selection), we force a width | |
89 | // This will prevent the control from moving horizontally if the number of events in the selection varies | |
90 | private static final int NB_EVENTS_FIXED_WIDTH = 50; | |
91 | ||
92 | ||
93 | // The "small font" height used to display time will be "default font" minus this constant | |
94 | private static final int SMALL_FONT_MODIFIER = 2; | |
95 | private static final int VERY_SMALL_FONT_MODIFIER = 4; | |
96 | ||
97 | // *** TODO *** | |
98 | // This need to be changed as soon the framework implement a "window" | |
99 | private static long DEFAULT_WINDOW_SIZE = (1L * 100 * 1000 * 1000); // 0.1sec | |
100 | ||
101 | // The last experiment received/used by the view | |
102 | private TmfExperiment<LttngEvent> lastUsedExperiment = null; | |
103 | ||
104 | // Parent of the view | |
105 | private Composite parent = null; | |
106 | ||
107 | // Request and canvas for the "full trace" part | |
108 | private HistogramRequest dataBackgroundFullRequest = null; | |
109 | private ParentHistogramCanvas fullExperimentCanvas = null; | |
110 | ||
111 | // Request and canvas for the "selected window" | |
112 | private HistogramRequest selectedWindowRequest = null; | |
113 | private ChildrenHistogramCanvas selectedWindowCanvas = null; | |
114 | ||
115 | // Content of the timeTextGroup | |
116 | // Since the user can modify them with erroneous value, | |
117 | // we will keep track of the value internally | |
118 | private long selectedWindowTime = 0L; | |
119 | private long selectedWindowTimerange = 0L; | |
120 | private long currentEventTime = 0L; | |
121 | ||
122 | // *** All the UI control below | |
123 | // | |
124 | // NOTE : All textboxes will be READ_ONLY. | |
125 | // So the user will be able to select/copy the value in them but not to change it | |
126 | private Text txtExperimentStartTime = null; | |
127 | private Text txtExperimentStopTime = null; | |
128 | ||
129 | private Text txtWindowStartTime = null; | |
130 | private Text txtWindowStopTime = null; | |
131 | private Text txtWindowMaxNbEvents = null; | |
132 | private Text txtWindowMinNbEvents = null; | |
133 | ||
134 | private static final String WINDOW_TIMERANGE_LABEL_TEXT = "Window Timerange "; | |
135 | private static final String WINDOW_CURRENT_TIME_LABEL_TEXT = "Cursor Centered on "; | |
136 | private static final String EVENT_CURRENT_TIME_LABEL_TEXT = "Current Event Time "; | |
137 | private TimeTextGroup ntgTimeRangeWindow = null; | |
138 | private TimeTextGroup ntgCurrentWindowTime = null; | |
139 | private TimeTextGroup ntgCurrentEventTime = null; | |
140 | ||
141 | /** | |
142 | * Default contructor of the view | |
143 | */ | |
144 | public HistogramView() { | |
145 | super(ID); | |
146 | } | |
147 | ||
148 | /** | |
149 | * Create the UI controls of this view | |
150 | * | |
151 | * @param parent The composite parent of this view | |
152 | */ | |
153 | @Override | |
154 | public void createPartControl(Composite newParent) { | |
155 | // Save the parent | |
156 | parent = newParent; | |
157 | ||
158 | // Default font | |
159 | Font font = parent.getFont(); | |
160 | FontData tmpFontData = font.getFontData()[0]; | |
161 | ||
162 | ||
163 | Font smallFont = null; | |
164 | int nbEventWidth = -1; | |
165 | int selectedCanvasWidth = -1; | |
166 | boolean doesTimeTextGroupNeedAdjustment = false; | |
167 | ||
168 | // Calculate if we need "small screen" fixes | |
169 | if ( parent.getDisplay().getBounds().width < SCREEN_SMALL_IF_SMALLER_THAN ) { | |
170 | // A lot smaller font for timstampe | |
171 | smallFont = new Font(font.getDevice(), tmpFontData.getName(), tmpFontData.getHeight() - VERY_SMALL_FONT_MODIFIER, tmpFontData.getStyle()); | |
172 | ||
173 | // Smaller selection window canvas | |
174 | selectedCanvasWidth = SMALL_SELECTED_WINDOW_CANVAS_WIDTH; | |
175 | // Smaller event number text field | |
176 | nbEventWidth = NB_EVENTS_FIXED_WIDTH/2; | |
177 | ||
178 | // Tell the text group to ajust | |
179 | doesTimeTextGroupNeedAdjustment = true; | |
180 | } | |
181 | else { | |
182 | // Slightly smaller font for timestamp | |
183 | smallFont = new Font(font.getDevice(), tmpFontData.getName(), tmpFontData.getHeight() - SMALL_FONT_MODIFIER, tmpFontData.getStyle()); | |
184 | // Usual size for selected window and event number text field | |
185 | nbEventWidth = NB_EVENTS_FIXED_WIDTH; | |
186 | selectedCanvasWidth = SELECTED_WINDOW_CANVAS_WIDTH; | |
187 | // No ajustement needed by the text group | |
188 | doesTimeTextGroupNeedAdjustment = false; | |
189 | } | |
190 | ||
191 | // Layout for the whole view, other elements will be in a child composite of this one | |
192 | // Contains : | |
193 | // Composite layoutSelectionWindow | |
194 | // Composite layoutTimesSpinner | |
195 | // Composite layoutExperimentHistogram | |
196 | Composite layoutFullView = new Composite(parent, SWT.NONE); | |
197 | GridLayout gridFullView = new GridLayout(); | |
198 | gridFullView.numColumns = 2; | |
199 | gridFullView.horizontalSpacing = 0; | |
200 | gridFullView.verticalSpacing = 0; | |
201 | gridFullView.marginHeight = 0; | |
202 | gridFullView.marginWidth = 0; | |
203 | layoutFullView.setLayout(gridFullView); | |
204 | ||
205 | ||
206 | // Layout that contain the SelectionWindow | |
207 | // Contains : | |
208 | // Label lblWindowStartTime | |
209 | // Label lblWindowStopTime | |
210 | // Label lblWindowMaxNbEvents | |
211 | // Label lblWindowMinNbEvents | |
212 | // ChildrenHistogramCanvas selectedWindowCanvas | |
213 | Composite layoutSelectionWindow = new Composite(layoutFullView, SWT.NONE); | |
214 | GridLayout gridSelectionWindow = new GridLayout(); | |
215 | gridSelectionWindow.numColumns = 3; | |
216 | gridSelectionWindow.marginHeight = 0; | |
217 | gridSelectionWindow.marginWidth = 0; | |
218 | gridSelectionWindow.horizontalSpacing = 0; | |
219 | gridSelectionWindow.verticalSpacing = 0; | |
220 | layoutSelectionWindow.setLayout(gridSelectionWindow); | |
221 | GridData gridDataSelectionWindow = new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1); | |
222 | layoutSelectionWindow.setLayoutData(gridDataSelectionWindow); | |
223 | ||
224 | ||
225 | // Layout that contain the time spinner | |
226 | // Contains : | |
227 | // NanosecTextGroup spTimeRangeWindow | |
228 | // NanosecTextGroup spCurrentWindowTime | |
229 | // NanosecTextGroup spCurrentEventTime | |
230 | Composite layoutTimesSpinner = new Composite(layoutFullView, SWT.NONE); | |
231 | GridLayout gridTimesSpinner = new GridLayout(); | |
232 | gridTimesSpinner.numColumns = 3; | |
233 | gridTimesSpinner.marginHeight = 0; | |
234 | gridTimesSpinner.marginWidth = 0; | |
235 | gridTimesSpinner.horizontalSpacing = 0; | |
236 | gridTimesSpinner.verticalSpacing = 0; | |
237 | layoutTimesSpinner.setLayout(gridTimesSpinner); | |
238 | GridData gridDataTimesSpinner = new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1); | |
239 | layoutTimesSpinner.setLayoutData(gridDataTimesSpinner); | |
240 | ||
241 | ||
242 | // Layout that contain the complete experiment histogram and related controls. | |
243 | // Contains : | |
244 | // Label lblExperimentStartTime | |
245 | // Label lblExperimentStopTime | |
246 | // ParentHistogramCanvas fullTraceCanvas | |
247 | Composite layoutExperimentHistogram = new Composite(layoutFullView, SWT.NONE); | |
248 | GridLayout gridExperimentHistogram = new GridLayout(); | |
249 | gridExperimentHistogram.numColumns = 2; | |
250 | gridExperimentHistogram.marginHeight = 0; | |
251 | gridExperimentHistogram.marginWidth = 0; | |
252 | gridExperimentHistogram.horizontalSpacing = 0; | |
253 | gridExperimentHistogram.verticalSpacing = 0; | |
254 | layoutExperimentHistogram.setLayout(gridExperimentHistogram); | |
255 | GridData gridDataExperimentHistogram = new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1); | |
256 | layoutExperimentHistogram.setLayoutData(gridDataExperimentHistogram); | |
257 | ||
258 | ||
259 | ||
260 | // *** Everything related to the selection window is below | |
261 | GridData gridDataSelectionWindowCanvas = new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 2); | |
262 | gridDataSelectionWindowCanvas.heightHint = SELECTED_WINDOW_CANVAS_HEIGHT; | |
263 | gridDataSelectionWindowCanvas.minimumHeight = SELECTED_WINDOW_CANVAS_HEIGHT; | |
264 | gridDataSelectionWindowCanvas.widthHint = selectedCanvasWidth; | |
265 | gridDataSelectionWindowCanvas.minimumWidth = selectedCanvasWidth; | |
266 | selectedWindowCanvas = new ChildrenHistogramCanvas(this, layoutSelectionWindow, SWT.BORDER); | |
267 | selectedWindowCanvas.setLayoutData(gridDataSelectionWindowCanvas); | |
268 | ||
269 | GridData gridDataWindowMaxEvents = new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1); | |
270 | // Force a width, to avoid the control to enlarge if the number of events change | |
271 | gridDataWindowMaxEvents.minimumWidth = nbEventWidth; | |
272 | txtWindowMaxNbEvents = new Text(layoutSelectionWindow, SWT.READ_ONLY); | |
273 | txtWindowMaxNbEvents.setFont(smallFont); | |
274 | txtWindowMaxNbEvents.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); | |
275 | txtWindowMaxNbEvents.setEditable(false); | |
276 | txtWindowMaxNbEvents.setText(""); | |
277 | txtWindowMaxNbEvents.setLayoutData(gridDataWindowMaxEvents); | |
278 | ||
279 | GridData gridDataWindowMinEvents = new GridData(SWT.LEFT, SWT.BOTTOM, true, false, 1, 1); | |
280 | // Force a width, to avoid the control to enlarge if the number of events change | |
281 | gridDataWindowMinEvents.minimumWidth = nbEventWidth; | |
282 | txtWindowMinNbEvents = new Text(layoutSelectionWindow, SWT.READ_ONLY); | |
283 | txtWindowMinNbEvents.setFont(smallFont); | |
284 | txtWindowMinNbEvents.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); | |
285 | txtWindowMinNbEvents.setEditable(false); | |
286 | txtWindowMinNbEvents.setText(""); | |
287 | txtWindowMinNbEvents.setLayoutData(gridDataWindowMinEvents); | |
288 | ||
289 | GridData gridDataWindowStart = new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1); | |
290 | txtWindowStartTime = new Text(layoutSelectionWindow, SWT.READ_ONLY); | |
291 | txtWindowStartTime.setFont(smallFont); | |
292 | txtWindowStartTime.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); | |
293 | txtWindowStartTime.setEditable(false); | |
294 | txtWindowStartTime.setText(""); | |
295 | txtWindowStartTime.setLayoutData(gridDataWindowStart); | |
296 | ||
297 | GridData gridDataWindowStop = new GridData(SWT.RIGHT, SWT.TOP, false, false, 1, 1); | |
298 | txtWindowStopTime = new Text(layoutSelectionWindow, SWT.READ_ONLY); | |
299 | txtWindowStopTime.setFont(smallFont); | |
300 | txtWindowStopTime.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); | |
301 | txtWindowStopTime.setEditable(false); | |
302 | txtWindowStopTime.setText(""); | |
303 | txtWindowStopTime.setLayoutData(gridDataWindowStop); | |
304 | ||
305 | GridData gridDataSpacer = new GridData(SWT.FILL, SWT.TOP, true, true, 1, 1); | |
306 | gridDataSpacer.minimumWidth = nbEventWidth; | |
307 | // *** HACK *** | |
308 | // To align properly AND to make sure the canvas size is fixed, we NEED to make sure all "section" of the | |
309 | // gridlayout are taken (and if possible of a fixed size). | |
310 | // However, SWT is VERY VERY DUMB and won't consider griddata that contain no control. | |
311 | // Since there will be missing a section, the SelectedWindowCanvas + NbEventsText will take 3 spaces, but | |
312 | // startTimeText + stopTimeText will take only 2 (as if empty the other griddata of 1 will get ignored). | |
313 | // StopTime will then take over the missing space; I want to align "stopTime" right on the end of canvas, so | |
314 | // the added space to stop time would make it being aligned improperly | |
315 | // So I NEED the empty griddata to be considered! | |
316 | // Visually : | |
317 | // |---------------|---------------|-----------| | |
318 | // |SelectionCanvas SelectionCanvas|NbEventText| | |
319 | // |SelectionCanvas SelectionCanvas|NbEventText| | |
320 | // |---------------|---------------|-----------| | |
321 | // |StartTime | StopTime| ??? | | |
322 | // |---------------|---------------|-----------| | |
323 | // | |
324 | // So since SWT will only consider griddata with control, | |
325 | // I need to create a totally useless control in the ??? section. | |
326 | // That's ugly, useless and it is generally a bad practice. | |
327 | // | |
328 | // *** SUB-HACK *** | |
329 | // Other interesting fact about SWT : the way it draws (Fill/Expand control in grid) will change if | |
330 | // the control is a Text or a Label. | |
331 | // A Label here will be "pushed" by startTime/stopTime Text and won't fill the full space as NbEventText. | |
332 | // A Text here will NOT be "pushed" and would give a nice visual output. | |
333 | // (NB : No, I am NOT kidding, try it for yourself!) | |
334 | // | |
335 | // Soooooo I guess I will use a Text here. Way to go SWT! | |
336 | // Downside is that disabled textbox has a slightly different color (even if you force it yourself) so if I want | |
337 | // to make the text "invisible", I have to keep it enabled (but read only), so it can be clicked on. | |
338 | // | |
339 | // Label uselessControlToByPassSWTStupidBug = new Label(layoutSelectionWindow, SWT.BORDER); // WON'T align correctly!!! | |
340 | Text uselessControlToByPassSWTStupidBug = new Text(layoutSelectionWindow, SWT.READ_ONLY); // WILL align correctly!!! | |
341 | uselessControlToByPassSWTStupidBug.setEditable(false); | |
342 | uselessControlToByPassSWTStupidBug.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); | |
343 | uselessControlToByPassSWTStupidBug.setLayoutData(gridDataSpacer); | |
344 | ||
345 | ||
346 | ||
347 | // *** Everything related to the time text group is below | |
348 | GridData gridDataCurrentEvent = new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 2); | |
349 | ntgCurrentEventTime = new TimeTextGroup(this, layoutTimesSpinner, SWT.BORDER, SWT.BORDER, EVENT_CURRENT_TIME_LABEL_TEXT, HistogramConstant.formatNanoSecondsTime( 0L ), doesTimeTextGroupNeedAdjustment); | |
350 | ntgCurrentEventTime.setLayoutData(gridDataCurrentEvent); | |
351 | ||
352 | GridData gridDataTimeRange = new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 2); | |
353 | ntgTimeRangeWindow = new TimeTextGroup(this, layoutTimesSpinner, SWT.BORDER, SWT.BORDER, WINDOW_TIMERANGE_LABEL_TEXT, HistogramConstant.formatNanoSecondsTime( 0L ), doesTimeTextGroupNeedAdjustment); | |
354 | ntgTimeRangeWindow.setLayoutData(gridDataTimeRange); | |
355 | ||
356 | GridData gridDataCurrentWindow = new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 2); | |
357 | ntgCurrentWindowTime = new TimeTextGroup(this, layoutTimesSpinner, SWT.BORDER, SWT.BORDER, WINDOW_CURRENT_TIME_LABEL_TEXT, HistogramConstant.formatNanoSecondsTime( 0L ), doesTimeTextGroupNeedAdjustment); | |
358 | ntgCurrentWindowTime.setLayoutData(gridDataCurrentWindow); | |
359 | ||
360 | ||
361 | ||
362 | // *** Everything related to the experiment canvas is below | |
363 | GridData gridDataExperimentCanvas = new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1); | |
364 | gridDataExperimentCanvas.heightHint = FULL_TRACE_CANVAS_HEIGHT; | |
365 | gridDataExperimentCanvas.minimumHeight = FULL_TRACE_CANVAS_HEIGHT; | |
366 | fullExperimentCanvas = new ParentHistogramCanvas(this, layoutExperimentHistogram, SWT.BORDER); | |
367 | fullExperimentCanvas.setLayoutData(gridDataExperimentCanvas); | |
368 | ||
369 | GridData gridDataExperimentStart = new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1); | |
370 | txtExperimentStartTime = new Text(layoutExperimentHistogram, SWT.READ_ONLY); | |
371 | txtExperimentStartTime.setFont(smallFont); | |
372 | txtExperimentStartTime.setText(""); | |
373 | txtExperimentStartTime.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); | |
374 | txtExperimentStartTime.setEditable(false); | |
375 | txtExperimentStartTime.setLayoutData(gridDataExperimentStart); | |
376 | ||
377 | GridData gridDataExperimentStop = new GridData(SWT.RIGHT, SWT.TOP, false, false, 1, 1); | |
378 | txtExperimentStopTime = new Text(layoutExperimentHistogram, SWT.READ_ONLY); | |
379 | txtExperimentStopTime.setFont(smallFont); | |
380 | txtExperimentStopTime.setText(""); | |
381 | txtExperimentStopTime.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); | |
382 | txtExperimentStopTime.setEditable(false); | |
383 | txtExperimentStopTime.setLayoutData(gridDataExperimentStop); | |
384 | } | |
385 | ||
386 | // *** FIXME *** | |
387 | // This is mainly used because of a because in the "experimentSelected()" notification, we shouldn't need this | |
388 | /** | |
389 | * Method called when the view receive the focus.<p> | |
390 | * If ExperimentSelected didn't send us a request yet, get the current Experiment and fire requests | |
391 | */ | |
392 | @SuppressWarnings("unchecked") | |
393 | @Override | |
394 | public void setFocus() { | |
395 | // WARNING : This does not seem to be thread safe | |
396 | TmfExperiment<LttngEvent> tmpExperiment = (TmfExperiment<LttngEvent>)TmfExperiment.getCurrentExperiment(); | |
397 | ||
398 | if ( (dataBackgroundFullRequest == null) && (tmpExperiment != null) ) { | |
399 | createCanvasAndRequests(tmpExperiment); | |
400 | } | |
401 | ||
402 | // Call a redraw for everything | |
403 | parent.redraw(); | |
404 | } | |
405 | ||
406 | /** | |
407 | * Method called when the user select (double-click on) an experiment.<p> | |
408 | * We will create the needed canvas and fire the requests. | |
409 | * | |
410 | * @param signal Signal received from the framework. Contain the experiment. | |
411 | */ | |
412 | @SuppressWarnings("unchecked") | |
413 | @TmfSignalHandler | |
414 | public void experimentSelected(TmfExperimentSelectedSignal<LttngEvent> signal) { | |
415 | TmfExperiment<LttngEvent> tmpExperiment = (TmfExperiment<LttngEvent>)signal.getExperiment(); | |
416 | createCanvasAndRequests(tmpExperiment); | |
417 | } | |
418 | ||
419 | // *** VERIFY *** | |
420 | // Not sure what this should do since I don't know when it will be called | |
421 | // Let's do the same thing as experimentSelected for now | |
422 | // | |
423 | /** | |
424 | * Method called when an experiment is updated (??).<p> | |
425 | * ...for now, do nothing, as udating an experiment running in the background might cause crash | |
426 | * | |
427 | * @param signal Signal received from the framework. Contain the experiment. | |
428 | */ | |
429 | // @SuppressWarnings("unchecked") | |
430 | @TmfSignalHandler | |
431 | public void experimentUpdated(TmfExperimentUpdatedSignal signal) { | |
432 | // | |
433 | // TmfExperiment<LttngEvent> tmpExperiment = (TmfExperiment<LttngEvent>)signal.getExperiment(); | |
434 | // | |
435 | // // Make sure the UI object are sane | |
436 | // resetControlsContent(); | |
437 | // | |
438 | // // Redraw the canvas right away to have something "clean" as soon as we can | |
439 | // fullExperimentCanvas.redraw(); | |
440 | // selectedWindowCanvas.redraw(); | |
441 | // | |
442 | // // Recreate the request | |
443 | // createCanvasAndRequests(tmpExperiment); | |
444 | } | |
445 | ||
446 | /** | |
447 | * Method called when synchonization is active and that the user select an event.<p> | |
448 | * We update the current event timeTextGroup and move the selected window if needed. | |
449 | * | |
450 | * @param signal Signal received from the framework. Contain the event. | |
451 | */ | |
452 | @TmfSignalHandler | |
453 | public void currentTimeUpdated(TmfTimeSynchSignal signal) { | |
454 | // In case we received our own signal | |
455 | if (signal.getSource() != this) { | |
456 | TmfTimestamp currentTime = signal.getCurrentTime(); | |
457 | ||
458 | // Update the current event controls | |
459 | currentEventTime = currentTime.getValue(); | |
460 | updateSelectedEventTime(); | |
461 | ||
462 | // If the given event is outside the selection window, recenter the window | |
463 | if ( isGivenTimestampInSelectedWindow( currentEventTime ) == false) { | |
464 | fullExperimentCanvas.setWindowCenterPosition( fullExperimentCanvas.getHistogramContent().getClosestXPositionFromTimestamp(currentEventTime) ); | |
465 | // Notify control that the window changed | |
466 | windowChangedNotification(); | |
467 | // Send a broadcast to the framework about the window change | |
468 | sendTmfRangeSynchSignalBroadcast(); | |
469 | } | |
470 | } | |
471 | } | |
472 | ||
473 | @TmfSignalHandler | |
474 | public void synchToTimeRange(TmfRangeSynchSignal signal) { | |
475 | if ( (signal != null) && (signal.getSource() != this) ) { | |
476 | if ( lastUsedExperiment != null ) { | |
477 | long currentTime = signal.getCurrentTime().getValue(); | |
478 | long windowStart = signal.getCurrentRange().getStartTime().getValue(); | |
479 | long windowEnd = signal.getCurrentRange().getEndTime().getValue(); | |
480 | long windowTimeWidth = (windowEnd - windowStart); | |
481 | ||
482 | // Recenter the window | |
483 | fullExperimentCanvas.setWindowCenterPosition( fullExperimentCanvas.getHistogramContent().getClosestXPositionFromTimestamp(windowStart + (windowTimeWidth/2)) ); | |
484 | fullExperimentCanvas.setSelectedWindowSize(windowTimeWidth); | |
485 | ||
486 | // *** HACK *** | |
487 | // Views could send us incorrect current event value (event outside the current window) | |
488 | // Here we make sure the value is sane, otherwise, we force it as the left border of the window | |
489 | if ( isGivenTimestampInSelectedWindow( currentTime ) == false ) { | |
490 | currentTime = windowStart; | |
491 | } | |
492 | currentEventTime = currentTime; | |
493 | ||
494 | // Notify control that the window changed | |
495 | windowChangedNotification(); | |
496 | ||
497 | // Make sure we redraw the change | |
498 | fullExperimentCanvas.redraw(); | |
499 | } | |
500 | } | |
501 | } | |
502 | ||
503 | ||
504 | /* | |
505 | * Create the canvas needed and issue the requests | |
506 | * | |
507 | * @param newExperiment Experiment we will use for the request | |
508 | */ | |
509 | private void createCanvasAndRequests(TmfExperiment<LttngEvent> newExperiment) { | |
510 | // Save the experiment we are about to use | |
511 | lastUsedExperiment = newExperiment; | |
512 | ||
9aae0442 ASL |
513 | // // Create a copy of the trace that will be use only by the full experiment request |
514 | // TmfExperiment<LttngEvent> experimentCopy = newExperiment.createTraceCopy(); | |
6e512b93 ASL |
515 | |
516 | // Create the content for the full experiment. | |
517 | // This NEED to be created first, as we use it in the selectedWindowCanvas | |
518 | fullExperimentCanvas.createNewHistogramContent(fullExperimentCanvas.getSize().x, FULL_TRACE_BAR_WIDTH, FULL_TRACE_CANVAS_HEIGHT, FULL_TRACE_DIFFERENCE_TO_AVERAGE); | |
519 | fullExperimentCanvas.createNewSelectedWindow(DEFAULT_WINDOW_SIZE); | |
9aae0442 ASL |
520 | |
521 | TmfTimeRange timeRange = getExperimentTimeRange(newExperiment); | |
522 | currentEventTime = timeRange.getStartTime().getValue(); | |
523 | ||
524 | // Set the window of the fullTrace canvas visible. | |
6e512b93 | 525 | fullExperimentCanvas.getCurrentWindow().setSelectedWindowVisible(true); |
9aae0442 | 526 | fullExperimentCanvas.getHistogramContent().resetTable(timeRange.getStartTime().getValue(), timeRange.getEndTime().getValue()); |
6e512b93 ASL |
527 | |
528 | // Create the content for the selected window. | |
529 | selectedWindowCanvas.createNewHistogramContent(selectedWindowCanvas.getSize().x ,SELECTED_WINDOW_BAR_WIDTH, SELECTED_WINDOW_CANVAS_HEIGHT, SELECTED_WINDOW_DIFFERENCE_TO_AVERAGE); | |
530 | selectedWindowCanvas.getHistogramContent().resetTable(fullExperimentCanvas.getCurrentWindow().getTimestampOfLeftPosition(), fullExperimentCanvas.getCurrentWindow().getTimestampOfRightPosition()); | |
531 | ||
532 | // Make sure the UI object are sane | |
533 | resetControlsContent(); | |
534 | ||
535 | // Redraw the canvas right away to have something "clean" as soon as we can | |
536 | if ( dataBackgroundFullRequest != null ) { | |
537 | fullExperimentCanvas.redraw(); | |
538 | selectedWindowCanvas.redraw(); | |
539 | } | |
540 | // Nullify the (possible) old request to be sure we start we something clean | |
541 | // Note : this is very important for the order of the request below, | |
542 | // see "TODO" in performSelectedWindowEventsRequest | |
543 | dataBackgroundFullRequest = null; | |
544 | selectedWindowRequest = null; | |
545 | ||
546 | // Perform both request. | |
547 | // Order is important here, the small/synchronous request for the selection window should go first | |
548 | performSelectedWindowEventsRequest(newExperiment); | |
9aae0442 ASL |
549 | // performAllTraceEventsRequest(experimentCopy); |
550 | performAllTraceEventsRequest(newExperiment); | |
6e512b93 | 551 | } |
9aae0442 ASL |
552 | |
553 | // Before completing its indexing, the experiment doesn't know start/end time. | |
554 | // However, LTTng individual traces have this knowledge so we should ask them | |
555 | // directly. | |
556 | private TmfTimeRange getExperimentTimeRange(TmfExperiment<LttngEvent> experiment) { | |
557 | // Before completing its indexing, the experiment doesn't know start/end time. | |
558 | // However, LTTng individual traces have this knowledge so we should ask them | |
559 | // directly. | |
560 | TmfTimestamp startTime = TmfTimestamp.BigCrunch; | |
561 | TmfTimestamp endTime = TmfTimestamp.BigBang; | |
562 | for (ITmfTrace trace : experiment.getTraces()) { | |
563 | TmfContext context = trace.seekLocation(null); | |
564 | context.setRank(0); | |
565 | TmfEvent event = trace.getNextEvent(context); | |
566 | TmfTimestamp traceStartTime = event.getTimestamp(); | |
567 | if (traceStartTime.compareTo(startTime, true) < 0) | |
568 | startTime = traceStartTime; | |
569 | TmfTimestamp traceEndTime = trace.getEndTime(); | |
570 | if (traceEndTime.compareTo(endTime, true) > 0) | |
571 | endTime = traceEndTime; | |
572 | } | |
573 | TmfTimeRange tmpRange = new TmfTimeRange(startTime, endTime); | |
574 | return tmpRange; | |
575 | } | |
576 | ||
6e512b93 ASL |
577 | /** |
578 | * Perform a new request for the Selection window.<p> | |
579 | * This assume the full experiment canvas has correct information about the selected window; | |
580 | * we need the fullExperimentCanvas' HistogramContent to be created and a selection window to be set. | |
581 | * | |
582 | * @param experiment The experiment we will select from | |
583 | */ | |
584 | public void performSelectedWindowEventsRequest(TmfExperiment<LttngEvent> experiment) { | |
585 | ||
586 | HistogramSelectedWindow curSelectedWindow = fullExperimentCanvas.getCurrentWindow(); | |
587 | ||
9aae0442 | 588 | // If no selection window exists, we will try to create one; |
6e512b93 ASL |
589 | // however this will most likely fail as the content is probably not created either |
590 | if ( curSelectedWindow == null ) { | |
591 | fullExperimentCanvas.createNewSelectedWindow( DEFAULT_WINDOW_SIZE ); | |
592 | curSelectedWindow = fullExperimentCanvas.getCurrentWindow(); | |
593 | } | |
594 | ||
595 | // The request will go from the Left timestamp of the window to the Right timestamp | |
596 | // This assume that out-of-bound value are handled by the SelectionWindow itself | |
597 | LttngTimestamp ts1 = new LttngTimestamp( curSelectedWindow.getTimestampOfLeftPosition() ); | |
598 | LttngTimestamp ts2 = new LttngTimestamp( curSelectedWindow.getTimestampOfRightPosition() ); | |
599 | TmfTimeRange tmpRange = new TmfTimeRange(ts1, ts2); | |
600 | ||
601 | // Set a (dynamic) time interval | |
602 | long intervalTime = ( (ts2.getValue() - ts1.getValue()) / selectedWindowCanvas.getHistogramContent().getNbElement() ); | |
603 | ||
9aae0442 | 604 | selectedWindowRequest = performRequest(experiment, selectedWindowCanvas, tmpRange, intervalTime, ExecutionType.SHORT); |
6e512b93 ASL |
605 | selectedWindowCanvas.redrawAsynchronously(); |
606 | } | |
607 | ||
608 | /** | |
609 | * Perform a new request for the full experiment.<p> | |
610 | * NOTE : this is very long, we need to implement a way to run this in parallel (see TODO) | |
611 | * | |
612 | * @param experiment The experiment we will select from | |
613 | */ | |
614 | public void performAllTraceEventsRequest(TmfExperiment<LttngEvent> experiment) { | |
615 | // Create a new time range from "start" to "end" | |
616 | // That way, we will get "everything" in the trace | |
9aae0442 ASL |
617 | // LttngTimestamp ts1 = new LttngTimestamp( experiment.getStartTime() ); |
618 | // LttngTimestamp ts2 = new LttngTimestamp( experiment.getEndTime() ); | |
619 | // TmfTimeRange tmpRange = new TmfTimeRange(ts1, ts2); | |
620 | ||
621 | TmfTimeRange tmpRange = getExperimentTimeRange(experiment); | |
622 | TmfTimestamp startTime = tmpRange.getStartTime(); | |
623 | TmfTimestamp endTime = tmpRange.getEndTime(); | |
6e512b93 ASL |
624 | |
625 | // Set a (dynamic) time interval | |
9aae0442 | 626 | long intervalTime = ( (endTime.getValue() - startTime.getValue()) / fullExperimentCanvas.getHistogramContent().getNbElement() ); |
6e512b93 ASL |
627 | |
628 | // *** VERIFY *** | |
629 | // This would enable "fixed interval" instead of dynamic one. | |
630 | // ... we don't need it, do we? | |
631 | // | |
632 | // long intervalTime = ((long)(0.001 * (double)1000000000)); | |
633 | ||
634 | // *** TODO *** | |
635 | // It would be interesting if there was a way to tell the framework to run the request "in parallel" here. | |
636 | // Mean a completetly independant copy of the Expereiment would be done and we would proceed on that. | |
637 | // | |
9aae0442 | 638 | dataBackgroundFullRequest = performRequest(experiment, fullExperimentCanvas, tmpRange, intervalTime, ExecutionType.LONG); |
6e512b93 ASL |
639 | fullExperimentCanvas.redrawAsynchronously(); |
640 | } | |
641 | ||
642 | // *** VERIFY *** | |
643 | // This function is synchronized, is it a good idea? | |
644 | // Tis is done to make sure requests arrive somewhat in order, | |
645 | // this is especially important when request are issued from different thread. | |
646 | /** | |
647 | * Create a new request from the given data and send it to the framework.<p> | |
648 | * The request will be queued and processed later. | |
649 | * | |
650 | * @param experiment The experiment we will process the request on | |
651 | * @param targetCanvas The canvas that will received the result | |
652 | * @param newRange The range of the request | |
653 | * @param newInterval The interval of time we use to store the result into the HistogramContent | |
654 | */ | |
9aae0442 | 655 | private synchronized HistogramRequest performRequest(TmfExperiment<LttngEvent> experiment, HistogramCanvas targetCanvas, TmfTimeRange newRange, long newInterval, ExecutionType execType) { |
6e512b93 ASL |
656 | HistogramRequest returnedRequest = null; |
657 | ||
658 | // *** FIXME *** | |
659 | // EVIL BUG! | |
660 | // We use int.MAX_VALUE because we want every events BUT we don't know the number inside the range. | |
661 | // HOWEVER, this would cause the request to run forever (or until it reach the end of trace). | |
662 | // Seeting an EndTime does not seems to stop the request | |
663 | returnedRequest = new HistogramRequest(newRange, Integer.MAX_VALUE, targetCanvas, newInterval ); | |
664 | ||
665 | // Send the request to the framework : it will be queued and processed later | |
9aae0442 | 666 | experiment.sendRequest(returnedRequest, execType); |
6e512b93 ASL |
667 | |
668 | return returnedRequest; | |
669 | } | |
670 | ||
671 | /** | |
672 | * Function used to warn that the selection window changed.<p> | |
673 | * This might be called because the window moved or because its size changed.<p> | |
674 | * | |
675 | * We will update the different control related to the selection window. | |
676 | */ | |
677 | public void windowChangedNotification() { | |
678 | ||
679 | if ( lastUsedExperiment != null ) { | |
680 | // If a request is ongoing, try to stop it | |
9aae0442 | 681 | if ( selectedWindowRequest != null && selectedWindowRequest.isCompleted() == false ) { |
6e512b93 ASL |
682 | selectedWindowRequest.cancel(); |
683 | } | |
684 | ||
685 | // Get the latest window information | |
686 | selectedWindowTime = fullExperimentCanvas.getCurrentWindow().getTimestampOfCenterPosition(); | |
687 | selectedWindowTimerange = fullExperimentCanvas.getCurrentWindow().getWindowTimeWidth(); | |
688 | ||
689 | // If the current event time is outside the new window, change the current event | |
690 | // The new current event will be the one closest to the LEFT side of the new window | |
691 | if ( isGivenTimestampInSelectedWindow(currentEventTime) == false ) { | |
692 | currentEventChangeNotification( fullExperimentCanvas.getCurrentWindow().getTimestampOfLeftPosition() ); | |
693 | } | |
694 | ||
695 | // Perform a new request to read data about the new window | |
696 | performSelectedWindowEventsRequest(lastUsedExperiment); | |
697 | } | |
698 | } | |
699 | ||
700 | /** | |
701 | * Function used to tell that the current event changed.<p> | |
702 | * This might be called because the user changed the current event or | |
703 | * because the last current event is now outside the selection window.<p> | |
704 | * | |
705 | * We update the related control and send a signal to notify other views of the new current event. | |
706 | * | |
707 | * @param newCurrentEventTime | |
708 | */ | |
709 | public void currentEventChangeNotification(long newCurrentEventTime) { | |
710 | ||
711 | // Notify other views in the framework | |
712 | if (currentEventTime != newCurrentEventTime) { | |
713 | currentEventTime = newCurrentEventTime; | |
714 | ||
715 | // Update the UI control | |
716 | updateSelectedEventTime(); | |
717 | } | |
718 | } | |
719 | ||
720 | public void sendTmfTimeSynchSignalBroadcast() { | |
721 | ||
722 | // System.out.println("sendTmfTimeSynchSignalBroadcast " + System.currentTimeMillis()); | |
723 | ||
724 | // Send a signal to the framework | |
725 | LttngTimestamp tmpTimestamp = new LttngTimestamp(currentEventTime); | |
726 | broadcast(new TmfTimeSynchSignal(this, tmpTimestamp)); | |
727 | } | |
728 | ||
729 | /** | |
730 | * Function used to tell that the timerange (window) changed.<p> | |
731 | * This will most likely be called if the time window is resized. | |
732 | * | |
733 | * We send a signal to notify other views of the new timerange. | |
734 | */ | |
735 | public void sendTmfRangeSynchSignalBroadcast() { | |
736 | ||
737 | // System.out.println("sendTmfRangeSynchSignalBroadcast " + System.currentTimeMillis()); | |
738 | ||
739 | // *** TODO *** | |
740 | // Not very elegant... we need to chance this below. | |
741 | // | |
742 | long centerTime = fullExperimentCanvas.getCurrentWindow().getTimestampOfCenterPosition(); | |
743 | long windowWidth = fullExperimentCanvas.getCurrentWindow().getWindowTimeWidth(); | |
744 | ||
745 | long startTime = centerTime-windowWidth; | |
746 | if ( startTime < fullExperimentCanvas.getHistogramContent().getStartTime() ) { | |
747 | startTime = fullExperimentCanvas.getHistogramContent().getStartTime(); | |
748 | } | |
749 | LttngTimestamp tmpStartTime = new LttngTimestamp(startTime); | |
750 | ||
751 | long endTime = centerTime+windowWidth; | |
752 | if ( endTime > fullExperimentCanvas.getHistogramContent().getEndTime() ) { | |
753 | endTime = fullExperimentCanvas.getHistogramContent().getEndTime(); | |
754 | } | |
755 | LttngTimestamp tmpEndTime = new LttngTimestamp(endTime); | |
756 | ||
757 | TmfTimeRange tmpTimeRange = new TmfTimeRange(tmpStartTime, tmpEndTime); | |
758 | LttngTimestamp tmpEventTime = new LttngTimestamp(currentEventTime); | |
759 | ||
760 | // Send a signal to the framework | |
761 | broadcast(new TmfRangeSynchSignal(this, tmpTimeRange, tmpEventTime)); | |
762 | } | |
763 | ||
764 | /** | |
765 | * Function that will be called when one of the time text group value is changed.<p> | |
766 | * Since we don't (and can't unless we subclass them) know which one, we check them all. | |
767 | */ | |
768 | public void timeTextGroupChangeNotification() { | |
769 | ||
770 | // Get all the time text group value | |
771 | long newCurrentTime = ntgCurrentEventTime.getValue(); | |
772 | long newSelectedWindowTime = ntgCurrentWindowTime.getValue(); | |
773 | long newSelectedWindowTimeRange = ntgTimeRangeWindow.getValue(); | |
774 | ||
775 | // If the user changed the current event time, call the notification | |
776 | if ( newCurrentTime != currentEventTime ) { | |
777 | currentEventChangeNotification( newCurrentTime ); | |
778 | // Send a broadcast to the framework about the window change | |
779 | sendTmfTimeSynchSignalBroadcast(); | |
780 | } | |
781 | ||
782 | // If the user changed the selected window time, recenter the window and call the notification | |
783 | if ( newSelectedWindowTime != selectedWindowTime ) { | |
784 | selectedWindowTime = newSelectedWindowTime; | |
785 | fullExperimentCanvas.setWindowCenterPosition( fullExperimentCanvas.getHistogramContent().getClosestXPositionFromTimestamp(selectedWindowTime) ); | |
786 | windowChangedNotification(); | |
787 | // Send a broadcast to the framework about the window change | |
788 | sendTmfRangeSynchSignalBroadcast(); | |
789 | } | |
790 | ||
791 | // If the user changed the selected window size, resize the window and call the notification | |
792 | if ( newSelectedWindowTimeRange != selectedWindowTimerange ) { | |
793 | selectedWindowTimerange = newSelectedWindowTimeRange; | |
794 | fullExperimentCanvas.resizeWindowByAbsoluteTime(selectedWindowTimerange); | |
795 | windowChangedNotification(); | |
796 | // Send a broadcast to the framework about the window change | |
797 | sendTmfRangeSynchSignalBroadcast(); | |
798 | } | |
799 | ||
800 | } | |
801 | ||
802 | /** | |
803 | * Getter for the last used experiment.<p> | |
804 | * This might be different than the current experiment or even null. | |
805 | * | |
806 | * @return the last experiment we used in this view | |
807 | */ | |
808 | public TmfExperiment<LttngEvent> getLastUsedExperiment() { | |
809 | return lastUsedExperiment; | |
810 | } | |
811 | ||
812 | /** | |
813 | * Check if a given timestamp is inside the selection window.<p> | |
814 | * This assume fullExperimentCanvas contain a valid HistogramContent | |
815 | * | |
816 | * @param timestamp the timestamp to check | |
817 | * | |
818 | * @return if the time is inside the selection window or not | |
819 | */ | |
820 | public boolean isGivenTimestampInSelectedWindow(long timestamp) { | |
821 | boolean returnedValue = true; | |
822 | ||
823 | // If the content is not set correctly, this will return weird (or even null) result | |
824 | if ( (timestamp < fullExperimentCanvas.getCurrentWindow().getTimestampOfLeftPosition() ) || | |
825 | (timestamp > fullExperimentCanvas.getCurrentWindow().getTimestampOfRightPosition() ) ) | |
826 | { | |
827 | returnedValue = false; | |
828 | } | |
829 | ||
830 | return returnedValue; | |
831 | } | |
832 | ||
833 | /** | |
834 | * Reset the content of all Controls.<p> | |
835 | * WARNING : Calls in there are not thread safe and can't be called from different thread than "main" | |
836 | */ | |
837 | public void resetControlsContent() { | |
838 | ||
839 | TmfExperiment<LttngEvent> tmpExperiment = getLastUsedExperiment(); | |
840 | ||
841 | // Use the previous Start and End time, or default if they are not available | |
842 | String startTime = null; | |
843 | String stopTime = null; | |
844 | if ( tmpExperiment != null ) { | |
845 | startTime = HistogramConstant.formatNanoSecondsTime( tmpExperiment.getStartTime().getValue() ); | |
846 | stopTime = HistogramConstant.formatNanoSecondsTime( tmpExperiment.getEndTime().getValue() ); | |
847 | } | |
848 | else { | |
849 | startTime = HistogramConstant.formatNanoSecondsTime( 0L ); | |
850 | stopTime = HistogramConstant.formatNanoSecondsTime( 0L ); | |
851 | } | |
852 | ||
853 | txtExperimentStartTime.setText( startTime ); | |
854 | txtExperimentStopTime.setText( stopTime ); | |
855 | txtExperimentStartTime.getParent().layout(); | |
856 | ||
857 | txtWindowMaxNbEvents.setText("" + 0); | |
858 | txtWindowMinNbEvents.setText("" + 0); | |
859 | txtWindowStartTime.setText( HistogramConstant.formatNanoSecondsTime( 0L ) ); | |
860 | txtWindowStopTime.setText( HistogramConstant.formatNanoSecondsTime( 0L ) ); | |
861 | txtWindowStartTime.getParent().layout(); | |
862 | ||
863 | ntgCurrentWindowTime.setValue( HistogramConstant.formatNanoSecondsTime( 0L ) ); | |
864 | ntgTimeRangeWindow.setValue( HistogramConstant.formatNanoSecondsTime( 0L ) ); | |
865 | ||
866 | // Using "startTime" here can avoid an useless TmfTimeSynchSignal here | |
867 | // However it look ugly to have only this time | |
868 | ntgCurrentEventTime.setValue( HistogramConstant.formatNanoSecondsTime( 0L ) ); | |
869 | } | |
870 | ||
871 | /** | |
872 | * Update the content of the controls related to the full experiment canvas<p> | |
873 | * WARNING : Calls in there are not thread safe and can't be called from different thread than "main" | |
874 | */ | |
875 | public void updateFullExperimentInformation() { | |
876 | ||
877 | String startTime = HistogramConstant.formatNanoSecondsTime( fullExperimentCanvas.getHistogramContent().getStartTime() ); | |
878 | String stopTime = HistogramConstant.formatNanoSecondsTime( fullExperimentCanvas.getHistogramContent().getEndTime() ); | |
879 | ||
880 | txtExperimentStartTime.setText( startTime ); | |
881 | txtExperimentStopTime.setText( stopTime ); | |
882 | ||
883 | // Take one of the parent and call its layout to update control size | |
884 | // Since both control have the same parent, only one call is needed | |
885 | txtExperimentStartTime.getParent().layout(); | |
886 | ||
887 | // Update the selected window, just in case | |
888 | // This should give a better user experience and it is low cost | |
889 | updateSelectedWindowInformation(); | |
890 | } | |
891 | ||
892 | /** | |
893 | * Update the content of the controls related to the selection window canvas<p> | |
894 | * WARNING : Calls in there are not thread safe and can't be called from different thread than "main" | |
895 | */ | |
896 | public void updateSelectedWindowInformation() { | |
897 | // Update the timestamp as well | |
898 | updateSelectedWindowTimestamp(); | |
899 | ||
900 | txtWindowMaxNbEvents.setText( Long.toString(selectedWindowCanvas.getHistogramContent().getHeighestEventCount()) ); | |
901 | txtWindowMinNbEvents.setText(Long.toString(0)); | |
902 | ||
903 | // Refresh the layout | |
904 | txtWindowMaxNbEvents.getParent().layout(); | |
905 | } | |
906 | ||
907 | /** | |
908 | * Update the content of the controls related to the timestamp of the selection window<p> | |
909 | * WARNING : Calls in there are not thread safe and can't be called from different thread than "main" | |
910 | */ | |
911 | public void updateSelectedWindowTimestamp() { | |
912 | String startTime = HistogramConstant.formatNanoSecondsTime( selectedWindowCanvas.getHistogramContent().getStartTime() ); | |
913 | String stopTime = HistogramConstant.formatNanoSecondsTime( selectedWindowCanvas.getHistogramContent().getEndTime() ); | |
914 | txtWindowStartTime.setText( startTime ); | |
915 | txtWindowStopTime.setText( stopTime ); | |
916 | ||
917 | ntgCurrentWindowTime.setValue( fullExperimentCanvas.getCurrentWindow().getTimestampOfCenterPosition() ); | |
918 | ntgTimeRangeWindow.setValue( fullExperimentCanvas.getCurrentWindow().getWindowTimeWidth() ); | |
919 | ||
920 | // If the current event time is outside the selection window, recenter our window | |
921 | if ( isGivenTimestampInSelectedWindow(ntgCurrentEventTime.getValue()) == false ) { | |
922 | currentEventChangeNotification( fullExperimentCanvas.getCurrentWindow().getTimestampOfCenterPosition() ); | |
923 | } | |
924 | ||
925 | // Take one control in each group to call to refresh the layout | |
926 | // Since both control have the same parent, only one call is needed | |
927 | txtWindowStartTime.getParent().layout(); | |
928 | ntgCurrentWindowTime.getParent().layout(); | |
929 | } | |
930 | ||
931 | /** | |
932 | * Update the controls related current event.<p> | |
933 | * The call here SHOULD be thread safe and can be call from any threads. | |
934 | */ | |
935 | public void updateSelectedEventTime() { | |
936 | ntgCurrentEventTime.setValueAsynchronously(currentEventTime); | |
937 | // Tell the selection canvas which event is currently selected | |
938 | // This give a nice graphic output | |
939 | selectedWindowCanvas.getHistogramContent().setSelectedEventTimeInWindow(currentEventTime); | |
940 | selectedWindowCanvas.redrawAsynchronously(); | |
941 | } | |
942 | ||
943 | /** | |
944 | * Method called when the view is moved.<p> | |
945 | * | |
946 | * Just redraw everything... | |
947 | * | |
948 | * @param event The controle event generated by the move. | |
949 | */ | |
950 | public void controlMoved(ControlEvent event) { | |
951 | parent.redraw(); | |
952 | } | |
953 | ||
954 | /** | |
955 | * Method called when the view is resized.<p> | |
956 | * | |
957 | * We will make sure that the size didn't change more than the content size.<p> | |
958 | * Otherwise we need to perform a new request for the full experiment because we are missing data). | |
959 | * | |
960 | * @param event The control event generated by the resize. | |
961 | */ | |
962 | public void controlResized(ControlEvent event) { | |
963 | ||
964 | // Ouch! The screen enlarged (screen resolution changed?) so far that we miss content to fill the space. | |
965 | if ( parent.getDisplay().getBounds().width > fullExperimentCanvas.getHistogramContent().getNbElement() ) { | |
966 | if ( lastUsedExperiment != null ) { | |
967 | createCanvasAndRequests(lastUsedExperiment); | |
968 | } | |
969 | } | |
970 | ||
971 | } | |
972 | } |