2 * Copyright (C) 2017 EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 package org
.lttng
.scope
.tmf2
.views
.ui
.timeline
.widgets
.timegraph
.toolbar
.modelconfig
;
12 import java
.util
.Arrays
;
13 import java
.util
.List
;
14 import java
.util
.stream
.Collectors
;
16 import org
.eclipse
.jdt
.annotation
.Nullable
;
17 import org
.lttng
.scope
.tmf2
.views
.core
.config
.ConfigOption
;
18 import org
.lttng
.scope
.tmf2
.views
.core
.timegraph
.model
.provider
.states
.ITimeGraphModelStateProvider
;
19 import org
.lttng
.scope
.tmf2
.views
.core
.timegraph
.model
.render
.ColorDefinition
;
20 import org
.lttng
.scope
.tmf2
.views
.core
.timegraph
.model
.render
.LineThickness
;
21 import org
.lttng
.scope
.tmf2
.views
.core
.timegraph
.model
.render
.StateDefinition
;
22 import org
.lttng
.scope
.tmf2
.views
.core
.timegraph
.model
.render
.states
.MultiStateInterval
;
23 import org
.lttng
.scope
.tmf2
.views
.ui
.jfx
.CountingGridPane
;
24 import org
.lttng
.scope
.tmf2
.views
.ui
.jfx
.JfxColorFactory
;
25 import org
.lttng
.scope
.tmf2
.views
.ui
.timeline
.widgets
.timegraph
.StateRectangle
;
26 import org
.lttng
.scope
.tmf2
.views
.ui
.timeline
.widgets
.timegraph
.TimeGraphWidget
;
28 import javafx
.beans
.property
.ReadOnlyProperty
;
29 import javafx
.event
.ActionEvent
;
30 import javafx
.scene
.Node
;
31 import javafx
.scene
.control
.ButtonBar
.ButtonData
;
32 import javafx
.scene
.control
.ButtonType
;
33 import javafx
.scene
.control
.ColorPicker
;
34 import javafx
.scene
.control
.Dialog
;
35 import javafx
.scene
.control
.Label
;
36 import javafx
.scene
.control
.MenuButton
;
37 import javafx
.scene
.control
.RadioMenuItem
;
38 import javafx
.scene
.control
.ToggleGroup
;
39 import javafx
.scene
.paint
.Color
;
40 import javafx
.scene
.paint
.Paint
;
41 import javafx
.scene
.shape
.Rectangle
;
42 import javafx
.scene
.text
.Text
;
44 class ModelConfigDialog
extends Dialog
<@Nullable Void
> {
46 private static final double H_GAP
= 10;
48 public ModelConfigDialog(TimeGraphWidget widget
) {
49 setTitle(Messages
.modelConfigDialogTitle
);
50 setHeaderText(Messages
.modelConfigDialogHeader
);
52 ButtonType resetToDefaultButtonType
= new ButtonType(Messages
.modelConfigDialogResetDefaultsButton
, ButtonData
.LEFT
);
53 getDialogPane().getButtonTypes().addAll(resetToDefaultButtonType
, ButtonType
.CLOSE
);
55 // TODO Allow configuring arrow, etc. providers too (different tabs?)
56 ITimeGraphModelStateProvider stateProvider
= widget
.getControl().getModelRenderProvider().getStateProvider();
57 List
<ColorDefControl
> stateControls
= stateProvider
.getStateDefinitions().stream()
58 .map(stateDef
-> new ColorDefControl(widget
, stateDef
))
59 .collect(Collectors
.toList());
61 /* Setup the GridPane which will be the contents of the dialog */
62 CountingGridPane grid
= new CountingGridPane();
65 grid
.appendRow(new Text(Messages
.modelConfigDialogRowHeaderState
),
66 new Text(Messages
.modelConfigDialogRowHeaderColor
),
67 new Text(Messages
.modelConfigDialogRowHeaderLineThickness
));
69 stateControls
.forEach(setter
-> grid
.appendRow(setter
.getNodes()));
71 /* Add an "empty row", then the control for multi-state intervals */
72 LineThicknessMenuButton multiStateThicknessButton
= new LineThicknessMenuButton(widget
,
73 MultiStateInterval
.MULTI_STATE_THICKNESS_OPTION
,
74 widget
.getDebugOptions().multiStatePaint
);
75 grid
.appendRow(new Text("")); //$NON-NLS-1$
76 grid
.appendRow(new Label("Multi-states"), new Text(), multiStateThicknessButton
);
78 getDialogPane().setContent(grid
);
81 * We do not set the dialog's 'resultConverter', there is nothing
82 * special to do on close (all changes are immediately valid).
85 /* Define how to "Reset Defaults" button works */
86 getDialogPane().lookupButton(resetToDefaultButtonType
).addEventFilter(ActionEvent
.ACTION
, e
-> {
88 * This button should not close the dialog. Consuming the event here
89 * will prevent the dialog from closing.
93 stateControls
.forEach(sc
-> {
94 sc
.getOptions().forEach(ConfigOption
::resetToDefault
);
97 multiStateThicknessButton
.getOption().resetToDefault();
98 multiStateThicknessButton
.load();
100 repaintAllRectangles(widget
);
105 // TODO Repaint the rectangles of the whole Timeline view, not just 1 widget
106 private static void repaintAllRectangles(TimeGraphWidget widget
) {
107 widget
.getRenderedStateRectangles().forEach(StateRectangle
::updatePaint
);
110 private static class ColorDefControl
{
112 private final TimeGraphWidget fWidget
;
113 private final StateDefinition fStateDef
;
115 private final Label fLabel
;
116 private final ColorPicker fColorPicker
;
117 private final LineThicknessMenuButton fLineThicknessButton
;
122 * TODO Use a "PaintPicker" dialog instead, so a full Paint object can
123 * be configured from the UI. There is apparently one in SceneBuilder.
125 public ColorDefControl(TimeGraphWidget widget
, StateDefinition stateDef
) {
127 fStateDef
= stateDef
;
129 fLabel
= new Label(stateDef
.getName());
130 fColorPicker
= new ColorPicker();
131 fColorPicker
.getStyleClass().add(ColorPicker
.STYLE_CLASS_BUTTON
);
132 fLineThicknessButton
= new LineThicknessMenuButton(widget
, stateDef
.getLineThickness(), fColorPicker
.valueProperty());
136 * Whenever a new color is selected in the UI, update the
137 * corresponding model color.
139 fColorPicker
.setOnAction(e
-> {
140 Color color
= fColorPicker
.getValue();
144 ColorDefinition colorDef
= JfxColorFactory
.colorToColorDef(color
);
145 fStateDef
.getColor().set(colorDef
);
147 repaintAllRectangles(widget
);
152 public Node
[] getNodes() {
153 return new Node
[] { fLabel
, fColorPicker
, fLineThicknessButton
};
156 public Iterable
<ConfigOption
<?
>> getOptions() {
157 return Arrays
.asList(fStateDef
.getColor(), fStateDef
.getLineThickness());
161 Color color
= JfxColorFactory
.getColorFromDef(fStateDef
.getColor().get());
162 fColorPicker
.setValue(color
);
164 fLineThicknessButton
.load();
168 private static class LineThicknessMenuButton
extends MenuButton
{
170 private static final double RECTANGLE_WIDTH
= 30;
172 private final ConfigOption
<LineThickness
> fOption
;
173 private final ReadOnlyProperty
<?
extends Paint
> fColorSource
;
175 public LineThicknessMenuButton(TimeGraphWidget widget
,
176 ConfigOption
<LineThickness
> option
,
177 ReadOnlyProperty
<?
extends Paint
> colorSource
) {
179 fColorSource
= colorSource
;
181 ToggleGroup tg
= new ToggleGroup();
182 List
<LineThicknessMenuButtonItem
> items
= Arrays
.stream(LineThickness
.values())
184 LineThicknessMenuButtonItem rmi
= new LineThicknessMenuButtonItem(lt
);
185 rmi
.setGraphic(getRectangleForThickness(lt
));
186 rmi
.setToggleGroup(tg
);
188 LineThickness currentThickness
= option
.get();
189 rmi
.setSelected(lt
== currentThickness
);
191 rmi
.setOnAction(e
-> {
193 LineThicknessMenuButton
.this.setGraphic(getRectangleForThickness(lt
));
194 repaintAllRectangles(widget
);
198 .collect(Collectors
.toList());
200 /* Initial value shown in the button */
201 setGraphic(getRectangleForThickness(option
.get()));
202 getItems().addAll(items
);
205 private Rectangle
getRectangleForThickness(LineThickness lt
) {
206 Rectangle rectangle
= new Rectangle(RECTANGLE_WIDTH
, StateRectangle
.getHeightFromThickness(lt
));
207 rectangle
.fillProperty().bind(fColorSource
);
211 public ConfigOption
<LineThickness
> getOption() {
216 LineThickness lt
= fOption
.get();
217 setGraphic(getRectangleForThickness(lt
));
219 .map(item
-> (LineThicknessMenuButtonItem
) item
)
220 .filter(item
-> item
.getLineThickness() == lt
)
221 .findFirst().get().setSelected(true);
225 private static class LineThicknessMenuButtonItem
extends RadioMenuItem
{
227 private final LineThickness fLineThickness
;
229 public LineThicknessMenuButtonItem(LineThickness lt
) {
233 public LineThickness
getLineThickness() {
234 return fLineThickness
;