| /******************************************************************************* |
| * Copyright (c) 2016 École Polytechnique de Montréal |
| * |
| * All rights reserved. This program and the accompanying materials are |
| * made available under the terms of the Eclipse Public License 2.0 which |
| * accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.internal.provisional.tmf.chart.ui.dialog; |
| |
| import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.layout.TableColumnLayout; |
| import org.eclipse.jface.viewers.ArrayContentProvider; |
| import org.eclipse.jface.viewers.CheckStateChangedEvent; |
| import org.eclipse.jface.viewers.CheckboxTableViewer; |
| import org.eclipse.jface.viewers.ColumnLabelProvider; |
| import org.eclipse.jface.viewers.ColumnPixelData; |
| import org.eclipse.jface.viewers.ColumnWeightData; |
| import org.eclipse.jface.viewers.ICheckStateListener; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TableViewer; |
| import org.eclipse.jface.viewers.TableViewerColumn; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.viewers.ViewerCell; |
| import org.eclipse.jface.viewers.ViewerFilter; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.TableEditor; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.Point; |
| 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.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Group; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.TableItem; |
| import org.eclipse.tracecompass.common.core.NonNullUtils; |
| import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.chart.ChartData; |
| import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.chart.ChartModel; |
| import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.chart.ChartSeries; |
| import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.chart.ChartType; |
| import org.eclipse.tracecompass.internal.provisional.tmf.chart.core.descriptor.IDataChartDescriptor; |
| import org.eclipse.tracecompass.internal.tmf.chart.ui.dialog.Messages; |
| import org.eclipse.tracecompass.internal.tmf.chart.ui.type.BarChartTypeDefinition; |
| import org.eclipse.tracecompass.internal.tmf.chart.ui.type.IChartTypeDefinition; |
| import org.eclipse.tracecompass.internal.tmf.chart.ui.type.ScatterChartTypeDefinition; |
| import org.eclipse.tracecompass.tmf.chart.core.model.IDataChartProvider; |
| import org.eclipse.ui.ISharedImages; |
| import org.eclipse.ui.PlatformUI; |
| |
| /** |
| * This dialog is used for configuring series before making a chart. |
| * |
| * @author Gabriel-Andrew Pollo-Guilbert |
| */ |
| public class ChartMakerDialog extends Dialog { |
| |
| private static final Image DELETE_IMAGE = NonNullUtils.checkNotNull(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE)); |
| |
| // ------------------------------------------------------------------------ |
| // Members |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Data model used for the creation of the chart |
| */ |
| private final IDataChartProvider<?> fDataProvider; |
| /** |
| * Table for displaying chart types |
| */ |
| private final TableViewer fTypeTable; |
| /** |
| * Table for displaying series |
| */ |
| private final TableViewer fSeriesTable; |
| /** |
| * Table for displaying valid X series |
| */ |
| private final TableViewer fSelectionXTable; |
| /** |
| * Checkbox table for displaying valid Y series |
| */ |
| private final CheckboxTableViewer fSelectionYTable; |
| /** |
| * Button used for creating a series |
| */ |
| private final Button fAddButton; |
| /** |
| * Warning label that choices might be restricted after selection |
| */ |
| private final Label fWarningLabel; |
| /** |
| * Checkbox for indicating whether X axis is logarithmic |
| */ |
| private final Button fXLogscaleButton; |
| /** |
| * Checkbox for indicating whether Y axis is logarithmic |
| */ |
| private final Button fYLogscaleButton; |
| /** |
| * List of created series |
| */ |
| private final List<ChartSeries> fSelectedSeries = new ArrayList<>(); |
| /** |
| * Parent composite |
| */ |
| private Composite fComposite; |
| /** |
| * Currently selected chart type |
| */ |
| private @Nullable IChartTypeDefinition fType; |
| |
| /** |
| * Filter for X data descriptors |
| */ |
| private @Nullable IDataChartDescriptor<?, ?> fXFilter; |
| /** |
| * Filter for Y data descriptors |
| */ |
| private @Nullable IDataChartDescriptor<?, ?> fYFilter; |
| /** |
| * Chart data created after the dialog |
| */ |
| private @Nullable ChartData fDataSeries; |
| /** |
| * Chart model created after the dialog |
| */ |
| private @Nullable ChartModel fChartModel; |
| |
| // ------------------------------------------------------------------------ |
| // Important methods |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Constructor. |
| * |
| * @param parent |
| * Parent shell |
| * @param model |
| * Model to choose source from |
| */ |
| public ChartMakerDialog(Shell parent, IDataChartProvider<?> model) { |
| super(parent); |
| |
| fComposite = parent; |
| fDataProvider = model; |
| |
| /* Create tables */ |
| fTypeTable = new TableViewer(parent, SWT.FULL_SELECTION | SWT.BORDER); |
| fSeriesTable = new TableViewer(parent, SWT.FULL_SELECTION | SWT.BORDER); |
| fSelectionXTable = new TableViewer(parent, SWT.FULL_SELECTION | SWT.BORDER | SWT.NO_SCROLL | SWT.V_SCROLL); |
| fSelectionYTable = checkNotNull(CheckboxTableViewer.newCheckList(parent, SWT.BORDER | SWT.NO_SCROLL | SWT.V_SCROLL)); |
| |
| /* Create buttons */ |
| fAddButton = new Button(parent, SWT.NONE); |
| fXLogscaleButton = new Button(parent, SWT.CHECK); |
| fYLogscaleButton = new Button(parent, SWT.CHECK); |
| fWarningLabel = new Label(parent, SWT.NONE); |
| |
| setShellStyle(getShellStyle() | SWT.RESIZE); |
| } |
| |
| /** |
| * @return The configured data series |
| */ |
| public @Nullable ChartData getDataSeries() { |
| return fDataSeries; |
| } |
| |
| /** |
| * @return The configured chart model |
| */ |
| public @Nullable ChartModel getChartModel() { |
| return fChartModel; |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Overriden methods |
| // ------------------------------------------------------------------------ |
| |
| @Override |
| public Point getInitialSize() { |
| return new Point(800, 600); |
| } |
| |
| @Override |
| public void create() { |
| super.create(); |
| |
| getButton(IDialogConstants.OK_ID).setEnabled(false); |
| } |
| |
| @Override |
| public Composite createDialogArea(@Nullable Composite parent) { |
| fComposite = checkNotNull((Composite) super.createDialogArea(parent)); |
| getShell().setText(Messages.ChartMakerDialog_Title); |
| |
| /* Layouts */ |
| GridLayout baseLayout = new GridLayout(); |
| baseLayout.numColumns = 2; |
| |
| GridData genericFillGridData = new GridData(); |
| genericFillGridData.horizontalAlignment = SWT.FILL; |
| genericFillGridData.verticalAlignment = SWT.FILL; |
| genericFillGridData.grabExcessHorizontalSpace = true; |
| genericFillGridData.grabExcessVerticalSpace = true; |
| |
| fComposite.setLayout(baseLayout); |
| |
| /* Chart type selector */ |
| createTypeTable(); |
| |
| /* Selected series viewer */ |
| createSelectedSeriesGroup(genericFillGridData); |
| |
| /* Series creator */ |
| createSeriesCreatorGroup(genericFillGridData); |
| |
| /* Options */ |
| createOptionsGroup(); |
| |
| return fComposite; |
| } |
| |
| // Create the type table, on the left side of the dialog |
| private void createTypeTable() { |
| GridData typeGridData = new GridData(); |
| typeGridData.verticalSpan = 3; |
| typeGridData.horizontalAlignment = SWT.FILL; |
| typeGridData.verticalAlignment = SWT.FILL; |
| typeGridData.grabExcessHorizontalSpace = false; |
| typeGridData.grabExcessVerticalSpace = true; |
| |
| TableViewerColumn typeColumn = new TableViewerColumn(fTypeTable, SWT.NONE); |
| typeColumn.getColumn().setWidth(50); |
| typeColumn.setLabelProvider(new TypeLabelProvider()); |
| |
| List<IChartTypeDefinition> types = new ArrayList<>(); |
| types.add(new BarChartTypeDefinition()); |
| types.add(new ScatterChartTypeDefinition()); |
| |
| fTypeTable.getTable().setParent(fComposite); |
| fTypeTable.getTable().setLayoutData(typeGridData); |
| fTypeTable.setContentProvider(ArrayContentProvider.getInstance()); |
| fTypeTable.addSelectionChangedListener(new TypeSelectionListener()); |
| fTypeTable.setInput(types); |
| } |
| |
| // Create the group that shows the selected series |
| private void createSelectedSeriesGroup(GridData genericFillGridData) { |
| /** |
| * FIXME: The labels in the first column cannot be aligned to the |
| * center. The workaround is to put a dummy column that won't appear. |
| */ |
| GridLayout genericGridLayout = new GridLayout(); |
| |
| TableViewerColumn dummyColumn = new TableViewerColumn(fSeriesTable, SWT.NONE); |
| dummyColumn.setLabelProvider(new SeriesDummyLabelProvider()); |
| |
| /* X series column */ |
| TableViewerColumn xSelectionColumn = new TableViewerColumn(fSeriesTable, SWT.NONE); |
| xSelectionColumn.getColumn().setText(Messages.ChartMakerDialog_XSeries); |
| xSelectionColumn.getColumn().setAlignment(SWT.CENTER); |
| xSelectionColumn.getColumn().setResizable(false); |
| xSelectionColumn.setLabelProvider(new SeriesXLabelProvider()); |
| |
| /* Y series column */ |
| TableViewerColumn ySelectionColumn = new TableViewerColumn(fSeriesTable, SWT.NONE); |
| ySelectionColumn.getColumn().setText(Messages.ChartMakerDialog_YSeries); |
| ySelectionColumn.getColumn().setAlignment(SWT.CENTER); |
| ySelectionColumn.getColumn().setResizable(false); |
| ySelectionColumn.setLabelProvider(new SeriesYLabelProvider()); |
| |
| /* Remove buttons column */ |
| TableViewerColumn removeColumn = new TableViewerColumn(fSeriesTable, SWT.NONE); |
| removeColumn.getColumn().setResizable(false); |
| removeColumn.setLabelProvider(new SeriesRemoveLabelProvider()); |
| |
| TableColumnLayout seriesLayout = new TableColumnLayout(); |
| seriesLayout.setColumnData(dummyColumn.getColumn(), new ColumnPixelData(0)); |
| seriesLayout.setColumnData(xSelectionColumn.getColumn(), new ColumnWeightData(50)); |
| seriesLayout.setColumnData(ySelectionColumn.getColumn(), new ColumnWeightData(50)); |
| seriesLayout.setColumnData(removeColumn.getColumn(), new ColumnPixelData(34)); |
| |
| Group seriesGroup = new Group(fComposite, SWT.BORDER | SWT.FILL); |
| seriesGroup.setText(Messages.ChartMakerDialog_SelectedSeries); |
| seriesGroup.setLayout(genericGridLayout); |
| seriesGroup.setLayoutData(genericFillGridData); |
| |
| Composite seriesComposite = new Composite(seriesGroup, SWT.NONE); |
| seriesComposite.setLayout(seriesLayout); |
| seriesComposite.setLayoutData(genericFillGridData); |
| |
| fSeriesTable.getTable().setParent(seriesComposite); |
| fSeriesTable.getTable().setHeaderVisible(true); |
| fSeriesTable.getTable().addListener(SWT.MeasureItem, new SeriesRowResize()); |
| fSeriesTable.setContentProvider(ArrayContentProvider.getInstance()); |
| fSeriesTable.setInput(fSelectedSeries); |
| } |
| |
| // Create the series selection group, listing all the available series |
| private void createSeriesCreatorGroup(GridData genericFillGridData) { |
| GridLayout creatorLayout = new GridLayout(); |
| creatorLayout.numColumns = 2; |
| creatorLayout.makeColumnsEqualWidth = true; |
| |
| Group creatorGroup = new Group(fComposite, SWT.BORDER); |
| creatorGroup.setText(Messages.ChartMakerDialog_SeriesCreator); |
| creatorGroup.setLayout(creatorLayout); |
| creatorGroup.setLayoutData(genericFillGridData); |
| |
| GridData creatorLabelGridData = new GridData(); |
| creatorLabelGridData.horizontalAlignment = SWT.CENTER; |
| creatorLabelGridData.verticalAlignment = SWT.BOTTOM; |
| |
| /* Top labels */ |
| Label creatorLabelX = new Label(creatorGroup, SWT.NONE); |
| creatorLabelX.setText(Messages.ChartMakerDialog_XAxis); |
| creatorLabelX.setLayoutData(creatorLabelGridData); |
| |
| Label creatorLabelY = new Label(creatorGroup, SWT.NONE); |
| creatorLabelY.setText(Messages.ChartMakerDialog_YAxis); |
| creatorLabelY.setLayoutData(creatorLabelGridData); |
| |
| /* X axis table */ |
| TableViewerColumn creatorXColumn = new TableViewerColumn(fSelectionXTable, SWT.NONE); |
| creatorXColumn.getColumn().setResizable(false); |
| creatorXColumn.setLabelProvider(new DataDescriptorLabelProvider()); |
| |
| TableColumnLayout creatorXLayout = new TableColumnLayout(); |
| creatorXLayout.setColumnData(creatorXColumn.getColumn(), new ColumnWeightData(100)); |
| |
| Composite creatorXComposite = new Composite(creatorGroup, SWT.NONE); |
| creatorXComposite.setLayout(creatorXLayout); |
| creatorXComposite.setLayoutData(genericFillGridData); |
| |
| fSelectionXTable.getTable().setParent(creatorXComposite); |
| fSelectionXTable.setContentProvider(ArrayContentProvider.getInstance()); |
| fSelectionXTable.setInput(fDataProvider.getDataDescriptors()); |
| fSelectionXTable.setFilters(new ViewerFilter[] { new CreatorXFilter() }); |
| fSelectionXTable.addSelectionChangedListener(new CreatorXSelectedEvent()); |
| |
| /* Y axis table */ |
| TableViewerColumn creatorYColumn = new TableViewerColumn(fSelectionYTable, SWT.NONE); |
| creatorYColumn.getColumn().setResizable(false); |
| creatorYColumn.setLabelProvider(new DataDescriptorLabelProvider()); |
| |
| TableColumnLayout creatorYLayout = new TableColumnLayout(); |
| creatorYLayout.setColumnData(creatorYColumn.getColumn(), new ColumnWeightData(100)); |
| |
| Composite creatorYComposite = new Composite(creatorGroup, SWT.NONE); |
| creatorYComposite.setLayout(creatorYLayout); |
| creatorYComposite.setLayoutData(genericFillGridData); |
| |
| fSelectionYTable.getTable().setParent(creatorYComposite); |
| fSelectionYTable.setContentProvider(ArrayContentProvider.getInstance()); |
| fSelectionYTable.setInput(fDataProvider.getDataDescriptors()); |
| fSelectionYTable.setFilters(new ViewerFilter[] { new CreatorYFilter() }); |
| fSelectionYTable.addCheckStateListener(new CreatorYSelectedEvent()); |
| |
| /* Selected series warning */ |
| fWarningLabel.setParent(creatorGroup); |
| fWarningLabel.setText(Messages.ChartMakerDialog_SelectionRestrictionWarning); |
| fWarningLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED)); |
| fWarningLabel.setVisible(false); |
| |
| /* Add button */ |
| GridData creatorButtonGridData = new GridData(); |
| creatorButtonGridData.horizontalAlignment = SWT.RIGHT; |
| creatorButtonGridData.widthHint = 30; |
| creatorButtonGridData.heightHint = 30; |
| |
| Image addImage = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ADD); |
| fAddButton.setParent(creatorGroup); |
| fAddButton.setLayoutData(creatorButtonGridData); |
| fAddButton.setImage(addImage); |
| fAddButton.addListener(SWT.Selection, new AddButtonClickedEvent()); |
| } |
| |
| private void createOptionsGroup() { |
| GridLayout optionsLayout = new GridLayout(); |
| optionsLayout.numColumns = 2; |
| |
| GridData configOptionsGridData = new GridData(); |
| configOptionsGridData.horizontalAlignment = SWT.FILL; |
| configOptionsGridData.grabExcessHorizontalSpace = true; |
| |
| Group optionsGroup = new Group(fComposite, SWT.BORDER); |
| optionsGroup.setText(Messages.ChartMakerDialog_Options); |
| optionsGroup.setLayout(optionsLayout); |
| optionsGroup.setLayoutData(configOptionsGridData); |
| |
| /* Checkboxes for logscale */ |
| fXLogscaleButton.setParent(optionsGroup); |
| fXLogscaleButton.setText(Messages.ChartMakerDialog_LogScaleX); |
| |
| fYLogscaleButton.setParent(optionsGroup); |
| fYLogscaleButton.setText(Messages.ChartMakerDialog_LogScaleY); |
| } |
| |
| @Override |
| public void okPressed() { |
| /* Create the data series */ |
| fDataSeries = new ChartData(fDataProvider, fSelectedSeries); |
| |
| /* Create the data model */ |
| ChartType type = checkNotNull(checkNotNull(fType).getType()); |
| String title = fDataProvider.getName(); |
| boolean xlog = fXLogscaleButton.getSelection(); |
| boolean ylog = fYLogscaleButton.getSelection(); |
| fChartModel = new ChartModel(type, title, xlog, ylog); |
| |
| super.okPressed(); |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Util methods |
| // ------------------------------------------------------------------------ |
| |
| private boolean checkIfSeriesCompatible(IChartTypeDefinition typeA, IChartTypeDefinition typeB) { |
| for (ChartSeries series : fSelectedSeries) { |
| if (typeA.checkIfXDescriptorValid(series.getX(), null) != typeB.checkIfXDescriptorValid(series.getX(), null)) { |
| return false; |
| } |
| |
| if (typeA.checkIfYDescriptorValid(series.getY(), null) != typeB.checkIfYDescriptorValid(series.getY(), null)) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| private boolean checkIfButtonReady() { |
| if (fSelectionXTable.getSelection().isEmpty()) { |
| return false; |
| } |
| |
| return (fSelectionYTable.getCheckedElements().length != 0); |
| } |
| |
| private boolean checkIfSeriesPresent(ChartSeries test) { |
| for (ChartSeries series : fSelectedSeries) { |
| if (series.getX() == test.getX() && series.getY() == test.getY()) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private @Nullable ChartSeries findRemoveButtonOwner(Button button) { |
| for (ChartSeries series : fSelectedSeries) { |
| ChartSeriesDialog line = (ChartSeriesDialog) series; |
| if (line.getButton() == button) { |
| return line; |
| } |
| } |
| |
| return null; |
| } |
| |
| private void removeIncompatibleSeries(IChartTypeDefinition type) { |
| Iterator<ChartSeries> iterator = fSelectedSeries.iterator(); |
| |
| while (iterator.hasNext()) { |
| ChartSeriesDialog series = (ChartSeriesDialog) iterator.next(); |
| |
| /* Check if the series is compatible, if not, remove it */ |
| if (!type.checkIfXDescriptorValid(series.getX(), null) || !type.checkIfYDescriptorValid(series.getY(), null)) { |
| series.dispose(); |
| |
| /* Remove the series of the series list */ |
| iterator.remove(); |
| } |
| } |
| } |
| |
| private void unselectIncompatibleSeries(IChartTypeDefinition type) { |
| /* Check if X selected series is compatible */ |
| IDataChartDescriptor<?, ?> descriptorX = (IDataChartDescriptor<?, ?>) fSelectionXTable.getStructuredSelection().getFirstElement(); |
| if (descriptorX != null && !type.checkIfXDescriptorValid(descriptorX, fXFilter)) { |
| fSelectionXTable.getTable().deselectAll(); |
| } |
| |
| /* Check if Y selected series are compatible */ |
| for (Object element : fSelectionYTable.getCheckedElements()) { |
| IDataChartDescriptor<?, ?> descriptorY = (IDataChartDescriptor<?, ?>) checkNotNull(element); |
| |
| if (!type.checkIfYDescriptorValid(descriptorY, fYFilter)) { |
| fSelectionYTable.setChecked(element, false); |
| } |
| } |
| } |
| |
| private void configureLogscaleCheckboxes() { |
| /* Enable X logscale checkbox if possible */ |
| if (checkNotNull(fType).checkIfXLogscalePossible(fXFilter)) { |
| fXLogscaleButton.setEnabled(true); |
| } else { |
| fXLogscaleButton.setEnabled(false); |
| fXLogscaleButton.setSelection(false); |
| } |
| |
| /* Enable Y logscale checkbox if possible */ |
| if (checkNotNull(fType).checkIfYLogscalePossible(fYFilter)) { |
| fYLogscaleButton.setEnabled(true); |
| } else { |
| fYLogscaleButton.setEnabled(false); |
| fYLogscaleButton.setSelection(false); |
| } |
| } |
| |
| private boolean tryResetXFilter() { |
| if (!fSelectedSeries.isEmpty()) { |
| return false; |
| } |
| |
| fXFilter = null; |
| return true; |
| } |
| |
| private boolean tryResetYFilter() { |
| if (!fSelectedSeries.isEmpty()) { |
| return false; |
| } |
| |
| if (fSelectionYTable.getCheckedElements().length != 0) { |
| return false; |
| } |
| |
| fYFilter = null; |
| return true; |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Listeners, Providers, etc |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * This class extension avoid the use of an hashmap for linking a series |
| * with a button. Each button in the series table are linked to a series. |
| */ |
| private class ChartSeriesDialog extends ChartSeries { |
| private final Button fButton; |
| |
| private ChartSeriesDialog(IDataChartDescriptor<?, ?> descriptorX, IDataChartDescriptor<?, ?> descriptorY) { |
| super(descriptorX, descriptorY); |
| // Create the button for this series |
| Button button = new Button((Composite) fSeriesTable.getControl(), SWT.PUSH); |
| button.setImage(DELETE_IMAGE); |
| button.addListener(SWT.Selection, new SeriesRemoveButtonEvent()); |
| fButton = button; |
| } |
| |
| private Button getButton() { |
| return fButton; |
| } |
| |
| public void dispose() { |
| fButton.dispose(); |
| } |
| |
| } |
| |
| /** |
| * This provider provides the image in the chart type selection table. |
| */ |
| private class TypeLabelProvider extends ColumnLabelProvider { |
| @Override |
| public @Nullable String getText(@Nullable Object element) { |
| IChartTypeDefinition type = checkNotNull((IChartTypeDefinition) element); |
| return type.getType().name(); |
| } |
| |
| @Override |
| public Image getImage(@Nullable Object element) { |
| IChartTypeDefinition type = checkNotNull((IChartTypeDefinition) element); |
| return new Image(fComposite.getDisplay(), type.getImageData()); |
| } |
| } |
| |
| /** |
| * This listener handle the selection in the chart type selection table. |
| */ |
| private class TypeSelectionListener implements ISelectionChangedListener { |
| @Override |
| public void selectionChanged(@Nullable SelectionChangedEvent event) { |
| IStructuredSelection selection = fTypeTable.getStructuredSelection(); |
| IChartTypeDefinition type = (IChartTypeDefinition) selection.getFirstElement(); |
| |
| if (type == null) { |
| return; |
| } |
| |
| /* Check if the series are compatible with the chart type */ |
| if (!fSelectedSeries.isEmpty() && !checkIfSeriesCompatible(checkNotNull(fType), type)) { |
| String warning = Messages.ChartMakerDialog_WarningConfirm; |
| String message = String.format(Messages.ChartMakerDialog_WarningIncompatibleSeries, |
| type.getType().toString().toLowerCase()); |
| |
| /* Ask the user if he wants to continue */ |
| boolean choice = MessageDialog.openConfirm(fComposite.getShell(), warning, message); |
| if (!choice) { |
| fTypeTable.setSelection(new StructuredSelection(fType)); |
| return; |
| } |
| |
| removeIncompatibleSeries(type); |
| fSeriesTable.refresh(); |
| } |
| |
| fType = type; |
| |
| /* Refresh controls */ |
| unselectIncompatibleSeries(fType); |
| |
| if (tryResetXFilter()) { |
| fSelectionXTable.refresh(); |
| } |
| |
| if (tryResetYFilter()) { |
| fSelectionYTable.refresh(); |
| } |
| |
| fAddButton.setEnabled(checkIfButtonReady()); |
| configureLogscaleCheckboxes(); |
| } |
| } |
| |
| /** |
| * This dummy provider is used as a workaround in a column's bug. |
| */ |
| private class SeriesDummyLabelProvider extends ColumnLabelProvider { |
| @Override |
| public @Nullable String getText(@Nullable Object element) { |
| return null; |
| } |
| } |
| |
| /** |
| * This provider provides the labels for the X column of the series table. |
| */ |
| private class SeriesXLabelProvider extends ColumnLabelProvider { |
| @Override |
| public String getText(@Nullable Object element) { |
| ChartSeries series = checkNotNull((ChartSeries) element); |
| return series.getX().getLabel(); |
| } |
| } |
| |
| /** |
| * This provider provides the labels for the Y column of the series table. |
| */ |
| private class SeriesYLabelProvider extends ColumnLabelProvider { |
| @Override |
| public String getText(@Nullable Object element) { |
| ChartSeries series = checkNotNull((ChartSeries) element); |
| return series.getY().getLabel(); |
| } |
| } |
| |
| /** |
| * This provider provides the buttons for removing a series in the series |
| * table. |
| */ |
| private class SeriesRemoveLabelProvider extends ColumnLabelProvider { |
| @Override |
| public @Nullable String getText(@Nullable Object element) { |
| return null; |
| } |
| |
| @Override |
| public void update(@Nullable ViewerCell cell) { |
| if (cell == null) { |
| return; |
| } |
| |
| /* Create a button if it doesn't exist */ |
| ChartSeriesDialog series = (ChartSeriesDialog) cell.getViewerRow().getElement(); |
| Button button = series.getButton(); |
| |
| /* Set the position of the button into the cell */ |
| TableItem item = (TableItem) cell.getItem(); |
| TableEditor editor = new TableEditor(item.getParent()); |
| editor.grabHorizontal = true; |
| editor.grabVertical = true; |
| editor.setEditor(button, item, cell.getColumnIndex()); |
| editor.layout(); |
| } |
| } |
| |
| /** |
| * This listener handles the event when the button for removing a series is |
| * clicked. |
| */ |
| private class SeriesRemoveButtonEvent implements Listener { |
| @Override |
| public void handleEvent(@Nullable Event event) { |
| if (event == null) { |
| return; |
| } |
| |
| /* Dispose the button of the series */ |
| Button button = (Button) checkNotNull(event.widget); |
| button.dispose(); |
| |
| /* Remove the series from the list */ |
| ChartSeries series = findRemoveButtonOwner(button); |
| fSelectedSeries.remove(series); |
| fSeriesTable.refresh(); |
| |
| /* Refresh controls */ |
| tryResetXFilter(); |
| fSelectionXTable.refresh(); |
| |
| tryResetYFilter(); |
| fSelectionYTable.refresh(); |
| |
| /* Disable OK button if no series are made */ |
| if (fSelectedSeries.isEmpty()) { |
| getButton(IDialogConstants.OK_ID).setEnabled(false); |
| fWarningLabel.setVisible(false); |
| } |
| |
| configureLogscaleCheckboxes(); |
| } |
| } |
| |
| /** |
| * This listener resizes the height of each row of the series table. |
| */ |
| private class SeriesRowResize implements Listener { |
| @Override |
| public void handleEvent(@Nullable Event event) { |
| if (event == null) { |
| return; |
| } |
| |
| event.height = 27; |
| } |
| } |
| |
| /** |
| * This provider provides labels for {@link DataChartDescriptor}. |
| */ |
| private class DataDescriptorLabelProvider extends ColumnLabelProvider { |
| @Override |
| public String getText(@Nullable Object element) { |
| IDataChartDescriptor<?, ?> descriptor = (IDataChartDescriptor<?, ?>) checkNotNull(element); |
| return descriptor.getLabel(); |
| } |
| } |
| |
| /** |
| * This filter is used for filtering labels in the X selection table. |
| */ |
| private class CreatorXFilter extends ViewerFilter { |
| @Override |
| public boolean select(@Nullable Viewer viewer, @Nullable Object parentElement, @Nullable Object element) { |
| IChartTypeDefinition type = fType; |
| |
| if (type == null) { |
| return false; |
| } |
| |
| IDataChartDescriptor<?, ?> descriptor = (IDataChartDescriptor<?, ?>) checkNotNull(element); |
| return type.checkIfXDescriptorValid(descriptor, fXFilter); |
| } |
| } |
| |
| /** |
| * This filter is used for filtering labels in the Y selection table. |
| */ |
| private class CreatorYFilter extends ViewerFilter { |
| @Override |
| public boolean select(@Nullable Viewer viewer, @Nullable Object parentElement, @Nullable Object element) { |
| IChartTypeDefinition type = fType; |
| |
| if (type == null) { |
| return false; |
| } |
| |
| IDataChartDescriptor<?, ?> descriptor = (IDataChartDescriptor<?, ?>) checkNotNull(element); |
| return type.checkIfYDescriptorValid(descriptor, fYFilter); |
| } |
| } |
| |
| /** |
| * This listener handles the event when a selection is made in the X |
| * selection table. |
| */ |
| private class CreatorXSelectedEvent implements ISelectionChangedListener { |
| @Override |
| public void selectionChanged(@Nullable SelectionChangedEvent event) { |
| /* Enable button if possible */ |
| fAddButton.setEnabled(checkIfButtonReady()); |
| } |
| } |
| |
| /** |
| * This listener handles the event when a value is checked in the Y |
| * selection table. |
| */ |
| private class CreatorYSelectedEvent implements ICheckStateListener { |
| @Override |
| public void checkStateChanged(@Nullable CheckStateChangedEvent event) { |
| if (event == null) { |
| return; |
| } |
| |
| /* Set Y filter if needed */ |
| if (event.getChecked()) { |
| if (fYFilter == null) { |
| IDataChartDescriptor<?, ?> descriptor = (IDataChartDescriptor<?, ?>) event.getElement(); |
| fYFilter = descriptor; |
| } |
| } else { |
| tryResetYFilter(); |
| } |
| |
| /* Refresh controls */ |
| fSelectionYTable.refresh(); |
| fAddButton.setEnabled(checkIfButtonReady()); |
| |
| configureLogscaleCheckboxes(); |
| } |
| } |
| |
| /** |
| * This listener handle the event when the add button of the series creator |
| * is clicked. |
| */ |
| private class AddButtonClickedEvent implements Listener { |
| @Override |
| public void handleEvent(@Nullable Event event) { |
| IDataChartDescriptor<?, ?> descriptorX = (IDataChartDescriptor<?, ?>) checkNotNull(fSelectionXTable.getStructuredSelection().getFirstElement()); |
| Object[] descriptorsY = fSelectionYTable.getCheckedElements(); |
| |
| /* Create a series for each Y axis */ |
| for (int i = 0; i < descriptorsY.length; i++) { |
| IDataChartDescriptor<?, ?> descriptorY = (IDataChartDescriptor<?, ?>) descriptorsY[i]; |
| ChartSeriesDialog series = new ChartSeriesDialog(descriptorX, checkNotNull(descriptorY)); |
| |
| if (!checkIfSeriesPresent(series)) { |
| fSelectedSeries.add(series); |
| } |
| } |
| |
| /* Set the X filter */ |
| if (fXFilter == null) { |
| fXFilter = descriptorX; |
| } |
| |
| /* Refresh controls */ |
| // FIXME: The first refresh creates the buttons, the second makes |
| // sure they show correctly, otherwise one button is displayed only |
| // half his size until another call to refresh magically makes them |
| // all show correctly |
| fSeriesTable.refresh(); |
| Display.getDefault().asyncExec(() -> fSeriesTable.refresh()); |
| fSelectionXTable.refresh(); |
| |
| /* Enable OK button */ |
| getButton(IDialogConstants.OK_ID).setEnabled(true); |
| fWarningLabel.setVisible(true); |
| |
| configureLogscaleCheckboxes(); |
| } |
| } |
| |
| } |