analysis.lami: Implementation of LAMI plugins
[deliverable/tracecompass.git] / analysis / org.eclipse.tracecompass.analysis.lami.ui / src / org / eclipse / tracecompass / internal / provisional / analysis / lami / ui / views / LamiSeriesDialog.java
1 /*******************************************************************************
2 * Copyright (c) 2016 EfficiOS Inc., Jonathan Rajotte-Julien
3 *
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 *******************************************************************************/
9
10 package org.eclipse.tracecompass.internal.provisional.analysis.lami.ui.views;
11
12 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
13
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;
19 import java.util.stream.IntStream;
20
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.eclipse.jface.dialogs.Dialog;
23 import org.eclipse.jface.dialogs.IDialogConstants;
24 import org.eclipse.jface.layout.TableColumnLayout;
25 import org.eclipse.jface.viewers.ArrayContentProvider;
26 import org.eclipse.jface.viewers.CheckboxTableViewer;
27 import org.eclipse.jface.viewers.ColumnLabelProvider;
28 import org.eclipse.jface.viewers.ColumnWeightData;
29 import org.eclipse.jface.viewers.ILabelProvider;
30 import org.eclipse.jface.viewers.IStructuredContentProvider;
31 import org.eclipse.jface.viewers.IStructuredSelection;
32 import org.eclipse.jface.viewers.TableViewer;
33 import org.eclipse.jface.viewers.TableViewerColumn;
34 import org.eclipse.swt.SWT;
35 import org.eclipse.swt.custom.SashForm;
36 import org.eclipse.swt.events.SelectionEvent;
37 import org.eclipse.swt.events.SelectionListener;
38 import org.eclipse.swt.layout.GridData;
39 import org.eclipse.swt.layout.GridLayout;
40 import org.eclipse.swt.widgets.Button;
41 import org.eclipse.swt.widgets.Composite;
42 import org.eclipse.swt.widgets.Control;
43 import org.eclipse.swt.widgets.Display;
44 import org.eclipse.swt.widgets.Group;
45 import org.eclipse.swt.widgets.Label;
46 import org.eclipse.swt.widgets.Shell;
47 import org.eclipse.swt.widgets.TableColumn;
48 import org.eclipse.swt.widgets.TableItem;
49 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.aspect.LamiTableEntryAspect;
50 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiChartModel.ChartType;
51 import org.eclipse.tracecompass.internal.provisional.analysis.lami.core.module.LamiXYSeriesDescription;
52 import org.eclipse.ui.dialogs.SelectionDialog;
53
54 /**
55 * Series creation dialog
56 *
57 * @author Jonathan Rajotte-Julien
58 */
59 public class LamiSeriesDialog extends SelectionDialog {
60
61 private static final int MINIMUM_COLUMN_WIDTH = 30;
62 private static final int MININAL_SERIES_TABLE_HEIGHT = 150;
63
64 /* The root element to populate the viewer with */
65 private final Object fXInputElement;
66 private final Object fYInputElement;
67 private final List<LamiXYSeriesDescription> series;
68
69 /* Providers for populating dialog */
70 private final ILabelProvider fXLabelProvider;
71 private final IStructuredContentProvider fXContentProvider;
72 private final ILabelProvider fYLabelProvider;
73 private final IStructuredContentProvider fYContentProvider;
74 private final IStructuredContentProvider fSeriesContentProvider;
75
76 private final boolean fRestrictXSeriesNumbers;
77
78 private final List<LamiAxisCheckBoxOption> fXCheckBoxOptions;
79 private final List<LamiAxisCheckBoxOption> fYCheckBoxOptions;
80
81 // the visual selection widget group
82 private TableViewer fXTableViewer;
83 private CheckboxTableViewer fYCheckBoxViewer;
84 private TableViewer fSeriesListViewer;
85
86 private Label fWarning;
87
88 /**
89 * @param parentShell
90 * The parent shell of the dialog
91 * @param chartType
92 * The chart type for which the dialog construct series
93 * @param xInput
94 * The possible X axis set of values
95 * @param yInput
96 * The possible Y axis set of values
97 * @param xContentProvider
98 * A content provider for the X axis set
99 * @param xLabelProvider
100 * The label provider for the X axis set
101 * @param yContentProvider
102 * The content provider for the Y axis set
103 * @param yLabelProvider
104 * The label provider for the Y axis set
105 */
106 public LamiSeriesDialog(Shell parentShell, ChartType chartType, Object xInput,
107 Object yInput,
108 IStructuredContentProvider xContentProvider,
109 ILabelProvider xLabelProvider,
110 IStructuredContentProvider yContentProvider,
111 ILabelProvider yLabelProvider) {
112 super(parentShell);
113 fXInputElement = xInput;
114 fYInputElement = yInput;
115 fXContentProvider = xContentProvider;
116 fXLabelProvider = xLabelProvider;
117 fYContentProvider = yContentProvider;
118 fYLabelProvider = yLabelProvider;
119 series = new ArrayList<>();
120 fSeriesContentProvider = checkNotNull(ArrayContentProvider.getInstance());
121
122 fXCheckBoxOptions = new ArrayList<>();
123 fYCheckBoxOptions = new ArrayList<>();
124 fSeriesListViewer = new TableViewer(parentShell);
125 fXTableViewer = new TableViewer(parentShell);
126 fYCheckBoxViewer = checkNotNull(CheckboxTableViewer.newCheckList(parentShell, SWT.NONE));
127
128 /* Dynamic restriction per chart type */
129 switch (chartType) {
130 case XY_SCATTER:
131 fRestrictXSeriesNumbers = false;
132 break;
133 case BAR_CHART:
134 case PIE_CHART:
135 default:
136 fRestrictXSeriesNumbers = true;
137 break;
138 }
139
140 this.fWarning = new Label(parentShell, SWT.NONE);
141 }
142
143 @Override
144 protected Control createDialogArea(@Nullable Composite parent) {
145
146 Composite composite = (Composite) super.createDialogArea(parent);
147 initializeDialogUnits(composite);
148
149 /* Base 3 column grid layout */
150 GridLayout gridLayout = new GridLayout(3, false);
151 composite.setLayout(gridLayout);
152
153 GridData gridData = new GridData(GridData.FILL_BOTH);
154 gridData.horizontalSpan = 3;
155 Group seriesGroup = new Group(composite, SWT.NONE);
156 seriesGroup.setLayoutData(gridData);
157 seriesGroup.setLayout(new GridLayout(3, false));
158 seriesGroup.setText(Messages.LamiSeriesDialog_series);
159
160 /*
161 * New sub group for the series table.
162 */
163 gridData = new GridData(GridData.FILL_BOTH);
164 gridData.horizontalSpan = 2;
165 gridData.heightHint = MININAL_SERIES_TABLE_HEIGHT;
166 Group seriesTableGroup = new Group(seriesGroup, SWT.NONE);
167 seriesTableGroup.setLayoutData(gridData);
168 TableColumnLayout layout = new TableColumnLayout();
169 seriesTableGroup.setLayout(layout);
170
171 /* Current series */
172 fSeriesListViewer = new TableViewer(seriesTableGroup, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
173 fSeriesListViewer.setContentProvider(fSeriesContentProvider);
174 fSeriesListViewer.setInput(series);
175 fSeriesListViewer.getTable().setHeaderVisible(true);
176 fSeriesListViewer.getTable().setLinesVisible(true);
177 TableViewerColumn column1 = createTableViewerColumn(fSeriesListViewer, Messages.LamiSeriesDialog_x_values, element -> element.getXAspect().getLabel());
178 TableViewerColumn column2 = createTableViewerColumn(fSeriesListViewer, Messages.LamiSeriesDialog_y_values, element -> element.getYAspect().getLabel());
179 layout.setColumnData(column1.getColumn(), new ColumnWeightData(1, MINIMUM_COLUMN_WIDTH, true));
180 layout.setColumnData(column2.getColumn(), new ColumnWeightData(1, MINIMUM_COLUMN_WIDTH, true));
181
182 /* Delete series button */
183 gridData = new GridData(GridData.CENTER);
184 gridData.horizontalSpan = 1;
185 Button deleteSeries = new Button(seriesGroup, SWT.PUSH);
186 deleteSeries.setText(Messages.LamiSeriesDialog_delete);
187 deleteSeries.setLayoutData(gridData);
188 deleteSeries.addSelectionListener(new SelectionListener() {
189 @Override
190 public void widgetSelected(@Nullable SelectionEvent e) {
191 /* Remove the selectecd series */
192 IStructuredSelection selections = (IStructuredSelection) fSeriesListViewer.getSelection();
193 for (Object selection : selections.toList()) {
194 series.remove(selection);
195 }
196 /* When table is empty reset to initial state */
197 if (series.isEmpty()) {
198 /* Make sure the OK button is disabled */
199 getButton(IDialogConstants.OK_ID).setEnabled(false);
200 /* Hide the selection warning */
201 fWarning.setVisible(false);
202
203 /*
204 * Reset the initial selection of the X axis selection table
205 */
206 fXTableViewer.refresh();
207 /* Reset check boxes options */
208 fXCheckBoxOptions.forEach(checkBox -> {
209 checkBox.setButtonEnabled(true);
210 });
211 fYCheckBoxOptions.forEach(checkBox -> {
212 checkBox.setButtonEnabled(true);
213 });
214 }
215 /* Refresh the series table to show the added series */
216 fSeriesListViewer.refresh();
217 }
218
219 @Override
220 public void widgetDefaultSelected(@Nullable SelectionEvent e) {
221 }
222 });
223
224 /*
225 * Series creator subgroup
226 */
227 gridData = new GridData(GridData.FILL_BOTH);
228 gridData.horizontalSpan = 3;
229 Group seriesCreatorGroup = new Group(composite, getShellStyle());
230 seriesCreatorGroup.setLayoutData(gridData);
231 seriesCreatorGroup.setLayout(new GridLayout(3, false));
232 seriesCreatorGroup.setText(Messages.LamiSeriesDialog_serie_creator);
233
234 /* X axis sash label */
235 gridData = new GridData(GridData.FILL_BOTH | GridData.VERTICAL_ALIGN_END);
236 gridData.horizontalSpan = 1;
237 Label xSeriesCreatorLabel = new Label(seriesCreatorGroup, SWT.CENTER);
238 xSeriesCreatorLabel.setLayoutData(gridData);
239 xSeriesCreatorLabel.setText(Messages.LamiSeriesDialog_x_axis);
240
241 gridData = new GridData(GridData.FILL_BOTH | GridData.VERTICAL_ALIGN_END);
242 gridData.horizontalSpan = 1;
243 Label ySeriesCreatorLabel = new Label(seriesCreatorGroup, SWT.CENTER);
244 ySeriesCreatorLabel.setLayoutData(gridData);
245 ySeriesCreatorLabel.setText(Messages.LamiSeriesDialog_y_axis);
246
247 /* Empty label for grid layout */
248 gridData = new GridData(GridData.FILL_BOTH);
249 gridData.horizontalSpan = 1;
250 Label emptyLabel = new Label(seriesCreatorGroup, SWT.CENTER);
251 emptyLabel.setLayoutData(gridData);
252
253 SashForm sash1 = new SashForm(seriesCreatorGroup, SWT.BORDER | SWT.HORIZONTAL);
254 gridData = new GridData(GridData.FILL_BOTH);
255 gridData.horizontalSpan = 2;
256 sash1.setLayoutData(gridData);
257 sash1.setVisible(true);
258
259 fXTableViewer = new TableViewer(sash1, getTableStyle());
260 fXTableViewer.setContentProvider(fXContentProvider);
261 fXTableViewer.setLabelProvider(fXLabelProvider);
262 fXTableViewer.setInput(fXInputElement);
263
264 fYCheckBoxViewer = checkNotNull(CheckboxTableViewer.newCheckList(sash1, SWT.BORDER));
265 fYCheckBoxViewer.setLabelProvider(fYLabelProvider);
266 fYCheckBoxViewer.setContentProvider(fYContentProvider);
267 fYCheckBoxViewer.setInput(fYInputElement);
268
269 gridData = new GridData(SWT.FILL, SWT.NONE, true, true);
270 gridData.horizontalSpan = 1;
271 Button button1 = new Button(seriesCreatorGroup, SWT.PUSH);
272 button1.setText(Messages.LamiSeriesDialog_add);
273 button1.setLayoutData(gridData);
274 button1.addSelectionListener(new SelectionListener() {
275
276 @Override
277 public void widgetSelected(@Nullable SelectionEvent e) {
278 Object[] ySelections = fYCheckBoxViewer.getCheckedElements();
279 IStructuredSelection xSelections = (IStructuredSelection) fXTableViewer.getSelection();
280 @Nullable Object x = xSelections.getFirstElement();
281 if (!(x instanceof LamiTableEntryAspect) || ySelections.length == 0) {
282 return;
283 }
284
285 /* Add selection to series if it doesn not already exist in the list */
286 for (Object y : ySelections) {
287 if(!(y instanceof LamiTableEntryAspect)) {
288 continue;
289 }
290 LamiXYSeriesDescription serie = new LamiXYSeriesDescription((LamiTableEntryAspect) x, ((LamiTableEntryAspect) y));
291 if (!series.contains(serie)) {
292 series.add(serie);
293 fSeriesListViewer.refresh();
294 }
295 }
296
297 /* Set label warning visible and enable OK button */
298 fWarning.setVisible(true);
299 getButton(IDialogConstants.OK_ID).setEnabled(true);
300
301 /* Update possible X selection based on current series */
302 TableItem[] items = fXTableViewer.getTable().getItems();
303 Arrays.stream(items).forEach(item -> {
304 LamiTableEntryAspect aspect = (LamiTableEntryAspect) item.getData();
305 if (!aspect.arePropertiesEqual(series.get(0).getXAspect())) {
306 fXTableViewer.remove(aspect);
307 }
308 if (fRestrictXSeriesNumbers && aspect != (series.get(0).getXAspect())) {
309 fXTableViewer.remove(aspect);
310 }
311 });
312
313 /*
314 * Disable all checkBox that do not apply to aspects series.
315 * Simply take the first one since all series should comply to
316 * the same restriction
317 */
318 fXCheckBoxOptions.forEach(checkBox -> {
319 checkBox.setButtonEnabled(checkBox.getPredicate().test(series.get(0).getXAspect()));
320 });
321 fYCheckBoxOptions.forEach(checkBox -> {
322 checkBox.setButtonEnabled(checkBox.getPredicate().test(series.get(0).getYAspect()));
323 });
324 }
325
326 @Override
327 public void widgetDefaultSelected(@Nullable SelectionEvent e) {
328 }
329 });
330
331
332 gridData = new GridData(GridData.FILL_BOTH | GridData.VERTICAL_ALIGN_END);
333 gridData.horizontalSpan = 3;
334 fWarning = new Label(seriesCreatorGroup, SWT.LEFT);
335 fWarning.setLayoutData(gridData);
336 fWarning.setText(Messages.LamiSeriesDialog_selectionRestrictionWarning);
337 fWarning.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
338 fWarning.setVisible(false);
339
340 gridData = new GridData(GridData.FILL_BOTH);
341 gridData.horizontalSpan = 3;
342 Group optionGroups = new Group(composite, getShellStyle());
343 optionGroups.setLayoutData(gridData);
344 optionGroups.setLayout(new GridLayout(3, false));
345 optionGroups.setText(Messages.LamiSeriesDialog_chart_options);
346
347 for (LamiAxisCheckBoxOption checkBox : fXCheckBoxOptions) {
348 Button button = new Button(optionGroups, SWT.CHECK);
349 button.setSelection(checkBox.getDefaultValue());
350 button.setText(checkBox.getName());
351 checkBox.setButton(button);
352 }
353
354 for (LamiAxisCheckBoxOption checkBox : fYCheckBoxOptions) {
355 Button button = new Button(optionGroups, SWT.CHECK);
356 button.setSelection(checkBox.getDefaultValue());
357 button.setText(checkBox.getName());
358 checkBox.setButton(button);
359 }
360
361 fYCheckBoxViewer.getTable().addSelectionListener(new SelectionListener() {
362
363 @Override
364 public void widgetSelected(@Nullable SelectionEvent e) {
365 /* On check */
366 if (e != null && e.detail == SWT.CHECK) {
367 /* Change possible selection */
368 IStructuredSelection selections = (IStructuredSelection) fYCheckBoxViewer.getSelection();
369 if (selections.getFirstElement() != null) {
370
371 boolean checked = fYCheckBoxViewer.getChecked(selections.getFirstElement());
372 /*
373 * If just selected look for stuff to disable. If not no
374 * need to look for stuff to disable since it was
375 * already done before.
376 */
377 if (checked) {
378 TableItem[] items = fYCheckBoxViewer.getTable().getItems();
379 Arrays.stream(items).forEach(item -> {
380 LamiTableEntryAspect aspect = (LamiTableEntryAspect) item.getData();
381 if (!aspect.arePropertiesEqual((LamiTableEntryAspect) checkNotNull(selections.getFirstElement()))) {
382 fYCheckBoxViewer.remove(aspect);
383 }
384 });
385 } else if (!checked && fYCheckBoxViewer.getCheckedElements().length == 0 && fSeriesListViewer.getTable().getItemCount() == 0) {
386 fYCheckBoxViewer.refresh();
387 }
388 }
389 }
390 }
391
392 @Override
393 public void widgetDefaultSelected(@Nullable SelectionEvent e) {
394 }
395 });
396
397 Dialog.applyDialogFont(composite);
398 return composite;
399 }
400
401 /*
402 * Disable OK button on dialog creation.
403 */
404 @Override
405 protected void createButtonsForButtonBar(@Nullable Composite parent) {
406 super.createButtonsForButtonBar(parent);
407 getButton(IDialogConstants.OK_ID).setEnabled(false);
408 }
409
410 /**
411 * Return the style flags for the table viewer.
412 *
413 * @return int
414 */
415 protected int getTableStyle() {
416 return SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER;
417 }
418
419 /**
420 * Add check box option for X series.
421 *
422 * @param name
423 * The name of the option. The actual text shown to the user.
424 * @param defaultValue
425 * The default state of the check box option.
426 * @param predicate
427 * The predicate to check if the option applies to the given
428 * aspect
429 * @return The index of the option value in the result table.
430 */
431 public int addXCheckBoxOption(String name, boolean defaultValue, Predicate<LamiTableEntryAspect> predicate) {
432 LamiAxisCheckBoxOption checkBox = new LamiAxisCheckBoxOption(name, defaultValue, predicate);
433 fXCheckBoxOptions.add(checkBox);
434 return fXCheckBoxOptions.size() - 1;
435 }
436
437 /**
438 * Add check box option for Y series.
439 *
440 * @param name
441 * The name of the option. The actual text shown to the user.
442 * @param defaultValue
443 * The default state of the check box option.
444 * @param predicate
445 * The predicate to check if the option applies to the given
446 * aspect
447 * @return The index of the option value in the result table.
448 */
449 public int addYCheckBoxOption(String name, boolean defaultValue, Predicate<LamiTableEntryAspect> predicate) {
450 LamiAxisCheckBoxOption checkbox = new LamiAxisCheckBoxOption(name, defaultValue, predicate);
451 fYCheckBoxOptions.add(checkbox);
452 return fYCheckBoxOptions.size() - 1;
453 }
454
455 /**
456 * @return The final values of X series check boxes.
457 */
458 public boolean[] getXCheckBoxOptionValues() {
459 boolean[] selections = new boolean[fXCheckBoxOptions.size()];
460 if (selections.length != 0) {
461 IntStream.range(0, selections.length).forEach(i -> selections[i] = fXCheckBoxOptions.get(i).getValue());
462 }
463 return selections;
464 }
465
466 /**
467 * @return The final values of Y series check boxes.
468 */
469 public boolean[] getYCheckBoxOptionValues() {
470 boolean[] selections = new boolean[fYCheckBoxOptions.size()];
471 if (selections.length != 0) {
472 IntStream.range(0, selections.length).forEach(i -> selections[i] = fYCheckBoxOptions.get(i).getValue());
473 }
474 return selections;
475 }
476
477 @Override
478 protected void okPressed() {
479 for (LamiAxisCheckBoxOption checkBox : fXCheckBoxOptions) {
480 checkBox.updateValue();
481 }
482 for (LamiAxisCheckBoxOption checkBox : fYCheckBoxOptions) {
483 checkBox.updateValue();
484 }
485 super.okPressed();
486 }
487
488 @Override
489 public Object[] getResult() {
490 return series.toArray();
491 }
492
493 private static <T extends Comparable<T>> TableViewerColumn createTableViewerColumn(TableViewer viewer, String name,
494 Function<LamiXYSeriesDescription, T> propertyFunction) {
495 TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.CENTER);
496 viewerColumn.setLabelProvider(new ColumnLabelProvider() {
497 @Override
498 public @Nullable String getText(@Nullable Object element) {
499 if (element != null) {
500 return propertyFunction.apply((LamiXYSeriesDescription) element).toString();
501 }
502 return null;
503 }
504 });
505
506 TableColumn column = viewerColumn.getColumn();
507 column.setText(name);
508 return viewerColumn;
509 }
510
511 }
This page took 0.044491 seconds and 6 git commands to generate.