Fix for bug 373698: Incorrect experiment range.
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng.ui / src / org / eclipse / linuxtools / lttng / ui / views / controlflow / ControlFlowView.java
CommitLineData
6e512b93 1/*******************************************************************************
8827c197 2 * Copyright (c) 2009, 2010 Ericsson
6e512b93 3 *
dfaf8391
FC
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6e512b93
ASL
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
860cadcf
FC
9 * Contributors:
10 * Alvaro Sanchez-Leon - Initial implementation
11 * Michel Dagenais (michel.dagenais@polymtl.ca) - Reference C implementation, used with permission
de7ddc02 12 * Bernd Hufmann - Bug fixes
6e512b93 13 *******************************************************************************/
8b29a712 14package org.eclipse.linuxtools.lttng.ui.views.controlflow;
6e512b93 15
dfaf8391
FC
16import java.util.Vector;
17
18import org.eclipse.jface.action.Action;
19import org.eclipse.jface.action.IMenuListener;
20import org.eclipse.jface.action.IMenuManager;
21import org.eclipse.jface.action.IToolBarManager;
22import org.eclipse.jface.action.MenuManager;
23import org.eclipse.jface.action.Separator;
24import org.eclipse.jface.dialogs.MessageDialog;
25import org.eclipse.jface.viewers.DoubleClickEvent;
26import org.eclipse.jface.viewers.IDoubleClickListener;
27import org.eclipse.jface.viewers.ISelection;
28import org.eclipse.jface.viewers.ISelectionChangedListener;
29import org.eclipse.jface.viewers.IStructuredContentProvider;
30import org.eclipse.jface.viewers.IStructuredSelection;
31import org.eclipse.jface.viewers.ITableLabelProvider;
32import org.eclipse.jface.viewers.LabelProvider;
33import org.eclipse.jface.viewers.SelectionChangedEvent;
34import org.eclipse.jface.viewers.StructuredViewer;
35import org.eclipse.jface.viewers.TableViewer;
36import org.eclipse.jface.viewers.Viewer;
37import org.eclipse.jface.viewers.ViewerFilter;
6c13869b
FC
38import org.eclipse.linuxtools.lttng.core.control.LttngCoreProviderFactory;
39import org.eclipse.linuxtools.lttng.core.event.LttngTimestamp;
40import org.eclipse.linuxtools.lttng.core.request.ILttngSyntEventRequest;
41import org.eclipse.linuxtools.lttng.core.state.evProcessor.ITransEventProcessor;
dfaf8391 42import org.eclipse.linuxtools.lttng.ui.TraceDebug;
8827c197 43import org.eclipse.linuxtools.lttng.ui.model.trange.ItemContainer;
dfaf8391 44import org.eclipse.linuxtools.lttng.ui.model.trange.TimeRangeEventProcess;
41dc35d0 45import org.eclipse.linuxtools.lttng.ui.views.common.AbsTimeUpdateView;
dfaf8391 46import org.eclipse.linuxtools.lttng.ui.views.common.ParamsUpdater;
8827c197 47import org.eclipse.linuxtools.lttng.ui.views.controlflow.evProcessor.FlowEventToHandlerFactory;
dfaf8391 48import org.eclipse.linuxtools.lttng.ui.views.controlflow.model.FlowModelFactory;
c48abe58 49import org.eclipse.linuxtools.lttng.ui.views.controlflow.model.FlowTimeRangeViewerProvider;
6c13869b
FC
50import org.eclipse.linuxtools.tmf.core.event.TmfEvent;
51import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
52import org.eclipse.linuxtools.tmf.core.experiment.TmfExperiment;
53import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType;
54import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;
55import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentSelectedSignal;
d61e0854 56import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentUpdatedSignal;
6c13869b
FC
57import org.eclipse.linuxtools.tmf.core.signal.TmfRangeSynchSignal;
58import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
59import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
dfaf8391 60import org.eclipse.linuxtools.tmf.ui.viewers.TmfViewerFactory;
dfaf8391
FC
61import org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.ITmfTimeFilterSelectionListener;
62import org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.ITmfTimeScaleSelectionListener;
63import org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.ITmfTimeSelectionListener;
64import org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.TmfTimeFilterSelectionEvent;
65import org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.TmfTimeScaleSelectionEvent;
66import org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.TmfTimeSelectionEvent;
67import org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.model.ITmfTimeAnalysisEntry;
dfaf8391
FC
68import org.eclipse.swt.SWT;
69import org.eclipse.swt.custom.SashForm;
70import org.eclipse.swt.custom.ScrolledComposite;
dfaf8391
FC
71import org.eclipse.swt.events.KeyEvent;
72import org.eclipse.swt.events.KeyListener;
73import org.eclipse.swt.graphics.Image;
74import org.eclipse.swt.graphics.Point;
75import org.eclipse.swt.graphics.Rectangle;
6e512b93 76import org.eclipse.swt.widgets.Composite;
dfaf8391
FC
77import org.eclipse.swt.widgets.Display;
78import org.eclipse.swt.widgets.Menu;
79import org.eclipse.swt.widgets.ScrollBar;
80import org.eclipse.swt.widgets.Table;
81import org.eclipse.swt.widgets.TableColumn;
82import org.eclipse.swt.widgets.TableItem;
83import org.eclipse.ui.IActionBars;
84import org.eclipse.ui.IWorkbenchActionConstants;
85import org.eclipse.ui.PlatformUI;
86import org.eclipse.ui.plugin.AbstractUIPlugin;
6e512b93
ASL
87
88/**
89 * <b><u>ControlFlowView</u></b>
90 */
41dc35d0
FC
91/**
92 * @author alvaro
93 *
94 */
95public class ControlFlowView extends AbsTimeUpdateView implements
dfaf8391 96 ITmfTimeSelectionListener, ITmfTimeScaleSelectionListener,
41dc35d0 97 ITmfTimeFilterSelectionListener {
6e512b93 98
3b38ea61 99 public static final String ID = "org.eclipse.linuxtools.lttng.ui.views.controlflow"; //$NON-NLS-1$
41dc35d0 100
dfaf8391
FC
101 // ========================================================================
102 // Table data
103 // ========================================================================
3b38ea61
FC
104
105 private final String PROCESS_COLUMN = Messages.getString("ControlFlowView.processColumn"); //$NON-NLS-1$
106 private final String BRAND_COLUMN = Messages.getString("ControlFlowView.brandColumn"); //$NON-NLS-1$
107 private final String PID_COLUMN = Messages.getString("ControlFlowView.pidColumn"); //$NON-NLS-1$
108 private final String TGID_COLUMN = Messages.getString("ControlFlowView.tgidColumn"); //$NON-NLS-1$
109 private final String PPID_COLUMN = Messages.getString("ControlFlowView.ppidColumn"); //$NON-NLS-1$
110 private final String CPU_COLUMN = Messages.getString("ControlFlowView.cpuColumn"); //$NON-NLS-1$
111 private final String BIRTH_SEC_COLUMN = Messages.getString("ControlFlowView.birthSecColumn"); //$NON-NLS-1$
112 private final String BIRTH_NSEC_COLUMN = Messages.getString("ControlFlowView.birthNSecColumn"); //$NON-NLS-1$
113 private final String TRACE = Messages.getString("ControlFlowView.TraceNameColumn"); //$NON-NLS-1$
dfaf8391
FC
114
115 private final String[] columnNames = new String[] { PROCESS_COLUMN, /* */
116 BRAND_COLUMN,/* */
117 PID_COLUMN,/* */
118 TGID_COLUMN,/* */
119 PPID_COLUMN,/* */
120 CPU_COLUMN, /* */
121 BIRTH_SEC_COLUMN,/* */
122 BIRTH_NSEC_COLUMN,/* */
123 TRACE /* */
124 };
125
126 // ========================================================================
127 // Data
128 // ========================================================================
dfaf8391
FC
129 private TableViewer tableViewer;
130 // private int totalNumItems = 0;
131 // Actions
132 private Action doubleClickAction;
133 private Action resetScale;
134 private Action nextEvent;
135 private Action prevEvent;
136 private Action nextTrace;
137 private Action prevTrace;
138 private Action showLegend;
139 private Action filterTraces;
140 private Action zoomIn;
141 private Action zoomOut;
8827c197 142 private Action zoomFilter;
dfaf8391 143
dfaf8391
FC
144 private ViewProcessFilter tableFilter = null;
145 private ScrolledComposite scrollFrame = null;
a79913eb
FC
146
147 private TmfTimeRange initTimeRange = TmfTimeRange.Null;
dfaf8391
FC
148
149 // private static SimpleDateFormat stimeformat = new SimpleDateFormat(
150 // "yy/MM/dd HH:mm:ss");
151
152 // private TraceModelImplFactory fact;
153
154 // ========================================================================
155 // Methods
156 // ========================================================================
157 /*
158 * The content provider class is responsible for providing objects to the
159 * view. It can wrap existing objects in adapters or simply return objects
160 * as-is. These objects may be sensitive to the current input of the view,
161 * or ignore it and always show the same content (like Task List, for
162 * example).
163 */
164
165 class ViewContentProvider implements
166 /* ILazyContentProvider, */IStructuredContentProvider {
167 private TableViewer cviewer = null;
168 private ITmfTimeAnalysisEntry[] elements = null;
169
170 public ViewContentProvider(TableViewer v) {
171 cviewer = v;
172 }
173
d4011df2 174 @Override
dfaf8391
FC
175 public void inputChanged(Viewer v, Object oldInput, Object newInput) {
176 this.elements = (ITmfTimeAnalysisEntry[]) newInput;
177 if (elements != null) {
3b38ea61 178 TraceDebug.debug("Total number of processes provided to Control Flow view: " + elements.length); //$NON-NLS-1$
dfaf8391 179 } else {
3b38ea61 180 TraceDebug.debug("New input = null"); //$NON-NLS-1$
dfaf8391
FC
181 }
182 }
183
d4011df2 184 @Override
dfaf8391
FC
185 public void dispose() {
186
187 }
188
189 // Needed with the use of virtual tables in order to initialize items
190 // which were not initially visible.
191 public void updateElement(int index) {
192 cviewer.replace(elements[index], index);
193 }
194
d4011df2 195 @Override
dfaf8391 196 public Object[] getElements(Object inputElement) {
dfaf8391
FC
197 return elements;
198 }
199 }
200
d4011df2
FC
201 class ViewLabelProvider extends LabelProvider implements ITableLabelProvider {
202 @Override
dfaf8391
FC
203 public String getColumnText(Object obj, int index) {
204 String strRes = ""; //$NON-NLS-1$
205 LttngTimestamp time;
206 if (obj instanceof TimeRangeEventProcess) {
207 TimeRangeEventProcess process = (TimeRangeEventProcess) obj;
208 switch (index) {
209 case 0:
210 strRes = process.getName();
211 break;
212 case 1:
213 strRes = process.getBrand();
214 break;
215 case 2:
216 strRes = process.getPid().toString();
217 break;
218 case 3:
219 strRes = process.getTgid().toString();
220 break;
221 case 4:
222 strRes = process.getPpid().toString();
223 break;
224 case 5:
225 strRes = process.getCpu().toString();
226 break;
227 case 6:
228 time = new LttngTimestamp(process.getCreationTime()
229 .longValue());
230 strRes = time.getSeconds();
231 break;
232 case 7:
233 time = new LttngTimestamp(process.getCreationTime()
234 .longValue());
235 strRes = time.getNanoSeconds();
236 break;
237 case 8:
238 strRes = process.getTraceID();
239 break;
240 default:
241 break;
242 }
243 } else {
244 return getText(obj);
245 }
246
247 return strRes;
248 }
249
d4011df2 250 @Override
dfaf8391
FC
251 public Image getColumnImage(Object obj, int index) {
252 return getImage(obj);
253 }
254
255 @Override
256 public Image getImage(Object obj) {
257 // No image needed for the time being
258 // return PlatformUI.getWorkbench().getSharedImages().getImage(
259 // ISharedImages.IMG_OBJ_ELEMENT);
260 return null;
261 }
262 }
263
264 class ViewProcessFilter extends ViewerFilter {
265
266 private Vector<ITmfTimeAnalysisEntry> filteredSet = new Vector<ITmfTimeAnalysisEntry>();
267 StructuredViewer viewer;
268
269 public ViewProcessFilter(StructuredViewer rviewer) {
270 this.viewer = rviewer;
271 }
272
273 public void setFilter(Vector<ITmfTimeAnalysisEntry> filtered) {
274 if (filtered != null) {
275 this.filteredSet = filtered;
276 viewer.refresh();
277 }
278 }
279
280 @Override
281 public boolean select(Viewer viewer, Object parentElement,
282 Object element) {
283 boolean filteredIn = true;
284 if (element instanceof ITmfTimeAnalysisEntry) {
285 ITmfTimeAnalysisEntry process = (ITmfTimeAnalysisEntry) element;
286 if (filteredSet.contains(process)) {
287 // The element is marked to be filtered out
288 return false;
289 }
290 } else {
3b38ea61 291 TraceDebug.debug("Unexpected type of filter element received: " //$NON-NLS-1$
dfaf8391
FC
292 + element.toString());
293 }
294 // Compare element versus a list of filtered out
295 return filteredIn;
296 }
297 }
298
6e512b93 299 /**
dfaf8391 300 * The constructor.
6e512b93
ASL
301 */
302 public ControlFlowView() {
41dc35d0 303 super(ID);
6e512b93
ASL
304 }
305
dfaf8391
FC
306 /**
307 * This is a callback that will allow us to create the viewer and initialize
308 * it.
6e512b93 309 */
8827c197
FC
310 /*
311 * (non-Javadoc)
312 *
313 * @see
314 * org.eclipse.linuxtools.tmf.ui.views.TmfView#createPartControl(org.eclipse
315 * .swt.widgets.Composite)
316 */
6e512b93
ASL
317 @Override
318 public void createPartControl(Composite parent) {
dfaf8391 319
8827c197
FC
320 scrollFrame = new ScrolledComposite(parent, SWT.V_SCROLL);
321
dfaf8391
FC
322 scrollFrame.setExpandVertical(true);
323 scrollFrame.setExpandHorizontal(true);
dfaf8391 324 scrollFrame.setAlwaysShowScrollBars(true);
8827c197
FC
325
326 SashForm sash = new SashForm(scrollFrame, SWT.NONE);
327 scrollFrame.setContent(sash);
328
329 tableViewer = new TableViewer(sash, SWT.FULL_SELECTION | SWT.H_SCROLL);
dfaf8391
FC
330 tableViewer.setContentProvider(new ViewContentProvider(tableViewer));
331 tableViewer.setLabelProvider(new ViewLabelProvider());
332 Table table = tableViewer.getTable();
8827c197 333 tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
d4011df2 334 @Override
8827c197
FC
335 public void selectionChanged(SelectionChangedEvent event) {
336 ISelection sel = event.getSelection();
337 if (!sel.isEmpty()) {
338 Object firstSel = null;
339 if (sel instanceof IStructuredSelection) {
340 firstSel = ((IStructuredSelection) sel).getFirstElement();
341
342 // Make sure the selection is visible
343 updateScrollOrigin();
344
345 if (firstSel instanceof ITmfTimeAnalysisEntry) {
346 ITmfTimeAnalysisEntry trace = (ITmfTimeAnalysisEntry) firstSel;
347 tsfviewer.setSelectedTrace(trace);
dfaf8391
FC
348 }
349 }
8827c197
FC
350 }
351 }
dfaf8391 352
8827c197
FC
353 /**
354 * Make sure the selected item is visible
355 */
356 private void updateScrollOrigin() {
357 Table table = tableViewer.getTable();
358 if (table != null && table.getItemCount() > 0) {
359 TableItem item = table.getSelection()[0];
360 if (item == null) {
361 // no selected reference to go up or down
362 return;
363 }
dfaf8391 364
8827c197
FC
365 Rectangle itemRect = item.getBounds();
366 int step = itemRect.height;
dfaf8391 367
8827c197
FC
368 // calculate height of horizontal bar
369 int hscrolly = 0;
370 ScrollBar hbar = scrollFrame.getHorizontalBar();
371 if (hbar != null) {
372 hscrolly = hbar.getSize().y;
373 }
dfaf8391 374
8827c197 375 int visibleHeight = scrollFrame.getSize().y - hscrolly;
dfaf8391 376
8827c197
FC
377 // the current scrollbar offset to adjust i.e. start
378 // of
379 // the visible window
380 Point origin = scrollFrame.getOrigin();
381 // end of visible window
382 int endy = origin.y + visibleHeight;
dfaf8391 383
8827c197
FC
384 int itemStartPos = itemRect.y + table.getHeaderHeight() + table.getBorderWidth()
385 + table.getParent().getBorderWidth();
dfaf8391 386
8827c197
FC
387 // Item End Position
388 int itemEndPos = itemStartPos + step;
dfaf8391 389
8827c197
FC
390 // check if need to go up
391 if (origin.y >= step && itemStartPos < origin.y) {
392 // one step up
393 scrollFrame.setOrigin(origin.x, origin.y - step);
8035003b 394
8827c197 395 }
dfaf8391
FC
396
397 // check if it needs to go down
8827c197
FC
398 if (itemEndPos > endy) {
399 // one step down
400 scrollFrame.setOrigin(origin.x, origin.y + step);
dfaf8391
FC
401
402 }
8827c197
FC
403 }
404 }
405 });
406
dfaf8391
FC
407 // Listen to page up /down and Home / Enc keys
408 tableViewer.getTable().addKeyListener(new KeyListener() {
d4011df2 409 @Override
dfaf8391
FC
410 public void keyPressed(KeyEvent e) {
411 Table table = tableViewer.getTable();
412 Point origin = scrollFrame.getOrigin();
413 if (table == null || table.getItemCount() < 1) {
414 // nothing to page
415 return;
416 }
417
418 TableItem item;
419 int count;
420
421 switch (e.keyCode) {
422 case SWT.PAGE_DOWN:
423 updateScrollPageDown();
424 break;
425 case SWT.PAGE_UP:
426 updateScrollUp();
427 break;
428 case SWT.HOME:
429 // Home
430 count = table.getItemCount();
431 item = table.getItem(0);
432 // Go to the top
433 scrollFrame.setOrigin(origin.x, 0);
434 break;
435 case SWT.END:
436 // End Selected
437 count = table.getItemCount();
438 item = table.getItem(count - 1);
439 int itemStartPos = item.getBounds().y;
440 // Get to the bottom
441 scrollFrame.setOrigin(origin.x, itemStartPos);
442 break;
443 default:
444 break;
445 }
446 }
447
d4011df2 448 @Override
dfaf8391
FC
449 public void keyReleased(KeyEvent e) {
450 // Nothing to do
451
452 }
453
454 /**
455 * Scroll one page down
456 */
457 private void updateScrollPageDown() {
458 // null protection before calling private method
459 Table table = tableViewer.getTable();
460 int step = table.getItemHeight();
461
462 int hscrolly = 0;
463 ScrollBar hbar = scrollFrame.getHorizontalBar();
464 if (hbar != null) {
465 hscrolly = hbar.getSize().y;
466 }
467
468 Point origin = scrollFrame.getOrigin();
469 int visibleHeight = scrollFrame.getSize().y - hscrolly;
470 int endy = origin.y + visibleHeight;
471
472 scrollFrame.setOrigin(origin.x, endy - step);
473 }
474
475 /**
476 * Scroll one page up
477 */
478 private void updateScrollUp() {
479 // null protection before calling private method
480 Table table = tableViewer.getTable();
481 int step = table.getItemHeight();
482
483 int hscrolly = 0;
484 ScrollBar hbar = scrollFrame.getHorizontalBar();
485 if (hbar != null) {
486 hscrolly = hbar.getSize().y;
487 }
488
489 Point origin = scrollFrame.getOrigin();
490 int visibleHeight = scrollFrame.getSize().y - hscrolly;
491 int pageUpPos = origin.y - visibleHeight + step;
492 pageUpPos = pageUpPos > 0 ? pageUpPos : 0;
493 scrollFrame.setOrigin(origin.x, pageUpPos);
494 }
495
496 });
497 // Describe table
498 applyTableLayout(table);
499
500 int borderWidth = table.getBorderWidth();
501
162eeb24 502 int itemHeight = table.getItemHeight() + getTableItemHeightAdjustement();
dfaf8391
FC
503 int headerHeight = table.getHeaderHeight();
504 table.getVerticalBar().setVisible(false);
505
c48abe58 506 tsfviewer = TmfViewerFactory.createViewer(sash, new FlowTimeRangeViewerProvider(getParamsUpdater()));
dfaf8391 507
41dc35d0 508 // Traces shall not be grouped to allow synchronisation
dfaf8391 509 tsfviewer.groupTraces(false);
8827c197 510 tsfviewer.setItemHeight(itemHeight);
dfaf8391
FC
511 tsfviewer.setBorderWidth(borderWidth);
512 tsfviewer.setHeaderHeight(headerHeight);
513 tsfviewer.setVisibleVerticalScroll(false);
514 // Names provided by the table
515 tsfviewer.setNameWidthPref(0);
516 tsfviewer.setAcceptSelectionAPIcalls(true);
517
518 // Viewer to notify selection to this class
41dc35d0 519 // This class will synchronise selections with table.
dfaf8391
FC
520 tsfviewer.addWidgetSelectionListner(this);
521 tsfviewer.addFilterSelectionListner(this);
522 tsfviewer.addWidgetTimeScaleSelectionListner(this);
523
524 sash.setWeights(new int[] { 1, 1 });
525 // Create the help context id for the viewer's control
526 // TODO: Associate with help system
527 PlatformUI.getWorkbench().getHelpSystem().setHelp(
528 tableViewer.getControl(),
529 "org.eclipse.linuxtools.lttnng.ui.views.flow.viewer"); //$NON-NLS-1$
530
531 makeActions();
532 hookContextMenu();
533 hookDoubleClickAction();
534 contributeToActionBars();
535
8827c197
FC
536 // scrollFrame.addControlListener(new ControlAdapter() {
537 //
538 // @Override
539 // public void controlResized(ControlEvent e) {
540 // tsfviewer.resizeControls();
541 // updateScrolls(scrollFrame);
542 // }
543 // });
dfaf8391
FC
544
545 // set the initial view parameter values
546 // Experiment start and end time
547 // as well as time space width in pixels, used by the time analysis
548 // widget
dfaf8391
FC
549 // Read relevant values
550 int timeSpaceWidth = tsfviewer.getTimeSpace();
8827c197
FC
551 if (timeSpaceWidth < 0) {
552 timeSpaceWidth = -timeSpaceWidth;
dfaf8391
FC
553 }
554
8827c197
FC
555 TmfExperiment<?> experiment = TmfExperiment.getCurrentExperiment();
556 if (experiment != null) {
557 TmfTimeRange experimentTRange = experiment.getTimeRange();
558
a79913eb
FC
559 if (experimentTRange != TmfTimeRange.Null) {
560 // send request and received the adjusted time used
561 TmfTimeRange adjustedTimeRange = initialExperimentDataRequest(this,
562 experimentTRange);
563
564 // initialize widget time boundaries and filtering parameters
565 ModelUpdateInit(experimentTRange, adjustedTimeRange, this);
566 }
8827c197 567 } else {
3b38ea61 568 TraceDebug.debug("No selected experiment information available"); //$NON-NLS-1$
8827c197 569 }
6e512b93
ASL
570 }
571
dfaf8391
FC
572 private void hookContextMenu() {
573 MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
574 menuMgr.setRemoveAllWhenShown(true);
575 menuMgr.addMenuListener(new IMenuListener() {
d4011df2 576 @Override
dfaf8391
FC
577 public void menuAboutToShow(IMenuManager manager) {
578 ControlFlowView.this.fillContextMenu(manager);
579 }
580 });
581 Menu menu = menuMgr.createContextMenu(tableViewer.getControl());
582 tableViewer.getControl().setMenu(menu);
583 getSite().registerContextMenu(menuMgr, tableViewer);
584 }
585
586 private void contributeToActionBars() {
587 IActionBars bars = getViewSite().getActionBars();
588 fillLocalPullDown(bars.getMenuManager());
589 fillLocalToolBar(bars.getToolBarManager());
590 }
591
592 private void fillLocalPullDown(IMenuManager manager) {
593 manager.add(new Separator());
c48abe58 594 manager.add(showLegend);
dfaf8391
FC
595 manager.add(new Separator());
596 manager.add(resetScale);
597 manager.add(nextEvent);
598 manager.add(prevEvent);
599 manager.add(nextTrace);
600 manager.add(prevTrace);
601 // manager.add(filterTraces);
602 manager.add(zoomIn);
603 manager.add(zoomOut);
8827c197 604 manager.add(zoomFilter);
dfaf8391
FC
605 manager.add(new Separator());
606 }
607
608 private void fillContextMenu(IMenuManager manager) {
c48abe58 609 manager.add(showLegend);
dfaf8391
FC
610 manager.add(new Separator());
611 manager.add(resetScale);
612 manager.add(nextEvent);
613 manager.add(prevEvent);
614 manager.add(nextTrace);
615 manager.add(prevTrace);
c48abe58 616 manager.add(showLegend);
dfaf8391
FC
617 // manager.add(filterTraces);
618 manager.add(zoomIn);
619 manager.add(zoomOut);
8827c197 620 manager.add(zoomFilter);
dfaf8391
FC
621 manager.add(new Separator());
622 manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
623 }
624
625 private void fillLocalToolBar(IToolBarManager manager) {
c48abe58 626 manager.add(showLegend);
dfaf8391
FC
627 manager.add(new Separator());
628 manager.add(resetScale);
629 manager.add(nextEvent);
630 manager.add(prevEvent);
631 manager.add(nextTrace);
632 manager.add(prevTrace);
633 // manager.add(filterTraces);
634 manager.add(zoomIn);
635 manager.add(zoomOut);
8827c197 636 manager.add(zoomFilter);
dfaf8391
FC
637 manager.add(new Separator());
638 }
639
640 private void makeActions() {
f1eb6a6b 641 // resetScale
dfaf8391
FC
642 resetScale = new Action() {
643 @Override
644 public void run() {
645 if (tsfviewer != null) {
646 tsfviewer.resetStartFinishTime();
647 }
648
649 }
650 };
651 resetScale.setText(Messages.getString("ControlFlowView.Action.Reset")); //$NON-NLS-1$
652 resetScale.setToolTipText(Messages
653 .getString("ControlFlowView.Action.Reset.ToolTip")); //$NON-NLS-1$
654 resetScale.setImageDescriptor(AbstractUIPlugin
655 .imageDescriptorFromPlugin(Messages
3b38ea61 656 .getString("ControlFlowView.tmf.UI"), //$NON-NLS-1$
7e71a0d6 657 "icons/elcl16/home_nav.gif")); //$NON-NLS-1$
dfaf8391 658
f1eb6a6b 659 // nextEvent
dfaf8391
FC
660 nextEvent = new Action() {
661 @Override
662 public void run() {
663 if (tsfviewer != null) {
664 tsfviewer.selectNextEvent();
665 }
666 }
667 };
668 nextEvent.setText(Messages
669 .getString("ControlFlowView.Action.NextEvent")); //$NON-NLS-1$
670 nextEvent.setToolTipText(Messages
671 .getString("ControlFlowView.Action.NextEvent.Tooltip")); //$NON-NLS-1$
672 nextEvent.setImageDescriptor(AbstractUIPlugin
673 .imageDescriptorFromPlugin(Messages
3b38ea61 674 .getString("ControlFlowView.tmf.UI"), //$NON-NLS-1$
7e71a0d6 675 "icons/elcl16/next_event.gif")); //$NON-NLS-1$
dfaf8391 676
f1eb6a6b 677 // prevEvent
dfaf8391 678 prevEvent = new Action() {
41dc35d0
FC
679 @Override
680 public void run() {
dfaf8391
FC
681 if (tsfviewer != null) {
682 tsfviewer.selectPrevEvent();
683 }
684 }
685 };
686 prevEvent.setText(Messages
687 .getString("ControlFlowView.Action.PrevEvent")); //$NON-NLS-1$
688 prevEvent.setToolTipText(Messages
689 .getString("ControlFlowView.Action.PrevEvent.Tooltip")); //$NON-NLS-1$
690 prevEvent.setImageDescriptor(AbstractUIPlugin
691 .imageDescriptorFromPlugin(Messages
3b38ea61 692 .getString("ControlFlowView.tmf.UI"), //$NON-NLS-1$
7e71a0d6 693 "icons/elcl16/prev_event.gif")); //$NON-NLS-1$
dfaf8391 694
f1eb6a6b 695 // nextTrace
dfaf8391
FC
696 nextTrace = new Action() {
697 @Override
698 public void run() {
699 if (tsfviewer != null) {
700 tsfviewer.selectNextTrace();
701 }
702 }
703 };
704 nextTrace.setText(Messages
705 .getString("ControlFlowView.Action.NextProcess")); //$NON-NLS-1$
706 nextTrace.setToolTipText(Messages
707 .getString("ControlFlowView.Action.NextProcess.ToolTip")); //$NON-NLS-1$
708 nextTrace.setImageDescriptor(AbstractUIPlugin
709 .imageDescriptorFromPlugin(Messages
3b38ea61 710 .getString("ControlFlowView.tmf.UI"), //$NON-NLS-1$
7e71a0d6 711 "icons/elcl16/next_item.gif")); //$NON-NLS-1$
dfaf8391 712
f1eb6a6b 713 // prevTrace
dfaf8391
FC
714 prevTrace = new Action() {
715 @Override
716 public void run() {
717 if (tsfviewer != null) {
718 tsfviewer.selectPrevTrace();
719 }
720 }
721 };
722 prevTrace.setText(Messages
723 .getString("ControlFlowView.Action.PreviousProcess")); //$NON-NLS-1$
724 prevTrace.setToolTipText(Messages
725 .getString("ControlFlowView.Action.PreviousProcess.Tooltip")); //$NON-NLS-1$
726 prevTrace.setImageDescriptor(AbstractUIPlugin
727 .imageDescriptorFromPlugin(Messages
3b38ea61 728 .getString("ControlFlowView.tmf.UI"), //$NON-NLS-1$
7e71a0d6 729 "icons/elcl16/prev_item.gif")); //$NON-NLS-1$
dfaf8391 730
f1eb6a6b 731 // showLegend
dfaf8391
FC
732 showLegend = new Action() {
733 @Override
734 public void run() {
735 if (tsfviewer != null) {
736 tsfviewer.showLegend();
737 }
738 }
739 };
740 showLegend.setText(Messages.getString("ControlFlowView.Action.Legend")); //$NON-NLS-1$
741 showLegend.setToolTipText(Messages
742 .getString("ControlFlowView.Action.Legend.ToolTip")); //$NON-NLS-1$
743
f1eb6a6b 744 // filterTraces
dfaf8391
FC
745 filterTraces = new Action() {
746 @Override
747 public void run() {
748 if (tsfviewer != null) {
749 tsfviewer.filterTraces();
750 }
751 }
752 };
753 filterTraces.setText(Messages
754 .getString("ControlFlowView.Action.Filter")); //$NON-NLS-1$
755 filterTraces.setToolTipText(Messages
756 .getString("ControlFlowView.Action.Filter.ToolTip")); //$NON-NLS-1$
757 filterTraces.setImageDescriptor(AbstractUIPlugin
758 .imageDescriptorFromPlugin(Messages
3b38ea61 759 .getString("ControlFlowView.tmf.UI"), //$NON-NLS-1$
7e71a0d6 760 "icons/elcl16/filter_items.gif")); //$NON-NLS-1$
dfaf8391 761
f1eb6a6b 762 // zoomIn
dfaf8391
FC
763 zoomIn = new Action() {
764 @Override
765 public void run() {
766 if (tsfviewer != null) {
767 tsfviewer.zoomIn();
768 }
769 }
770 };
771 zoomIn.setText(Messages.getString("ControlFlowView.Action.ZoomIn")); //$NON-NLS-1$
772 zoomIn.setToolTipText(Messages
773 .getString("ControlFlowView.Action.ZoomIn.Tooltip")); //$NON-NLS-1$
774 zoomIn.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(
3b38ea61 775 Messages.getString("ControlFlowView.tmf.UI"), //$NON-NLS-1$
7e71a0d6 776 "icons/elcl16/zoomin_nav.gif")); //$NON-NLS-1$
dfaf8391 777
f1eb6a6b 778 // zoomOut
dfaf8391
FC
779 zoomOut = new Action() {
780 @Override
781 public void run() {
782 if (tsfviewer != null) {
783 tsfviewer.zoomOut();
784 }
785 }
786 };
787 zoomOut.setText(Messages.getString("ControlFlowView.Action.ZoomOut")); //$NON-NLS-1$
788 zoomOut.setToolTipText(Messages
789 .getString("ControlFlowView.Action.ZoomOut.tooltip")); //$NON-NLS-1$
790 zoomOut.setImageDescriptor(AbstractUIPlugin.imageDescriptorFromPlugin(
3b38ea61 791 Messages.getString("ControlFlowView.tmf.UI"), //$NON-NLS-1$
7e71a0d6 792 "icons/elcl16/zoomout_nav.gif")); //$NON-NLS-1$
8827c197
FC
793
794 // zoomFilter
795 zoomFilter = new Action() {
dfaf8391
FC
796 @Override
797 public void run() {
8827c197
FC
798 // Nothing to do, however the selection status is needed by the
799 // application
dfaf8391
FC
800 }
801 };
8827c197
FC
802 zoomFilter.setText(Messages
803 .getString("ControlFlowView.Action.ZoomFilter")); //$NON-NLS-1$
804 zoomFilter.setToolTipText(Messages
805 .getString("ControlFlowView.Action.ZoomFilter.tooltip")); //$NON-NLS-1$
806 zoomFilter.setImageDescriptor(AbstractUIPlugin
807 .imageDescriptorFromPlugin(Messages
3b38ea61 808 .getString("ControlFlowView.tmf.UI"), //$NON-NLS-1$
7e71a0d6 809 "icons/elcl16/filter_items.gif")); //$NON-NLS-1$
8827c197
FC
810 zoomFilter.setChecked(false);
811
dfaf8391
FC
812 // PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_ELCL_SYNCED);
813
814 doubleClickAction = new Action() {
815 @Override
816 public void run() {
817 ISelection selection = tableViewer.getSelection();
818 Object obj = ((IStructuredSelection) selection)
819 .getFirstElement();
820 showMessage("Double-click detected on " + obj.toString()); //$NON-NLS-1$
821 }
822 };
823 }
824
825 private void hookDoubleClickAction() {
826 tableViewer.addDoubleClickListener(new IDoubleClickListener() {
d4011df2 827 @Override
dfaf8391
FC
828 public void doubleClick(DoubleClickEvent event) {
829 doubleClickAction.run();
830 }
831 });
832 }
833
834 private void showMessage(String message) {
835 MessageDialog.openInformation(tableViewer.getControl().getShell(),
836 Messages.getString("ControlFlowView.msgSlogan"), message); //$NON-NLS-1$
837 }
838
839 /**
840 * Passing the focus request to the viewer's control.
6e512b93
ASL
841 */
842 @Override
843 public void setFocus() {
dfaf8391
FC
844 tableViewer.getControl().setFocus();
845 }
846
8827c197
FC
847 /*
848 * (non-Javadoc)
849 *
850 * @see org.eclipse.linuxtools.lttng.ui.views.common.AbsTimeUpdateView#
851 * tsfTmProcessSelEvent
852 * (org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.TmfTimeSelectionEvent
853 * )
854 */
550d787e 855 @Override
dfaf8391 856 public void tsfTmProcessSelEvent(TmfTimeSelectionEvent event) {
8827c197
FC
857 // common implementation
858 super.tsfTmProcessSelEvent(event);
dfaf8391
FC
859
860 // Reselect the table viewer to widget selection
861 ISelection sel = tsfviewer.getSelectionTrace();
862 if (sel != null && !sel.isEmpty()) {
863 tableViewer.setSelection(sel);
864 }
dfaf8391
FC
865 }
866
8827c197
FC
867 /*
868 * (non-Javadoc)
dfaf8391 869 *
8827c197
FC
870 * @see org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.
871 * ITmfTimeScaleSelectionListener
872 * #tsfTmProcessTimeScaleEvent(org.eclipse.linuxtools
873 * .tmf.ui.viewers.timeAnalysis.TmfTimeScaleSelectionEvent)
dfaf8391 874 */
550d787e 875 @Override
c1c69938 876 public void tsfTmProcessTimeScaleEvent(TmfTimeScaleSelectionEvent event) {
8827c197 877 super.tsfTmProcessTimeScaleEvent(event);
dfaf8391 878 }
8035003b 879
dfaf8391
FC
880 private void applyTableLayout(Table table) {
881 for (int i = 0; i < columnNames.length; i++) {
882 TableColumn tableColumn = new TableColumn(table, SWT.LEFT);
883 tableColumn.setText(columnNames[i]);
884 tableColumn.pack();
885 }
886 table.setHeaderVisible(true);
887 table.setLinesVisible(true);
888 }
889
8827c197
FC
890 /*
891 * (non-Javadoc)
892 *
893 * @see
894 * org.eclipse.linuxtools.lttng.ui.views.common.AbsTimeUpdateView#displayModel
895 * (org.eclipse.linuxtools.tmf.ui.viewers.timeAnalysis.model.
896 * ITmfTimeAnalysisEntry[], long, long, boolean, long, long,
897 * java.lang.Object)
d712a5f3 898 */
550d787e 899 @Override
8827c197
FC
900 public void displayModel(final ITmfTimeAnalysisEntry[] items,
901 final long startBoundTime, final long endBoundTime,
902 final boolean updateTimeBounds, final long startVisibleWindow,
903 final long endVisibleWindow, final Object source) {
3e9fdb8b
FC
904
905 if(tableViewer != null) {
906 final Table table = tableViewer.getTable();
db1ea19b
FC
907
908 // Ignore update if widget is disposed
909 if (table.isDisposed()) return;
910
3e9fdb8b 911 Display display = table.getDisplay();
db1ea19b 912
3e9fdb8b
FC
913 // Perform the updates on the UI thread)
914 display.asyncExec(new Runnable() {
d4011df2 915 @Override
3e9fdb8b 916 public void run() {
db1ea19b
FC
917 if (!table.isDisposed()) {
918 tableViewer.setInput(items); // This shall be the minimal
919 // initial
920 tableFilter = new ViewProcessFilter(tableViewer);
921 tableViewer.setFilters(new ViewerFilter[] { tableFilter });
922
923 resizeTableColumns(table);
924 table.update();
925 tableViewer.refresh();
926
927 tsfviewer.display(items, startBoundTime, endBoundTime,
928 updateTimeBounds);
929
930 // validate visible boundaries
931 if (startVisibleWindow > -1 && endVisibleWindow > -1) {
932 tsfviewer.setSelectVisTimeWindow(startVisibleWindow,
933 endVisibleWindow, source);
934 }
935
936 tsfviewer.resizeControls();
937
15beb3f1
FC
938 // Adjust asynchronously the size of the vertical scroll bar to fit the
939 // contents
940 tableViewer.getTable().getDisplay().asyncExec(new Runnable() {
941 @Override
942 public void run() {
b12f4544 943 if ((scrollFrame != null) && (!scrollFrame.isDisposed())) {
15beb3f1
FC
944 updateScrolls(scrollFrame);
945 }
946 }
947 });
3e9fdb8b 948 }
dfaf8391 949 }
3e9fdb8b
FC
950 });
951 }
dfaf8391
FC
952 }
953
954 @Override
955 public void dispose() {
956 // dispose parent resources
957 super.dispose();
dfaf8391 958
dfaf8391
FC
959 tsfviewer.removeFilterSelectionListner(this);
960 tsfviewer.removeWidgetSelectionListner(this);
961 tsfviewer.removeWidgetTimeScaleSelectionListner(this);
962 tableViewer = null;
963 tsfviewer = null;
964 }
965
966 /**
967 * @param tableComposite
968 * @param table
969 */
970 private synchronized void resizeTableColumns(Table table) {
971 if (table != null) {
dfaf8391
FC
972 TableColumn[] columns = table.getColumns();
973 for (TableColumn column : columns) {
974 column.pack();
dfaf8391
FC
975 }
976 }
977 }
978
d4011df2 979 @Override
dfaf8391
FC
980 public void tmfTaProcessFilterSelection(TmfTimeFilterSelectionEvent event) {
981 if (tableFilter != null) {
982 Vector<ITmfTimeAnalysisEntry> filteredout = event.getFilteredOut();
983 if (filteredout != null) {
984 tableFilter.setFilter(filteredout);
985 } else {
986 tableFilter.setFilter(new Vector<ITmfTimeAnalysisEntry>());
987 }
988 tableViewer.refresh();
989 }
990 }
991
dfaf8391
FC
992 /**
993 * @param scrollFrame
994 * @param wrapper
995 */
8827c197
FC
996 private void updateScrolls(final ScrolledComposite scrollFrame) {
997 scrollFrame.setMinSize(tableViewer.getTable().computeSize(SWT.DEFAULT, SWT.DEFAULT));
dfaf8391
FC
998 }
999
1000 /**
8827c197 1001 * Registers as listener of time selection from other views
dfaf8391 1002 *
8827c197 1003 * @param signal
dfaf8391 1004 */
550d787e 1005 @Override
8827c197
FC
1006 @TmfSignalHandler
1007 public void synchToTime(TmfTimeSynchSignal signal) {
1008 super.synchToTime(signal);
dfaf8391
FC
1009 }
1010
1011 /**
8827c197
FC
1012 * Annotation Registers as listener of time range selection from other views
1013 * The implementation handles the entry of the signal.
dfaf8391
FC
1014 *
1015 * @param signal
1016 */
1017 @TmfSignalHandler
8827c197
FC
1018 public void synchToTimeRange(TmfRangeSynchSignal signal) {
1019 if (zoomFilter != null) {
1020 synchToTimeRange(signal, zoomFilter.isChecked());
dfaf8391 1021 }
6e512b93
ASL
1022 }
1023
39332b5c 1024 @Override
8827c197
FC
1025 public void modelIncomplete(ILttngSyntEventRequest request) {
1026 // Nothing to do
1027 // The data will be refreshed on the next request
41dc35d0
FC
1028 }
1029
1030 /*
1031 * (non-Javadoc)
1032 *
8827c197
FC
1033 * @see org.eclipse.linuxtools.lttng.ui.views.common.AbsTimeUpdateView#
1034 * getEventProcessor()
41dc35d0 1035 */
39332b5c 1036 @Override
8827c197
FC
1037 public ITransEventProcessor getEventProcessor() {
1038 return FlowEventToHandlerFactory.getInstance();
1039 }
d712a5f3 1040
8827c197
FC
1041 /**
1042 * @param signal
1043 */
1044 @TmfSignalHandler
1045 public void experimentSelected(
1046 TmfExperimentSelectedSignal<? extends TmfEvent> signal) {
1047 if (signal != null) {
1048 TmfTimeRange experimentTRange = signal.getExperiment()
1049 .getTimeRange();
1050
a79913eb
FC
1051 initTimeRange = TmfTimeRange.Null;
1052 if (experimentTRange != TmfTimeRange.Null) {
1053 // prepare time intervals in widget
1054 ModelUpdateInit(experimentTRange, experimentTRange, signal
1055 .getSource());
1056
1057 // request initial data
1058 initialExperimentDataRequest(signal
1059 .getSource(), experimentTRange);
1060 }
1061 }
1062 }
1063
1064 @TmfSignalHandler
1065 public void experimentRangeUpdated(TmfExperimentRangeUpdatedSignal signal) {
1066 if (initTimeRange == TmfTimeRange.Null && signal.getExperiment().equals(TmfExperiment.getCurrentExperiment())) {
1067 TmfTimeRange experimentTRange = signal.getRange();
1068
1069 if (experimentTRange != TmfTimeRange.Null) {
1070 // prepare time intervals in widget
1071 ModelUpdateInit(experimentTRange, experimentTRange, signal.getSource());
8827c197 1072
a79913eb
FC
1073 // request initial data
1074 initialExperimentDataRequest(signal.getSource(), experimentTRange);
1075 }
d712a5f3 1076 }
41dc35d0
FC
1077 }
1078
d61e0854
PT
1079 @TmfSignalHandler
1080 public void experimentUpdated(TmfExperimentUpdatedSignal signal) {
1081 if (signal.getExperiment().equals(TmfExperiment.getCurrentExperiment())) {
1082 final TmfTimeRange range = signal.getExperiment().getTimeRange();
1083 if (range != TmfTimeRange.Null) {
1084 Display.getDefault().asyncExec(new Runnable() {
1085 @Override
1086 public void run() {
1087 tsfviewer.setTimeBounds(range.getStartTime().getValue(), range.getEndTime().getValue());
1088 }});
1089 }
1090 }
1091 }
1092
8827c197
FC
1093 /**
1094 * @param source
1095 * @param experimentTRange
1096 * @return Adjusted time window used for the request (smaller window to
1097 * initialize view)
41dc35d0 1098 */
8827c197
FC
1099 private TmfTimeRange initialExperimentDataRequest(Object source,
1100 TmfTimeRange experimentTRange) {
1101 // Adjust the initial time window to a shorter interval to allow
1102 // user to select the interesting area based on the perspective
1103 TmfTimeRange initTimeWindow = getInitTRange(experimentTRange);
41dc35d0 1104
a79913eb 1105 eventRequest(initTimeWindow, experimentTRange, true, ExecutionType.FOREGROUND);
41dc35d0 1106 if (TraceDebug.isDEBUG()) {
3b38ea61
FC
1107 TraceDebug.debug("Initialization request time range is: " //$NON-NLS-1$
1108 + initTimeWindow.getStartTime().toString() + "-" //$NON-NLS-1$
8827c197 1109 + initTimeWindow.getEndTime().toString());
41dc35d0 1110 }
8827c197 1111
a79913eb 1112 initTimeRange = initTimeWindow;
8827c197 1113 return initTimeWindow;
41dc35d0 1114 }
542c8a2e 1115
162eeb24
FC
1116 /*
1117 * SWT doesn't seem to report correctly the table item height, at least in
1118 * the case of KDE.
1119 *
1120 * This method provides an adjustment term according to the desktop session.
1121 *
1122 * @return Height adjustment
1123 */
1124 private int getTableItemHeightAdjustement() {
1125 int ajustement = 0;
1126 String desktopSession = System.getenv("DESKTOP_SESSION"); //$NON-NLS-1$
1127
1128 if (desktopSession != null) {
1129 if (desktopSession.equals("kde")) { //$NON-NLS-1$
1130 ajustement = 2;
1131 }
542c8a2e 1132 }
162eeb24
FC
1133
1134 return ajustement;
542c8a2e 1135 }
542c8a2e 1136
8827c197
FC
1137 /*
1138 * (non-Javadoc)
1139 *
1140 * @see org.eclipse.linuxtools.lttng.ui.views.common.AbsTimeUpdateView#
1141 * getParamsUpdater()
1142 */
1143 @Override
1144 protected ParamsUpdater getParamsUpdater() {
1145 return FlowModelFactory.getParamsUpdater();
1146 }
1147
1148 /*
1149 * (non-Javadoc)
1150 *
1151 * @see org.eclipse.linuxtools.lttng.ui.views.common.AbsTimeUpdateView#
1152 * getItemContainer()
1153 */
1154 @Override
1155 protected ItemContainer<?> getItemContainer() {
1156 return FlowModelFactory.getProcContainer();
1157 }
c1c69938
FC
1158
1159 /*
1160 * (non-Javadoc)
1161 * @see org.eclipse.linuxtools.lttng.ui.views.common.AbsTimeUpdateView#getProviderId()
1162 */
1163 @Override
1164 protected int getProviderId() {
1165 return LttngCoreProviderFactory.CONTROL_FLOW_LTTNG_SYTH_EVENT_PROVIDER;
1166 }
8827c197 1167}
This page took 0.096176 seconds and 5 git commands to generate.