public static String ControlFlowView_uncheckInactiveToolTip;
public static String ControlFlowView_attributeSyscallName;
public static String ControlFlowView_attributeCpuName;
+
public static String ControlFlowView_flatViewLabel;
public static String ControlFlowView_flatViewToolTip;
public static String ControlFlowView_hierarchicalViewLabel;
package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow;
+import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
+
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Activator;
import org.eclipse.tracecompass.internal.analysis.os.linux.ui.Messages;
import org.eclipse.tracecompass.internal.analysis.os.linux.ui.actions.FollowThreadAction;
+import org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.filters.ActiveThreadsFilter;
+import org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.filters.DynamicFilterDialog;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.Resolution;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
+import org.eclipse.ui.PlatformUI;
+import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
/**
private IAction fHierarchicalAction;
+ private @NonNull ActiveThreadsFilter fActiveThreadsFilter = new ActiveThreadsFilter(null, false);
+
+ private final ActiveThreadsFilterAction fActiveThreadsRapidToggle = new ActiveThreadsFilterAction();
+
+ class ActiveThreadsFilterAction extends Action {
+ public ActiveThreadsFilterAction() {
+ super(PackageMessages.ControlFlowView_DynamicFiltersActiveThreadToggleLabel, IAction.AS_CHECK_BOX);
+ setToolTipText(PackageMessages.ControlFlowView_DynamicFiltersActiveThreadToggleToolTip);
+ addPropertyChangeListener(new IPropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ if (!(event.getNewValue() instanceof Boolean)) {
+ return;
+ }
+
+ Boolean enabled = (Boolean) event.getNewValue();
+
+ /* Always remove the previous Active Threads filter */
+ getTimeGraphCombo().removeFilter(fActiveThreadsFilter);
+
+ if (enabled) {
+ fActiveThreadsFilter.setEnabled(true);
+ getTimeGraphCombo().addFilter(fActiveThreadsFilter);
+
+ /* Use flat representation */
+ if (fFlatAction != null) {
+ applyFlatPresentation();
+ fFlatAction.setChecked(true);
+ fHierarchicalAction.setChecked(false);
+ }
+ } else {
+ fActiveThreadsFilter.setEnabled(false);
+ }
+
+ refresh();
+ }
+ });
+ }
+ }
+
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
@Override
protected void fillLocalMenu(IMenuManager manager) {
super.fillLocalMenu(manager);
- final MenuManager item = new MenuManager(Messages.ControlFlowView_threadPresentation);
+
+ MenuManager item = new MenuManager(Messages.ControlFlowView_threadPresentation);
fFlatAction = createFlatAction();
item.add(fFlatAction);
item.add(fHierarchicalAction);
manager.add(item);
+ item = new MenuManager(PackageMessages.ControlFlowView_DynamicFiltersMenuLabel);
+ item.add(fActiveThreadsRapidToggle);
+ item.add(new Separator());
+
+ IAction dynamicFiltersConfigureAction = createDynamicFilterConfigureAction();
+ item.add(dynamicFiltersConfigureAction);
+
+ manager.add(item);
}
+
+
/**
* Base Action for the "Go to Next/Previous Event for thread" actions
*/
}
}
+ private IAction createDynamicFilterConfigureAction() {
+ return new Action(PackageMessages.ControlFlowView_DynamicFiltersConfigureLabel, IAction.AS_PUSH_BUTTON) {
+ @Override
+ public void run() {
+ DynamicFilterDialog dialog = new DynamicFilterDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), fActiveThreadsFilter);
+ if (dialog.open() == Window.OK) {
+ /* Remove the previous Active Threads filter */
+ checkNotNull(getTimeGraphCombo()).removeFilter(fActiveThreadsFilter);
+
+ ActiveThreadsFilter newFilter = dialog.getActiveThreadsResult();
+ ActiveThreadsFilter previousFilter = fActiveThreadsFilter;
+
+ /* Set the filter to the view */
+ fActiveThreadsFilter = newFilter;
+
+ boolean enabled = fActiveThreadsFilter.isEnabled();
+ if (enabled) {
+ checkNotNull(getTimeGraphCombo()).addFilter(newFilter);
+ }
+
+ /*
+ * Prevent double refresh from change state of setChecked
+ * and ensure that a refresh is done if the mode of the
+ * filter is changed or options are changed
+ */
+ if (previousFilter.isEnabled() && newFilter.isEnabled()) {
+ boolean changed = !Objects.equal(previousFilter.getCpuRanges(), newFilter.getCpuRanges()) || previousFilter.isCpuRangesBased() != newFilter.isCpuRangesBased();
+ if (changed) {
+ refresh();
+ }
+ } else {
+ fActiveThreadsRapidToggle.setChecked(enabled);
+ }
+ }
+ }
+ };
+ }
+
private IAction createHierarchicalAction() {
IAction action = new Action(Messages.ControlFlowView_hierarchicalViewLabel, IAction.AS_RADIO_BUTTON) {
@Override
IAction action = new Action(Messages.ControlFlowView_flatViewLabel, IAction.AS_RADIO_BUTTON) {
@Override
public void run() {
- ITmfTrace parentTrace = getTrace();
- synchronized (fFlatTraces) {
- fFlatTraces.add(parentTrace);
- for (ITmfTrace trace : TmfTraceManager.getTraceSet(parentTrace)) {
- final ITmfStateSystem ss = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
- List<@NonNull TimeGraphEntry> entryList = getEntryList(ss);
- if (entryList != null) {
- for (TimeGraphEntry traceEntry : entryList) {
- hierarchicalToFlatTree(traceEntry);
- }
- }
- }
- }
+ applyFlatPresentation();
refresh();
}
};
+ action.setChecked(true);
action.setToolTipText(Messages.ControlFlowView_flatViewToolTip);
return action;
}
+ private void applyFlatPresentation() {
+ ITmfTrace parentTrace = getTrace();
+ synchronized (fFlatTraces) {
+ fFlatTraces.add(parentTrace);
+ for (ITmfTrace trace : TmfTraceManager.getTraceSet(parentTrace)) {
+ final ITmfStateSystem ss = TmfStateSystemAnalysisModule.getStateSystem(trace, KernelAnalysisModule.ID);
+ List<@NonNull TimeGraphEntry> entryList = getEntryList(ss);
+ if (entryList != null) {
+ for (TimeGraphEntry traceEntry : entryList) {
+ hierarchicalToFlatTree(traceEntry);
+ }
+ }
+ }
+ }
+ }
+
@Override
protected String getNextText() {
return Messages.ControlFlowView_nextProcessActionNameText;
@Override
public void traceSelected(TmfTraceSelectedSignal signal) {
super.traceSelected(signal);
+
+ /* Update the Flat and Hierarchical actions */
synchronized (fFlatTraces) {
if (fFlatTraces.contains(signal.getTrace())) {
fHierarchicalAction.setChecked(false);
fHierarchicalAction.setChecked(true);
}
}
+
+ /* Update the Dynamic Filters related actions */
+ ViewerFilter activeThreadFilter = null;
+ ViewerFilter[] traceFilters = getFiltersMap().get(signal.getTrace());
+ if (traceFilters != null) {
+ activeThreadFilter = getActiveThreadsFilter(traceFilters);
+ }
+
+ if (activeThreadFilter == null) {
+ fActiveThreadsFilter = new ActiveThreadsFilter(null, false);
+ } else {
+ fActiveThreadsFilter = (@NonNull ActiveThreadsFilter) checkNotNull(activeThreadFilter);
+ }
+
+ fActiveThreadsRapidToggle.setChecked(fActiveThreadsFilter.isEnabled());
}
// ------------------------------------------------------------------------
}
return null;
}
+
+ private static ActiveThreadsFilter getActiveThreadsFilter(ViewerFilter[] filters) {
+ return (ActiveThreadsFilter) Arrays.stream(filters).filter(filter -> filter instanceof ActiveThreadsFilter).findFirst().orElse(null);
+ }
+
+ @Override
+ protected void updateFilters() {
+ super.updateFilters();
+ fActiveThreadsFilter.updateData();
+ }
+
}
public static String ControlFlowView_PreviousEventActionTooltip;
public static String ControlFlowView_PreviousEventJobName;
+ public static String ControlFlowView_DynamicFiltersActiveThreadToggleLabel;
+ public static String ControlFlowView_DynamicFiltersActiveThreadToggleToolTip;
+ public static String ControlFlowView_DynamicFiltersConfigureLabel;
+ public static String ControlFlowView_DynamicFiltersMenuLabel;
static {
NLS.initializeMessages(BUNDLE_NAME, PackageMessages.class);
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc.
+ *
+ * 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
+ ******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.filters;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelAnalysisModule;
+import org.eclipse.tracecompass.analysis.os.linux.core.kernel.KernelThreadInformationProvider;
+import org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.ControlFlowEntry;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+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.core.trace.TmfTraceUtils;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Range;
+
+/**
+ * Provide active threads filtering for the control flow view. <br>
+ * <br>
+ * The Active Thread filter can be used in two mode: <br>
+ * Show threads running on a range of CPUs <br>
+ * Show all threads considered active <br>
+ *
+ * @author Jonathan Rajotte Julien
+ */
+public class ActiveThreadsFilter extends ViewerFilter {
+
+ /** The filtering CPU ranges */
+ private final @NonNull List<Range<Long>> fCpuRanges;
+
+ /** The local cache for On CPU filtering */
+ private @NonNull Set<Integer> fCachedOnCpusThreadForTimeRange = new HashSet<>();
+ /** The local cache for Active Threads filtering */
+ private @NonNull Set<Integer> fCachedActiveThreadForTimeRange = new HashSet<>();
+
+ /** The cached time range */
+ private TmfTimeRange fCachedTimeRange;
+
+ /** Whether the filter is enabled */
+ private boolean fEnabled = false;
+ /** Whether the filter is an On CPU filter */
+ private boolean fCpuRangesBasedFiltering = false;
+
+ /**
+ * Create an Active Threads filter with CPU ranges criteria.
+ *
+ * @param cpuRanges
+ * The CPU ranges for the filter if any.
+ * @param cpuRangesBasedFiltering
+ * Whether or not to filter based on CPU ranges.
+ */
+ public ActiveThreadsFilter(List<Range<Long>> cpuRanges, boolean cpuRangesBasedFiltering) {
+ super();
+ if (cpuRanges != null) {
+ fCpuRanges = ImmutableList.copyOf(cpuRanges);
+ } else {
+ fCpuRanges = new ArrayList<>();
+ }
+
+ fCpuRangesBasedFiltering = cpuRangesBasedFiltering;
+ }
+
+ /**
+ * @return If the filter is enabled
+ */
+ public boolean isEnabled() {
+ return fEnabled;
+ }
+
+ /**
+ * @return If the filter is based on CPU ranges filtering
+ */
+ public boolean isCpuRangesBased() {
+ return fCpuRangesBasedFiltering;
+ }
+
+ /**
+ * Set the enabled state of the filter
+ *
+ * @param enabled
+ * The state of the filter
+ */
+ public void setEnabled(boolean enabled) {
+ fEnabled = enabled;
+ }
+
+ /**
+ * Get the CPU ranges of the filter
+ *
+ * @return The CPU ranges of the filter
+ */
+ public @NonNull List<Range<Long>> getCpuRanges() {
+ return fCpuRanges;
+ }
+
+ @Override
+ public boolean select(Viewer viewer, Object parentElement, Object element) {
+
+ if (!fEnabled || !(element instanceof ControlFlowEntry)) {
+ return true;
+ }
+ ControlFlowEntry cfe = (ControlFlowEntry) element;
+
+ /* Check if on CPU */
+ if (fCpuRangesBasedFiltering && fCachedOnCpusThreadForTimeRange.contains(cfe.getThreadId())) {
+ return true;
+ } else if (fCachedActiveThreadForTimeRange.contains(cfe.getThreadId())) {
+ return true;
+ }
+
+ /* Not active per see. Check children if any is active */
+ for (@NonNull
+ TimeGraphEntry child : cfe.getChildren()) {
+ if (select(viewer, cfe, child)) {
+ return true;
+ }
+ }
+
+ /* No children are active */
+ return false;
+ }
+
+ private static @NonNull Set<Integer> getOnCpuThreads(List<Range<Long>> cpuRanges) {
+ if (cpuRanges == null) {
+ return new HashSet<>();
+ }
+
+ TmfTraceManager traceManager = TmfTraceManager.getInstance();
+ TmfTraceContext traceContext = traceManager.getCurrentTraceContext();
+ TmfTimeRange winRange = traceContext.getWindowRange();
+
+ ITmfTrace trace = traceManager.getActiveTrace();
+
+ if (trace == null) {
+ return new HashSet<>();
+ }
+
+ KernelAnalysisModule kernelAnalysisModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, KernelAnalysisModule.class, KernelAnalysisModule.ID);
+
+ long beginTS = winRange.getStartTime().getValue();
+ long endTS = winRange.getEndTime().getValue();
+
+ if (kernelAnalysisModule == null) {
+ /* TODO: what to do here ? */
+ return new HashSet<>();
+ }
+
+ /* Convert range to sets */
+ @NonNull
+ Set<@NonNull Long> cpus = new HashSet<>();
+ for (Range<Long> range : cpuRanges) {
+ Long minimum = range.lowerEndpoint();
+ Long maximum = range.upperEndpoint();
+ for (Long i = minimum; i <= maximum; i++) {
+ cpus.add(i);
+ }
+ }
+
+ Set<Integer> set = KernelThreadInformationProvider.getThreadsOfCpus(kernelAnalysisModule, cpus, beginTS, endTS);
+
+ if (set == null) {
+ set = new HashSet<>();
+ }
+
+ return set;
+ }
+
+ private static @NonNull Set<Integer> getActiveThreads() {
+ TmfTraceManager traceManager = TmfTraceManager.getInstance();
+ TmfTraceContext traceContext = traceManager.getCurrentTraceContext();
+ TmfTimeRange winRange = traceContext.getWindowRange();
+
+ ITmfTrace trace = traceManager.getActiveTrace();
+
+ if (trace == null) {
+ return new HashSet<>();
+ }
+
+ KernelAnalysisModule kernelModule = TmfTraceUtils.getAnalysisModuleOfClass(trace, KernelAnalysisModule.class, KernelAnalysisModule.ID);
+
+ long beginTS = winRange.getStartTime().getValue();
+ long endTS = winRange.getEndTime().getValue();
+
+ if (kernelModule == null) {
+ /* TODO: what to do here ? */
+ return new HashSet<>();
+ }
+
+ Set<Integer> set = KernelThreadInformationProvider.getActiveThreadsForRange(kernelModule, beginTS, endTS);
+
+ if (set == null) {
+ set = new HashSet<>();
+ }
+
+ return set;
+ }
+
+ /**
+ * Update the filter internal data
+ */
+ public void updateData() {
+ TmfTraceManager traceManager = TmfTraceManager.getInstance();
+ TmfTraceContext traceContext = traceManager.getCurrentTraceContext();
+ TmfTimeRange winRange = traceContext.getWindowRange();
+ long beginTS = winRange.getStartTime().getValue();
+ long endTS = winRange.getEndTime().getValue();
+
+ TmfTimeRange timeRange = new TmfTimeRange(TmfTimestamp.fromNanos(beginTS), TmfTimestamp.fromNanos(endTS));
+
+ /* Caching result for subsequent select() call for other entry */
+ if (fEnabled && (fCachedTimeRange == null || !fCachedTimeRange.equals(timeRange))) {
+ fCachedTimeRange = timeRange;
+ if (fCpuRangesBasedFiltering) {
+ fCachedOnCpusThreadForTimeRange = getOnCpuThreads(fCpuRanges);
+ } else {
+ fCachedActiveThreadForTimeRange = getActiveThreads();
+ }
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(fCpuRanges, fCpuRangesBasedFiltering, fEnabled);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ ActiveThreadsFilter other = (ActiveThreadsFilter) obj;
+ return Objects.equals(fCpuRanges, other.fCpuRanges) &&
+ fCpuRangesBasedFiltering == other.fCpuRangesBasedFiltering &&
+ fEnabled == other.fEnabled;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc.
+ *
+ * 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
+ ******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.filters;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringJoiner;
+import java.util.regex.Pattern;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TitleAreaDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.VerifyEvent;
+import org.eclipse.swt.events.VerifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import com.google.common.collect.Range;
+
+/**
+ * The Dynamic Filters configuration dialog.
+ *
+ * @author Jonathan Rajotte Julien
+ */
+public class DynamicFilterDialog extends TitleAreaDialog {
+
+ private static final @NonNull String INTERNAL_RANGE_SEPARATOR = "-"; //$NON-NLS-1$
+ private static final @NonNull String RANGES_DELIMITER = ","; //$NON-NLS-1$
+
+ /** The internal ActiveThreadsFilter result */
+ private @NonNull ActiveThreadsFilter fInternalActiveThreadsFilter;
+
+ private Button fActiveThreadEnabledButton;
+ private Button fAllActiveThreadsRadionButton;
+ private Button fCpuRangesRadioButton;
+ private Text fCpuRangesField;
+
+ /**
+ * Create a DynamicFilterDialog f
+ *
+ * @param parentShell
+ * The parent shell
+ * @param filter
+ * An
+ * {@link org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.filters.ActiveThreadsFilter
+ * ActiveThreadFilter} instance.
+ */
+ public DynamicFilterDialog(Shell parentShell, @NonNull ActiveThreadsFilter filter) {
+ super(parentShell);
+ fInternalActiveThreadsFilter = filter;
+ }
+
+ @Override
+ public void create() {
+ super.create();
+ setTitle(Messages.DynamicFilterDialog_Title);
+
+ /* TODO: This is used for swtbot testing to discover the dialog */
+ this.getShell().setText(Messages.DynamicFilterDialog_Title);
+ }
+
+ private static boolean validateCpuRange(final String newString) {
+ /* Pattern for CPUS ranges e.g.: 1,1-200,2,3 */
+ return Pattern.matches("^((\\d+(\\-\\d+)?, ?)*(\\d+(\\-\\d+)?))+$", newString); //$NON-NLS-1$
+ }
+
+ private void createActiveThreadSection(Composite parent) {
+ boolean usesCpuRanges = false;
+ boolean filterActive = false;
+
+ ActiveThreadsFilter filter = fInternalActiveThreadsFilter;
+
+ filterActive = fInternalActiveThreadsFilter.isEnabled();
+ usesCpuRanges = filter.isCpuRangesBased();
+
+ GridData gd;
+ GridLayout gl;
+ Group activeThreadGroup = new Group(parent, SWT.SHADOW_NONE | SWT.BORDER);
+ activeThreadGroup.setText(Messages.DynamicFilterDialog_ActiveThreadsFilterName);
+
+ activeThreadGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ gl = new GridLayout(1, true);
+ gl.marginLeft = gl.marginRight = 0;
+ activeThreadGroup.setLayout(gl);
+
+ fActiveThreadEnabledButton = new Button(activeThreadGroup, SWT.CHECK);
+ fActiveThreadEnabledButton.setText(Messages.DynamicFilterDialog_ActiveThreadsFilterName);
+ fActiveThreadEnabledButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ /* Cpu selection */
+ Group cpuSelectionGroup = new Group(activeThreadGroup, SWT.SHADOW_NONE);
+ cpuSelectionGroup.setText(Messages.DynamicFilterDialog_OptionsGroupLabel);
+ cpuSelectionGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ cpuSelectionGroup.setLayout(new GridLayout(2, false));
+
+ fAllActiveThreadsRadionButton = new Button(cpuSelectionGroup, SWT.RADIO);
+ fAllActiveThreadsRadionButton.setText(Messages.DynamicFilterDialog_RadioButtonAllActiveThreads);
+ fAllActiveThreadsRadionButton.setToolTipText(Messages.DynamicFilterDialog_RadioButtonAllActiveThreadsToolTip);
+
+ fAllActiveThreadsRadionButton.setSelection(!usesCpuRanges);
+ gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.horizontalSpan = 2;
+ fAllActiveThreadsRadionButton.setLayoutData(gd);
+
+ fCpuRangesRadioButton = new Button(cpuSelectionGroup, SWT.RADIO);
+ fCpuRangesRadioButton.setText(Messages.DynamicFilterDialog_CpuRangesLabel);
+ fCpuRangesRadioButton.setToolTipText(Messages.DynamicFilterDialog_CpuRangesTooltip);
+
+ fCpuRangesRadioButton.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true));
+
+ fCpuRangesField = new Text(cpuSelectionGroup, SWT.SINGLE | SWT.BORDER);
+ fCpuRangesField.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, true, true));
+ fCpuRangesField.setMessage(Messages.DynamicFilterDialog_CpuRangesExamples);
+
+ fCpuRangesRadioButton.setToolTipText(Messages.DynamicFilterDialog_CpuRangesTooltip);
+
+ /* Attach an automatic validation to the field */
+ fCpuRangesField.addVerifyListener(new VerifyListener() {
+ @Override
+ public void verifyText(VerifyEvent e) {
+ /* Reconstruct the string */
+ final String oldString = fCpuRangesField.getText();
+ final String newString = oldString.substring(0, e.start) + e.text + oldString.substring(e.end);
+
+ /* Validate the string */
+ boolean valid = validateCpuRange(newString);
+
+ Button okButton = getButton(IDialogConstants.OK_ID);
+ if (okButton != null) {
+ getButton(IDialogConstants.OK_ID).setEnabled(valid);
+ }
+ if (valid) {
+ setErrorMessage(null);
+ } else {
+ setErrorMessage(Messages.DynamicFilterDialog_InvalidRangesErrorMsg);
+ }
+ }
+ });
+
+ fAllActiveThreadsRadionButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ super.widgetSelected(e);
+ boolean selected = ((Button) e.widget).getSelection();
+ if (!selected) {
+ return;
+ }
+ setErrorMessage(null);
+ getButton(IDialogConstants.OK_ID).setEnabled(true);
+ }
+ });
+
+ fCpuRangesRadioButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ super.widgetSelected(e);
+ boolean selected = ((Button) e.widget).getSelection();
+ fCpuRangesField.setEnabled(selected);
+ validateCpuRange(fCpuRangesField.getText());
+ }
+ });
+
+ fActiveThreadEnabledButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ super.widgetSelected(e);
+ boolean selected = ((Button) e.widget).getSelection();
+ cpuSelectionGroup.setEnabled(selected);
+ fAllActiveThreadsRadionButton.setEnabled(selected);
+ fCpuRangesRadioButton.setEnabled(selected);
+ fCpuRangesField.setEnabled(selected && fCpuRangesRadioButton.getSelection());
+ }
+ });
+
+ /* Set the base state for the ui control */
+ fActiveThreadEnabledButton.setSelection(filterActive);
+ cpuSelectionGroup.setEnabled(filterActive);
+ fCpuRangesRadioButton.setEnabled(filterActive);
+ fAllActiveThreadsRadionButton.setEnabled(filterActive);
+
+ fAllActiveThreadsRadionButton.setSelection(!usesCpuRanges);
+ fCpuRangesRadioButton.setSelection(usesCpuRanges);
+
+ fCpuRangesField.setEnabled(filterActive && usesCpuRanges);
+
+ /* Populate the CPU ranges fields */
+ if (!filter.getCpuRanges().isEmpty()) {
+ StringJoiner joiner = new StringJoiner(RANGES_DELIMITER);
+ for (Range<Long> range : filter.getCpuRanges()) {
+ String rangeString = range.lowerEndpoint().toString();
+ if (range.lowerEndpoint() != range.upperEndpoint()) {
+ rangeString = rangeString.concat(INTERNAL_RANGE_SEPARATOR + range.upperEndpoint());
+ }
+ joiner.add(rangeString);
+ }
+ fCpuRangesField.setText(joiner.toString());
+ }
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite area = (Composite) super.createDialogArea(parent);
+ Composite container = new Composite(area, SWT.NONE);
+ container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ GridLayout layout = new GridLayout(1, true);
+ container.setLayout(layout);
+
+ createActiveThreadSection(container);
+ return area;
+ }
+
+ @Override
+ protected boolean isResizable() {
+ return true;
+ }
+
+ private void saveInput() {
+ if (!(fAllActiveThreadsRadionButton.getSelection() || fCpuRangesRadioButton.getSelection())
+ || (fAllActiveThreadsRadionButton.getSelection() && fCpuRangesRadioButton.getSelection())) {
+ throw new IllegalStateException(Messages.DynamicFilterDialog_InvalidRadioButtonState);
+ }
+
+ List<Range<Long>> ranges = null;
+ ranges = parseCpuRangesText(fCpuRangesField.getText());
+
+ fInternalActiveThreadsFilter = new ActiveThreadsFilter(ranges, fCpuRangesRadioButton.getSelection());
+ fInternalActiveThreadsFilter.setEnabled(fActiveThreadEnabledButton.getSelection());
+ }
+
+ private static List<Range<Long>> parseCpuRangesText(final String string) {
+ if (!validateCpuRange(string)) {
+ return null;
+ }
+
+ string.split(RANGES_DELIMITER);
+ List<Range<Long>> results = new ArrayList<>();
+ for (String range : Arrays.asList(string.split(RANGES_DELIMITER))) {
+ if (range.contains(INTERNAL_RANGE_SEPARATOR)) {
+ /* Parse as a range */
+ String[] split = range.split(INTERNAL_RANGE_SEPARATOR);
+ if (split.length != 2) {
+ /* Invalid range */
+ continue;
+ }
+
+ long[] sorted = Arrays.asList(split).stream().map(Long::parseLong).sorted().mapToLong(Long::longValue).toArray();
+ results.add(Range.closed(sorted[0], sorted[1]));
+ } else {
+ /* Parse as an individual number */
+ Long value = Long.parseLong(range);
+ results.add(Range.closed(value, value));
+ }
+ }
+ return results;
+ }
+
+ @Override
+ protected void okPressed() {
+ saveInput();
+ super.okPressed();
+ }
+
+ @Override
+ public boolean isHelpAvailable() {
+ return false;
+ }
+
+ /**
+ * Get the resulting ActiveThreadsFilter
+ *
+ * @return The configured
+ * {@link org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.filters.ActiveThreadsFilter
+ * ActiveThreadFilter} instance.
+ */
+ public @NonNull ActiveThreadsFilter getActiveThreadsResult() {
+ return fInternalActiveThreadsFilter;
+ }
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2016 EfficiOS Inc.
+ *
+ * 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
+ ******************************************************************************/
+
+package org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.filters;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * The messages for
+ * {@link org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.filters}
+ *
+ * @author Jonathan Rajotte Julien
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.internal.analysis.os.linux.ui.views.controlflow.filters.messages"; //$NON-NLS-1$
+ /** The CPUs ranges example */
+ public static String DynamicFilterDialog_CpuRangesExamples;
+ /** The CPUs radio button label*/
+ public static String DynamicFilterDialog_CpuRangesLabel;
+ /** The CPUs radio button tooltip */
+ public static String DynamicFilterDialog_CpuRangesTooltip;
+ /** The active thread filter name */
+ public static String DynamicFilterDialog_ActiveThreadsFilterName;
+ /** Thrown error if the radios button are in a invalid state */
+ public static String DynamicFilterDialog_InvalidRadioButtonState;
+ /** The error message displayed when input ranges are invalid */
+ public static String DynamicFilterDialog_InvalidRangesErrorMsg;
+ /** The Options sub groups label */
+ public static String DynamicFilterDialog_OptionsGroupLabel;
+ /** The All CPUs option label */
+ public static String DynamicFilterDialog_RadioButtonAllActiveThreads;
+ /** The All CPUs option tooltip */
+ public static String DynamicFilterDialog_RadioButtonAllActiveThreadsToolTip;
+ /** The dialog title */
+ public static String DynamicFilterDialog_Title;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
--- /dev/null
+###############################################################################
+# Copyright (c) 2016 EfficiOS Inc.
+#
+# 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
+###############################################################################
+
+DynamicFilterDialog_CpuRangesExamples=e.g. 0-3,5,7-8
+DynamicFilterDialog_CpuRangesLabel=Active Threads on CPUs:
+DynamicFilterDialog_ActiveThreadsFilterName=Show Active Threads Only
+DynamicFilterDialog_CpuRangesTooltip=Show active threads for specified CPU
+DynamicFilterDialog_RadioButtonAllActiveThreadsToolTip=Show all active threads
+DynamicFilterDialog_InvalidRadioButtonState=Invalid radio button state
+DynamicFilterDialog_InvalidRangesErrorMsg=Invalid CPUs Ranges
+DynamicFilterDialog_OptionsGroupLabel=Options
+DynamicFilterDialog_RadioButtonAllActiveThreads=All Active Threads
+DynamicFilterDialog_Title=Dynamic Filters Configuration
ControlFlowView_PreviousEventActionName = Go to previous event
ControlFlowView_PreviousEventActionTooltip = Go to previous event of the selected thread
ControlFlowView_PreviousEventJobName = Searching for previous matching event
+
+ControlFlowView_DynamicFiltersActiveThreadToggleLabel=&Active Threads only
+ControlFlowView_DynamicFiltersActiveThreadToggleToolTip=Toggle active threads filtering
+ControlFlowView_DynamicFiltersConfigureLabel=&Configure...
+ControlFlowView_DynamicFiltersMenuLabel=&Dynamic Filters
* the pointed state date and start/stop times
* the pointed state duration (seconds)
+==== Dynamics Filters ====
+
+Dynamic filters are filters that are processed and applied each time the control flow view visible time range changes.
+
+The dynamics filters can be rapidly toggled in their view sub menu.
+
+[[Image:images/DynamicFilters/DynamicFiltersToggle.png]]
+
+
+The dynamics filters can be fine tuned in the configuration dialog.
+
+[[Image:images/DynamicFilters/DynamicFiltersConfigure.png]]
+
+Note: Dynamic filters can induce performance degradation.
+
+===== Show Active Threads Only =====
+
+The Show Active Threads Only filter allow a user to increase the signal to noise ratio by filtering out all <u>inactive</u> threads.
+
+A thread is considered inactive when it is in the following state:
+
+* non-existing
+* unknown
+* wait and blocked
+* wait and unknown
+
+A user can fine tune this filter by providing ranges of CPUs allowing the filter to only show active thread running on the specified CPUs.
+
+[[Image:images/DynamicFilters/DynamicFilter_ShowActiveThreadsConfigure.png]]
+
=== Toolbar ===
<!-- Keep in sync with ref:resource-view-toolbar -->
|
| Thread Presentation
| Select the threads layout. Two layouts are available. '''Flat''' layout lists the threads in a flat list per trace. '''Hierarchical''' layout shows the threads in a parent-child tree per trace.
+|-
+|
+| Dynamic Filters
+| Select and configure the Dynamic Filters to be applied.
|}
=== Marker Axis ===
/*******************************************************************************
- * Copyright (c) 2015 Ericsson
+ * Copyright (c) 2015, 2016 Ericsson, EfficiOS Inc.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
package org.eclipse.tracecompass.lttng2.kernel.ui.swtbot.tests;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import org.eclipse.swtbot.swt.finder.keyboard.Keyboard;
import org.eclipse.swtbot.swt.finder.keyboard.KeyboardFactory;
import org.eclipse.swtbot.swt.finder.keyboard.Keystrokes;
+import org.eclipse.swtbot.swt.finder.waits.Conditions;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotCheckBox;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotRadio;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotText;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotToolbarButton;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree;
import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem;
@RunWith(SWTBotJunit4ClassRunner.class)
public class ControlFlowViewTest extends KernelTimeGraphViewTestBase {
+ private static final String DIALOG_OK = "OK";
+ private static final String DIALOG_CANCEL = "Cancel";
+
+ private static final String THREAD_PRESENTATION_HIERARCHICAL = "Hierarchical";
+ private static final String THREAD_PRESENTATION_FLAT = "Flat";
+
+ private static final String DYNAMIC_FILTER_ACTIVE_THREADS_ONLY_TOGGLE = "Active Threads only";
+ private static final String DYNAMIC_FILTER_ON_CPU_FIELD_MESSAGE = "e.g. 0-3,5,7-8";
+ private static final String DYNAMIC_FILTERS_ALL_ACTIVE_RADIO = "All Active Threads";
+ private static final String DYNAMIC_FILTERS_ON_CPU_RADIO = "Active Threads on CPUs:";
+ private static final String DYNAMIC_FILTERS_SHOW_ACTIVE_THREADS_ONLY_CHECKBOX = "Show Active Threads Only";
+ private static final String DYNAMIC_FILTERS_SHELL_TEXT = "Dynamic Filters Configuration";
+ private static final String DYNAMIC_FILTER_CONFIGURE_LABEL = "Configure...";
+
private static final String CHECK_SELECTED = "Check selected";
private static final String CHECK_ALL = "Check all";
private static final String CHECK_SUBTREE = "Check subtree";
bot.button(CHECK_ALL).click();
checked = UIThreadRunnable.syncExec(treeCheckCounter);
assertEquals("Filtered", 26, checked.intValue());
- bot.button("OK").click();
+ bot.button(DIALOG_OK).click();
SWTBotTimeGraph timeGraph = new SWTBotTimeGraph(getViewBot().bot());
SWTBotTimeGraphEntry traceEntry = timeGraph.getEntry(LttngTraceGenerator.getName());
for (SWTBotTimeGraphEntry entry : traceEntry.getEntries()) {
}
}
+ /**
+ * Test dynamic filters dialog
+ */
+ @Test
+ public void testDynamicFiltersDialog() {
+
+ String valid_cpu_ranges = "0,1,2-100";
+ String invalid_cpu_ranges = "-1,1";
+
+ /* Change window range to 10 ms */
+ TmfTimeRange range = new TmfTimeRange(START_TIME, START_TIME.normalize(10000000L, ITmfTimestamp.NANOSECOND_SCALE));
+ TmfSignalManager.dispatchSignal(new TmfWindowRangeUpdatedSignal(this, range));
+ TmfSignalManager.dispatchSignal(new TmfSelectionRangeUpdatedSignal(this, range.getStartTime(), range.getEndTime()));
+ timeGraphIsReadyCondition(range);
+
+ getViewBot().viewMenu(DYNAMIC_FILTER_CONFIGURE_LABEL).click();
+ fBot.waitUntil(Conditions.shellIsActive(DYNAMIC_FILTERS_SHELL_TEXT));
+ SWTBotShell shell = fBot.shell(DYNAMIC_FILTERS_SHELL_TEXT);
+ shell.activate();
+
+ /* Make sure nothing is checked and radio buttons are disabled */
+ SWTBotCheckBox activeThreadsCheckbox = shell.bot().checkBox(DYNAMIC_FILTERS_SHOW_ACTIVE_THREADS_ONLY_CHECKBOX);
+ SWTBotRadio onCpuRadio = shell.bot().radio(DYNAMIC_FILTERS_ON_CPU_RADIO);
+ SWTBotRadio allActiveRadio = shell.bot().radio(DYNAMIC_FILTERS_ALL_ACTIVE_RADIO);
+ SWTBotText onCpuField = shell.bot().textWithMessage(DYNAMIC_FILTER_ON_CPU_FIELD_MESSAGE);
+
+ assertFalse(activeThreadsCheckbox.isChecked());
+ assertFalse(onCpuRadio.isEnabled());
+ assertFalse(allActiveRadio.isEnabled());
+ assertFalse(onCpuField.isEnabled());
+
+ /*
+ * Test Active Filter buttons toggle
+ */
+ activeThreadsCheckbox.click();
+
+ /* All objects should be enabled except for the CPU ranges field */
+ assertTrue(activeThreadsCheckbox.isChecked());
+ assertTrue(allActiveRadio.isEnabled());
+ assertTrue(onCpuRadio.isEnabled());
+ assertFalse(onCpuField.isEnabled());
+
+ /*
+ * The All Active Threads option should be the default for a new filter
+ */
+ assertTrue(allActiveRadio.isSelected());
+
+ /*
+ * Select All Threads on CPUs option
+ */
+ onCpuRadio.click();
+
+ /* All objects should be enabled */
+ assertTrue(activeThreadsCheckbox.isChecked());
+ assertTrue(allActiveRadio.isEnabled());
+ assertTrue(onCpuRadio.isEnabled());
+ assertTrue(onCpuField.isEnabled());
+
+ assertFalse(allActiveRadio.isSelected());
+ assertTrue(onCpuRadio.isSelected());
+
+ /*
+ * Select All Active Threads then Active Threads on CPUs to validate
+ * toggle of options
+ */
+ allActiveRadio.click();
+
+ /* All objects should be enabled except for the CPU ranges field */
+ assertTrue(activeThreadsCheckbox.isChecked());
+ assertTrue(allActiveRadio.isEnabled());
+ assertTrue(onCpuRadio.isEnabled());
+ assertFalse(onCpuField.isEnabled());
+
+ assertTrue(allActiveRadio.isSelected());
+ assertFalse(onCpuRadio.isSelected());
+
+ /* Select Active Threads on CPUs */
+ onCpuRadio.click();
+
+ /* All objects should be enabled */
+ assertTrue(activeThreadsCheckbox.isChecked());
+ assertTrue(allActiveRadio.isEnabled());
+ assertTrue(onCpuRadio.isEnabled());
+ assertTrue(onCpuField.isEnabled());
+
+ assertFalse(allActiveRadio.isSelected());
+ assertTrue(onCpuRadio.isSelected());
+
+ /* Put an invalid value in the CPU ranges field */
+ onCpuField.setText(invalid_cpu_ranges);
+
+ /* Make sure the OK button is not enabled when in an invalid state */
+ assertFalse(shell.bot().button(DIALOG_OK).isEnabled());
+
+ /* Put a valid value in the CPU ranges field */
+ onCpuField.setText(valid_cpu_ranges);
+
+ /* Make sure the OK button is enabled when in a valid state */
+ assertTrue(shell.bot().button(DIALOG_OK).isEnabled());
+
+ shell.bot().button(DIALOG_OK).click();
+ timeGraphIsReadyCondition(range);
+
+ /* Make sure that the quick Active Thread Filter toggle is checked */
+ assertTrue(getViewBot().viewMenu(DYNAMIC_FILTER_ACTIVE_THREADS_ONLY_TOGGLE).isChecked());
+
+ /* Make sure that the Flat presentation is checked */
+ assertTrue(getViewBot().viewMenu(THREAD_PRESENTATION_FLAT).isChecked());
+ assertFalse(getViewBot().viewMenu(THREAD_PRESENTATION_HIERARCHICAL).isChecked());
+
+ /* Reopen the dialog */
+ getViewBot().viewMenu(DYNAMIC_FILTER_CONFIGURE_LABEL).click();
+ fBot.waitUntil(Conditions.shellIsActive(DYNAMIC_FILTERS_SHELL_TEXT));
+ shell = fBot.shell(DYNAMIC_FILTERS_SHELL_TEXT);
+ shell.activate();
+
+ /* Make sure nothing is checked and radio buttons are disabled */
+ activeThreadsCheckbox = shell.bot().checkBox(DYNAMIC_FILTERS_SHOW_ACTIVE_THREADS_ONLY_CHECKBOX);
+ onCpuRadio = shell.bot().radio(DYNAMIC_FILTERS_ON_CPU_RADIO);
+ allActiveRadio = shell.bot().radio(DYNAMIC_FILTERS_ALL_ACTIVE_RADIO);
+ onCpuField = shell.bot().textWithMessage(DYNAMIC_FILTER_ON_CPU_FIELD_MESSAGE);
+
+ /* Make sure the previous settings are set correctly */
+ assertTrue(activeThreadsCheckbox.isChecked());
+ assertTrue(allActiveRadio.isEnabled());
+ assertTrue(onCpuRadio.isEnabled());
+ assertTrue(onCpuField.isEnabled());
+ assertFalse(allActiveRadio.isSelected());
+ assertTrue(onCpuRadio.isSelected());
+ assertTrue(onCpuField.isEnabled());
+ assertEquals("CPU ranges not equal", onCpuField.getText(), valid_cpu_ranges);
+
+ /*
+ * Change to All Active Threads option click OK then reopen. The
+ * previous CPU range should still be there.
+ */
+
+ allActiveRadio.click();
+ /* Make sure that the ranges are still visible but disabled */
+ assertFalse(onCpuField.isEnabled());
+ assertEquals("Cpu ranges not equal", onCpuField.getText(), valid_cpu_ranges);
+
+ /* Close the dialog */
+ shell.bot().button(DIALOG_OK).click();
+ timeGraphIsReadyCondition(range);
+
+ /* Open the dialog */
+ getViewBot().viewMenu(DYNAMIC_FILTER_CONFIGURE_LABEL).click();
+ fBot.waitUntil(Conditions.shellIsActive(DYNAMIC_FILTERS_SHELL_TEXT));
+ shell = fBot.shell(DYNAMIC_FILTERS_SHELL_TEXT);
+ shell.activate();
+
+ activeThreadsCheckbox = shell.bot().checkBox(DYNAMIC_FILTERS_SHOW_ACTIVE_THREADS_ONLY_CHECKBOX);
+ onCpuRadio = shell.bot().radio(DYNAMIC_FILTERS_ON_CPU_RADIO);
+ allActiveRadio = shell.bot().radio(DYNAMIC_FILTERS_ALL_ACTIVE_RADIO);
+ onCpuField = shell.bot().textWithMessage(DYNAMIC_FILTER_ON_CPU_FIELD_MESSAGE);
+
+ /* Range field should have a value in it */
+ assertTrue(activeThreadsCheckbox.isChecked());
+ assertTrue(allActiveRadio.isEnabled());
+ assertTrue(onCpuRadio.isEnabled());
+ assertFalse(onCpuField.isEnabled());
+ assertTrue(allActiveRadio.isSelected());
+ assertFalse(onCpuRadio.isSelected());
+ assertFalse(onCpuField.isEnabled());
+ assertEquals("CPU ranges not equal", onCpuField.getText(), valid_cpu_ranges);
+
+ shell.bot().button(DIALOG_CANCEL).click();
+ }
+
/**
* Test tool bar buttons "Follow CPU Forward" and "Follow CPU Backward"
*/
return markerEventSources;
}
+ /**
+ * Gets the trace to viewer filters map.
+ *
+ * @return The trace to viewer filters map
+ * @since 2.2
+ */
+ protected @NonNull Map<ITmfTrace, ViewerFilter[]> getFiltersMap() {
+ return checkNotNull(fFiltersMap);
+ }
+
/**
* Refresh the display
*/
}
fDirty.incrementAndGet();
+ /* Update view filters */
+ updateFilters();
+
boolean hasEntries = false;
synchronized (fEntryListMap) {
fEntryList = fEntryListMap.get(fTrace);
});
}
+ /**
+ * Update view specific filters. A view that possess filter should override
+ * this method to gain access to asynchronous update on refresh
+ *
+ * @since 2.2
+ */
+ protected void updateFilters() {
+ /*
+ * Do nothing. Sub classes are responsible for their view specific filters.
+ */
+ }
+
/**
* Redraw the canvas
*/
public void removeFilter(@NonNull ViewerFilter filter) {
fInhibitTreeSelection = true;
ViewerFilter wrapper = fViewerFilterMap.get(filter);
- fTreeViewer.removeFilter(wrapper);
+ if (wrapper != null) {
+ fTreeViewer.removeFilter(wrapper);
+ }
fTimeGraphViewer.removeFilter(filter);
fViewerFilterMap.remove(filter);
alignTreeItems(true);