blob: f235c2db3ff356f79623ae36c33c7815c2326dbb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Ericsson
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Author:
* Sonia Farrah
*******************************************************************************/
package org.eclipse.tracecompass.incubator.internal.callstack.ui.flamegraph;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils.FlowScopeLog;
import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils.FlowScopeLogBuilder;
import org.eclipse.tracecompass.incubator.analysis.core.weighted.tree.IWeightedTreeGroupDescriptor;
import org.eclipse.tracecompass.incubator.callstack.core.callgraph.AllGroupDescriptor;
import org.eclipse.tracecompass.incubator.callstack.core.callgraph.CallGraph;
import org.eclipse.tracecompass.incubator.callstack.core.callgraph.CallGraphGroupBy;
import org.eclipse.tracecompass.incubator.callstack.core.callgraph.ICallGraphProvider;
import org.eclipse.tracecompass.incubator.callstack.core.instrumented.ICalledFunction;
import org.eclipse.tracecompass.incubator.internal.callstack.ui.Activator;
import org.eclipse.tracecompass.tmf.core.analysis.IAnalysisModule;
import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
import org.eclipse.tracecompass.tmf.core.symbols.ISymbolProvider;
import org.eclipse.tracecompass.tmf.core.symbols.SymbolProviderManager;
import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderPreferencePage;
import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderConfigDialog;
import org.eclipse.tracecompass.tmf.ui.symbols.TmfSymbolProviderUpdatedSignal;
import org.eclipse.tracecompass.tmf.ui.views.SaveImageUtil;
import org.eclipse.tracecompass.tmf.ui.views.TmfView;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
/**
* View to display the flame graph .This uses the flameGraphNode tree generated
* by CallGraphAnalysisUI.
*
* @author Sonia Farrah
*/
@NonNullByDefault({})
public class FlameGraphView extends TmfView {
/**
* ID of the view
*/
public static final String ID = FlameGraphView.class.getPackage().getName() + ".flamegraphView"; //$NON-NLS-1$
private static final String SYMBOL_MAPPING_ICON_PATH = "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
private static final @NonNull String GROUP_BY_ICON_PATH = "icons/etool16/group_by.gif"; //$NON-NLS-1$
private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$
private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
private static final ImageDescriptor AGGREGATE_BY_ICON = Activator.getDefault().getImageDescripterFromPath(GROUP_BY_ICON_PATH);
private TimeGraphViewer fTimeGraphViewer;
private FlameGraphContentProvider fTimeGraphContentProvider;
private TimeGraphPresentationProvider fPresentationProvider;
private ITmfTrace fTrace;
private static final @NonNull Logger LOGGER = Logger.getLogger(FlameGraphView.class.getName());
private final @NonNull MenuManager fEventMenuManager = new MenuManager();
private Action fAggregateByAction;
private Action fSortByNameAction;
private Action fSortByIdAction;
// The action to import a binary file mapping */
private Action fConfigureSymbolsAction;
private final Multimap<ITmfTrace, ISymbolProvider> fSymbolProviders = LinkedHashMultimap.create();
private @Nullable IWeightedTreeGroupDescriptor fGroupBy = null;
/**
* A plain old semaphore is used since different threads will be competing
* for the same resource.
*/
private final Semaphore fLock = new Semaphore(1);
// Variable used to specify when the graph is dirty, ie waiting for data refresh
private final AtomicInteger fDirty = new AtomicInteger();
private Job fJob;
/**
* Constructor
*/
public FlameGraphView() {
super(ID);
}
/**
* Constructor with ID
*
* @param id
* The ID of the view
*/
protected FlameGraphView(String id) {
super(id);
}
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
fTimeGraphViewer = new TimeGraphViewer(parent, SWT.NONE);
fTimeGraphContentProvider = new FlameGraphContentProvider();
fPresentationProvider = new FlameGraphPresentationProvider();
fTimeGraphViewer.setTimeGraphContentProvider(fTimeGraphContentProvider);
fTimeGraphViewer.setTimeGraphProvider(fPresentationProvider);
fTimeGraphViewer.setTimeFormat(TimeFormat.NUMBER);
IEditorPart editor = getSite().getPage().getActiveEditor();
if (editor instanceof ITmfTraceEditor) {
ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
if (trace != null) {
traceSelected(new TmfTraceSelectedSignal(this, trace));
}
}
contributeToActionBars();
loadSortOption();
TmfSignalManager.register(this);
getSite().setSelectionProvider(fTimeGraphViewer.getSelectionProvider());
createTimeEventContextMenu();
fTimeGraphViewer.getTimeGraphControl().addMouseListener(new MouseAdapter() {
@Override
public void mouseDoubleClick(MouseEvent e) {
TimeGraphControl timeGraphControl = getTimeGraphViewer().getTimeGraphControl();
ISelection selection = timeGraphControl.getSelection();
if (selection instanceof IStructuredSelection) {
for (Object object : ((IStructuredSelection) selection).toList()) {
if (object instanceof FlamegraphEvent) {
FlamegraphEvent event = (FlamegraphEvent) object;
long startTime = event.getTime();
long endTime = startTime + event.getDuration();
getTimeGraphViewer().setStartFinishTime(startTime, endTime);
break;
}
}
}
}
});
}
/**
* Get the time graph viewer
*
* @return the time graph viewer
*/
@VisibleForTesting
public TimeGraphViewer getTimeGraphViewer() {
return fTimeGraphViewer;
}
/**
* Handler for the trace selected signal
*
* @param signal
* The incoming signal
*/
@TmfSignalHandler
public void traceSelected(final TmfTraceSelectedSignal signal) {
fTrace = signal.getTrace();
Display.getDefault().asyncExec(() -> buildFlameGraph(getCallgraphModules(), null, null));
}
/**
* Get the callgraph modules used to build the view
*
* @return The call graph provider modules
*/
protected Iterable<ICallGraphProvider> getCallgraphModules() {
ITmfTrace trace = fTrace;
if (trace == null) {
return null;
}
String analysisId = NonNullUtils.nullToEmptyString(getViewSite().getSecondaryId());
Iterable<ICallGraphProvider> modules = TmfTraceUtils.getAnalysisModulesOfClass(trace, ICallGraphProvider.class);
return StreamSupport.stream(modules.spliterator(), false)
.filter(m -> {
if (m instanceof IAnalysisModule) {
return ((IAnalysisModule) m).getId().equals(analysisId);
}
return true;
})
.collect(Collectors.toSet());
}
/**
* Get the necessary data for the flame graph and display it
*
* @param callGraphProviders
* the callGraphAnalysis
* @param selStart
* The selection start timestamp or <code>null</code> to show all
* data
* @param selEnd
* The selection end timestamp or <code>null</code> to show all
* data
*/
@VisibleForTesting
public void buildFlameGraph(Iterable<ICallGraphProvider> callGraphProviders, @Nullable ITmfTimestamp selStart, @Nullable ITmfTimestamp selEnd) {
/*
* Note for synchronization:
*
* Acquire the lock at entry. then we have 4 places to release it
*
* 1- if the lock failed
*
* 2- if the data is null and we have no UI to update
*
* 3- when the job starts running and can thus be canceled
*/
Job job = fJob;
if (job != null) {
job.cancel();
}
try (FlowScopeLog log = new FlowScopeLogBuilder(LOGGER, Level.FINE, "FlameGraphView:Building").setCategory(getViewId()).build()) { //$NON-NLS-1$
try {
fLock.acquire();
} catch (InterruptedException e) {
Activator.getDefault().logError(e.getMessage(), e);
fLock.release();
}
/*
* Load the symbol provider for the current trace, even if it does not provide a
* call stack analysis module. See
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=494212
*/
ITmfTrace trace = fTrace;
if (trace != null) {
/*
* Load the symbol provider for the current trace, even if it does not provide a
* call stack analysis module. See
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=494212
*/
Collection<ISymbolProvider> symbolProviders = fSymbolProviders.get(trace);
if (symbolProviders.isEmpty()) {
symbolProviders = SymbolProviderManager.getInstance().getSymbolProviders(trace);
symbolProviders.forEach(provider -> provider.loadConfiguration(new NullProgressMonitor()));
fSymbolProviders.putAll(trace, symbolProviders);
}
}
if (!callGraphProviders.iterator().hasNext()) {
fTimeGraphViewer.setInput(null);
fLock.release();
return;
}
for (ICallGraphProvider provider : callGraphProviders) {
if (provider instanceof IAnalysisModule) {
((IAnalysisModule) provider).schedule();
}
}
job = new Job(Messages.FlameGraphView_RetrievingData) {
@Override
protected IStatus run(IProgressMonitor monitor) {
try (FlowScopeLog runLog = new FlowScopeLogBuilder(LOGGER, Level.FINE, "FlameGraphView:GettingFlameGraphs").setParentScope(log).build()) { //$NON-NLS-1$
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
// Set the view as dirty before releasing the lock
fDirty.incrementAndGet();
fLock.release();
Set<CallGraph> callgraphs = new HashSet<>();
IWeightedTreeGroupDescriptor group = fGroupBy;
for (ICallGraphProvider provider : callGraphProviders) {
if (provider instanceof IAnalysisModule) {
((IAnalysisModule) provider).waitForCompletion(monitor);
}
// FIXME: This waits for completion, there is no way of cancelling this call, so
// make the views responsive to updates in the model, so that we can return a
// partial callgraph
CallGraph callGraph;
if (selStart == null || selEnd == null) {
callGraph = provider.getCallGraph();
} else {
callGraph = provider.getCallGraph(selStart, selEnd);
}
if (group == null) {
callgraphs.add(callGraph);
} else {
callgraphs.add(CallGraphGroupBy.groupCallGraphBy(group, callGraph));
}
}
if (monitor.isCanceled()) {
// Decrease dirtiness, job canceled
fDirty.decrementAndGet();
return Status.CANCEL_STATUS;
}
Display.getDefault().asyncExec(() -> {
try (FlowScopeLog asyncLog = new FlowScopeLogBuilder(LOGGER, Level.FINE, "FlameGraphView:SettingInput").setParentScope(runLog).build()) { //$NON-NLS-1$
fTimeGraphViewer.setInput(callgraphs);
fTimeGraphViewer.resetStartFinishTime();
} finally {
// Finished updating, decrease dirtiness
fDirty.decrementAndGet();
}
});
return Status.OK_STATUS;
}
}
};
IWorkbenchSiteProgressService service = null;
IWorkbenchPartSite site = getSite();
if (site != null) {
service = site.getService(IWorkbenchSiteProgressService.class);
}
fJob = job;
if (service != null) {
service.schedule(job);
} else {
job.schedule();
}
}
}
/**
* Await the next refresh
*
* @return Whether the view is ready with new data
*
* @throws InterruptedException
* something took too long
*/
@VisibleForTesting
public boolean isDirty() throws InterruptedException {
/*
* wait for the semaphore to be available, then release it immediately
* and verify dirtiness
*/
fLock.acquire();
fLock.release();
return (fDirty.get() != 0);
}
/**
* Trace is closed: clear the data structures and the view
*
* @param signal
* the signal received
*/
@TmfSignalHandler
public void traceClosed(final TmfTraceClosedSignal signal) {
if (signal.getTrace() == fTrace) {
fTimeGraphViewer.setInput(null);
}
}
@Override
public void setFocus() {
fTimeGraphViewer.setFocus();
}
// ------------------------------------------------------------------------
// Helper methods
// ------------------------------------------------------------------------
private void createTimeEventContextMenu() {
fEventMenuManager.setRemoveAllWhenShown(true);
TimeGraphControl timeGraphControl = fTimeGraphViewer.getTimeGraphControl();
final Menu timeEventMenu = fEventMenuManager.createContextMenu(timeGraphControl);
timeGraphControl.addTimeGraphEntryMenuListener(new MenuDetectListener() {
@Override
public void menuDetected(MenuDetectEvent event) {
/*
* The TimeGraphControl will call the TimeGraphEntryMenuListener
* before the TimeEventMenuListener. We need to clear the menu
* for the case the selection was done on the namespace where
* the time event listener below won't be called afterwards.
*/
timeGraphControl.setMenu(null);
event.doit = false;
}
});
timeGraphControl.addTimeEventMenuListener(new MenuDetectListener() {
@Override
public void menuDetected(MenuDetectEvent event) {
Menu menu = timeEventMenu;
if (event.data instanceof FlamegraphEvent) {
timeGraphControl.setMenu(menu);
return;
}
timeGraphControl.setMenu(null);
event.doit = false;
}
});
fEventMenuManager.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
fillTimeEventContextMenu(fEventMenuManager);
fEventMenuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
}
});
getSite().registerContextMenu(fEventMenuManager, fTimeGraphViewer.getSelectionProvider());
}
/**
* Fill context menu
*
* @param menuManager
* a menuManager to fill
*/
protected void fillTimeEventContextMenu(@NonNull IMenuManager menuManager) {
ISelection selection = getSite().getSelectionProvider().getSelection();
if (selection instanceof IStructuredSelection) {
for (Object object : ((IStructuredSelection) selection).toList()) {
if (object instanceof FlamegraphEvent) {
final FlamegraphEvent flamegraphEvent = (FlamegraphEvent) object;
final ICalledFunction maxSeg = flamegraphEvent.getMaxObject();
if (maxSeg != null) {
menuManager.add(new Action(Messages.FlameGraphView_GotoMaxDuration) {
@Override
public void run() {
TmfSelectionRangeUpdatedSignal sig = new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp.fromNanos(maxSeg.getStart()), TmfTimestamp.fromNanos(maxSeg.getEnd()), fTrace);
broadcast(sig);
}
});
}
final ICalledFunction minSeg = flamegraphEvent.getMinObject();
if (minSeg != null) {
menuManager.add(new Action(Messages.FlameGraphView_GotoMinDuration) {
@Override
public void run() {
TmfSelectionRangeUpdatedSignal sig = new TmfSelectionRangeUpdatedSignal(this, TmfTimestamp.fromNanos(minSeg.getStart()), TmfTimestamp.fromNanos(minSeg.getEnd()), fTrace);
broadcast(sig);
}
});
}
}
}
}
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(getConfigureSymbolsAction());
manager.add(getAggregateByAction());
manager.add(getSortByNameAction());
manager.add(getSortByIdAction());
manager.add(new Separator());
}
private Action getAggregateByAction() {
if (fAggregateByAction == null) {
fAggregateByAction = new Action(Messages.FlameGraphView_GroupByName, IAction.AS_DROP_DOWN_MENU) {
@Override
public void run() {
SortOption sortOption = fTimeGraphContentProvider.getSortOption();
if (sortOption == SortOption.BY_NAME) {
setSortOption(SortOption.BY_NAME_REV);
} else {
setSortOption(SortOption.BY_NAME);
}
}
};
fAggregateByAction.setToolTipText(Messages.FlameGraphView_GroupByTooltip);
fAggregateByAction.setImageDescriptor(AGGREGATE_BY_ICON);
fAggregateByAction.setMenuCreator(new IMenuCreator () {
Menu menu = null;
@Override
public void dispose() {
if (menu != null) {
menu.dispose();
menu = null;
}
}
@Override
public Menu getMenu(Control parent) {
if (menu != null) {
menu.dispose();
}
menu = new Menu(parent);
Iterable<ICallGraphProvider> callgraphModules = getCallgraphModules();
Iterator<ICallGraphProvider> iterator = callgraphModules.iterator();
if (!iterator.hasNext()) {
return menu;
}
ICallGraphProvider provider = iterator.next();
// Add the all group element
Action allGroupAction = createActionForGroup(provider, AllGroupDescriptor.getInstance());
new ActionContributionItem(allGroupAction).fill(menu, -1);
Collection<IWeightedTreeGroupDescriptor> series = provider.getGroupDescriptors();
series.forEach(group -> {
IWeightedTreeGroupDescriptor subGroup = group;
do {
Action groupAction = createActionForGroup(provider, subGroup);
new ActionContributionItem(groupAction).fill(menu, -1);
subGroup = subGroup.getNextGroup();
} while (subGroup != null);
});
return menu;
}
@Override
public Menu getMenu(Menu parent) {
return null;
}
});
}
return fAggregateByAction;
}
private Action createActionForGroup(ICallGraphProvider provider, IWeightedTreeGroupDescriptor descriptor) {
return new Action(descriptor.getName(), IAction.AS_RADIO_BUTTON) {
@Override
public void run() {
fGroupBy = descriptor;
buildFlameGraph(Collections.singleton(provider), null, null);
}
};
}
private Action getSortByNameAction() {
if (fSortByNameAction == null) {
fSortByNameAction = new Action(Messages.FlameGraph_SortByThreadName, IAction.AS_CHECK_BOX) {
@Override
public void run() {
SortOption sortOption = fTimeGraphContentProvider.getSortOption();
if (sortOption == SortOption.BY_NAME) {
setSortOption(SortOption.BY_NAME_REV);
} else {
setSortOption(SortOption.BY_NAME);
}
}
};
fSortByNameAction.setToolTipText(Messages.FlameGraph_SortByThreadName);
fSortByNameAction.setImageDescriptor(SORT_BY_NAME_ICON);
}
return fSortByNameAction;
}
private Action getSortByIdAction() {
if (fSortByIdAction == null) {
fSortByIdAction = new Action(Messages.FlameGraph_SortByThreadId, IAction.AS_CHECK_BOX) {
@Override
public void run() {
SortOption sortOption = fTimeGraphContentProvider.getSortOption();
if (sortOption == SortOption.BY_ID) {
setSortOption(SortOption.BY_ID_REV);
} else {
setSortOption(SortOption.BY_ID);
}
}
};
fSortByIdAction.setToolTipText(Messages.FlameGraph_SortByThreadId);
fSortByIdAction.setImageDescriptor(SORT_BY_ID_ICON);
}
return fSortByIdAction;
}
private Action getConfigureSymbolsAction() {
if (fConfigureSymbolsAction != null) {
return fConfigureSymbolsAction;
}
fConfigureSymbolsAction = new Action(Messages.FlameGraphView_ConfigureSymbolProvidersText) {
@Override
public void run() {
SymbolProviderConfigDialog dialog = new SymbolProviderConfigDialog(getSite().getShell(), getProviderPages());
if (dialog.open() == IDialogConstants.OK_ID) {
// fPresentationProvider.resetFunctionNames();
// refresh();
}
}
};
fConfigureSymbolsAction.setToolTipText(Messages.FlameGraphView_ConfigureSymbolProvidersTooltip);
fConfigureSymbolsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(SYMBOL_MAPPING_ICON_PATH));
/*
* The updateConfigureSymbolsAction() method (called by refresh()) will
* set the action to true if applicable after the symbol provider has
* been properly loaded.
*/
fConfigureSymbolsAction.setEnabled(true);
return fConfigureSymbolsAction;
}
/**
* @return an array of {@link ISymbolProviderPreferencePage} that will
* configure the current traces
*/
private ISymbolProviderPreferencePage[] getProviderPages() {
List<ISymbolProviderPreferencePage> pages = new ArrayList<>();
ITmfTrace trace = fTrace;
if (trace != null) {
for (ITmfTrace subTrace : TmfTraceManager.getTraceSet(trace)) {
for (ISymbolProvider provider : SymbolProviderManager.getInstance().getSymbolProviders(subTrace)) {
if (provider instanceof org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider) {
org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider provider2 = (org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider) provider;
ISymbolProviderPreferencePage page = provider2.createPreferencePage();
if (page != null) {
pages.add(page);
}
}
}
}
}
return pages.toArray(new ISymbolProviderPreferencePage[pages.size()]);
}
private void setSortOption(SortOption sortOption) {
// reset defaults
getSortByNameAction().setChecked(false);
getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
getSortByIdAction().setChecked(false);
getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
if (sortOption.equals(SortOption.BY_NAME)) {
fTimeGraphContentProvider.setSortOption(SortOption.BY_NAME);
getSortByNameAction().setChecked(true);
} else if (sortOption.equals(SortOption.BY_NAME_REV)) {
fTimeGraphContentProvider.setSortOption(SortOption.BY_NAME_REV);
getSortByNameAction().setChecked(true);
getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
} else if (sortOption.equals(SortOption.BY_ID)) {
fTimeGraphContentProvider.setSortOption(SortOption.BY_ID);
getSortByIdAction().setChecked(true);
} else if (sortOption.equals(SortOption.BY_ID_REV)) {
fTimeGraphContentProvider.setSortOption(SortOption.BY_ID_REV);
getSortByIdAction().setChecked(true);
getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
}
saveSortOption();
fTimeGraphViewer.refresh();
}
private void saveSortOption() {
SortOption sortOption = fTimeGraphContentProvider.getSortOption();
IDialogSettings settings = Activator.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(getClass().getName());
if (section == null) {
section = settings.addNewSection(getClass().getName());
}
section.put(SORT_OPTION_KEY, sortOption.name());
}
private void loadSortOption() {
IDialogSettings settings = Activator.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(getClass().getName());
if (section == null) {
return;
}
String sortOption = section.get(SORT_OPTION_KEY);
if (sortOption == null) {
return;
}
setSortOption(SortOption.fromName(sortOption));
}
/**
* Symbol map provider updated
*
* @param signal
* the signal
*/
@TmfSignalHandler
public void symbolMapUpdated(TmfSymbolProviderUpdatedSignal signal) {
// if (signal.getSource() != this) {
fTimeGraphViewer.refresh();
// }
}
@Override
protected @Nullable IAction createSaveAction() {
return SaveImageUtil.createSaveAction(getName(), this::getTimeGraphViewer);
}
}