Force pin action on all views
[deliverable/tracecompass.git] / pcap / org.eclipse.tracecompass.tmf.pcap.ui / src / org / eclipse / tracecompass / internal / tmf / pcap / ui / stream / StreamListView.java
CommitLineData
b6eb4dce 1/*******************************************************************************
ec34bf48 2 * Copyright (c) 2014, 2015 Ericsson
b6eb4dce
VP
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 * Vincent Perot - Initial API and implementation
ec34bf48 11 * Patrick Tasse - Support aspect filters
b6eb4dce
VP
12 *******************************************************************************/
13
2bdf0193 14package org.eclipse.tracecompass.internal.tmf.pcap.ui.stream;
b6eb4dce 15
b6eb4dce
VP
16import java.util.HashMap;
17import java.util.List;
18import java.util.Map;
bcd98b74 19import java.util.Map.Entry;
b6eb4dce 20
b6eb4dce 21import org.eclipse.jdt.annotation.Nullable;
b6eb4dce
VP
22import org.eclipse.swt.SWT;
23import org.eclipse.swt.custom.CTabFolder;
24import org.eclipse.swt.custom.CTabItem;
25import org.eclipse.swt.events.SelectionAdapter;
26import org.eclipse.swt.events.SelectionEvent;
27import org.eclipse.swt.widgets.Composite;
28import org.eclipse.swt.widgets.Display;
29import org.eclipse.swt.widgets.Event;
30import org.eclipse.swt.widgets.Listener;
31import org.eclipse.swt.widgets.Menu;
32import org.eclipse.swt.widgets.MenuItem;
33import org.eclipse.swt.widgets.Table;
34import org.eclipse.swt.widgets.TableColumn;
35import org.eclipse.swt.widgets.TableItem;
2bdf0193 36import org.eclipse.tracecompass.internal.tmf.pcap.core.analysis.StreamListAnalysis;
2bdf0193
AM
37import org.eclipse.tracecompass.internal.tmf.pcap.core.event.TmfPacketStream;
38import org.eclipse.tracecompass.internal.tmf.pcap.core.event.TmfPacketStreamBuilder;
ec34bf48
PT
39import org.eclipse.tracecompass.internal.tmf.pcap.core.event.aspect.PcapDestinationAspect;
40import org.eclipse.tracecompass.internal.tmf.pcap.core.event.aspect.PcapSourceAspect;
2bdf0193
AM
41import org.eclipse.tracecompass.internal.tmf.pcap.core.protocol.TmfPcapProtocol;
42import org.eclipse.tracecompass.internal.tmf.pcap.core.signal.TmfPacketStreamSelectedSignal;
43import org.eclipse.tracecompass.internal.tmf.pcap.core.trace.PcapTrace;
44import org.eclipse.tracecompass.internal.tmf.pcap.ui.Activator;
d187a29b 45import org.eclipse.tracecompass.tmf.core.event.aspect.TmfBaseAspects;
2bdf0193
AM
46import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
47import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterAndNode;
ec34bf48 48import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterAspectNode;
2bdf0193
AM
49import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterContainsNode;
50import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
51import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterOrNode;
52import org.eclipse.tracecompass.tmf.core.signal.TmfSignal;
53import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
54import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
55import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
56import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
57import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
58import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
21852dfa 59import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
b8585c7c 60import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
2bdf0193
AM
61import org.eclipse.tracecompass.tmf.ui.project.model.TraceUtils;
62import org.eclipse.tracecompass.tmf.ui.views.TmfView;
63import org.eclipse.tracecompass.tmf.ui.views.filter.FilterManager;
64import org.eclipse.tracecompass.tmf.ui.views.filter.FilterView;
b6eb4dce
VP
65import org.eclipse.ui.IViewPart;
66import org.eclipse.ui.IWorkbench;
67import org.eclipse.ui.IWorkbenchPage;
68import org.eclipse.ui.PartInitException;
69import org.eclipse.ui.PlatformUI;
70
e883975e
PT
71import com.google.common.collect.Lists;
72
b6eb4dce
VP
73/**
74 * Class that represents the Stream List View. Such a view lists all the
75 * available streams from the current experiment. <br>
76 * <br>
77 * TODO Switch to TmfUiRefreshHandler once the behavior is fixed
78 *
79 * FIXME analysis is leaking ressource. Someone I will not name told me not to worry about it since
80 * AnalysisModule will not be autocloseable later.
81 *
82 * @author Vincent Perot
83 */
84public class StreamListView extends TmfView {
85
86 /**
87 * The Stream List View ID.
88 */
89 public static final String ID = "org.eclipse.linuxtools.tmf.pcap.ui.view.stream.list"; //$NON-NLS-1$
90
91 private static final String[] COLUMN_NAMES =
92 { Messages.StreamListView_ID,
93 Messages.StreamListView_EndpointA,
94 Messages.StreamListView_EndpointB,
95 Messages.StreamListView_TotalPackets,
96 Messages.StreamListView_TotalBytes,
97 Messages.StreamListView_PacketsAtoB,
98 Messages.StreamListView_BytesAtoB,
99 Messages.StreamListView_PacketsBtoA,
100 Messages.StreamListView_BytesBtoA,
101 Messages.StreamListView_StartTime,
102 Messages.StreamListView_StopTime,
103 Messages.StreamListView_Duration,
104 Messages.StreamListView_BPSAtoB,
105 Messages.StreamListView_BPSBtoA
106 };
107
108 private static final int[] COLUMN_SIZES =
109 { 75,
110 350,
111 350,
112 110,
113 110,
114 110,
115 110,
116 110,
117 110,
118 180,
119 180,
120 110,
121 110,
122 110 };
123
124 private static final String KEY_PROTOCOL = "$protocol$"; //$NON-NLS-1$
125 private static final String KEY_STREAM = "$stream$"; //$NON-NLS-1$
126
127 private static final String EMPTY_STRING = ""; //$NON-NLS-1$
128
129 private static final long WAIT_TIME = 1000;
130
131 private @Nullable CTabFolder fTabFolder;
c88feda9 132 private @Nullable Map<TmfPcapProtocol, Table> fTableMap;
b6eb4dce
VP
133
134 private @Nullable TmfPacketStream fCurrentStream;
135 private @Nullable ITmfTrace fCurrentTrace;
136
137 private volatile boolean fStopThread;
138
139 /**
140 * Constructor of the StreamListView class.
141 */
142 public StreamListView() {
143 super(ID);
144 }
145
146 /**
147 * Handler called when an trace is opened.
148 *
149 * @param signal
150 * Contains the information about the selection.
151 */
152 @TmfSignalHandler
153 public void traceOpened(TmfTraceOpenedSignal signal) {
154 fCurrentTrace = signal.getTrace();
155 resetView();
156 queryAnalysis();
157 }
158
159 /**
160 * Handler called when an trace is closed. Checks if the trace is the
161 * current trace and update the view accordingly.
162 *
163 * @param signal
164 * Contains the information about the selection.
165 */
166 @TmfSignalHandler
167 public void traceClosed(TmfTraceClosedSignal signal) {
168 if (fCurrentTrace == signal.getTrace()) {
169 fCurrentTrace = null;
170 resetView();
171 }
172 }
173
174 /**
175 * Handler called when an trace is selected. Checks if the trace has changed
176 * and requests the selected trace if it has not yet been cached.
177 *
178 * @param signal
179 * Contains the information about the selection.
180 */
181 @TmfSignalHandler
182 public void traceSelected(TmfTraceSelectedSignal signal) {
183 if (fCurrentTrace != signal.getTrace()) {
184 fCurrentTrace = signal.getTrace();
185 resetView();
186 queryAnalysis();
187 }
188 }
189
190 private void queryAnalysis() {
191 Thread thread = new Thread(new Runnable() {
192
193 @Override
194 public void run() {
195 ITmfTrace trace = fCurrentTrace;
71325eeb 196 if (trace == null) {
b6eb4dce
VP
197 return;
198 }
b8585c7c 199 StreamListAnalysis analysis = TmfTraceUtils.getAnalysisModuleOfClass(trace, StreamListAnalysis.class, StreamListAnalysis.ID);
b6eb4dce
VP
200 if (analysis == null) {
201 return;
202 }
203 while (!analysis.isFinished() && !fStopThread) {
204 updateUI();
205 try {
206 Thread.sleep(WAIT_TIME);
207 } catch (InterruptedException e) {
208 String message = e.getMessage();
209 if (message == null) {
210 message = EMPTY_STRING;
211 }
212 Activator.logError(message, e);
213 return;
214 }
215 }
216 // Update UI one more time (daft punk)
217 if (!fStopThread) {
218 updateUI();
219 }
220
221 }
222 });
223
224 fStopThread = false;
225 thread.start();
226 }
227
228 private void resetView() {
229
230 // Stop thread if needed
231 fStopThread = true;
232
233 // Remove all content in tables
234 final Display display = Display.getDefault();
235 if (display == null || display.isDisposed()) {
236 return;
237 }
238 display.asyncExec(new Runnable() {
239
240 @Override
241 public void run() {
242 if (display.isDisposed()) {
243 return;
244 }
c88feda9 245 Map<TmfPcapProtocol, Table> tableMap = fTableMap;
b6eb4dce
VP
246 if (tableMap == null) {
247 return;
248 }
bcd98b74
MK
249 for (Table table : tableMap.values()) {
250 if (!table.isDisposed()) {
251 table.removeAll();
b6eb4dce
VP
252 }
253 }
254 }
255 });
256 }
257
258 private void updateUI() {
259 final Display display = Display.getDefault();
260 if (display == null || display.isDisposed()) {
261 return;
262 }
263 display.asyncExec(new Runnable() {
264
265 @Override
266 public void run() {
267 if (display.isDisposed()) {
268 return;
269 }
270 ITmfTrace trace = fCurrentTrace;
271 if (trace == null) {
272 return;
273 }
274
b8585c7c 275 StreamListAnalysis analysis = TmfTraceUtils.getAnalysisModuleOfClass(trace, StreamListAnalysis.class, StreamListAnalysis.ID);
b6eb4dce
VP
276 if (analysis == null) {
277 return;
278 }
279
c88feda9 280 Map<TmfPcapProtocol, Table> tables = fTableMap;
b6eb4dce
VP
281 if (tables == null) {
282 return;
283 }
bcd98b74
MK
284 for (Entry<TmfPcapProtocol, Table> protocolEntry : tables.entrySet()) {
285 TmfPcapProtocol protocol = protocolEntry.getKey();
b6eb4dce 286 TmfPacketStreamBuilder builder = analysis.getBuilder(protocol);
bcd98b74
MK
287 Table table = protocolEntry.getValue();
288 if (builder != null && !(table.isDisposed())) {
b6eb4dce
VP
289 for (TmfPacketStream stream : builder.getStreams()) {
290
291 TableItem item;
bcd98b74
MK
292 if (stream.getID() < table.getItemCount()) {
293 item = table.getItem(stream.getID());
b6eb4dce 294 } else {
bcd98b74 295 item = new TableItem(table, SWT.NONE);
b6eb4dce
VP
296 }
297 item.setText(0, String.valueOf(stream.getID()));
298 item.setText(1, stream.getFirstEndpoint().toString());
299 item.setText(2, stream.getSecondEndpoint().toString());
300 item.setText(3, String.valueOf(stream.getNbPackets()));
301 item.setText(4, String.valueOf(stream.getNbBytes()));
302 item.setText(5, String.valueOf(stream.getNbPacketsAtoB()));
303 item.setText(6, String.valueOf(stream.getNbBytesAtoB()));
304 item.setText(7, String.valueOf(stream.getNbPacketsBtoA()));
305 item.setText(8, String.valueOf(stream.getNbBytesBtoA()));
306 item.setText(9, stream.getStartTime().toString());
307 item.setText(10, stream.getStopTime().toString());
308 item.setText(11, String.format("%.3f", stream.getDuration())); //$NON-NLS-1$
309 item.setText(12, String.format("%.3f", stream.getBPSAtoB())); //$NON-NLS-1$
310 item.setText(13, String.format("%.3f", stream.getBPSBtoA())); //$NON-NLS-1$
311 item.setData(KEY_STREAM, stream);
312 }
313 }
314 }
315 }
316
317 });
318 }
319
320 @Override
321 public void createPartControl(@Nullable Composite parent) {
322 // Initialize
7ab857a1
MAL
323 final Map<TmfPcapProtocol, Table> tables = new HashMap<>();
324 fTableMap = tables;
21852dfa 325 fCurrentTrace = TmfTraceManager.getInstance().getActiveTrace();
b6eb4dce
VP
326 fCurrentStream = null;
327
328 // Add a tab folder
329 fTabFolder = new CTabFolder(parent, SWT.NONE);
330 fTabFolder.addSelectionListener(new SelectionAdapter() {
331
332 @Override
333 public void widgetSelected(@Nullable SelectionEvent e) {
7ab857a1 334 if (e == null) {
b6eb4dce
VP
335 return;
336 }
c88feda9 337 TmfPcapProtocol protocol = (TmfPcapProtocol) e.item.getData(KEY_PROTOCOL);
94411c58
AM
338 final Table table = tables.get(protocol);
339 if (table != null) {
340 table.deselectAll();
341 }
b6eb4dce
VP
342 fCurrentStream = null;
343 }
344
345 });
346
347 // Add items and tables for each protocol
e20e3d49 348 for (TmfPcapProtocol protocol : TmfPcapProtocol.values()) {
b6eb4dce
VP
349 if (protocol.supportsStream()) {
350 CTabItem item = new CTabItem(fTabFolder, SWT.NONE);
351 item.setText(protocol.getName());
352 item.setData(KEY_PROTOCOL, protocol);
353 Table table = new Table(fTabFolder, SWT.NONE);
354 table.setHeaderVisible(true);
355 table.setLinesVisible(true);
356
357 // Add columns to table
358 for (int i = 0; i < COLUMN_NAMES.length || i < COLUMN_SIZES.length; i++) {
359 TableColumn column = new TableColumn(table, SWT.NONE);
360 column.setText(COLUMN_NAMES[i]);
361 column.setWidth(COLUMN_SIZES[i]);
362 }
363 item.setControl(table);
364 table.addSelectionListener(new SelectionAdapter() {
365
366 @Override
367 public void widgetSelected(@Nullable SelectionEvent e) {
368 if (e == null) {
369 return;
370 }
371 fCurrentStream = (TmfPacketStream) e.item.getData(KEY_STREAM);
372 }
373
374 });
375
b6eb4dce
VP
376 tables.put(protocol, table);
377
378 // Add right click menu
379 Menu menu = new Menu(table);
380 MenuItem menuItem = new MenuItem(menu, SWT.PUSH);
381 menuItem.setText(Messages.StreamListView_FollowStream);
382 menuItem.addListener(SWT.Selection, new Listener() {
383
384 @Override
385 public void handleEvent(@Nullable Event event) {
386 TmfSignal signal = new TmfPacketStreamSelectedSignal(this, 0, fCurrentStream);
387 TmfSignalManager.dispatchSignal(signal);
388 }
389 });
390 menuItem = new MenuItem(menu, SWT.PUSH);
391 menuItem.setText(Messages.StreamListView_Clear);
392 menuItem.addListener(SWT.Selection, new Listener() {
393
394 @Override
395 public void handleEvent(@Nullable Event event) {
396 TmfSignal signal = new TmfPacketStreamSelectedSignal(this, 0, null);
397 TmfSignalManager.dispatchSignal(signal);
398
399 }
400 });
401 menuItem = new MenuItem(menu, SWT.PUSH);
402 menuItem.setText(Messages.StreamListView_ExtractAsFilter);
403 menuItem.addListener(SWT.Selection, new Listener() {
404
405 @Override
406 public void handleEvent(@Nullable Event event) {
407 // Generate filter.
408 ITmfFilterTreeNode filter = generateFilter();
409
410 // Update view and XML
411 updateFilters(filter);
412
413 }
414
415 private void updateFilters(@Nullable ITmfFilterTreeNode filter) {
416 if (filter == null) {
417 return;
418 }
419
420 // Update XML
e883975e
PT
421 List<ITmfFilterTreeNode> filters = Lists.newArrayList(FilterManager.getSavedFilters());
422 boolean newFilter = true;
423 for (ITmfFilterTreeNode savedFilter : filters) {
424 // Use toString(explicit) equality because equals() is not implemented
425 if (savedFilter.toString(true).equals(filter.toString(true))) {
426 newFilter = false;
427 break;
428 }
b6eb4dce 429 }
e883975e
PT
430 if (newFilter) {
431 filters.add(filter);
432 FilterManager.setSavedFilters(filters.toArray(new ITmfFilterTreeNode[filters.size()]));
b6eb4dce
VP
433 }
434
435 // Update Filter View
436 try {
437 final IWorkbench wb = PlatformUI.getWorkbench();
438 final IWorkbenchPage activePage = wb.getActiveWorkbenchWindow().getActivePage();
439 IViewPart view = activePage.showView(FilterView.ID);
440 FilterView filterView = (FilterView) view;
441 filterView.addFilter(filter);
442 } catch (final PartInitException e) {
443 TraceUtils.displayErrorMsg(Messages.StreamListView_ExtractAsFilter, "Error opening view " + FilterView.ID + e.getMessage()); //$NON-NLS-1$
444 Activator.logError("Error opening view " + FilterView.ID, e); //$NON-NLS-1$
445 return;
446 }
447
448 }
449
450 private @Nullable ITmfFilterTreeNode generateFilter() {
451 TmfPacketStream stream = fCurrentStream;
452 if (stream == null) {
453 return null;
454 }
455
456 // First stage - root
457 String name = Messages.StreamListView_FilterName_Stream + ' ' + stream.getProtocol().getShortName() + ' ' + stream.getFirstEndpoint()
458 + " <--> " + stream.getSecondEndpoint(); //$NON-NLS-1$
459 TmfFilterNode root = new TmfFilterNode(name);
460
461 // Second stage - and
462 TmfFilterAndNode and = new TmfFilterAndNode(root);
463
464 // Third stage - protocol + or
465 TmfFilterContainsNode protocolFilter = new TmfFilterContainsNode(and);
d187a29b 466 protocolFilter.setEventAspect(TmfBaseAspects.getContentsAspect().forField(stream.getProtocol().getName()));
40dfafb3 467 protocolFilter.setTraceTypeId(TmfFilterAspectNode.BASE_ASPECT_ID);
b6eb4dce
VP
468 protocolFilter.setValue(EMPTY_STRING);
469 TmfFilterOrNode or = new TmfFilterOrNode(and);
470
471 // Fourth stage - and
472 TmfFilterAndNode andA = new TmfFilterAndNode(or);
473 TmfFilterAndNode andB = new TmfFilterAndNode(or);
474
475 // Fourth stage - endpoints
476 TmfFilterContainsNode endpointAAndA = new TmfFilterContainsNode(andA);
ec34bf48
PT
477 endpointAAndA.setEventAspect(PcapSourceAspect.INSTANCE);
478 endpointAAndA.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
b6eb4dce
VP
479 endpointAAndA.setValue(stream.getFirstEndpoint());
480 TmfFilterContainsNode endpointBAndA = new TmfFilterContainsNode(andA);
ec34bf48
PT
481 endpointBAndA.setEventAspect(PcapDestinationAspect.INSTANCE);
482 endpointBAndA.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
b6eb4dce
VP
483 endpointBAndA.setValue(stream.getSecondEndpoint());
484 TmfFilterContainsNode endpointAAndB = new TmfFilterContainsNode(andB);
ec34bf48
PT
485 endpointAAndB.setEventAspect(PcapSourceAspect.INSTANCE);
486 endpointAAndB.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
b6eb4dce
VP
487 endpointAAndB.setValue(stream.getSecondEndpoint());
488 TmfFilterContainsNode endpointBAndB = new TmfFilterContainsNode(andB);
ec34bf48
PT
489 endpointBAndB.setEventAspect(PcapDestinationAspect.INSTANCE);
490 endpointBAndB.setTraceTypeId(PcapTrace.TRACE_TYPE_ID);
b6eb4dce
VP
491 endpointBAndB.setValue(stream.getFirstEndpoint());
492
493 return root;
494 }
495 });
496 table.setMenu(menu);
497 }
498 }
499
500 // Ask the analysis for data.
501 queryAnalysis();
502 }
503
504 @Override
505 public void setFocus() {
506 CTabFolder tabFolder = fTabFolder;
507 if (tabFolder != null && !(tabFolder.isDisposed())) {
508 tabFolder.setFocus();
509 }
510 }
511
6e1b4486
JR
512 @Override
513 protected boolean canBePinned() {
514 //TODO: actionPin is not defined
515 return false;
516 }
517
b6eb4dce 518}
This page took 0.086405 seconds and 5 git commands to generate.