1 /*******************************************************************************
2 * Copyright (c) 2016 EfficiOS Inc., Jonathan Rajotte-Julien
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
8 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.internal
.provisional
.analysis
.lami
.ui
.views
;
12 import static org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
.checkNotNull
;
14 import java
.util
.ArrayList
;
15 import java
.util
.Arrays
;
16 import java
.util
.List
;
17 import java
.util
.function
.Function
;
18 import java
.util
.function
.Predicate
;
20 import org
.eclipse
.jdt
.annotation
.Nullable
;
21 import org
.eclipse
.jface
.dialogs
.Dialog
;
22 import org
.eclipse
.jface
.dialogs
.IDialogConstants
;
23 import org
.eclipse
.jface
.layout
.TableColumnLayout
;
24 import org
.eclipse
.jface
.viewers
.ArrayContentProvider
;
25 import org
.eclipse
.jface
.viewers
.CheckboxTableViewer
;
26 import org
.eclipse
.jface
.viewers
.ColumnLabelProvider
;
27 import org
.eclipse
.jface
.viewers
.ColumnWeightData
;
28 import org
.eclipse
.jface
.viewers
.ILabelProvider
;
29 import org
.eclipse
.jface
.viewers
.IStructuredContentProvider
;
30 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
31 import org
.eclipse
.jface
.viewers
.TableViewer
;
32 import org
.eclipse
.jface
.viewers
.TableViewerColumn
;
33 import org
.eclipse
.swt
.SWT
;
34 import org
.eclipse
.swt
.custom
.SashForm
;
35 import org
.eclipse
.swt
.events
.SelectionEvent
;
36 import org
.eclipse
.swt
.events
.SelectionListener
;
37 import org
.eclipse
.swt
.layout
.GridData
;
38 import org
.eclipse
.swt
.layout
.GridLayout
;
39 import org
.eclipse
.swt
.widgets
.Button
;
40 import org
.eclipse
.swt
.widgets
.Composite
;
41 import org
.eclipse
.swt
.widgets
.Control
;
42 import org
.eclipse
.swt
.widgets
.Display
;
43 import org
.eclipse
.swt
.widgets
.Group
;
44 import org
.eclipse
.swt
.widgets
.Label
;
45 import org
.eclipse
.swt
.widgets
.Shell
;
46 import org
.eclipse
.swt
.widgets
.TableColumn
;
47 import org
.eclipse
.swt
.widgets
.TableItem
;
48 import org
.eclipse
.tracecompass
.internal
.provisional
.analysis
.lami
.core
.aspect
.LamiTableEntryAspect
;
49 import org
.eclipse
.tracecompass
.internal
.provisional
.analysis
.lami
.core
.module
.LamiChartModel
.ChartType
;
50 import org
.eclipse
.tracecompass
.internal
.provisional
.analysis
.lami
.core
.module
.LamiXYSeriesDescription
;
51 import org
.eclipse
.ui
.dialogs
.SelectionDialog
;
54 * Series creation dialog
56 * @author Jonathan Rajotte-Julien
58 public class LamiSeriesDialog
extends SelectionDialog
{
60 private static final int MINIMUM_COLUMN_WIDTH
= 30;
61 private static final int MININAL_SERIES_TABLE_HEIGHT
= 150;
63 /* The root element to populate the viewer with */
64 private final Object fXInputElement
;
65 private final Object fYInputElement
;
66 private final List
<LamiXYSeriesDescription
> series
;
68 /* Providers for populating dialog */
69 private final ILabelProvider fXLabelProvider
;
70 private final IStructuredContentProvider fXContentProvider
;
71 private final ILabelProvider fYLabelProvider
;
72 private final IStructuredContentProvider fYContentProvider
;
73 private final IStructuredContentProvider fSeriesContentProvider
;
75 private final boolean fRestrictXSeriesNumbers
;
77 private final List
<LamiAxisCheckBoxOption
> fXCheckBoxOptions
;
78 private final List
<LamiAxisCheckBoxOption
> fYCheckBoxOptions
;
80 // the visual selection widget group
81 private TableViewer fXTableViewer
;
82 private CheckboxTableViewer fYCheckBoxViewer
;
83 private TableViewer fSeriesListViewer
;
85 private Label fWarning
;
89 * The parent shell of the dialog
91 * The chart type for which the dialog construct series
93 * The possible X axis set of values
95 * The possible Y axis set of values
96 * @param xContentProvider
97 * A content provider for the X axis set
98 * @param xLabelProvider
99 * The label provider for the X axis set
100 * @param yContentProvider
101 * The content provider for the Y axis set
102 * @param yLabelProvider
103 * The label provider for the Y axis set
105 public LamiSeriesDialog(Shell parentShell
, ChartType chartType
, Object xInput
,
107 IStructuredContentProvider xContentProvider
,
108 ILabelProvider xLabelProvider
,
109 IStructuredContentProvider yContentProvider
,
110 ILabelProvider yLabelProvider
) {
112 fXInputElement
= xInput
;
113 fYInputElement
= yInput
;
114 fXContentProvider
= xContentProvider
;
115 fXLabelProvider
= xLabelProvider
;
116 fYContentProvider
= yContentProvider
;
117 fYLabelProvider
= yLabelProvider
;
118 series
= new ArrayList
<>();
119 fSeriesContentProvider
= checkNotNull(ArrayContentProvider
.getInstance());
121 fXCheckBoxOptions
= new ArrayList
<>();
122 fYCheckBoxOptions
= new ArrayList
<>();
123 fSeriesListViewer
= new TableViewer(parentShell
);
124 fXTableViewer
= new TableViewer(parentShell
);
125 fYCheckBoxViewer
= checkNotNull(CheckboxTableViewer
.newCheckList(parentShell
, SWT
.NONE
));
127 /* Dynamic restriction per chart type */
130 fRestrictXSeriesNumbers
= false;
135 fRestrictXSeriesNumbers
= true;
139 this.fWarning
= new Label(parentShell
, SWT
.NONE
);
143 protected Control
createDialogArea(@Nullable Composite parent
) {
145 Composite composite
= (Composite
) super.createDialogArea(parent
);
146 initializeDialogUnits(composite
);
148 /* Base 3 column grid layout */
149 GridLayout gridLayout
= new GridLayout(3, false);
150 composite
.setLayout(gridLayout
);
152 GridData gridData
= new GridData(GridData
.FILL_BOTH
);
153 gridData
.horizontalSpan
= 3;
154 Group seriesGroup
= new Group(composite
, SWT
.NONE
);
155 seriesGroup
.setLayoutData(gridData
);
156 seriesGroup
.setLayout(new GridLayout(3, false));
157 seriesGroup
.setText(Messages
.LamiSeriesDialog_series
);
160 * New sub group for the series table.
162 gridData
= new GridData(GridData
.FILL_BOTH
);
163 gridData
.horizontalSpan
= 2;
164 gridData
.heightHint
= MININAL_SERIES_TABLE_HEIGHT
;
165 Group seriesTableGroup
= new Group(seriesGroup
, SWT
.NONE
);
166 seriesTableGroup
.setLayoutData(gridData
);
167 TableColumnLayout layout
= new TableColumnLayout();
168 seriesTableGroup
.setLayout(layout
);
171 fSeriesListViewer
= new TableViewer(seriesTableGroup
, SWT
.MULTI
| SWT
.H_SCROLL
| SWT
.V_SCROLL
| SWT
.BORDER
);
172 fSeriesListViewer
.setContentProvider(fSeriesContentProvider
);
173 fSeriesListViewer
.setInput(series
);
174 fSeriesListViewer
.getTable().setHeaderVisible(true);
175 fSeriesListViewer
.getTable().setLinesVisible(true);
176 TableViewerColumn column1
= createTableViewerColumn(fSeriesListViewer
, Messages
.LamiSeriesDialog_x_values
, element
-> element
.getXAspect().getLabel());
177 TableViewerColumn column2
= createTableViewerColumn(fSeriesListViewer
, Messages
.LamiSeriesDialog_y_values
, element
-> element
.getYAspect().getLabel());
178 layout
.setColumnData(column1
.getColumn(), new ColumnWeightData(1, MINIMUM_COLUMN_WIDTH
, true));
179 layout
.setColumnData(column2
.getColumn(), new ColumnWeightData(1, MINIMUM_COLUMN_WIDTH
, true));
181 /* Delete series button */
182 gridData
= new GridData(GridData
.CENTER
);
183 gridData
.horizontalSpan
= 1;
184 Button deleteSeries
= new Button(seriesGroup
, SWT
.PUSH
);
185 deleteSeries
.setText(Messages
.LamiSeriesDialog_delete
);
186 deleteSeries
.setLayoutData(gridData
);
187 deleteSeries
.addSelectionListener(new SelectionListener() {
189 public void widgetSelected(@Nullable SelectionEvent e
) {
190 /* Remove the selectecd series */
191 IStructuredSelection selections
= (IStructuredSelection
) fSeriesListViewer
.getSelection();
192 for (Object selection
: selections
.toList()) {
193 series
.remove(selection
);
195 /* When table is empty reset to initial state */
196 if (series
.isEmpty()) {
197 /* Make sure the OK button is disabled */
198 getButton(IDialogConstants
.OK_ID
).setEnabled(false);
199 /* Hide the selection warning */
200 fWarning
.setVisible(false);
203 * Reset the initial selection of the X axis selection table
205 fXTableViewer
.refresh();
206 /* Reset check boxes options */
207 fXCheckBoxOptions
.forEach(checkBox
-> {
208 checkBox
.setButtonEnabled(true);
210 fYCheckBoxOptions
.forEach(checkBox
-> {
211 checkBox
.setButtonEnabled(true);
214 /* Refresh the series table to show the added series */
215 fSeriesListViewer
.refresh();
219 public void widgetDefaultSelected(@Nullable SelectionEvent e
) {
224 * Series creator subgroup
226 gridData
= new GridData(GridData
.FILL_BOTH
);
227 gridData
.horizontalSpan
= 3;
228 Group seriesCreatorGroup
= new Group(composite
, getShellStyle());
229 seriesCreatorGroup
.setLayoutData(gridData
);
230 seriesCreatorGroup
.setLayout(new GridLayout(3, false));
231 seriesCreatorGroup
.setText(Messages
.LamiSeriesDialog_serie_creator
);
233 /* X axis sash label */
234 gridData
= new GridData(GridData
.FILL_BOTH
| GridData
.VERTICAL_ALIGN_END
);
235 gridData
.horizontalSpan
= 1;
236 Label xSeriesCreatorLabel
= new Label(seriesCreatorGroup
, SWT
.CENTER
);
237 xSeriesCreatorLabel
.setLayoutData(gridData
);
238 xSeriesCreatorLabel
.setText(Messages
.LamiSeriesDialog_x_axis
);
240 gridData
= new GridData(GridData
.FILL_BOTH
| GridData
.VERTICAL_ALIGN_END
);
241 gridData
.horizontalSpan
= 1;
242 Label ySeriesCreatorLabel
= new Label(seriesCreatorGroup
, SWT
.CENTER
);
243 ySeriesCreatorLabel
.setLayoutData(gridData
);
244 ySeriesCreatorLabel
.setText(Messages
.LamiSeriesDialog_y_axis
);
246 /* Empty label for grid layout */
247 gridData
= new GridData(GridData
.FILL_BOTH
);
248 gridData
.horizontalSpan
= 1;
249 Label emptyLabel
= new Label(seriesCreatorGroup
, SWT
.CENTER
);
250 emptyLabel
.setLayoutData(gridData
);
252 SashForm sash1
= new SashForm(seriesCreatorGroup
, SWT
.BORDER
| SWT
.HORIZONTAL
);
253 gridData
= new GridData(GridData
.FILL_BOTH
);
254 gridData
.horizontalSpan
= 2;
255 sash1
.setLayoutData(gridData
);
256 sash1
.setVisible(true);
258 fXTableViewer
= new TableViewer(sash1
, getTableStyle());
259 fXTableViewer
.setContentProvider(fXContentProvider
);
260 fXTableViewer
.setLabelProvider(fXLabelProvider
);
261 fXTableViewer
.setInput(fXInputElement
);
263 fYCheckBoxViewer
= checkNotNull(CheckboxTableViewer
.newCheckList(sash1
, SWT
.BORDER
));
264 fYCheckBoxViewer
.setLabelProvider(fYLabelProvider
);
265 fYCheckBoxViewer
.setContentProvider(fYContentProvider
);
266 fYCheckBoxViewer
.setInput(fYInputElement
);
268 gridData
= new GridData(SWT
.FILL
, SWT
.NONE
, true, true);
269 gridData
.horizontalSpan
= 1;
270 Button button1
= new Button(seriesCreatorGroup
, SWT
.PUSH
);
271 button1
.setText(Messages
.LamiSeriesDialog_add
);
272 button1
.setLayoutData(gridData
);
273 button1
.addSelectionListener(new SelectionListener() {
276 public void widgetSelected(@Nullable SelectionEvent e
) {
277 Object
[] ySelections
= fYCheckBoxViewer
.getCheckedElements();
278 IStructuredSelection xSelections
= (IStructuredSelection
) fXTableViewer
.getSelection();
279 @Nullable Object x
= xSelections
.getFirstElement();
280 if (!(x
instanceof LamiTableEntryAspect
) || ySelections
.length
== 0) {
284 /* Add selection to series if it doesn not already exist in the list */
285 for (Object y
: ySelections
) {
286 if(!(y
instanceof LamiTableEntryAspect
)) {
289 LamiXYSeriesDescription serie
= new LamiXYSeriesDescription((LamiTableEntryAspect
) x
, ((LamiTableEntryAspect
) y
));
290 if (!series
.contains(serie
)) {
292 fSeriesListViewer
.refresh();
296 /* Set label warning visible and enable OK button */
297 fWarning
.setVisible(true);
298 getButton(IDialogConstants
.OK_ID
).setEnabled(true);
300 /* Update possible X selection based on current series */
301 TableItem
[] items
= fXTableViewer
.getTable().getItems();
302 Arrays
.stream(items
).forEach(item
-> {
303 LamiTableEntryAspect aspect
= (LamiTableEntryAspect
) item
.getData();
304 if (!aspect
.arePropertiesEqual(series
.get(0).getXAspect())) {
305 fXTableViewer
.remove(aspect
);
307 if (fRestrictXSeriesNumbers
&& aspect
!= (series
.get(0).getXAspect())) {
308 fXTableViewer
.remove(aspect
);
313 * Disable all checkBox that do not apply to aspects series.
314 * Simply take the first one since all series should comply to
315 * the same restriction
317 fXCheckBoxOptions
.forEach(checkBox
-> {
318 checkBox
.setButtonEnabled(checkBox
.getPredicate().test(series
.get(0).getXAspect()));
320 fYCheckBoxOptions
.forEach(checkBox
-> {
321 checkBox
.setButtonEnabled(checkBox
.getPredicate().test(series
.get(0).getYAspect()));
326 public void widgetDefaultSelected(@Nullable SelectionEvent e
) {
331 gridData
= new GridData(GridData
.FILL_BOTH
| GridData
.VERTICAL_ALIGN_END
);
332 gridData
.horizontalSpan
= 3;
333 fWarning
= new Label(seriesCreatorGroup
, SWT
.LEFT
);
334 fWarning
.setLayoutData(gridData
);
335 fWarning
.setText(Messages
.LamiSeriesDialog_selectionRestrictionWarning
);
336 fWarning
.setForeground(Display
.getCurrent().getSystemColor(SWT
.COLOR_RED
));
337 fWarning
.setVisible(false);
339 gridData
= new GridData(GridData
.FILL_BOTH
);
340 gridData
.horizontalSpan
= 3;
341 Group optionGroups
= new Group(composite
, getShellStyle());
342 optionGroups
.setLayoutData(gridData
);
343 optionGroups
.setLayout(new GridLayout(3, false));
344 optionGroups
.setText(Messages
.LamiSeriesDialog_chart_options
);
346 for (LamiAxisCheckBoxOption checkBox
: fXCheckBoxOptions
) {
347 Button button
= new Button(optionGroups
, SWT
.CHECK
);
348 button
.setSelection(checkBox
.getDefaultValue());
349 button
.setText(checkBox
.getName());
350 checkBox
.setButton(button
);
353 for (LamiAxisCheckBoxOption checkBox
: fYCheckBoxOptions
) {
354 Button button
= new Button(optionGroups
, SWT
.CHECK
);
355 button
.setSelection(checkBox
.getDefaultValue());
356 button
.setText(checkBox
.getName());
357 checkBox
.setButton(button
);
360 fYCheckBoxViewer
.getTable().addSelectionListener(new SelectionListener() {
363 public void widgetSelected(@Nullable SelectionEvent e
) {
365 if (e
!= null && e
.detail
== SWT
.CHECK
) {
366 /* Change possible selection */
367 IStructuredSelection selections
= (IStructuredSelection
) fYCheckBoxViewer
.getSelection();
368 if (selections
.getFirstElement() != null) {
370 boolean checked
= fYCheckBoxViewer
.getChecked(selections
.getFirstElement());
372 * If just selected look for stuff to disable. If not no
373 * need to look for stuff to disable since it was
374 * already done before.
377 TableItem
[] items
= fYCheckBoxViewer
.getTable().getItems();
378 Arrays
.stream(items
).forEach(item
-> {
379 LamiTableEntryAspect aspect
= (LamiTableEntryAspect
) item
.getData();
380 if (!aspect
.arePropertiesEqual((LamiTableEntryAspect
) checkNotNull(selections
.getFirstElement()))) {
381 fYCheckBoxViewer
.remove(aspect
);
384 } else if (!checked
&& fYCheckBoxViewer
.getCheckedElements().length
== 0 && fSeriesListViewer
.getTable().getItemCount() == 0) {
385 fYCheckBoxViewer
.refresh();
392 public void widgetDefaultSelected(@Nullable SelectionEvent e
) {
396 Dialog
.applyDialogFont(composite
);
401 * Disable OK button on dialog creation.
404 protected void createButtonsForButtonBar(@Nullable Composite parent
) {
405 super.createButtonsForButtonBar(parent
);
406 getButton(IDialogConstants
.OK_ID
).setEnabled(false);
410 * Return the style flags for the table viewer.
414 protected int getTableStyle() {
415 return SWT
.SINGLE
| SWT
.H_SCROLL
| SWT
.V_SCROLL
| SWT
.BORDER
;
419 * Add check box option for X series.
422 * The name of the option. The actual text shown to the user.
423 * @param defaultValue
424 * The default state of the check box option.
426 * The predicate to check if the option applies to the given
428 * @return The index of the option value in the result table.
430 public int addXCheckBoxOption(String name
, boolean defaultValue
, Predicate
<LamiTableEntryAspect
> predicate
) {
431 LamiAxisCheckBoxOption checkBox
= new LamiAxisCheckBoxOption(name
, defaultValue
, predicate
);
432 fXCheckBoxOptions
.add(checkBox
);
433 return fXCheckBoxOptions
.size() - 1;
437 * Add check box option for Y series.
440 * The name of the option. The actual text shown to the user.
441 * @param defaultValue
442 * The default state of the check box option.
444 * The predicate to check if the option applies to the given
446 * @return The index of the option value in the result table.
448 public int addYCheckBoxOption(String name
, boolean defaultValue
, Predicate
<LamiTableEntryAspect
> predicate
) {
449 LamiAxisCheckBoxOption checkbox
= new LamiAxisCheckBoxOption(name
, defaultValue
, predicate
);
450 fYCheckBoxOptions
.add(checkbox
);
451 return fYCheckBoxOptions
.size() - 1;
455 * @return The final values of X series check boxes.
457 public boolean[] getXCheckBoxOptionValues() {
458 boolean[] selections
= new boolean[fXCheckBoxOptions
.size()];
459 for (int i
= 0; i
< selections
.length
; i
++) {
460 selections
[i
] = fXCheckBoxOptions
.get(i
).getValue();
466 * @return The final values of Y series check boxes.
468 public boolean[] getYCheckBoxOptionValues() {
469 boolean[] selections
= new boolean[fYCheckBoxOptions
.size()];
470 for (int i
= 0; i
< selections
.length
; i
++) {
471 selections
[i
] = fYCheckBoxOptions
.get(i
).getValue();
477 protected void okPressed() {
478 for (LamiAxisCheckBoxOption checkBox
: fXCheckBoxOptions
) {
479 checkBox
.updateValue();
481 for (LamiAxisCheckBoxOption checkBox
: fYCheckBoxOptions
) {
482 checkBox
.updateValue();
488 public Object
[] getResult() {
489 return series
.toArray();
492 private static <T
extends Comparable
<T
>> TableViewerColumn
createTableViewerColumn(TableViewer viewer
, String name
,
493 Function
<LamiXYSeriesDescription
, T
> propertyFunction
) {
494 TableViewerColumn viewerColumn
= new TableViewerColumn(viewer
, SWT
.CENTER
);
495 viewerColumn
.setLabelProvider(new ColumnLabelProvider() {
497 public @Nullable String
getText(@Nullable Object element
) {
498 if (element
!= null) {
499 return propertyFunction
.apply((LamiXYSeriesDescription
) element
).toString();
505 TableColumn column
= viewerColumn
.getColumn();
506 column
.setText(name
);