From 4298a04594b6304048505896f54ca9b3492a94e1 Mon Sep 17 00:00:00 2001 From: Alexandre Montplaisir Date: Wed, 26 Apr 2017 16:04:41 -0400 Subject: [PATCH] timegraph: Add menu button to create custom event series Since the current time graph models do not provide event series themselves, we can offer a way to create some from the UI for simple (and demo) purposes. Eventually this custom series creation could be moved outside of the timegraph widget. Refs #9. Signed-off-by: Alexandre Montplaisir --- .../timegraph/TimeGraphDrawnEventControl.java | 17 +- .../timegraph/toolbar/ViewerToolBar.java | 4 +- .../drawnevents/CreateEventSeriesDialog.java | 177 ++++++++++++++++++ .../drawnevents/EventSeriesMenuButton.java | 155 +++++++++++++++ .../toolbar/drawnevents/Messages.java | 44 +++++ .../PredicateDrawnEventProvider.java | 120 ++++++++++++ .../toolbar/drawnevents/messages.properties | 20 ++ .../toolbar/drawnevents/package-info.java | 11 ++ 8 files changed, 541 insertions(+), 7 deletions(-) create mode 100644 tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/CreateEventSeriesDialog.java create mode 100644 tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/EventSeriesMenuButton.java create mode 100644 tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/Messages.java create mode 100644 tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/PredicateDrawnEventProvider.java create mode 100644 tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/messages.properties create mode 100644 tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/package-info.java diff --git a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/TimeGraphDrawnEventControl.java b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/TimeGraphDrawnEventControl.java index 41513453..3660df52 100644 --- a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/TimeGraphDrawnEventControl.java +++ b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/TimeGraphDrawnEventControl.java @@ -40,7 +40,7 @@ import javafx.scene.shape.SVGPath; import javafx.scene.shape.Shape; -class TimeGraphDrawnEventControl { +public class TimeGraphDrawnEventControl { private final TimeGraphWidget fWidget; private final Group fParentGroup; @@ -179,7 +179,12 @@ private Collection prepareDrawnEvents(TimeGraphTreeRender treeRender, Tim private static Shape getShapeFromEvent(TimeGraphDrawnEvent event) { Color color = JfxColorFactory.getColorFromDef(event.getEventSeries().getColor().get()); SymbolStyle symbol = event.getEventSeries().getSymbolStyle().get(); + Shape shape = getShapeFromSymbol(symbol); + shape.setFill(color); + return shape; + } + public static Shape getShapeFromSymbol(SymbolStyle symbol) { Shape shape; switch (symbol) { case CIRCLE: @@ -187,10 +192,11 @@ private static Shape getShapeFromEvent(TimeGraphDrawnEvent event) { break; case DIAMOND: { - SVGPath path = new SVGPath(); - path.setContent("M5,0 L10,9 L5,18 L0,9 Z"); //$NON-NLS-1$ - path.relocate(-5, -9); - shape = path; + shape = new Polygon(5.0, 0.0, + 10.0, 5.0, + 5.0, 10.0, + 0.0, 5.0); + shape.relocate(-5.0, -5.0); } break; @@ -232,7 +238,6 @@ private static Shape getShapeFromEvent(TimeGraphDrawnEvent event) { } - shape.setFill(color); shape.setStroke(Color.BLACK); return shape; } diff --git a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/ViewerToolBar.java b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/ViewerToolBar.java index ebf2e0bb..83c69f8d 100644 --- a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/ViewerToolBar.java +++ b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/ViewerToolBar.java @@ -13,6 +13,7 @@ import org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.StateRectangle; import org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.TimeGraphWidget; import org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.toolbar.debugopts.DebugOptionsButton; +import org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.toolbar.drawnevents.EventSeriesMenuButton; import org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.toolbar.modelconfig.ModelConfigButton; import org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.toolbar.nav.NavigationButtons; @@ -63,11 +64,12 @@ public ViewerToolBar(TimeGraphWidget viewer) { navButtons.getForwardButton(), navButtons.getMenuButton() ), + getStateInfoButton(viewer), new Separator(), new ModelConfigButton(viewer), - getStateInfoButton(viewer), new ArrowSeriesMenuButton(viewer), + new EventSeriesMenuButton(viewer), new SortingModeMenuButton(viewer), new FilterModeMenuButton(viewer), new Separator(), diff --git a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/CreateEventSeriesDialog.java b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/CreateEventSeriesDialog.java new file mode 100644 index 00000000..3424dee5 --- /dev/null +++ b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/CreateEventSeriesDialog.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2017 EfficiOS Inc., Alexandre Montplaisir + * + * 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.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.toolbar.drawnevents; + +import java.util.function.Predicate; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; +import org.lttng.scope.tmf2.views.core.config.ConfigOption; +import org.lttng.scope.tmf2.views.core.timegraph.model.provider.ITimeGraphModelProvider; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.ColorDefinition; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.drawnevents.TimeGraphDrawnEventSeries; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.drawnevents.TimeGraphDrawnEventSeries.SymbolStyle; +import org.lttng.scope.tmf2.views.ui.jfx.CountingGridPane; +import org.lttng.scope.tmf2.views.ui.jfx.JfxColorFactory; +import org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.TimeGraphDrawnEventControl; + +import javafx.beans.property.ReadOnlyProperty; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ColorPicker; +import javafx.scene.control.ComboBox; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.ListCell; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.scene.layout.VBox; +import javafx.scene.paint.Color; +import javafx.scene.shape.Shape; +import javafx.scene.text.Font; +import javafx.scene.text.FontPosture; +import javafx.scene.text.FontWeight; +import javafx.util.Callback; + +class CreateEventSeriesDialog extends Dialog<@Nullable PredicateDrawnEventProvider> { + + private static final Color DEFAULT_SYMBOL_COLOR = Color.ORANGE; + private static final double PADDING = 10; + + private static final Font HEADER_FONT = Font.font(null, FontWeight.BOLD, FontPosture.REGULAR, -1); + private static final Insets HEADER_PADDING = new Insets(10, 0, 10, 0); + + private final TextField fEventNameField; + + private final ColorPicker fSymbolColorPicker; + private final ShapePicker fSymbolShapePicker; + + public CreateEventSeriesDialog(ITimeGraphModelProvider modelProvider) { + setTitle(Messages.createEventSeriesDialogTitle); + + /* Dialog buttons, standard "OK" and "Cancel" */ + getDialogPane().getButtonTypes().addAll(ButtonType.CANCEL, ButtonType.OK); + + /* Dialog contents */ + Label filterHeader = new Label(Messages.createEventSeriesDialogSectionFilterDef); + filterHeader.setFont(HEADER_FONT); + filterHeader.setPadding(HEADER_PADDING); + + fEventNameField = new TextField(); + CountingGridPane filterGrid = new CountingGridPane(); + filterGrid.setHgap(PADDING); + filterGrid.setVgap(PADDING); + filterGrid.appendRow(new Label(Messages.createEventSeriesDialogFieldEventName), fEventNameField); + + Label symbolHeader = new Label(Messages.createEventSeriesDialogSectionSymbolDef); + symbolHeader.setFont(HEADER_FONT); + symbolHeader.setPadding(HEADER_PADDING); + + fSymbolColorPicker = new ColorPicker(DEFAULT_SYMBOL_COLOR); + fSymbolShapePicker = new ShapePicker(fSymbolColorPicker.valueProperty()); + CountingGridPane symbolGrid = new CountingGridPane(); + symbolGrid.setHgap(PADDING); + symbolGrid.setVgap(PADDING); + symbolGrid.appendRow(new Label(Messages.createEventSeriesDialogFieldColor), fSymbolColorPicker); + symbolGrid.appendRow(new Label(Messages.createEventSeriesDialogFieldShape), fSymbolShapePicker); + + VBox vbox = new VBox(filterHeader, filterGrid, symbolHeader, symbolGrid); + vbox.setAlignment(Pos.CENTER); + getDialogPane().setContent(vbox); + + /* + * Disable the OK button until the input is valid + * + * TODO ControlsFX Validation framework might be useful when more + * fields/options are added. + */ + final Button okButton = (Button) getDialogPane().lookupButton(ButtonType.OK); + okButton.setDisable(true); + fEventNameField.textProperty().addListener((observable, oldValue, newValue) -> { + okButton.setDisable(newValue.trim().length() <= 0); + }); + + /* What to do when the dialog is closed */ + setResultConverter(dialogButton -> { + if (dialogButton != ButtonType.OK) { + return null; + } + + String eventName = fEventNameField.getText(); + if (eventName == null || eventName.isEmpty()) { + return null; + } + + TimeGraphDrawnEventSeries series = generateEventSeries(); + Predicate predicate = event -> event.getName().equals(eventName); + return new PredicateDrawnEventProvider(series, modelProvider, predicate); + }); + + } + + /** + * Generate an event series from the current value of the controls + * + * @return The corresponding event series + */ + private TimeGraphDrawnEventSeries generateEventSeries() { + String seriesName = fEventNameField.getText(); + ColorDefinition colorDef = JfxColorFactory.colorToColorDef(fSymbolColorPicker.getValue()); + SymbolStyle style = fSymbolShapePicker.getSelectionModel().getSelectedItem(); + + return new TimeGraphDrawnEventSeries( + seriesName == null ? "" : seriesName, //$NON-NLS-1$ + new ConfigOption<>(colorDef), + new ConfigOption<>(style)); + } + + private static class ShapePicker extends ComboBox { + + public ShapePicker(ReadOnlyProperty colorSource) { + getItems().addAll(SymbolStyle.values()); + + Callback<@Nullable ListView, ListCell> cellFactory = + p -> new ListCell() { + { + setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + } + + @Override + protected void updateItem(SymbolStyle item, boolean empty) { + super.updateItem(item, empty); + if (empty) { + setGraphic(null); + } else { + Node graphic = getGraphicFromSymbol(item, colorSource); + setGraphic(graphic); + } + } + }; + + setButtonCell(cellFactory.call(null)); + setCellFactory(cellFactory); + + /* Select the first symbol by default */ + getSelectionModel().select(0); + } + + private static Node getGraphicFromSymbol(SymbolStyle symbol, ReadOnlyProperty colorSource) { + Shape graphic = TimeGraphDrawnEventControl.getShapeFromSymbol(symbol); + graphic.fillProperty().bind(colorSource); + return graphic; + } + + } + +} diff --git a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/EventSeriesMenuButton.java b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/EventSeriesMenuButton.java new file mode 100644 index 00000000..f59452a3 --- /dev/null +++ b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/EventSeriesMenuButton.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2017 EfficiOS Inc., Alexandre Montplaisir + * + * 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.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.toolbar.drawnevents; + +import java.util.Optional; + +import org.eclipse.jdt.annotation.Nullable; +import org.lttng.scope.tmf2.views.core.timegraph.model.provider.ITimeGraphModelProvider; +import org.lttng.scope.tmf2.views.core.timegraph.model.provider.drawnevents.ITimeGraphDrawnEventProvider; +import org.lttng.scope.tmf2.views.core.timegraph.model.provider.drawnevents.TimeGraphDrawnEventProviderManager; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.drawnevents.TimeGraphDrawnEventSeries; +import org.lttng.scope.tmf2.views.ui.jfx.JfxColorFactory; +import org.lttng.scope.tmf2.views.ui.jfx.JfxUtils; +import org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.TimeGraphDrawnEventControl; +import org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.TimeGraphWidget; + +import com.google.common.collect.Iterables; + +import javafx.application.Platform; +import javafx.collections.ListChangeListener; +import javafx.collections.SetChangeListener; +import javafx.scene.control.CheckMenuItem; +import javafx.scene.control.MenuButton; +import javafx.scene.control.MenuItem; +import javafx.scene.control.SeparatorMenuItem; +import javafx.scene.paint.Color; +import javafx.scene.shape.Shape; + +/** + * Menu button showing listing the existing drawn-event providers, with menu + * items to create/clear such providers. + * + * TODO This button and its related actions are independent from a time graph + * widget. They could be moved elsewhere in the UI at some point. + * + * @author Alexandre Montplaisir + */ +public class EventSeriesMenuButton extends MenuButton { + + private static final TimeGraphDrawnEventProviderManager PROVIDER_MANAGER = + TimeGraphDrawnEventProviderManager.instance(); + + /** + * Constructor + * + * @param widget + * Time graph widget to which this button refers + */ + public EventSeriesMenuButton(TimeGraphWidget widget) { + setText(Messages.eventSeriesMenuButtonName); + + MenuItem separator = new SeparatorMenuItem(); + + /* + * There are minimum 3 items in the menu. Whenever there are more (from + * registered providers), make the separator visible. + */ + getItems().addListener((ListChangeListener) change -> { + separator.visibleProperty().set(change.getList().size() > 3); + }); + + /* Load the already-registered providers */ + PROVIDER_MANAGER.getRegisteredProviders().forEach(this::addProviderToMenu); + + /* Watch for future addition/removal of providers */ + PROVIDER_MANAGER.getRegisteredProviders().addListener((SetChangeListener) change -> { + ITimeGraphDrawnEventProvider addedProvider = change.getElementAdded(); + if (addedProvider != null) { + addProviderToMenu(addedProvider); + } + ITimeGraphDrawnEventProvider removedProvider = change.getElementRemoved(); + if (removedProvider != null) { + removeProviderFromMenu(removedProvider); + } + }); + + + MenuItem addNewSeriesMenuItem = new MenuItem(Messages.newEventSeriesMenuItem); + addNewSeriesMenuItem.setOnAction(e -> { + ITimeGraphModelProvider modelProvider = widget.getControl().getModelRenderProvider(); + CreateEventSeriesDialog dialog = new CreateEventSeriesDialog(modelProvider); + dialog.setOnShowing(h -> Platform.runLater(() -> JfxUtils.centerDialogOnScreen(dialog, EventSeriesMenuButton.this))); + Optional<@Nullable PredicateDrawnEventProvider> results = dialog.showAndWait(); + ITimeGraphDrawnEventProvider provider = results.orElse(null); + if (provider != null) { + PROVIDER_MANAGER.getRegisteredProviders().add(provider); + provider.enabledProperty().set(true); + } + }); + + MenuItem clearSeriesMenuItem = new MenuItem(Messages.clearEventSeriesMenuItem); + clearSeriesMenuItem.setOnAction(e -> { + // TODO Eventually we could track which providers were created from + // this button/dialog, and only clear those here. + PROVIDER_MANAGER.getRegisteredProviders().clear(); + }); + + getItems().addAll(separator, addNewSeriesMenuItem, clearSeriesMenuItem); + } + + private void addProviderToMenu(ITimeGraphDrawnEventProvider provider) { + CheckMenuItem item = new EventProviderMenuItem(provider); + int index = getItems().size() - 3; + getItems().add(index, item); + } + + private void removeProviderFromMenu(ITimeGraphDrawnEventProvider provider) { + MenuItem itemToRemove = Iterables + .tryFind(getItems(), item -> { + return (item instanceof EventProviderMenuItem + && ((EventProviderMenuItem) item).getProvider().equals(provider)); + }) + .orNull(); + + if (itemToRemove != null) { + getItems().remove(itemToRemove); + } + } + + /** + * Menu item that represents a particular + * {@link ITimeGraphDrawnEventProvider}. + */ + private static class EventProviderMenuItem extends CheckMenuItem { + + private final ITimeGraphDrawnEventProvider fProvider; + + public EventProviderMenuItem(ITimeGraphDrawnEventProvider provider) { + fProvider = provider; + + TimeGraphDrawnEventSeries series = provider.getEventSeries(); + + setMnemonicParsing(false); + setText(series.getSeriesName()); + selectedProperty().bindBidirectional(provider.enabledProperty()); + + Shape graphic = TimeGraphDrawnEventControl.getShapeFromSymbol(series.getSymbolStyle().get()); + Color color = JfxColorFactory.getColorFromDef(series.getColor().get()); + graphic.setFill(color); + setGraphic(graphic); + } + + public ITimeGraphDrawnEventProvider getProvider() { + return fProvider; + } + } + +} diff --git a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/Messages.java b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/Messages.java new file mode 100644 index 00000000..74d0b99f --- /dev/null +++ b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/Messages.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 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.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.toolbar.drawnevents; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.osgi.util.NLS; + +/** + * Message bundle for the package + * + * @noreference Messages class + */ +@NonNullByDefault({}) +@SuppressWarnings("javadoc") +public class Messages extends NLS { + + private static final String BUNDLE_NAME = Messages.class.getPackage().getName() + ".messages"; //$NON-NLS-1$ + + public static String eventSeriesMenuButtonName; + + public static String newEventSeriesMenuItem; + public static String clearEventSeriesMenuItem; + + public static String createEventSeriesDialogTitle; + public static String createEventSeriesDialogSectionFilterDef; + public static String createEventSeriesDialogFieldEventName; + public static String createEventSeriesDialogSectionSymbolDef; + public static String createEventSeriesDialogFieldColor; + public static String createEventSeriesDialogFieldShape; + + static { + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/PredicateDrawnEventProvider.java b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/PredicateDrawnEventProvider.java new file mode 100644 index 00000000..f530109a --- /dev/null +++ b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/PredicateDrawnEventProvider.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2017 EfficiOS Inc., Alexandre Montplaisir + * + * 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.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.toolbar.drawnevents; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.FutureTask; +import java.util.function.Predicate; + +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.tracecompass.tmf.core.event.ITmfEvent; +import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest; +import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest.ExecutionType; +import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest; +import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace; +import org.lttng.scope.tmf2.views.core.TimeRange; +import org.lttng.scope.tmf2.views.core.context.ViewGroupContext; +import org.lttng.scope.tmf2.views.core.timegraph.model.provider.ITimeGraphModelProvider; +import org.lttng.scope.tmf2.views.core.timegraph.model.provider.drawnevents.TimeGraphDrawnEventProvider; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.TimeGraphEvent; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.drawnevents.TimeGraphDrawnEvent; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.drawnevents.TimeGraphDrawnEventRender; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.drawnevents.TimeGraphDrawnEventSeries; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.tree.TimeGraphTreeElement; +import org.lttng.scope.tmf2.views.core.timegraph.model.render.tree.TimeGraphTreeRender; + +import com.google.common.collect.ImmutableList; + +class PredicateDrawnEventProvider extends TimeGraphDrawnEventProvider { + + /** Maximum number of matching events */ + private static final int MAX = 2000; + + private final ITimeGraphModelProvider fModelProvider; + private final Predicate fPredicate; + + public PredicateDrawnEventProvider(TimeGraphDrawnEventSeries drawnEventSeries, + ITimeGraphModelProvider modelProvider, + Predicate predicate) { + super(drawnEventSeries); + fModelProvider = modelProvider; + fPredicate = predicate; + + /* Just use whatever trace is currently active */ + traceProperty().bind(ViewGroupContext.getCurrent().currentTraceProperty()); + } + + @Override + public TimeGraphDrawnEventRender getEventRender(TimeGraphTreeRender treeRender, + TimeRange timeRange, @Nullable FutureTask task) { + + /* Very TMF-specific */ + ITmfTrace trace = traceProperty().get(); + if (trace == null) { + return new TimeGraphDrawnEventRender(timeRange, Collections.EMPTY_LIST); + } + + long startIndex = 0; + + List traceEvents = new LinkedList<>(); + TmfEventRequest req = new TmfEventRequest(ITmfEvent.class, + timeRange.toTmfTimeRange(), + startIndex, + ITmfEventRequest.ALL_DATA, + ExecutionType.BACKGROUND) { + + private int matches = 0; + + @Override + public void handleData(ITmfEvent event) { + super.handleData(event); + if (task != null && task.isCancelled()) { + cancel(); + } + + if (fPredicate.test(event)) { + matches++; + traceEvents.add(event); + if (matches > MAX) { + done(); + } + } + } + }; + trace.sendRequest(req); + try { + req.waitForCompletion(); + } catch (InterruptedException e) { + } + + if (req.isCancelled()) { + return new TimeGraphDrawnEventRender(timeRange, Collections.EMPTY_LIST); + } + + List drawnEvents = traceEvents.stream() + .map(traceEvent -> { + long timestamp = traceEvent.getTimestamp().toNanos(); + TimeGraphTreeElement treeElem = fModelProvider.matchEventToTreeElement(traceEvent); + if (treeElem == null) { + return null; + } + return new TimeGraphEvent(timestamp, treeElem); + }) + .filter(Objects::nonNull) + .map(tgEvent -> new TimeGraphDrawnEvent(tgEvent, getEventSeries(), null)) + .collect(ImmutableList.toImmutableList()); + + return new TimeGraphDrawnEventRender(timeRange, drawnEvents); + } + +} diff --git a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/messages.properties b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/messages.properties new file mode 100644 index 00000000..421f5642 --- /dev/null +++ b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/messages.properties @@ -0,0 +1,20 @@ +############################################################################### +# Copyright (c) 2017 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 +############################################################################### + +eventSeriesMenuButtonName = Event Series + +newEventSeriesMenuItem = New Event Series... +clearEventSeriesMenuItem = Clear All + +createEventSeriesDialogTitle = Create New Event Series +createEventSeriesDialogSectionFilterDef = Filter Definition +createEventSeriesDialogFieldEventName = Event Name +createEventSeriesDialogSectionSymbolDef = Symbol +createEventSeriesDialogFieldColor = Color +createEventSeriesDialogFieldShape = Shape diff --git a/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/package-info.java b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/package-info.java new file mode 100644 index 00000000..a063272c --- /dev/null +++ b/tmf2/org.lttng.scope.tmf2.views.ui/src/org/lttng/scope/tmf2/views/ui/timeline/widgets/timegraph/toolbar/drawnevents/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2017 EfficiOS Inc., Alexandre Montplaisir + * + * 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 + */ + +@org.eclipse.jdt.annotation.NonNullByDefault +package org.lttng.scope.tmf2.views.ui.timeline.widgets.timegraph.toolbar.drawnevents;