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