48d73aec04f25e63597e82b05862e11919cd7475
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng.ui / src / org / eclipse / linuxtools / lttng / ui / views / histogram / HistogramView.java
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;
16 import org.eclipse.linuxtools.tmf.component.ITmfDataProvider.ExecutionType;
17 import org.eclipse.linuxtools.tmf.event.TmfEvent;
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;
26 import org.eclipse.linuxtools.tmf.trace.ITmfTrace;
27 import org.eclipse.linuxtools.tmf.trace.TmfContext;
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
513 // // Create a copy of the trace that will be use only by the full experiment request
514 // TmfExperiment<LttngEvent> experimentCopy = newExperiment.createTraceCopy();
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);
520
521 TmfTimeRange timeRange = getExperimentTimeRange(newExperiment);
522 currentEventTime = timeRange.getStartTime().getValue();
523
524 // Set the window of the fullTrace canvas visible.
525 fullExperimentCanvas.getCurrentWindow().setSelectedWindowVisible(true);
526 fullExperimentCanvas.getHistogramContent().resetTable(timeRange.getStartTime().getValue(), timeRange.getEndTime().getValue());
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);
549 // performAllTraceEventsRequest(experimentCopy);
550 performAllTraceEventsRequest(newExperiment);
551 }
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
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
588 // If no selection window exists, we will try to create one;
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
604 selectedWindowRequest = performRequest(experiment, selectedWindowCanvas, tmpRange, intervalTime, ExecutionType.SHORT);
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
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();
624
625 // Set a (dynamic) time interval
626 long intervalTime = ( (endTime.getValue() - startTime.getValue()) / fullExperimentCanvas.getHistogramContent().getNbElement() );
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 //
638 dataBackgroundFullRequest = performRequest(experiment, fullExperimentCanvas, tmpRange, intervalTime, ExecutionType.LONG);
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 */
655 private synchronized HistogramRequest performRequest(TmfExperiment<LttngEvent> experiment, HistogramCanvas targetCanvas, TmfTimeRange newRange, long newInterval, ExecutionType execType) {
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
666 experiment.sendRequest(returnedRequest, execType);
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
681 if ( selectedWindowRequest != null && selectedWindowRequest.isCompleted() == false ) {
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 }
This page took 0.052474 seconds and 4 git commands to generate.