| /******************************************************************************* |
| * Copyright (c) 2010, 2019 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Patrick Tasse - Initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.tmf.ui.views.timechart; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IMarkerDelta; |
| import org.eclipse.core.resources.IResourceChangeEvent; |
| import org.eclipse.core.resources.IResourceChangeListener; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.jface.action.IStatusLineManager; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; |
| import org.eclipse.tracecompass.tmf.core.resources.ITmfMarker; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfEventFilterAppliedSignal; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfEventSearchAppliedSignal; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfTraceUpdatedSignal; |
| import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal; |
| import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimePreferencesConstants; |
| import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp; |
| import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimePreferences; |
| import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange; |
| import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp; |
| import org.eclipse.tracecompass.tmf.core.trace.ITmfContext; |
| import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; |
| import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext; |
| import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager; |
| import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo; |
| import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned; |
| import org.eclipse.tracecompass.tmf.ui.views.TmfView; |
| import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSetting; |
| import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSettingsManager; |
| import org.eclipse.tracecompass.tmf.ui.views.colors.IColorSettingsListener; |
| import org.eclipse.tracecompass.tmf.ui.views.timechart.TimeChartEvent.RankRange; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphRangeListener; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphSelectionEvent; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry; |
| import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat; |
| |
| /** |
| * Generic Time Chart view, which is similar to a Gantt chart for trace analysis |
| * |
| * @version 1.0 |
| * @author Patrick Tasse |
| */ |
| public class TimeChartView extends TmfView implements ITimeGraphRangeListener, ITimeGraphSelectionListener, ITimeGraphTimeListener, IColorSettingsListener, IResourceChangeListener, ITmfTimeAligned { |
| |
| /** TimeChartView's ID */ |
| public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.timechart"; //$NON-NLS-1$ |
| |
| private final int fDisplayWidth; |
| private TimeGraphViewer fViewer; |
| private final List<TimeChartAnalysisEntry> fTimeAnalysisEntries = new ArrayList<>(); |
| private final Map<ITmfTrace, TimeChartDecorationProvider> fDecorationProviders = new HashMap<>(); |
| private final List<DecorateThread> fDecorateThreads = new ArrayList<>(); |
| private final Map<ITmfTrace, ProcessTraceThread> fProcessTraceThreads = new HashMap<>(); |
| private long fStartTime = 0; |
| private long fStopTime = Long.MAX_VALUE; |
| private boolean fRefreshBusy = false; |
| private boolean fRefreshPending = false; |
| private boolean fRedrawBusy = false; |
| private boolean fRedrawPending = false; |
| private final Object fSyncObj = new Object(); |
| private TimeChartAnalysisProvider fPresentationProvider; |
| |
| /** |
| * Default constructor |
| */ |
| public TimeChartView() { |
| super("Time Chart"); //$NON-NLS-1$ |
| fDisplayWidth = Display.getDefault().getBounds().width; |
| } |
| |
| @Override |
| public void createPartControl(Composite parent) { |
| super.createPartControl(parent); |
| fViewer = new TimeGraphViewer(parent, SWT.NONE); |
| fPresentationProvider = new TimeChartAnalysisProvider(); |
| fViewer.setTimeGraphProvider(fPresentationProvider); |
| fViewer.addTimeListener(this); |
| fViewer.addRangeListener(this); |
| fViewer.addSelectionListener(this); |
| fViewer.setMinimumItemWidth(1); |
| fViewer.getTimeGraphControl().setBlendSubPixelEvents(true); |
| |
| IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager(); |
| fViewer.getTimeGraphControl().setStatusLineManager(statusLineManager); |
| |
| for (ITmfTrace trace : TmfTraceManager.getInstance().getOpenedTraces()) { |
| IFile bookmarksFile = TmfTraceManager.getInstance().getTraceEditorFile(trace); |
| TimeChartAnalysisEntry timeAnalysisEntry = new TimeChartAnalysisEntry(trace, fDisplayWidth * 2); |
| fTimeAnalysisEntries.add(timeAnalysisEntry); |
| fDecorationProviders.put(trace, new TimeChartDecorationProvider(bookmarksFile)); |
| startProcessTraceThread(timeAnalysisEntry); |
| } |
| fViewer.setInput(fTimeAnalysisEntries.toArray(new TimeChartAnalysisEntry[0])); |
| |
| ColorSettingsManager.addColorSettingsListener(this); |
| ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); |
| |
| updateTimeFormat(); |
| } |
| |
| @Override |
| public void dispose() { |
| ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); |
| synchronized (fDecorateThreads) { |
| for (DecorateThread thread : fDecorateThreads) { |
| thread.cancel(); |
| } |
| } |
| ColorSettingsManager.removeColorSettingsListener(this); |
| super.dispose(); |
| } |
| |
| @Override |
| public void setFocus() { |
| fViewer.setFocus(); |
| } |
| |
| private void startProcessTraceThread(TimeChartAnalysisEntry entry) { |
| synchronized (fProcessTraceThreads) { |
| ProcessTraceThread thread = fProcessTraceThreads.get(entry.getTrace()); |
| if (thread != null) { |
| thread.restart(); |
| } else { |
| thread = new ProcessTraceThread(entry); |
| fProcessTraceThreads.put(entry.getTrace(), thread); |
| thread.start(); |
| } |
| } |
| } |
| |
| private class ProcessTraceThread extends Thread { |
| |
| private final TimeChartAnalysisEntry fTimeAnalysisEntry; |
| private boolean fRestart; |
| |
| public ProcessTraceThread(TimeChartAnalysisEntry timeAnalysisEntry) { |
| super("ProcessTraceJob:" + timeAnalysisEntry.getName()); //$NON-NLS-1$ |
| fTimeAnalysisEntry = timeAnalysisEntry; |
| } |
| |
| public void restart() { |
| synchronized (fProcessTraceThreads) { |
| fRestart = true; |
| } |
| } |
| |
| @Override |
| public void run() { |
| while (true) { |
| updateTraceEntry(fTimeAnalysisEntry, Long.MAX_VALUE, |
| TmfTimestamp.BIG_BANG.toNanos(), |
| TmfTimestamp.BIG_CRUNCH.toNanos()); |
| synchronized (fProcessTraceThreads) { |
| if (fRestart) { |
| fRestart = false; |
| } else { |
| fProcessTraceThreads.remove(fTimeAnalysisEntry.getTrace()); |
| return; |
| } |
| } |
| } |
| } |
| } |
| |
| private void updateTraceEntry(TimeChartAnalysisEntry timeAnalysisEntry, long stopRank, long startTime, long stopTime) { |
| ITmfTrace trace = timeAnalysisEntry.getTrace(); |
| TimeChartDecorationProvider decorationProvider = fDecorationProviders.get(trace); |
| if (decorationProvider == null) { |
| return; // the trace has been closed |
| } |
| ITmfContext context = null; |
| // TmfTimestamp lastTimestamp = null; |
| boolean done = false; |
| while (!done) { |
| synchronized (timeAnalysisEntry) { |
| if (timeAnalysisEntry.getLastRank() >= trace.getNbEvents()) { |
| done = true; |
| break; |
| } |
| if (context == null || context.getRank() != timeAnalysisEntry.getLastRank()) { |
| if (context != null) { |
| context.dispose(); |
| } |
| if (timeAnalysisEntry.getLastRank() != -1) { |
| context = trace.seekEvent(timeAnalysisEntry.getLastRank()); |
| } else { |
| // context = trace.seekLocation(null); |
| context = trace.seekEvent(0); |
| } |
| } |
| while (true) { |
| long rank = context.getRank(); |
| ITmfEvent event = trace.getNext(context); |
| if (event == null) { |
| done = true; |
| break; |
| } |
| // if (!event.getTimestamp().equals(lastTimestamp)) { |
| TimeChartEvent timeEvent = new TimeChartEvent(timeAnalysisEntry, event, rank, decorationProvider); |
| if (timeEvent.getTime() >= startTime && timeEvent.getTime() <= stopTime) { |
| timeAnalysisEntry.addTraceEvent(timeEvent); |
| } |
| // lastTimestamp = event.getTimestamp(); |
| // } *** commented out so that color setting priority gets |
| // set even if the event has same time |
| if (context.getRank() == trace.getNbEvents() || context.getRank() == stopRank) { |
| done = true; |
| break; |
| } |
| if (context.getRank() % trace.getCacheSize() == 1) { |
| // break for UI refresh |
| break; |
| } |
| } |
| // timeAnalysisEntry.setLastRank(Math.min(trace.getNbEvents(), |
| // stopRank)); |
| timeAnalysisEntry.setLastRank(context.getRank()); |
| } |
| redrawViewer(true); |
| } |
| if (context != null) { |
| context.dispose(); |
| } |
| } |
| |
| private void refreshViewer() { |
| synchronized (fSyncObj) { |
| if (fRefreshBusy) { |
| fRefreshPending = true; |
| return; |
| } |
| fRefreshBusy = true; |
| } |
| // Perform the refresh on the UI thread |
| Display.getDefault().asyncExec(() -> { |
| if (fViewer.getControl().isDisposed()) { |
| return; |
| } |
| fViewer.setInput(fTimeAnalysisEntries.toArray(new TimeChartAnalysisEntry[0])); |
| fViewer.resetStartFinishTime(false); |
| synchronized (fSyncObj) { |
| fRefreshBusy = false; |
| if (fRefreshPending) { |
| fRefreshPending = false; |
| refreshViewer(); |
| } |
| } |
| }); |
| } |
| |
| private void redrawViewer(boolean resetTimeIntervals) { |
| synchronized (fSyncObj) { |
| if (fRedrawBusy) { |
| fRedrawPending = true; |
| return; |
| } |
| fRedrawBusy = true; |
| } |
| final boolean reset = resetTimeIntervals; |
| // Perform the refresh on the UI thread |
| Display.getDefault().asyncExec(() -> { |
| if (fViewer.getControl().isDisposed()) { |
| return; |
| } |
| if (reset) { |
| fViewer.setTimeRange(fTimeAnalysisEntries.toArray(new TimeChartAnalysisEntry[0])); |
| fViewer.setTimeBounds(); |
| } |
| fViewer.getControl().redraw(); |
| fViewer.getControl().update(); |
| synchronized (fSyncObj) { |
| fRedrawBusy = false; |
| if (fRedrawPending) { |
| fRedrawPending = false; |
| redrawViewer(reset); |
| } |
| } |
| }); |
| } |
| |
| private void itemize(long startTime, long stopTime) { |
| for (int i = 0; i < fTimeAnalysisEntries.size(); i++) { |
| Thread thread = new ItemizeThread(fTimeAnalysisEntries.get(i), startTime, stopTime); |
| thread.start(); |
| } |
| } |
| |
| private class ItemizeThread extends Thread { |
| |
| private final TimeChartAnalysisEntry fTimeAnalysisEntry; |
| private final long startTime; |
| private final long stopTime; |
| private final long fMaxDuration; |
| |
| private ItemizeThread(TimeChartAnalysisEntry timeAnalysisEntry, long startTime, long stopTime) { |
| super("Itemize Thread:" + timeAnalysisEntry.getName()); //$NON-NLS-1$ |
| fTimeAnalysisEntry = timeAnalysisEntry; |
| this.startTime = startTime; |
| this.stopTime = stopTime; |
| fMaxDuration = 3 * (stopTime - startTime) / fDisplayWidth; |
| } |
| |
| @Override |
| public void run() { |
| itemizeTraceEntry(fTimeAnalysisEntry); |
| } |
| |
| public void itemizeTraceEntry(TimeChartAnalysisEntry timeAnalysisEntry) { |
| Iterator<ITimeEvent> iterator = timeAnalysisEntry.getTimeEventsIterator(); |
| TimeChartEvent event = null; |
| boolean hasNext = true; |
| while (hasNext) { |
| synchronized (timeAnalysisEntry) { |
| while ((hasNext = iterator.hasNext()) == true) { |
| event = (TimeChartEvent) iterator.next(); |
| if (event.getTime() + event.getDuration() > startTime && event.getTime() < stopTime && event.getDuration() > fMaxDuration |
| && event.getNbEvents() > 1) { |
| break; |
| } |
| } |
| } |
| if (hasNext && event != null) { |
| if (event.getItemizedEntry() == null) { |
| itemizeEvent(event); |
| } else { |
| itemizeTraceEntry(event.getItemizedEntry()); |
| } |
| } |
| } |
| } |
| |
| public void itemizeEvent(TimeChartEvent event) { |
| synchronized (event) { |
| if (event.isItemizing()) { |
| return; |
| } |
| event.setItemizing(true); |
| } |
| TimeChartAnalysisEntry timeAnalysisEntry = new TimeChartAnalysisEntry(fTimeAnalysisEntry.getTrace(), (int) Math.min( |
| event.getNbEvents() + 1, fDisplayWidth * 2)); |
| synchronized (event.getRankRangeList()) { |
| for (RankRange range : event.getRankRangeList()) { |
| timeAnalysisEntry.setLastRank(range.getFirstRank()); |
| updateTraceEntry(timeAnalysisEntry, range.getLastRank() + 1, event.getTime(), event.getTime() + event.getDuration()); |
| } |
| } |
| event.setItemizedEntry(timeAnalysisEntry); |
| redrawViewer(false); |
| itemizeTraceEntry(timeAnalysisEntry); |
| synchronized (event) { |
| event.setItemizing(false); |
| } |
| } |
| } |
| |
| private void redecorate() { |
| synchronized (fDecorateThreads) { |
| for (DecorateThread thread : fDecorateThreads) { |
| thread.cancel(); |
| } |
| fDecorateThreads.clear(); |
| for (int i = 0; i < fTimeAnalysisEntries.size(); i++) { |
| DecorateThread thread = new DecorateThread(fTimeAnalysisEntries.get(i)); |
| thread.start(); |
| fDecorateThreads.add(thread); |
| } |
| } |
| } |
| |
| private class DecorateThread extends Thread { |
| private volatile boolean interrupted = false; |
| private final TimeChartAnalysisEntry fTimeAnalysisEntry; |
| private final TimeChartDecorationProvider fDecorationProvider; |
| private ITmfContext fContext; |
| private int fCount = 0; |
| |
| private DecorateThread(TimeChartAnalysisEntry timeAnalysisEntry) { |
| super("Decorate Thread:" + timeAnalysisEntry.getName()); //$NON-NLS-1$ |
| fTimeAnalysisEntry = timeAnalysisEntry; |
| fDecorationProvider = fDecorationProviders.get(timeAnalysisEntry.getTrace()); |
| } |
| |
| @Override |
| public void run() { |
| resetTraceEntry(fTimeAnalysisEntry); |
| redrawViewer(false); |
| decorateTraceEntry(fTimeAnalysisEntry, null); |
| redrawViewer(false); |
| synchronized (fDecorateThreads) { |
| fDecorateThreads.remove(this); |
| } |
| if (fContext != null) { |
| fContext.dispose(); |
| } |
| } |
| |
| public void resetTraceEntry(TimeChartAnalysisEntry timeAnalysisEntry) { |
| Iterator<ITimeEvent> iterator = timeAnalysisEntry.getTimeEventsIterator(); |
| TimeChartEvent event = null; |
| boolean hasNext = true; |
| while (!interrupted && hasNext) { |
| synchronized (timeAnalysisEntry) { |
| while ((hasNext = iterator.hasNext()) == true) { |
| event = (TimeChartEvent) iterator.next(); |
| break; |
| } |
| } |
| if (hasNext && event != null) { |
| // TODO possible concurrency problem here with ItemizeJob |
| event.setColorSettingPriority(ColorSettingsManager.PRIORITY_NONE); |
| if (event.getItemizedEntry() != null) { |
| resetTraceEntry(event.getItemizedEntry()); |
| } |
| } |
| } |
| } |
| |
| public void decorateTraceEntry(TimeChartAnalysisEntry timeAnalysisEntry, TimeChartEvent parentEvent) { |
| // Set max duration high to ensure iterator does not consider |
| // itemized events |
| Iterator<ITimeEvent> iterator = timeAnalysisEntry.getTimeEventsIterator(0, Long.MAX_VALUE, Long.MAX_VALUE); |
| TimeChartEvent event = null; |
| int entryPriority = ColorSettingsManager.PRIORITY_NONE; |
| boolean entryIsBookmarked = false; |
| boolean entryIsVisible = false; |
| boolean entryIsSearchMatch = false; |
| boolean hasNext = true; |
| while (!interrupted && hasNext) { |
| synchronized (timeAnalysisEntry) { |
| while ((hasNext = iterator.hasNext()) == true) { |
| event = (TimeChartEvent) iterator.next(); |
| break; |
| } |
| } |
| if (hasNext && event != null) { |
| // TODO possible concurrency problem here with ItemizeJob |
| if (event.getItemizedEntry() == null) { |
| decorateEvent(event); |
| } else { |
| decorateTraceEntry(event.getItemizedEntry(), event); |
| } |
| entryPriority = Math.min(entryPriority, event.getColorSettingPriority()); |
| entryIsBookmarked |= event.isBookmarked(); |
| entryIsVisible |= event.isVisible(); |
| entryIsSearchMatch |= event.isSearchMatch(); |
| if (++fCount % timeAnalysisEntry.getTrace().getCacheSize() == 0) { |
| redrawViewer(false); |
| } |
| } |
| } |
| if (parentEvent != null) { |
| parentEvent.setColorSettingPriority(entryPriority); |
| parentEvent.setIsBookmarked(entryIsBookmarked); |
| parentEvent.setIsVisible(entryIsVisible); |
| parentEvent.setIsSearchMatch(entryIsSearchMatch); |
| } |
| } |
| |
| public void decorateEvent(TimeChartEvent timeChartEvent) { |
| // TODO possible concurrency problem here with ItemizeJob |
| TimeChartAnalysisEntry timeAnalysisEntry = (TimeChartAnalysisEntry) timeChartEvent.getEntry(); |
| ITmfTrace trace = timeAnalysisEntry.getTrace(); |
| int priority = ColorSettingsManager.PRIORITY_NONE; |
| boolean isBookmarked = false; |
| boolean isVisible = false; |
| boolean isSearchMatch = false; |
| synchronized (timeChartEvent.getRankRangeList()) { |
| for (RankRange range : timeChartEvent.getRankRangeList()) { |
| if (interrupted) { |
| return; |
| } |
| if (fContext == null || fContext.getRank() != range.getFirstRank()) { |
| if (fContext != null) { |
| fContext.dispose(); |
| } |
| fContext = trace.seekEvent(range.getFirstRank()); |
| fContext.setRank(range.getFirstRank()); |
| } |
| while (true) { |
| if (interrupted) { |
| return; |
| } |
| long rank = fContext.getRank(); |
| ITmfEvent event = trace.getNext(fContext); |
| if (event == null) { |
| break; |
| } |
| long eventTime = event.getTimestamp().toNanos(); |
| if (eventTime >= timeChartEvent.getTime() && eventTime <= timeChartEvent.getTime() + timeChartEvent.getDuration()) { |
| priority = Math.min(priority, ColorSettingsManager.getColorSettingPriority(event)); |
| } |
| isBookmarked |= fDecorationProvider.isBookmark(rank); |
| isVisible |= fDecorationProvider.isVisible(event); |
| isSearchMatch |= fDecorationProvider.isSearchMatch(event); |
| if (fContext.getRank() > range.getLastRank()) { |
| break; |
| } |
| } |
| } |
| } |
| timeChartEvent.setColorSettingPriority(priority); |
| timeChartEvent.setIsBookmarked(isBookmarked); |
| timeChartEvent.setIsVisible(isVisible); |
| timeChartEvent.setIsSearchMatch(isSearchMatch); |
| } |
| |
| public void cancel() { |
| interrupted = true; |
| } |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Listeners |
| // ------------------------------------------------------------------------ |
| |
| @Override |
| public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) { |
| fStartTime = event.getStartTime(); |
| fStopTime = event.getEndTime(); |
| itemize(fStartTime, fStopTime); |
| final ITmfTimestamp startTimestamp = TmfTimestamp.fromNanos(event.getStartTime()); |
| final ITmfTimestamp endTimestamp = TmfTimestamp.fromNanos(event.getEndTime()); |
| TmfTimeRange range = new TmfTimeRange(startTimestamp, endTimestamp); |
| broadcast(new TmfWindowRangeUpdatedSignal(this, range)); |
| } |
| |
| @Override |
| public void selectionChanged(TimeGraphSelectionEvent event) { |
| ITimeGraphEntry timeAnalysisEntry = null; |
| if (event.getSelection() instanceof TimeChartAnalysisEntry) { |
| timeAnalysisEntry = event.getSelection(); |
| } else if (event.getSelection() instanceof TimeChartEvent) { |
| timeAnalysisEntry = ((TimeChartEvent) event.getSelection()).getEntry(); |
| } |
| if (timeAnalysisEntry instanceof TimeChartAnalysisEntry) { |
| broadcast(new TmfTraceSelectedSignal(this, ((TimeChartAnalysisEntry) timeAnalysisEntry).getTrace())); |
| } |
| } |
| |
| @Override |
| public void timeSelected(TimeGraphTimeEvent event) { |
| broadcast(new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp.fromNanos(event.getBeginTime()), TmfTimestamp.fromNanos(event.getEndTime()))); |
| } |
| |
| @Override |
| public void colorSettingsChanged(ColorSetting[] colorSettings) { |
| fPresentationProvider.colorSettingsChanged(colorSettings); |
| // Set presentation provider again to trigger re-creation of new color |
| // settings which are stored in the TimeGraphControl class |
| fViewer.setTimeGraphProvider(fPresentationProvider); |
| redecorate(); |
| } |
| |
| @Override |
| public void resourceChanged(IResourceChangeEvent event) { |
| for (IMarkerDelta delta : event.findMarkerDeltas(IMarker.BOOKMARK, false)) { |
| for (TimeChartDecorationProvider provider : fDecorationProviders.values()) { |
| if (delta.getResource().equals(provider.getBookmarksFile())) { |
| if (delta.getKind() == IResourceDelta.REMOVED || |
| delta.getMarker().getAttribute(IMarker.LOCATION, -1) != -1 || |
| delta.getMarker().getAttribute(ITmfMarker.MARKER_RANK, (String) null) != null) { |
| provider.refreshBookmarks(); |
| } |
| } |
| } |
| } |
| redecorate(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Signal handlers |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Handler for the Trace Opened signal |
| * |
| * @param signal |
| * The incoming signal |
| */ |
| @TmfSignalHandler |
| public void traceOpened(TmfTraceOpenedSignal signal) { |
| final ITmfTrace trace = signal.getTrace(); |
| final IFile bookmarksFile = signal.getEditorFile(); |
| TimeChartAnalysisEntry timeAnalysisEntry = null; |
| for (int i = 0; i < fTimeAnalysisEntries.size(); i++) { |
| if (fTimeAnalysisEntries.get(i).getTrace().equals(trace)) { |
| timeAnalysisEntry = fTimeAnalysisEntries.get(i); |
| break; |
| } |
| } |
| if (timeAnalysisEntry == null) { |
| timeAnalysisEntry = new TimeChartAnalysisEntry(trace, fDisplayWidth * 2); |
| fTimeAnalysisEntries.add(timeAnalysisEntry); |
| fDecorationProviders.put(trace, new TimeChartDecorationProvider(bookmarksFile)); |
| startProcessTraceThread(timeAnalysisEntry); |
| } |
| refreshViewer(); |
| } |
| |
| /** |
| * Handler for the Trace Closed signal |
| * |
| * @param signal |
| * The incoming signal |
| */ |
| @TmfSignalHandler |
| public void traceClosed(TmfTraceClosedSignal signal) { |
| final ITmfTrace trace = signal.getTrace(); |
| for (int i = 0; i < fTimeAnalysisEntries.size(); i++) { |
| if (fTimeAnalysisEntries.get(i).getTrace().equals(trace)) { |
| fTimeAnalysisEntries.remove(i); |
| fDecorationProviders.remove(trace); |
| synchronized (fDecorateThreads) { |
| for (DecorateThread thread : fDecorateThreads) { |
| if (thread.fTimeAnalysisEntry.getTrace() == trace) { |
| thread.cancel(); |
| fDecorateThreads.remove(thread); |
| break; |
| } |
| } |
| } |
| refreshViewer(); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Handler for the Trace Selected signal |
| * |
| * @param signal |
| * The incoming signal |
| */ |
| @TmfSignalHandler |
| public void traceSelected(TmfTraceSelectedSignal signal) { |
| if (signal.getSource() != this) { |
| ITmfTrace trace = signal.getTrace(); |
| for (int i = 0; i < fTimeAnalysisEntries.size(); i++) { |
| if (fTimeAnalysisEntries.get(i).getTrace().equals(trace)) { |
| fViewer.setSelection(fTimeAnalysisEntries.get(i), true); |
| break; |
| } |
| } |
| TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext(); |
| long beginTime = ctx.getSelectionRange().getStartTime().toNanos(); |
| long endTime = ctx.getSelectionRange().getEndTime().toNanos(); |
| fViewer.setSelectionRange(beginTime, endTime, false); |
| } |
| } |
| |
| /** |
| * Handler for the Trace Updated signal |
| * |
| * @param signal |
| * The incoming signal |
| */ |
| @TmfSignalHandler |
| public void traceUpdated(TmfTraceUpdatedSignal signal) { |
| final ITmfTrace trace = signal.getTrace(); |
| for (int i = 0; i < fTimeAnalysisEntries.size(); i++) { |
| TimeChartAnalysisEntry timeAnalysisEntry = fTimeAnalysisEntries.get(i); |
| if (timeAnalysisEntry.getTrace().equals(trace)) { |
| startProcessTraceThread(timeAnalysisEntry); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Handler for the selection range updated signal. |
| * |
| * @param signal |
| * The incoming signal |
| * @since 1.0 |
| */ |
| @TmfSignalHandler |
| public void selectionRangeUpdated(TmfSelectionRangeUpdatedSignal signal) { |
| final long beginTime = signal.getBeginTime().toNanos(); |
| final long endTime = signal.getEndTime().toNanos(); |
| |
| Display.getDefault().asyncExec(() -> { |
| if (beginTime == endTime) { |
| fViewer.setSelectedTime(beginTime, true); |
| if (fStartTime != fViewer.getTime0() || fStopTime != fViewer.getTime1()) { |
| fStartTime = fViewer.getTime0(); |
| fStopTime = fViewer.getTime1(); |
| itemize(fStartTime, fStopTime); |
| } |
| } else { |
| fViewer.setSelectionRange(beginTime, endTime, true); |
| } |
| }); |
| } |
| |
| /** |
| * Handler for the window range updated signal. |
| * |
| * @param signal |
| * The incoming signal |
| * @since 1.0 |
| */ |
| @TmfSignalHandler |
| public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) { |
| if (signal.getSource() == this) { |
| return; |
| } |
| final long startTime = signal.getCurrentRange().getStartTime().toNanos(); |
| final long endTime = signal.getCurrentRange().getEndTime().toNanos(); |
| Display.getDefault().asyncExec(() -> { |
| fStartTime = startTime; |
| fStopTime = endTime; |
| itemize(fStartTime, fStopTime); |
| fViewer.setStartFinishTime(startTime, endTime); |
| }); |
| } |
| |
| /** |
| * Handler for the Event Filter Applied signal |
| * |
| * @param signal |
| * The incoming signal |
| */ |
| @TmfSignalHandler |
| public void filterApplied(TmfEventFilterAppliedSignal signal) { |
| TimeChartDecorationProvider decorationProvider = fDecorationProviders.get(signal.getTrace()); |
| if (decorationProvider == null) { |
| return; |
| } |
| decorationProvider.filterApplied(signal.getEventFilter()); |
| redecorate(); |
| } |
| |
| /** |
| * Handler for the Event Search Applied signal |
| * |
| * @param signal |
| * The incoming signal |
| */ |
| @TmfSignalHandler |
| public void searchApplied(TmfEventSearchAppliedSignal signal) { |
| TimeChartDecorationProvider decorationProvider = fDecorationProviders.get(signal.getTrace()); |
| if (decorationProvider == null) { |
| return; |
| } |
| decorationProvider.searchApplied(signal.getSearchFilter()); |
| redecorate(); |
| } |
| |
| /** |
| * Handler for the Timestamp Format Updated signal |
| * |
| * @param signal |
| * the format of the timestamps was updated. |
| * @since 5.0 |
| */ |
| @TmfSignalHandler |
| public void updateTimeFormat(final TmfTimestampFormatUpdateSignal signal) { |
| updateTimeFormat(); |
| fViewer.refresh(); |
| } |
| |
| private void updateTimeFormat() { |
| String datime = TmfTimePreferences.getPreferenceMap().get(ITmfTimePreferencesConstants.DATIME); |
| if (ITmfTimePreferencesConstants.TIME_ELAPSED_FMT.equals(datime)) { |
| fViewer.setTimeFormat(TimeFormat.RELATIVE); |
| } else { |
| fViewer.setTimeFormat(TimeFormat.CALENDAR); |
| } |
| } |
| |
| /** |
| * @since 1.0 |
| */ |
| @Override |
| public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() { |
| if (fViewer == null) { |
| return null; |
| } |
| return fViewer.getTimeViewAlignmentInfo(); |
| } |
| |
| /** |
| * @since 1.0 |
| */ |
| @Override |
| public int getAvailableWidth(int requestedOffset) { |
| return fViewer.getAvailableWidth(requestedOffset); |
| } |
| |
| /** |
| * @since 1.0 |
| */ |
| @Override |
| public void performAlign(int offset, int width) { |
| fViewer.performAlign(offset, width); |
| } |
| } |