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