X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.charts%2Fsrc%2Forg%2Fsimantics%2Fcharts%2Fui%2FChartDialog.java;fp=bundles%2Forg.simantics.charts%2Fsrc%2Forg%2Fsimantics%2Fcharts%2Fui%2FChartDialog.java;h=f703f96bc8f57415692e7a89489532d21d17c896;hp=8615828da36fc850de782a93370c51d52fc7a6d3;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hpb=24e2b34260f219f0d1644ca7a138894980e25b14 diff --git a/bundles/org.simantics.charts/src/org/simantics/charts/ui/ChartDialog.java b/bundles/org.simantics.charts/src/org/simantics/charts/ui/ChartDialog.java index 8615828da..f703f96bc 100644 --- a/bundles/org.simantics.charts/src/org/simantics/charts/ui/ChartDialog.java +++ b/bundles/org.simantics.charts/src/org/simantics/charts/ui/ChartDialog.java @@ -1,557 +1,557 @@ -package org.simantics.charts.ui; - -import java.awt.Color; -import java.text.Format; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.Dialog; -import org.eclipse.jface.fieldassist.ControlDecoration; -import org.eclipse.jface.fieldassist.FieldDecorationRegistry; -import org.eclipse.jface.layout.GridDataFactory; -import org.eclipse.jface.layout.GridLayoutFactory; -import org.eclipse.jface.preference.ColorSelector; -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.DoubleClickEvent; -import org.eclipse.jface.viewers.IDoubleClickListener; -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.ListViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.KeyAdapter; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.RGB; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Scale; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; -import org.simantics.Simantics; -import org.simantics.charts.Activator; -import org.simantics.charts.query.ChartAndSubscriptionItemData; -import org.simantics.charts.query.ChartAndSubscriptionItemReadQuery; -import org.simantics.charts.ui.ChartData.ItemKey; -import org.simantics.db.exception.DatabaseException; -import org.simantics.modeling.ui.chart.property.ChartComposite; -import org.simantics.trend.configuration.TrendItem; -import org.simantics.trend.configuration.YAxisMode; -import org.simantics.trend.impl.Plot; -import org.simantics.utils.format.TimeFormat; -import org.simantics.utils.ui.ISelectionUtils; - -/** - * Dialog for chart properties: - * - *
- * Name:             [ Process ]
- * Time Start:       [   ]
- * Length:           [   ]
- * Scroll Increment: [--|--] n%
- * Axis Mode:        [Single/Multi]
- * [ ] Hairline Tracks Experiment Time
- * 
- * --- Styling ------------------------------------------
- * | [ ] Background Vertical Gradient {color1} {color2} |
- * | [ ] Show Grid                    {grid color}      |
- * | [ ] Show Milestones                                |
- * ------------------------------------------------------
- * 
- * --- Item visibility ---------------
- * | Visible          Hidden         |
- * | -----------      -------------- |
- * | |         | HIDE |            | |
- * | |         | SHOW |            | |
- * | -----------      -------------- |
- * -----------------------------------
- * 
- * - * @author toni.kalajainen@semantum.fi - * @author Tuukka Lehtonen - */ -public class ChartDialog extends Dialog { - - private static final RGB DEFAULT_BG_COLOR1 = toRGB(Plot.PLOT_AREA_BG_GRADIENT_COLOR_BOTTOM.getColorComponents(new float[3]), null); - private static final RGB DEFAULT_BG_COLOR2 = toRGB(Plot.PLOT_AREA_BG_GRADIENT_COLOR_TOP.getColorComponents(new float[3]), null); - private static final RGB DEFAULT_GRID_COLOR = toRGB(Plot.GRID_LINE_COLOR.getColorComponents(new float[3]), null); - - Format timeFormat = new TimeFormat(100, 3); - - // UI - Label lName, lStartTime, lLength, lScrollIncrement, lAxisMode; - Text tName, tStartTime, tLength; - Scale sIncrement; - Combo cAxisMode; - Button bBackgroundGradient; - ColorSelector backgroundColor1; - ColorSelector backgroundColor2; - Button bShowGrid; - ColorSelector gridColor; - Button bMilestones; - Button bTrackExperimentTime; - ListViewer lVisibleItems; - ListViewer lHiddenItems; - - ControlDecoration tStartTimeDecor; - ControlDecoration tLengthDecor; - - final ChartData baseData = new ChartData(); - final ChartData data; - final Runnable applyAction; - - /** - * Set when a chart item dialog has previously been opened by this dialog. - */ - ChartAndSubscriptionItemDialog currentItemDialog = null; - - public ChartDialog(Shell parentShell, ChartData data, Runnable applyAction) { - super(parentShell); - this.data = data; - this.baseData.readFrom(data); - this.applyAction = applyAction; - setShellStyle(SWT.RESIZE | SWT.TITLE | SWT.CLOSE | SWT.BORDER); - } - - @Override - protected void createButtonsForButtonBar(Composite parent) { - if (applyAction != null) - createButton(parent, ChartDialogConstants.APPLY_ID, ChartDialogConstants.APPLY_LABEL, true); - super.createButtonsForButtonBar(parent); - } - - @Override - protected Control createDialogArea(Composite parent) { - Composite c = (Composite) super.createDialogArea(parent); - GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(9).applyTo(c); - createDialogAreaContents(c); - return c; - } - - protected void createDialogAreaContents(Composite c) { - GridDataFactory gd1 = GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(1, 1); - GridDataFactory gd2 = GridDataFactory.fillDefaults().indent(5, 0).grab(true, false).span(8, 1); - - // 1st line - Chart: [chart name] - lName = new Label(c, 0); - lName.setText("&Name:"); - gd1.applyTo(lName); - tName = new Text(c, SWT.BORDER); - tName.setEnabled( true ); - if ( data.name != null ) tName.setText( data.name ); - gd2.applyTo(tName); - - // 2nd line - start time + length - Label l = new Label(c, 0); - l.setText("Chart Time Window Preference (Auto-scale)"); - GridDataFactory.fillDefaults().span(9, 1).applyTo(l); - - lStartTime = new Label(c, 0); - lStartTime.setText("&Time Start:"); - gd1.applyTo(lStartTime); - tStartTime = new Text(c, SWT.BORDER); - tStartTime.setToolTipText("Chart Window Fixed Start Time in Seconds or Yy Dd HH:mm:ss.ddd"); - if ( data.timeStart!=null ) { - String str = timeFormat.format(data.timeStart); - tStartTime.setText(str); - } - gd2.applyTo(tStartTime); - tStartTime.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - data.timeStart = parseTime(tStartTime, false, 0.0); - validate(); - } - }); - - lLength = new Label(c, 0); - lLength.setText("&Length:"); - gd1.applyTo(lLength); - tLength = new Text(c, SWT.BORDER); - tLength.setToolTipText("Chart Window Fixed Time Axis Length in Seconds or Yy Dd HH:mm:ss.ddd"); - if ( data.timeLength!=null ) { - String str = timeFormat.format(data.timeLength); - tLength.setText(str); - } - gd2.applyTo(tLength); - tLength.addModifyListener(new ModifyListener() { - @Override - public void modifyText(ModifyEvent e) { - data.timeLength = parseTime(tLength, false, 0.0); - validate(); - } - }); - - // 3rd line - Increment scrollbar - lScrollIncrement = new Label(c, 0); - lScrollIncrement.setText("Scroll Increment:"); - gd1.applyTo(lScrollIncrement); - sIncrement = new Scale(c, SWT.HORIZONTAL); - sIncrement.setMinimum(1); - sIncrement.setMaximum(100); - sIncrement.setIncrement(10); - sIncrement.setPageIncrement(10); - if (data.timeIncrement!=null) { - sIncrement.setSelection( (int) (double) data.timeIncrement ); - } - gd2.copy().span(7, 1).applyTo(sIncrement); - final Text sIncrementText = new Text(c, SWT.READ_ONLY | SWT.RIGHT); - gd1.copy().hint(35, SWT.DEFAULT).applyTo(sIncrementText); - sIncrement.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - sIncrementText.setText(sIncrement.getSelection() + " %"); - } - }); - sIncrementText.setText(sIncrement.getSelection() + " %"); - - // 4th line -- AxisMode + Milestone - lAxisMode = new Label(c, 0); - lAxisMode.setText("A&xis Mode:"); - gd1.applyTo(lAxisMode); - cAxisMode = new Combo(c, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY); - GridDataFactory.fillDefaults().indent(5, 0).span(1, 1).applyTo(cAxisMode); - cAxisMode.add("Single"); - cAxisMode.add("Multi"); - String _mode = data.axisMode==YAxisMode.SingleAxis ? "Single" : "Multi"; - cAxisMode.setText( _mode ); - // Filler - GridDataFactory.fillDefaults().span(7, 1).applyTo(new Label(c, 0)); - - bTrackExperimentTime = new Button(c, SWT.CHECK); - bTrackExperimentTime.setText("Ha&irline Tracks Experiment Time"); - bTrackExperimentTime.setSelection( data.trackExperimentTime ); - GridDataFactory.fillDefaults().span(9, 1).applyTo(bTrackExperimentTime); - - // Styling group begins - - Group gStyling = new Group(c, 0); - gStyling.setText("Styling"); - GridDataFactory.fillDefaults().indent(0, 5).grab(true, true).span(9, 1).applyTo(gStyling); - GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(4).applyTo(gStyling); - - // Background color settings - { - bBackgroundGradient = new Button(gStyling, SWT.CHECK); - bBackgroundGradient.setText("&Background Vertical Gradient"); - bBackgroundGradient.setToolTipText("Solid Color or Vertical Gradient"); - bBackgroundGradient.setSelection(data.backgroundGradient); - bBackgroundGradient.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - data.backgroundGradient = bBackgroundGradient.getSelection(); - setBackgroundGradient(data.backgroundGradient); - } - }); - GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(bBackgroundGradient); - - backgroundColor1 = new ColorSelector(gStyling); - backgroundColor2 = new ColorSelector(gStyling); - backgroundColor1.getButton().setToolTipText("Select Gradient Bottom Color"); - backgroundColor2.getButton().setToolTipText("Select Gradient Top Color"); - GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(backgroundColor1.getButton()); - GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(backgroundColor2.getButton()); - backgroundColor1.setColorValue(toRGB(data.backgroundColor1, DEFAULT_BG_COLOR1)); - backgroundColor2.setColorValue(toRGB(data.backgroundColor2, DEFAULT_BG_COLOR2)); - setBackgroundGradient(data.backgroundGradient); - - Button bResetBackgroundColors = new Button(gStyling, SWT.PUSH); - bResetBackgroundColors.setText("Reset"); - bResetBackgroundColors.setToolTipText("Reset Background Color to Default"); - bResetBackgroundColors.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent e) { - backgroundColor1.setColorValue(toRGB(null, DEFAULT_BG_COLOR1)); - backgroundColor2.setColorValue(toRGB(null, DEFAULT_BG_COLOR2)); - } - }); - } - - // Grid settings - { - bShowGrid = new Button(gStyling, SWT.CHECK); - bShowGrid.setText("Show &Grid"); - bShowGrid.setToolTipText("Toggle Background Grid Visibility"); - bShowGrid.setSelection(data.showGrid); - GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(bShowGrid); - - gridColor = new ColorSelector(gStyling); - gridColor.getButton().setToolTipText("Select Grid Color"); - GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(gridColor.getButton()); - gridColor.setColorValue(toRGB(data.gridColor, DEFAULT_GRID_COLOR)); - - Button bResetGridColor = new Button(gStyling, SWT.PUSH); - bResetGridColor.setText("Reset"); - bResetGridColor.setToolTipText("Reset Grid Color to Default"); - bResetGridColor.addSelectionListener(new SelectionAdapter() { - public void widgetSelected(SelectionEvent e) { - gridColor.setColorValue(toRGB(null, DEFAULT_GRID_COLOR)); - } - }); - } - - // Grid settings - { - GridDataFactory.fillDefaults().span(1, 1).applyTo(new Label(gStyling, 0)); - bMilestones = new Button(gStyling, SWT.CHECK); - bMilestones.setText("Show &Milestones"); - bMilestones.setToolTipText("Toggle Milestone Event Visibility"); - bMilestones.setSelection( data.showMilestones ); - GridDataFactory.fillDefaults().indent(0, 0).span(4, 1).applyTo(bMilestones); - } - - // Item visibility group begins - - Group gItemVisibility = new Group(c, 0); - gItemVisibility.setText("Item Visibility"); - GridDataFactory.fillDefaults().indent(0, 5).grab(true, true).span(9, 1).applyTo(gItemVisibility); - GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(3).applyTo(gItemVisibility); - - Label visible = new Label(gItemVisibility, 0); - visible.setText("Visible"); - GridDataFactory.fillDefaults().grab(true, false).applyTo(visible); - new Label(gItemVisibility, 0); - Label hidden = new Label(gItemVisibility, 0); - hidden.setText("Hidden"); - GridDataFactory.fillDefaults().grab(true, false).applyTo(hidden); - - lVisibleItems = new ListViewer(gItemVisibility, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); - GridDataFactory.fillDefaults().hint(200, 200).grab(true, true).applyTo(lVisibleItems.getControl()); - Composite addRemoveButtons = new Composite(gItemVisibility, 0); - GridLayoutFactory.fillDefaults().numColumns(1).applyTo(addRemoveButtons); - GridDataFactory.fillDefaults().grab(false, true).span(1, 1).applyTo(addRemoveButtons); - Button hideButton = new Button(addRemoveButtons, SWT.PUSH); - hideButton.setText("&Hide \u2192"); - GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(hideButton); - Button showButton = new Button(addRemoveButtons, SWT.PUSH); - showButton.setText("\u2190 &Show"); - GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(showButton); - lHiddenItems = new ListViewer(gItemVisibility, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); - GridDataFactory.fillDefaults().hint(200, 200).grab(true, true).applyTo(lHiddenItems.getControl()); - - lVisibleItems.addDoubleClickListener(new OpenChartItemProperties()); - lVisibleItems.setContentProvider(new ItemContentProvider(false)); - lHiddenItems.addDoubleClickListener(new OpenChartItemProperties()); - lHiddenItems.setContentProvider(new ItemContentProvider(true)); - lVisibleItems.setLabelProvider(new ItemLabeler()); - lHiddenItems.setLabelProvider(new ItemLabeler()); - lVisibleItems.setInput(data); - lHiddenItems.setInput(data); - - lVisibleItems.getList().addKeyListener(new SelectAllListener(lVisibleItems)); - lHiddenItems.getList().addKeyListener(new SelectAllListener(lHiddenItems)); - showButton.addSelectionListener(new ShowHideListener(false)); - hideButton.addSelectionListener(new ShowHideListener(true)); - - Image image = FieldDecorationRegistry.getDefault() - .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR) - .getImage(); - - tStartTimeDecor = createDecoration(tStartTime, SWT.LEFT | SWT.CENTER, image); - tLengthDecor = createDecoration(tLength, SWT.LEFT | SWT.CENTER, image); - } - - class ShowHideListener extends SelectionAdapter { - private boolean hide; - - public ShowHideListener(boolean hide) { - this.hide = hide; - } - - @Override - public void widgetSelected(SelectionEvent e) { - ISelection selection = hide ? lVisibleItems.getSelection() : lHiddenItems.getSelection(); - Set selected = ISelectionUtils.filterSetSelection(selection, ItemKey.class); - if (!selected.isEmpty()) { - if (hide) { - data.hiddenItems.addAll(selected); - } else { - data.hiddenItems.removeAll(selected); - } - lVisibleItems.refresh(); - lHiddenItems.refresh(); - } - } - } - - static class SelectAllListener extends KeyAdapter { - private ListViewer list; - - public SelectAllListener(ListViewer list) { - this.list = list; - } - - @Override - public void keyPressed(KeyEvent e) { - if (e.stateMask == SWT.CTRL && e.keyCode == 'a') { - list.getList().selectAll(); - } - } - }; - - class ItemContentProvider extends ArrayContentProvider { - private final boolean expectedHidden; - - public ItemContentProvider(boolean expectedHidden) { - this.expectedHidden = expectedHidden; - } - - @Override - public Object[] getElements(Object inputElement) { - List result = new ArrayList<>(); - for (ItemKey item : data.allItems.keySet()) - if (data.hiddenItems.contains(item) == expectedHidden) - result.add(item); - return result.toArray(); - } - } - - private void setBackgroundGradient(boolean backgroundGradient) { - backgroundColor2.setEnabled(backgroundGradient); - backgroundColor1.getButton().setToolTipText(backgroundGradient ? "Select Gradient Bottom Color" : "Select Solid Color"); - } - - protected Double parseTime(Text text, boolean returnDefault, double defaultValue) { - if (text == null) - return null; - String s = text.getText(); - Double time = ChartComposite.START_VALIDATOR.parse(s); - if (time == null) - return returnDefault ? defaultValue : null; - return time; - } - - protected ControlDecoration createDecoration(Control control, int position, Image image) { - ControlDecoration d = new ControlDecoration(control, position); - d.setMarginWidth(2); - d.setImage(image); - d.hide(); - return d; - } - - class ItemLabeler extends LabelProvider { - @Override - public String getText(Object element) { - ItemKey item = (ItemKey) element; - TrendItem ti = data.allItems.get(item); - return ti.label; - } - } - - protected void parseUiToData() { - data.name = tName.getText(); - data.backgroundColor1 = toColorComponents( backgroundColor1.getColorValue() ); - data.backgroundColor2 = toColorComponents( backgroundColor2.getColorValue() ); - data.showGrid = bShowGrid.getSelection(); - data.gridColor = toColorComponents( gridColor.getColorValue() ); - data.showMilestones = bMilestones.getSelection(); - data.trackExperimentTime = bTrackExperimentTime.getSelection(); - data.axisMode = cAxisMode.getSelectionIndex()==0?YAxisMode.SingleAxis:YAxisMode.MultiAxis; - data.timeIncrement = (double) sIncrement.getSelection(); - data.timeLength = ChartComposite.LENGTH_VALIDATOR.parse(tLength.getText()); - data.timeStart = ChartComposite.START_VALIDATOR.parse(tStartTime.getText()); - } - - @Override - protected void buttonPressed(int buttonId) { - if (ChartDialogConstants.APPLY_ID == buttonId) { - applyPressed(); - } else { - super.buttonPressed(buttonId); - } - } - - private void applyPressed() { - if (applyAction != null) { - parseUiToData(); - if (!baseData.equals(data)) { - baseData.readFrom(data); - applyAction.run(); - } - } - } - - @Override - protected void okPressed() { - parseUiToData(); - if (applyAction != null && !baseData.equals(data)) - applyAction.run(); - super.okPressed(); - } - - @Override - protected void configureShell(Shell newShell) { - super.configureShell(newShell); - newShell.setText("Edit Chart"); - } - - public void validate() { - String startTimeError = ChartComposite.START_VALIDATOR.isValid(tStartTime.getText()); - String lengthError = ChartComposite.LENGTH_VALIDATOR.isValid(tLength.getText()); - setDecoration(tStartTimeDecor, startTimeError); - setDecoration(tLengthDecor, lengthError); - boolean ok = startTimeError == null && lengthError == null; - setFinishable(ok); - } - - private void setDecoration(ControlDecoration decor, String desc) { - if (decor == null) - return; - if (desc != null) { - decor.setDescriptionText(desc); - decor.show(); - } else { - decor.hide(); - } - } - - protected void setFinishable(boolean ok) { - getButton(OK).setEnabled(ok); - } - - private static RGB toRGB(float[] components, RGB defaultValue) { - if (components == null || components.length < 3) - return defaultValue; - Color c = new Color(components[0], components[1], components[2]); - return new RGB(c.getRed(), c.getGreen(), c.getBlue()); - } - - private static float[] toColorComponents(RGB rgb) { - return new Color(rgb.red, rgb.green, rgb.blue).getColorComponents(new float[3]); - } - - class OpenChartItemProperties implements IDoubleClickListener { - @Override - public void doubleClick(DoubleClickEvent event) { - final ItemKey item = ISelectionUtils.filterSingleSelection(event.getSelection(), ItemKey.class); - if (item == null) - return; - try { - final ChartAndSubscriptionItemData data = Simantics.getSession().syncRequest( - new ChartAndSubscriptionItemReadQuery(item.resource.getResource())); - if (currentItemDialog != null && currentItemDialog.getShell() != null && !currentItemDialog.getShell().isDisposed()) { - // TODO: reinitialize existing dialog with the specified data. - // Close current dialog before opening new one. - currentItemDialog.close(); - } - currentItemDialog = ChartDoubleClickHandler.openChartItemPropertiesDialog( - event.getViewer().getControl().getShell(), - item.resource.getResource(), - data, - false); - } catch (DatabaseException e) { - Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Problems opening chart item property dialog.")); - } - } - } - -} +package org.simantics.charts.ui; + +import java.awt.Color; +import java.text.Format; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.fieldassist.ControlDecoration; +import org.eclipse.jface.fieldassist.FieldDecorationRegistry; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.preference.ColorSelector; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.ListViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Scale; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.simantics.Simantics; +import org.simantics.charts.Activator; +import org.simantics.charts.query.ChartAndSubscriptionItemData; +import org.simantics.charts.query.ChartAndSubscriptionItemReadQuery; +import org.simantics.charts.ui.ChartData.ItemKey; +import org.simantics.db.exception.DatabaseException; +import org.simantics.modeling.ui.chart.property.ChartComposite; +import org.simantics.trend.configuration.TrendItem; +import org.simantics.trend.configuration.YAxisMode; +import org.simantics.trend.impl.Plot; +import org.simantics.utils.format.TimeFormat; +import org.simantics.utils.ui.ISelectionUtils; + +/** + * Dialog for chart properties: + * + *
+ * Name:             [ Process ]
+ * Time Start:       [   ]
+ * Length:           [   ]
+ * Scroll Increment: [--|--] n%
+ * Axis Mode:        [Single/Multi]
+ * [ ] Hairline Tracks Experiment Time
+ * 
+ * --- Styling ------------------------------------------
+ * | [ ] Background Vertical Gradient {color1} {color2} |
+ * | [ ] Show Grid                    {grid color}      |
+ * | [ ] Show Milestones                                |
+ * ------------------------------------------------------
+ * 
+ * --- Item visibility ---------------
+ * | Visible          Hidden         |
+ * | -----------      -------------- |
+ * | |         | HIDE |            | |
+ * | |         | SHOW |            | |
+ * | -----------      -------------- |
+ * -----------------------------------
+ * 
+ * + * @author toni.kalajainen@semantum.fi + * @author Tuukka Lehtonen + */ +public class ChartDialog extends Dialog { + + private static final RGB DEFAULT_BG_COLOR1 = toRGB(Plot.PLOT_AREA_BG_GRADIENT_COLOR_BOTTOM.getColorComponents(new float[3]), null); + private static final RGB DEFAULT_BG_COLOR2 = toRGB(Plot.PLOT_AREA_BG_GRADIENT_COLOR_TOP.getColorComponents(new float[3]), null); + private static final RGB DEFAULT_GRID_COLOR = toRGB(Plot.GRID_LINE_COLOR.getColorComponents(new float[3]), null); + + Format timeFormat = new TimeFormat(100, 3); + + // UI + Label lName, lStartTime, lLength, lScrollIncrement, lAxisMode; + Text tName, tStartTime, tLength; + Scale sIncrement; + Combo cAxisMode; + Button bBackgroundGradient; + ColorSelector backgroundColor1; + ColorSelector backgroundColor2; + Button bShowGrid; + ColorSelector gridColor; + Button bMilestones; + Button bTrackExperimentTime; + ListViewer lVisibleItems; + ListViewer lHiddenItems; + + ControlDecoration tStartTimeDecor; + ControlDecoration tLengthDecor; + + final ChartData baseData = new ChartData(); + final ChartData data; + final Runnable applyAction; + + /** + * Set when a chart item dialog has previously been opened by this dialog. + */ + ChartAndSubscriptionItemDialog currentItemDialog = null; + + public ChartDialog(Shell parentShell, ChartData data, Runnable applyAction) { + super(parentShell); + this.data = data; + this.baseData.readFrom(data); + this.applyAction = applyAction; + setShellStyle(SWT.RESIZE | SWT.TITLE | SWT.CLOSE | SWT.BORDER); + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + if (applyAction != null) + createButton(parent, ChartDialogConstants.APPLY_ID, ChartDialogConstants.APPLY_LABEL, true); + super.createButtonsForButtonBar(parent); + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite c = (Composite) super.createDialogArea(parent); + GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(9).applyTo(c); + createDialogAreaContents(c); + return c; + } + + protected void createDialogAreaContents(Composite c) { + GridDataFactory gd1 = GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(1, 1); + GridDataFactory gd2 = GridDataFactory.fillDefaults().indent(5, 0).grab(true, false).span(8, 1); + + // 1st line - Chart: [chart name] + lName = new Label(c, 0); + lName.setText("&Name:"); + gd1.applyTo(lName); + tName = new Text(c, SWT.BORDER); + tName.setEnabled( true ); + if ( data.name != null ) tName.setText( data.name ); + gd2.applyTo(tName); + + // 2nd line - start time + length + Label l = new Label(c, 0); + l.setText("Chart Time Window Preference (Auto-scale)"); + GridDataFactory.fillDefaults().span(9, 1).applyTo(l); + + lStartTime = new Label(c, 0); + lStartTime.setText("&Time Start:"); + gd1.applyTo(lStartTime); + tStartTime = new Text(c, SWT.BORDER); + tStartTime.setToolTipText("Chart Window Fixed Start Time in Seconds or Yy Dd HH:mm:ss.ddd"); + if ( data.timeStart!=null ) { + String str = timeFormat.format(data.timeStart); + tStartTime.setText(str); + } + gd2.applyTo(tStartTime); + tStartTime.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + data.timeStart = parseTime(tStartTime, false, 0.0); + validate(); + } + }); + + lLength = new Label(c, 0); + lLength.setText("&Length:"); + gd1.applyTo(lLength); + tLength = new Text(c, SWT.BORDER); + tLength.setToolTipText("Chart Window Fixed Time Axis Length in Seconds or Yy Dd HH:mm:ss.ddd"); + if ( data.timeLength!=null ) { + String str = timeFormat.format(data.timeLength); + tLength.setText(str); + } + gd2.applyTo(tLength); + tLength.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + data.timeLength = parseTime(tLength, false, 0.0); + validate(); + } + }); + + // 3rd line - Increment scrollbar + lScrollIncrement = new Label(c, 0); + lScrollIncrement.setText("Scroll Increment:"); + gd1.applyTo(lScrollIncrement); + sIncrement = new Scale(c, SWT.HORIZONTAL); + sIncrement.setMinimum(1); + sIncrement.setMaximum(100); + sIncrement.setIncrement(10); + sIncrement.setPageIncrement(10); + if (data.timeIncrement!=null) { + sIncrement.setSelection( (int) (double) data.timeIncrement ); + } + gd2.copy().span(7, 1).applyTo(sIncrement); + final Text sIncrementText = new Text(c, SWT.READ_ONLY | SWT.RIGHT); + gd1.copy().hint(35, SWT.DEFAULT).applyTo(sIncrementText); + sIncrement.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + sIncrementText.setText(sIncrement.getSelection() + " %"); + } + }); + sIncrementText.setText(sIncrement.getSelection() + " %"); + + // 4th line -- AxisMode + Milestone + lAxisMode = new Label(c, 0); + lAxisMode.setText("A&xis Mode:"); + gd1.applyTo(lAxisMode); + cAxisMode = new Combo(c, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY); + GridDataFactory.fillDefaults().indent(5, 0).span(1, 1).applyTo(cAxisMode); + cAxisMode.add("Single"); + cAxisMode.add("Multi"); + String _mode = data.axisMode==YAxisMode.SingleAxis ? "Single" : "Multi"; + cAxisMode.setText( _mode ); + // Filler + GridDataFactory.fillDefaults().span(7, 1).applyTo(new Label(c, 0)); + + bTrackExperimentTime = new Button(c, SWT.CHECK); + bTrackExperimentTime.setText("Ha&irline Tracks Experiment Time"); + bTrackExperimentTime.setSelection( data.trackExperimentTime ); + GridDataFactory.fillDefaults().span(9, 1).applyTo(bTrackExperimentTime); + + // Styling group begins + + Group gStyling = new Group(c, 0); + gStyling.setText("Styling"); + GridDataFactory.fillDefaults().indent(0, 5).grab(true, true).span(9, 1).applyTo(gStyling); + GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(4).applyTo(gStyling); + + // Background color settings + { + bBackgroundGradient = new Button(gStyling, SWT.CHECK); + bBackgroundGradient.setText("&Background Vertical Gradient"); + bBackgroundGradient.setToolTipText("Solid Color or Vertical Gradient"); + bBackgroundGradient.setSelection(data.backgroundGradient); + bBackgroundGradient.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + data.backgroundGradient = bBackgroundGradient.getSelection(); + setBackgroundGradient(data.backgroundGradient); + } + }); + GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(bBackgroundGradient); + + backgroundColor1 = new ColorSelector(gStyling); + backgroundColor2 = new ColorSelector(gStyling); + backgroundColor1.getButton().setToolTipText("Select Gradient Bottom Color"); + backgroundColor2.getButton().setToolTipText("Select Gradient Top Color"); + GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(backgroundColor1.getButton()); + GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(backgroundColor2.getButton()); + backgroundColor1.setColorValue(toRGB(data.backgroundColor1, DEFAULT_BG_COLOR1)); + backgroundColor2.setColorValue(toRGB(data.backgroundColor2, DEFAULT_BG_COLOR2)); + setBackgroundGradient(data.backgroundGradient); + + Button bResetBackgroundColors = new Button(gStyling, SWT.PUSH); + bResetBackgroundColors.setText("Reset"); + bResetBackgroundColors.setToolTipText("Reset Background Color to Default"); + bResetBackgroundColors.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + backgroundColor1.setColorValue(toRGB(null, DEFAULT_BG_COLOR1)); + backgroundColor2.setColorValue(toRGB(null, DEFAULT_BG_COLOR2)); + } + }); + } + + // Grid settings + { + bShowGrid = new Button(gStyling, SWT.CHECK); + bShowGrid.setText("Show &Grid"); + bShowGrid.setToolTipText("Toggle Background Grid Visibility"); + bShowGrid.setSelection(data.showGrid); + GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(bShowGrid); + + gridColor = new ColorSelector(gStyling); + gridColor.getButton().setToolTipText("Select Grid Color"); + GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(gridColor.getButton()); + gridColor.setColorValue(toRGB(data.gridColor, DEFAULT_GRID_COLOR)); + + Button bResetGridColor = new Button(gStyling, SWT.PUSH); + bResetGridColor.setText("Reset"); + bResetGridColor.setToolTipText("Reset Grid Color to Default"); + bResetGridColor.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + gridColor.setColorValue(toRGB(null, DEFAULT_GRID_COLOR)); + } + }); + } + + // Grid settings + { + GridDataFactory.fillDefaults().span(1, 1).applyTo(new Label(gStyling, 0)); + bMilestones = new Button(gStyling, SWT.CHECK); + bMilestones.setText("Show &Milestones"); + bMilestones.setToolTipText("Toggle Milestone Event Visibility"); + bMilestones.setSelection( data.showMilestones ); + GridDataFactory.fillDefaults().indent(0, 0).span(4, 1).applyTo(bMilestones); + } + + // Item visibility group begins + + Group gItemVisibility = new Group(c, 0); + gItemVisibility.setText("Item Visibility"); + GridDataFactory.fillDefaults().indent(0, 5).grab(true, true).span(9, 1).applyTo(gItemVisibility); + GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(3).applyTo(gItemVisibility); + + Label visible = new Label(gItemVisibility, 0); + visible.setText("Visible"); + GridDataFactory.fillDefaults().grab(true, false).applyTo(visible); + new Label(gItemVisibility, 0); + Label hidden = new Label(gItemVisibility, 0); + hidden.setText("Hidden"); + GridDataFactory.fillDefaults().grab(true, false).applyTo(hidden); + + lVisibleItems = new ListViewer(gItemVisibility, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); + GridDataFactory.fillDefaults().hint(200, 200).grab(true, true).applyTo(lVisibleItems.getControl()); + Composite addRemoveButtons = new Composite(gItemVisibility, 0); + GridLayoutFactory.fillDefaults().numColumns(1).applyTo(addRemoveButtons); + GridDataFactory.fillDefaults().grab(false, true).span(1, 1).applyTo(addRemoveButtons); + Button hideButton = new Button(addRemoveButtons, SWT.PUSH); + hideButton.setText("&Hide \u2192"); + GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(hideButton); + Button showButton = new Button(addRemoveButtons, SWT.PUSH); + showButton.setText("\u2190 &Show"); + GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(showButton); + lHiddenItems = new ListViewer(gItemVisibility, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); + GridDataFactory.fillDefaults().hint(200, 200).grab(true, true).applyTo(lHiddenItems.getControl()); + + lVisibleItems.addDoubleClickListener(new OpenChartItemProperties()); + lVisibleItems.setContentProvider(new ItemContentProvider(false)); + lHiddenItems.addDoubleClickListener(new OpenChartItemProperties()); + lHiddenItems.setContentProvider(new ItemContentProvider(true)); + lVisibleItems.setLabelProvider(new ItemLabeler()); + lHiddenItems.setLabelProvider(new ItemLabeler()); + lVisibleItems.setInput(data); + lHiddenItems.setInput(data); + + lVisibleItems.getList().addKeyListener(new SelectAllListener(lVisibleItems)); + lHiddenItems.getList().addKeyListener(new SelectAllListener(lHiddenItems)); + showButton.addSelectionListener(new ShowHideListener(false)); + hideButton.addSelectionListener(new ShowHideListener(true)); + + Image image = FieldDecorationRegistry.getDefault() + .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR) + .getImage(); + + tStartTimeDecor = createDecoration(tStartTime, SWT.LEFT | SWT.CENTER, image); + tLengthDecor = createDecoration(tLength, SWT.LEFT | SWT.CENTER, image); + } + + class ShowHideListener extends SelectionAdapter { + private boolean hide; + + public ShowHideListener(boolean hide) { + this.hide = hide; + } + + @Override + public void widgetSelected(SelectionEvent e) { + ISelection selection = hide ? lVisibleItems.getSelection() : lHiddenItems.getSelection(); + Set selected = ISelectionUtils.filterSetSelection(selection, ItemKey.class); + if (!selected.isEmpty()) { + if (hide) { + data.hiddenItems.addAll(selected); + } else { + data.hiddenItems.removeAll(selected); + } + lVisibleItems.refresh(); + lHiddenItems.refresh(); + } + } + } + + static class SelectAllListener extends KeyAdapter { + private ListViewer list; + + public SelectAllListener(ListViewer list) { + this.list = list; + } + + @Override + public void keyPressed(KeyEvent e) { + if (e.stateMask == SWT.CTRL && e.keyCode == 'a') { + list.getList().selectAll(); + } + } + }; + + class ItemContentProvider extends ArrayContentProvider { + private final boolean expectedHidden; + + public ItemContentProvider(boolean expectedHidden) { + this.expectedHidden = expectedHidden; + } + + @Override + public Object[] getElements(Object inputElement) { + List result = new ArrayList<>(); + for (ItemKey item : data.allItems.keySet()) + if (data.hiddenItems.contains(item) == expectedHidden) + result.add(item); + return result.toArray(); + } + } + + private void setBackgroundGradient(boolean backgroundGradient) { + backgroundColor2.setEnabled(backgroundGradient); + backgroundColor1.getButton().setToolTipText(backgroundGradient ? "Select Gradient Bottom Color" : "Select Solid Color"); + } + + protected Double parseTime(Text text, boolean returnDefault, double defaultValue) { + if (text == null) + return null; + String s = text.getText(); + Double time = ChartComposite.START_VALIDATOR.parse(s); + if (time == null) + return returnDefault ? defaultValue : null; + return time; + } + + protected ControlDecoration createDecoration(Control control, int position, Image image) { + ControlDecoration d = new ControlDecoration(control, position); + d.setMarginWidth(2); + d.setImage(image); + d.hide(); + return d; + } + + class ItemLabeler extends LabelProvider { + @Override + public String getText(Object element) { + ItemKey item = (ItemKey) element; + TrendItem ti = data.allItems.get(item); + return ti.label; + } + } + + protected void parseUiToData() { + data.name = tName.getText(); + data.backgroundColor1 = toColorComponents( backgroundColor1.getColorValue() ); + data.backgroundColor2 = toColorComponents( backgroundColor2.getColorValue() ); + data.showGrid = bShowGrid.getSelection(); + data.gridColor = toColorComponents( gridColor.getColorValue() ); + data.showMilestones = bMilestones.getSelection(); + data.trackExperimentTime = bTrackExperimentTime.getSelection(); + data.axisMode = cAxisMode.getSelectionIndex()==0?YAxisMode.SingleAxis:YAxisMode.MultiAxis; + data.timeIncrement = (double) sIncrement.getSelection(); + data.timeLength = ChartComposite.LENGTH_VALIDATOR.parse(tLength.getText()); + data.timeStart = ChartComposite.START_VALIDATOR.parse(tStartTime.getText()); + } + + @Override + protected void buttonPressed(int buttonId) { + if (ChartDialogConstants.APPLY_ID == buttonId) { + applyPressed(); + } else { + super.buttonPressed(buttonId); + } + } + + private void applyPressed() { + if (applyAction != null) { + parseUiToData(); + if (!baseData.equals(data)) { + baseData.readFrom(data); + applyAction.run(); + } + } + } + + @Override + protected void okPressed() { + parseUiToData(); + if (applyAction != null && !baseData.equals(data)) + applyAction.run(); + super.okPressed(); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Edit Chart"); + } + + public void validate() { + String startTimeError = ChartComposite.START_VALIDATOR.isValid(tStartTime.getText()); + String lengthError = ChartComposite.LENGTH_VALIDATOR.isValid(tLength.getText()); + setDecoration(tStartTimeDecor, startTimeError); + setDecoration(tLengthDecor, lengthError); + boolean ok = startTimeError == null && lengthError == null; + setFinishable(ok); + } + + private void setDecoration(ControlDecoration decor, String desc) { + if (decor == null) + return; + if (desc != null) { + decor.setDescriptionText(desc); + decor.show(); + } else { + decor.hide(); + } + } + + protected void setFinishable(boolean ok) { + getButton(OK).setEnabled(ok); + } + + private static RGB toRGB(float[] components, RGB defaultValue) { + if (components == null || components.length < 3) + return defaultValue; + Color c = new Color(components[0], components[1], components[2]); + return new RGB(c.getRed(), c.getGreen(), c.getBlue()); + } + + private static float[] toColorComponents(RGB rgb) { + return new Color(rgb.red, rgb.green, rgb.blue).getColorComponents(new float[3]); + } + + class OpenChartItemProperties implements IDoubleClickListener { + @Override + public void doubleClick(DoubleClickEvent event) { + final ItemKey item = ISelectionUtils.filterSingleSelection(event.getSelection(), ItemKey.class); + if (item == null) + return; + try { + final ChartAndSubscriptionItemData data = Simantics.getSession().syncRequest( + new ChartAndSubscriptionItemReadQuery(item.resource.getResource())); + if (currentItemDialog != null && currentItemDialog.getShell() != null && !currentItemDialog.getShell().isDisposed()) { + // TODO: reinitialize existing dialog with the specified data. + // Close current dialog before opening new one. + currentItemDialog.close(); + } + currentItemDialog = ChartDoubleClickHandler.openChartItemPropertiesDialog( + event.getViewer().getControl().getShell(), + item.resource.getResource(), + data, + false); + } catch (DatabaseException e) { + Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Problems opening chart item property dialog.")); + } + } + } + +}