tmf: Move TmfExperiment to its own package
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / editors / TmfEventsEditor.java
1 /*******************************************************************************
2 * Copyright (c) 2010, 2014 Ericsson, École Polytechnique de Montréal
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 * Patrick Tasse - Initial API and implementation
11 * Geneviève Bastien - Experiment instantiated with experiment type
12 *******************************************************************************/
13
14 package org.eclipse.tracecompass.tmf.ui.editors;
15
16 import java.util.Collection;
17 import java.util.LinkedHashSet;
18 import java.util.Set;
19
20 import org.eclipse.core.resources.IFile;
21 import org.eclipse.core.resources.IMarker;
22 import org.eclipse.core.resources.IMarkerDelta;
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.resources.IResourceChangeEvent;
25 import org.eclipse.core.resources.IResourceChangeListener;
26 import org.eclipse.core.resources.IResourceDelta;
27 import org.eclipse.core.resources.ResourcesPlugin;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.core.runtime.IProgressMonitor;
30 import org.eclipse.core.runtime.InvalidRegistryObjectException;
31 import org.eclipse.core.runtime.ListenerList;
32 import org.eclipse.jdt.annotation.NonNull;
33 import org.eclipse.jdt.annotation.Nullable;
34 import org.eclipse.jface.action.IStatusLineManager;
35 import org.eclipse.jface.util.SafeRunnable;
36 import org.eclipse.jface.viewers.ISelection;
37 import org.eclipse.jface.viewers.ISelectionChangedListener;
38 import org.eclipse.jface.viewers.ISelectionProvider;
39 import org.eclipse.jface.viewers.SelectionChangedEvent;
40 import org.eclipse.jface.viewers.StructuredSelection;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Display;
43 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
44 import org.eclipse.tracecompass.tmf.core.TmfCommonConstants;
45 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
46 import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
47 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
48 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
49 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
50 import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
51 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
52 import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
53 import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
54 import org.eclipse.tracecompass.tmf.ui.project.model.Messages;
55 import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement;
56 import org.eclipse.tracecompass.tmf.ui.project.model.TmfOpenTraceHelper;
57 import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement;
58 import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry;
59 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement;
60 import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceTypeUIUtils;
61 import org.eclipse.tracecompass.tmf.ui.viewers.events.TmfEventsTable;
62 import org.eclipse.tracecompass.tmf.ui.viewers.events.columns.TmfEventTableColumn;
63 import org.eclipse.ui.IEditorInput;
64 import org.eclipse.ui.IEditorPart;
65 import org.eclipse.ui.IEditorSite;
66 import org.eclipse.ui.IFileEditorInput;
67 import org.eclipse.ui.IPartListener;
68 import org.eclipse.ui.IPropertyListener;
69 import org.eclipse.ui.IReusableEditor;
70 import org.eclipse.ui.IWorkbenchPart;
71 import org.eclipse.ui.PartInitException;
72 import org.eclipse.ui.ide.IGotoMarker;
73 import org.eclipse.ui.part.FileEditorInput;
74 import org.eclipse.ui.views.properties.IPropertySheetPage;
75
76 /**
77 * Editor for TMF events
78 *
79 * @version 1.0
80 * @author Patrick Tasse
81 * @since 2.0
82 */
83 public class TmfEventsEditor extends TmfEditor implements ITmfTraceEditor, IReusableEditor, IPropertyListener, IResourceChangeListener, ISelectionProvider, ISelectionChangedListener, IPartListener, IGotoMarker {
84
85 /** ID for this class */
86 public static final String ID = "org.eclipse.linuxtools.tmf.ui.editors.events"; //$NON-NLS-1$
87
88 private TmfEventsTable fEventsTable;
89 private IFile fFile;
90 private ITmfTrace fTrace;
91 private Composite fParent;
92 private ListenerList fSelectionChangedListeners = new ListenerList();
93 private boolean fTraceSelected;
94 private IMarker fPendingGotoMarker;
95
96 @Override
97 public void doSave(final IProgressMonitor monitor) {
98 }
99
100 @Override
101 public void doSaveAs() {
102 }
103
104 @Override
105 public void init(final IEditorSite site, IEditorInput input) throws PartInitException {
106 IFileEditorInput fileEditorInput;
107 if (input instanceof TmfEditorInput) {
108 fFile = ((TmfEditorInput) input).getFile();
109 fTrace = ((TmfEditorInput) input).getTrace();
110 /* change the input to a FileEditorInput to allow open handlers to find this editor */
111 fileEditorInput = new FileEditorInput(fFile);
112 } else if (input instanceof IFileEditorInput) {
113 fileEditorInput = (IFileEditorInput) input;
114 fFile = fileEditorInput.getFile();
115 if (fFile == null) {
116 throw new PartInitException("Invalid IFileEditorInput: " + fileEditorInput); //$NON-NLS-1$
117 }
118 try {
119 final String traceTypeId = fFile.getPersistentProperty(TmfCommonConstants.TRACETYPE);
120 if (traceTypeId == null) {
121 throw new PartInitException(Messages.TmfOpenTraceHelper_NoTraceType);
122 }
123 if (traceTypeId.equals(TmfExperiment.class.getCanonicalName())) {
124 // Special case: experiment bookmark resource
125 final TmfProjectElement project = TmfProjectRegistry.getProject(fFile.getProject(), true);
126 if (project == null) {
127 throw new PartInitException(Messages.TmfOpenTraceHelper_NoTraceType);
128 }
129 for (final TmfExperimentElement experimentElement : project.getExperimentsFolder().getExperiments()) {
130 if (experimentElement.getResource().equals(fFile.getParent())) {
131 setPartName(experimentElement.getName());
132 super.setSite(site);
133 super.setInput(fileEditorInput);
134 TmfOpenTraceHelper.reopenTraceFromElement(experimentElement, this);
135 return;
136 }
137 }
138 } else if (traceTypeId.equals(TmfTrace.class.getCanonicalName())) {
139 // Special case: trace bookmark resource
140 final TmfProjectElement project = TmfProjectRegistry.getProject(fFile.getProject(), true);
141 for (final TmfTraceElement traceElement : project.getTracesFolder().getTraces()) {
142 if (traceElement.getResource().equals(fFile.getParent())) {
143 setPartName(traceElement.getName());
144 super.setSite(site);
145 super.setInput(fileEditorInput);
146 TmfOpenTraceHelper.reopenTraceFromElement(traceElement, this);
147 return;
148 }
149 }
150 } else {
151 final TmfProjectElement project = TmfProjectRegistry.getProject(fFile.getProject(), true);
152 for (final TmfTraceElement traceElement : project.getTracesFolder().getTraces()) {
153 if (traceElement.getResource().equals(fFile)) {
154 setPartName(traceElement.getName());
155 super.setSite(site);
156 super.setInput(fileEditorInput);
157 TmfOpenTraceHelper.reopenTraceFromElement(traceElement, this);
158 return;
159 }
160 }
161 }
162 } catch (final PartInitException e) {
163 throw e;
164 } catch (final InvalidRegistryObjectException e) {
165 Activator.getDefault().logError("Error initializing TmfEventsEditor", e); //$NON-NLS-1$
166 } catch (final CoreException e) {
167 Activator.getDefault().logError("Error initializing TmfEventsEditor", e); //$NON-NLS-1$
168 }
169 } else {
170 throw new PartInitException("Invalid IEditorInput: " + input.getClass()); //$NON-NLS-1$
171 }
172 if (fTrace == null) {
173 throw new PartInitException("Invalid IEditorInput: " + fFile.getName()); //$NON-NLS-1$
174 }
175 super.setSite(site);
176 super.setInput(fileEditorInput);
177 }
178
179 @Override
180 public boolean isDirty() {
181 return false;
182 }
183
184 @Override
185 public boolean isSaveAsAllowed() {
186 return false;
187 }
188
189 @Override
190 public void setInput(final IEditorInput input) {
191 super.setInput(input);
192 firePropertyChange(IEditorPart.PROP_INPUT);
193 }
194
195 @Override
196 public void propertyChanged(final Object source, final int propId) {
197 if (propId == IEditorPart.PROP_INPUT && getEditorInput() instanceof TmfEditorInput) {
198 if (fTrace != null) {
199 broadcast(new TmfTraceClosedSignal(this, fTrace));
200 }
201 fTraceSelected = false;
202 fFile = ((TmfEditorInput) getEditorInput()).getFile();
203 fTrace = ((TmfEditorInput) getEditorInput()).getTrace();
204 /* change the input to a FileEditorInput to allow open handlers to find this editor */
205 super.setInput(new FileEditorInput(fFile));
206 fEventsTable.dispose();
207 if (fTrace != null) {
208 setPartName(fTrace.getName());
209 fEventsTable = createEventsTable(fParent, fTrace.getCacheSize());
210 fEventsTable.addSelectionChangedListener(this);
211 fEventsTable.setTrace(fTrace, true);
212 fEventsTable.refreshBookmarks(fFile);
213 if (fPendingGotoMarker != null) {
214 fEventsTable.gotoMarker(fPendingGotoMarker);
215 fPendingGotoMarker = null;
216 }
217
218 /* ensure start time is set */
219 final ITmfContext context = fTrace.seekEvent(0);
220 fTrace.getNext(context);
221 context.dispose();
222
223 broadcast(new TmfTraceOpenedSignal(this, fTrace, fFile));
224 } else {
225 setPartName(getEditorInput().getName());
226 fEventsTable = new TmfEventsTable(fParent, 0);
227 fEventsTable.addSelectionChangedListener(this);
228 }
229 fParent.layout();
230 }
231 }
232
233 @Override
234 public void createPartControl(final Composite parent) {
235 fParent = parent;
236 if (fTrace != null) {
237 setPartName(fTrace.getName());
238 fEventsTable = createEventsTable(parent, fTrace.getCacheSize());
239 fEventsTable.addSelectionChangedListener(this);
240 fEventsTable.setTrace(fTrace, true);
241 fEventsTable.refreshBookmarks(fFile);
242
243 /* ensure start time is set */
244 final ITmfContext context = fTrace.seekEvent(0);
245 fTrace.getNext(context);
246 context.dispose();
247
248 broadcast(new TmfTraceOpenedSignal(this, fTrace, fFile));
249 } else {
250 fEventsTable = new TmfEventsTable(parent, 0);
251 fEventsTable.addSelectionChangedListener(this);
252 }
253 IStatusLineManager statusLineManager = getEditorSite().getActionBars().getStatusLineManager();
254 fEventsTable.setStatusLineManager(statusLineManager);
255 addPropertyListener(this);
256 ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
257 // we need to wrap the ISelectionProvider interface in the editor because
258 // the events table can be replaced later while the selection changed listener
259 // is only added once by the platform to the selection provider set here
260 getSite().setSelectionProvider(this);
261 getSite().getPage().addPartListener(this);
262 }
263
264 @Override
265 public void dispose() {
266 if (getSite() != null) {
267 getSite().getPage().removePartListener(this);
268 }
269 ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
270 removePropertyListener(this);
271 if (fTrace != null) {
272 broadcast(new TmfTraceClosedSignal(this, fTrace));
273 }
274 if (fEventsTable != null) {
275 fEventsTable.dispose();
276 }
277 super.dispose();
278 }
279
280 /**
281 * Create the event table
282 *
283 * @param parent
284 * The parent composite
285 * @param cacheSize
286 * The cache size
287 * @return The event table instance
288 */
289 protected @NonNull TmfEventsTable createEventsTable(final Composite parent, final int cacheSize) {
290 return getEventTable(fTrace, parent, cacheSize);
291 }
292
293 /**
294 * Get the event table for the given trace. It will be of the type defined
295 * by the extension point if applicable, else it will be a default table
296 * with the extension-point-defined columns (if any).
297 *
298 * @param trace
299 * The event table is for this trace
300 * @param parent
301 * The parent composite of the table
302 * @param cacheSize
303 * The cache size to use
304 * @return The event table for the trace
305 */
306 private static @NonNull TmfEventsTable getEventTable(ITmfTrace trace,
307 final Composite parent, final int cacheSize) {
308 if (trace instanceof TmfExperiment) {
309 return getExperimentEventTable((TmfExperiment) trace, parent, cacheSize);
310 }
311
312 TmfEventsTable table = TmfTraceTypeUIUtils.getEventTable(trace, parent, cacheSize);
313 if (table != null) {
314 /*
315 * The trace type specified an event table type, we will give it to
316 * them.
317 */
318 return table;
319 }
320
321 /*
322 * The trace type did not specify an event table, we will use a default
323 * table with the columns it asked for (if any).
324 */
325 Collection<? extends TmfEventTableColumn> columns = TmfTraceTypeUIUtils.getEventTableColumns(trace);
326 if (columns != null) {
327 return new TmfEventsTable(parent, cacheSize, columns);
328 }
329
330 /*
331 * No columns were defined either, use a default table with the default
332 * columns.
333 */
334 return new TmfEventsTable(parent, cacheSize);
335
336 }
337
338 /**
339 * Get the events table for an experiment. If all traces in the experiment
340 * are of the same type, use the same behavior as if it was one trace of
341 * that type.
342 *
343 * @param experiment
344 * the experiment
345 * @param parent
346 * the parent Composite
347 * @param cacheSize
348 * the event table cache size
349 * @return An event table of the appropriate type
350 */
351 private static @NonNull TmfEventsTable getExperimentEventTable(
352 final TmfExperiment experiment, final Composite parent,
353 final int cacheSize) {
354
355 String commonTraceType = getCommonTraceType(experiment);
356 if (commonTraceType != null) {
357 /*
358 * All the traces in this experiment are of the same type, let's
359 * just use the normal table for that type.
360 */
361 return getEventTable(experiment.getTraces()[0], parent, cacheSize);
362 }
363
364 /*
365 * There are different trace types in the experiment, so we are
366 * definitely using a TmfEventsTable. Aggregate the columns from all
367 * trace types.
368 */
369 ITmfTrace[] traces = experiment.getTraces();
370 Set<TmfEventTableColumn> cols = new LinkedHashSet<>();
371
372 for (ITmfTrace trace : traces) {
373 Collection<? extends TmfEventTableColumn> traceCols =
374 TmfTraceTypeUIUtils.getEventTableColumns(trace);
375 if (traceCols == null) {
376 cols.addAll(TmfEventsTable.DEFAULT_COLUMNS);
377 } else {
378 cols.addAll(traceCols);
379 }
380 }
381
382 return new TmfEventsTable(parent, cacheSize, cols);
383 }
384
385 /**
386 * Check if an experiment contains traces of all the same type. If so,
387 * returns this type as a String. If not, returns null.
388 *
389 * @param experiment
390 * The experiment
391 * @return The common trace type if there is one, or 'null' if there are
392 * different types.
393 */
394 private static @Nullable String getCommonTraceType(TmfExperiment experiment) {
395 String commonTraceType = null;
396 try {
397 for (final ITmfTrace trace : experiment.getTraces()) {
398 final IResource resource = trace.getResource();
399 if (resource == null) {
400 return null;
401 }
402
403 final String traceType = resource.getPersistentProperty(TmfCommonConstants.TRACETYPE);
404 if ((commonTraceType != null) && !commonTraceType.equals(traceType)) {
405 return null;
406 }
407 commonTraceType = traceType;
408 }
409 } catch (CoreException e) {
410 /*
411 * One of the traces didn't advertise its type, we can't infer
412 * anything.
413 */
414 return null;
415 }
416 return commonTraceType;
417 }
418
419 @Override
420 public ITmfTrace getTrace() {
421 return fTrace;
422 }
423
424 @Override
425 public void setFocus() {
426 fEventsTable.setFocus();
427 }
428
429 @Override
430 public Object getAdapter(final Class adapter) {
431 if (IGotoMarker.class.equals(adapter)) {
432 if (fTrace == null || fEventsTable == null) {
433 return this;
434 }
435 return fEventsTable;
436 } else if (IPropertySheetPage.class.equals(adapter)) {
437 return new UnsortedPropertySheetPage();
438 }
439 return super.getAdapter(adapter);
440 }
441
442 /**
443 * @since 2.1
444 */
445 @Override
446 public void gotoMarker(IMarker marker) {
447 if (fTrace == null || fEventsTable == null) {
448 fPendingGotoMarker = marker;
449 } else {
450 fEventsTable.gotoMarker(marker);
451 }
452 }
453
454 @Override
455 public void resourceChanged(final IResourceChangeEvent event) {
456 for (final IMarkerDelta delta : event.findMarkerDeltas(IMarker.BOOKMARK, false)) {
457 if (delta.getResource().equals(fFile)) {
458 if (delta.getKind() == IResourceDelta.REMOVED) {
459 final IMarker bookmark = delta.getMarker();
460 Display.getDefault().asyncExec(new Runnable() {
461 @Override
462 public void run() {
463 fEventsTable.removeBookmark(bookmark);
464 }
465 });
466 } else if (delta.getKind() == IResourceDelta.CHANGED) {
467 Display.getDefault().asyncExec(new Runnable() {
468 @Override
469 public void run() {
470 fEventsTable.getTable().refresh();
471 }
472 });
473 }
474 }
475 }
476 }
477
478 // ------------------------------------------------------------------------
479 // ISelectionProvider
480 // ------------------------------------------------------------------------
481
482 /**
483 * @since 2.0
484 */
485 @Override
486 public void addSelectionChangedListener(ISelectionChangedListener listener) {
487 fSelectionChangedListeners.add(listener);
488 }
489
490 /**
491 * @since 2.0
492 */
493 @Override
494 public ISelection getSelection() {
495 if (fEventsTable == null) {
496 return StructuredSelection.EMPTY;
497 }
498 return fEventsTable.getSelection();
499 }
500
501 /**
502 * @since 2.0
503 */
504 @Override
505 public void removeSelectionChangedListener(ISelectionChangedListener listener) {
506 fSelectionChangedListeners.remove(listener);
507 }
508
509 /**
510 * @since 2.0
511 */
512 @Override
513 public void setSelection(ISelection selection) {
514 // not implemented
515 }
516
517 /**
518 * Notifies any selection changed listeners that the viewer's selection has changed.
519 * Only listeners registered at the time this method is called are notified.
520 *
521 * @param event a selection changed event
522 *
523 * @see ISelectionChangedListener#selectionChanged
524 * @since 2.0
525 */
526 protected void fireSelectionChanged(final SelectionChangedEvent event) {
527 Object[] listeners = fSelectionChangedListeners.getListeners();
528 for (int i = 0; i < listeners.length; ++i) {
529 final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i];
530 SafeRunnable.run(new SafeRunnable() {
531 @Override
532 public void run() {
533 l.selectionChanged(event);
534 }
535 });
536 }
537 }
538
539 // ------------------------------------------------------------------------
540 // ISelectionChangedListener
541 // ------------------------------------------------------------------------
542
543 /**
544 * @since 2.0
545 */
546 @Override
547 public void selectionChanged(SelectionChangedEvent event) {
548 fireSelectionChanged(event);
549 }
550
551 // ------------------------------------------------------------------------
552 // IPartListener
553 // ------------------------------------------------------------------------
554
555 /**
556 * @since 2.0
557 */
558 @Override
559 public void partActivated(IWorkbenchPart part) {
560 if (part == this && fTrace != null) {
561 if (fTraceSelected) {
562 return;
563 }
564 fTraceSelected = true;
565 broadcast(new TmfTraceSelectedSignal(this, fTrace));
566 }
567 }
568
569 /**
570 * @since 2.0
571 */
572 @Override
573 public void partBroughtToTop(IWorkbenchPart part) {
574 if (part == this && fTrace != null) {
575 if (fTraceSelected) {
576 return;
577 }
578 fTraceSelected = true;
579 broadcast(new TmfTraceSelectedSignal(this, fTrace));
580 }
581 }
582
583 /**
584 * @since 2.0
585 */
586 @Override
587 public void partClosed(IWorkbenchPart part) {
588 }
589
590 /**
591 * @since 2.0
592 */
593 @Override
594 public void partDeactivated(IWorkbenchPart part) {
595 }
596
597 /**
598 * @since 2.0
599 */
600 @Override
601 public void partOpened(IWorkbenchPart part) {
602 }
603
604 // ------------------------------------------------------------------------
605 // Global commands
606 // ------------------------------------------------------------------------
607
608 /**
609 * Add a bookmark
610 */
611 public void addBookmark() {
612 fEventsTable.addBookmark(fFile);
613 }
614
615
616 // ------------------------------------------------------------------------
617 // Signal handlers
618 // ------------------------------------------------------------------------
619
620 /**
621 * Handler for the Trace Selected signal
622 *
623 * @param signal The incoming signal
624 */
625 @TmfSignalHandler
626 public void traceSelected(final TmfTraceSelectedSignal signal) {
627 if ((signal.getSource() != this)) {
628 if (signal.getTrace().equals(fTrace)) {
629 getSite().getPage().bringToTop(this);
630 } else {
631 fTraceSelected = false;
632 }
633 }
634 }
635
636 /**
637 * Update the display to use the updated timestamp format
638 *
639 * @param signal the incoming signal
640 * @since 2.0
641 */
642 @TmfSignalHandler
643 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
644 if (fEventsTable != null) {
645 fEventsTable.refresh();
646 }
647 }
648
649 }
This page took 0.053438 seconds and 5 git commands to generate.