]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.charts/src/org/simantics/charts/ui/ChartAndSubscriptionItemDialog.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.charts / src / org / simantics / charts / ui / ChartAndSubscriptionItemDialog.java
diff --git a/bundles/org.simantics.charts/src/org/simantics/charts/ui/ChartAndSubscriptionItemDialog.java b/bundles/org.simantics.charts/src/org/simantics/charts/ui/ChartAndSubscriptionItemDialog.java
new file mode 100644 (file)
index 0000000..e7b1104
--- /dev/null
@@ -0,0 +1,629 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.charts.ui;\r
+\r
+import java.awt.Color;\r
+\r
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;\r
+import org.eclipse.core.runtime.preferences.InstanceScope;\r
+import org.eclipse.jface.dialogs.Dialog;\r
+import org.eclipse.jface.fieldassist.ControlDecoration;\r
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;\r
+import org.eclipse.jface.layout.GridDataFactory;\r
+import org.eclipse.jface.layout.GridLayoutFactory;\r
+import org.eclipse.jface.preference.ColorSelector;\r
+import org.eclipse.jface.util.IPropertyChangeListener;\r
+import org.eclipse.jface.util.PropertyChangeEvent;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.ModifyEvent;\r
+import org.eclipse.swt.events.ModifyListener;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.RGB;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Combo;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Control;\r
+import org.eclipse.swt.widgets.Group;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Spinner;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.simantics.charts.preference.ChartPreferences;\r
+import org.simantics.charts.query.ChartAndSubscriptionItemData;\r
+import org.simantics.databoard.util.URIStringUtils;\r
+import org.simantics.modeling.preferences.SubscriptionPreferences;\r
+import org.simantics.trend.configuration.Scale;\r
+import org.simantics.trend.configuration.TrendItem.DrawMode;\r
+import org.simantics.trend.impl.JarisPaints;\r
+\r
+/**\r
+ * ChartAndSubscriptionItemDialog is a dialog that has the following property\r
+ * queries:\r
+ *   Chart name  (Read only)\r
+ *   Variable    (Read only)\r
+ *   Label\r
+ *   Draw Mode   (Enumeration)\r
+ *   Scale, min, max ( Enum, int, int)\r
+ *   Subscription ( Text )\r
+ *   Deadband, Interval, Gain, Bias, Unit (Double)\r
+ *   Stroke settings (width, color)\r
+ * \r
+ * If the dialog is opened in binary mode the content is more stripped.\r
+ *   Chart name\r
+ *   Variable\r
+ *   Label\r
+ *   Subscription\r
+ *   Stroke settings\r
+ * \r
+ * @author toni.kalajainen\r
+ */\r
+public class ChartAndSubscriptionItemDialog extends Dialog {\r
+\r
+    private static final String MANUAL = "Manual";\r
+    private static final String AUTO = "Auto";\r
+\r
+    // UI\r
+    Label lChart, lRVI, lLabel, lDrawMode, lScale, lMin, lMax, lSubscription, lDeadband, lInterval, lGain, lBias, lUnit;\r
+    Text tRVI, tLabel, tDeadband, tInterval, tGain, tBias, tUnit;\r
+    Combo cSubscription;\r
+    Button saveAsPrefs;\r
+\r
+    // chart specific, not initialized, if includeChartSpecificProperties=false\r
+    Text tChart, tMin, tMax;\r
+    Combo cDrawMode, cScale;\r
+    Spinner sStrokeWidth;\r
+    ColorSelector colorSelector;\r
+\r
+    // Input error decorations\r
+    ControlDecoration tMinDecor;\r
+    ControlDecoration tMaxDecor;\r
+    ControlDecoration tDeadbandDecor;\r
+    ControlDecoration tIntervalDecor;\r
+    ControlDecoration tGainDecor;\r
+    ControlDecoration tBiasDecor;\r
+\r
+    //\r
+    ChartAndSubscriptionItemData baseData = new ChartAndSubscriptionItemData();\r
+    ChartAndSubscriptionItemData data;\r
+\r
+    final Runnable applyAction;\r
+\r
+    IEclipsePreferences chartnode; // chart specific, not initialized, if includeChartSpecificProperties=false\r
+    IEclipsePreferences subscriptionnode;\r
+    boolean includeChartSpecificProperties;\r
+\r
+    public ChartAndSubscriptionItemDialog(Shell parentShell, ChartAndSubscriptionItemData data, boolean includeChartSpecificProperties) {\r
+        this(parentShell, data, includeChartSpecificProperties, null);\r
+    }\r
+\r
+    public ChartAndSubscriptionItemDialog(Shell parentShell, ChartAndSubscriptionItemData data, boolean includeChartSpecificProperties, Runnable applyAction) {\r
+        super(parentShell);\r
+        this.data = data;\r
+        this.baseData.readFrom(data);\r
+        this.includeChartSpecificProperties = includeChartSpecificProperties;\r
+        this.applyAction = applyAction;\r
+\r
+        if(includeChartSpecificProperties)\r
+            chartnode = InstanceScope.INSTANCE.getNode( ChartPreferences.P_NODE );\r
+        subscriptionnode = InstanceScope.INSTANCE.getNode( SubscriptionPreferences.P_NODE );\r
+\r
+        setShellStyle(SWT.RESIZE | SWT.TITLE | SWT.CLOSE | SWT.BORDER);\r
+    }\r
+\r
+    @Override\r
+    protected Control createContents(Composite parent) {\r
+        Control c = super.createContents(parent);\r
+        validate();\r
+        return c;\r
+    }\r
+\r
+    @Override\r
+    protected void createButtonsForButtonBar(Composite parent) {\r
+        if (applyAction != null)\r
+            createButton(parent, ChartDialogConstants.APPLY_ID, ChartDialogConstants.APPLY_LABEL, true);\r
+        super.createButtonsForButtonBar(parent);\r
+    }\r
+\r
+    public void setInput(ChartAndSubscriptionItemData data) {\r
+        // TODO: implement so that this reinitializes the UI of the dialog according to the new specified data\r
+    }\r
+\r
+    protected void disposeDialogAreaContents() {\r
+        Composite area = (Composite) dialogArea;\r
+        for (Control child : area.getChildren())\r
+            child.dispose();\r
+    }\r
+\r
+    @Override\r
+    protected Control createDialogArea(Composite parent) {\r
+        Composite c = (Composite) super.createDialogArea(parent);\r
+        GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(9).applyTo(c);\r
+        createDialogAreaContents(c);\r
+        return c;\r
+    }\r
+\r
+    protected void createDialogAreaContents(Composite c) {\r
+        GridDataFactory gd1 = GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(1, 1);\r
+        GridDataFactory gd2 = GridDataFactory.fillDefaults().grab(true, false).indent(5, 0).span(8, 1);\r
+\r
+        // 1st line - Chart: [chart name]\r
+        if(includeChartSpecificProperties) {\r
+            lChart = new Label(c, 0);\r
+            lChart.setText("Chart:");\r
+            gd1.applyTo(lChart);\r
+            tChart = new Text(c, SWT.BORDER | SWT.READ_ONLY);\r
+            //tChart.setEnabled( false );\r
+            if ( data.chartName != null ) tChart.setText( data.chartName );\r
+            gd2.applyTo(tChart);\r
+        }\r
+\r
+        // 2nd line - Variable Reference: [chart item label]\r
+        lRVI = new Label(c, 0);\r
+        lRVI.setText("Variable: ");\r
+        gd1.applyTo(lRVI);\r
+        tRVI = new Text(c, SWT.BORDER | SWT.READ_ONLY);\r
+        //tRVI.setEnabled(false);\r
+        if ( data.variableReference!=null ) tRVI.setText(URIStringUtils.unescape( data.variableReference ));\r
+        gd2.applyTo(tRVI);\r
+\r
+        // 3rd line - Label: [chart item label]\r
+        lLabel = new Label(c, 0);\r
+        lLabel.setText("&Label: ");\r
+        gd1.applyTo(lLabel);\r
+        tLabel = new Text(c, SWT.BORDER);\r
+        if ( data.label!=null ) tLabel.setText(data.label);\r
+        gd2.applyTo(tLabel);\r
+\r
+//        if (!data.binaryMode) {\r
+//             // 4th line - DrawMode: [ drop-down-list V ]\r
+//             lDrawMode = new Label(c, 0);\r
+//             lDrawMode.setText("DrawMode :");\r
+//             gd1.applyTo(lDrawMode);\r
+//             cDrawMode = new Combo(c, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);\r
+//             for (DrawMode dm : DrawMode.values()) cDrawMode.add( dm.name() );\r
+//             String _drawmode = data.drawmode!=null ? data.drawmode.toString() : chartnode.get( ChartPreferences.P_DRAWMODE, ChartPreferences.DEFAULT_DRAWMODE ); \r
+//             cDrawMode.setText( _drawmode );\r
+//             gd2.applyTo(cDrawMode);\r
+//        }\r
+\r
+        if (!data.binaryMode && includeChartSpecificProperties) {\r
+               // 5th line - Scale: [ Auto/Manual ] Min: [ ## ] Max: [ ## ]\r
+               lScale = new Label(c, 0);\r
+               lScale.setText("&Scale: ");\r
+               gd1.applyTo(lScale);\r
+\r
+               Composite scaleComposite = new Composite(c, 0);\r
+               gd2.applyTo(scaleComposite);\r
+               GridLayoutFactory.fillDefaults().numColumns(8).applyTo(scaleComposite);\r
+\r
+               cScale = new Combo(scaleComposite, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);\r
+               cScale.add(AUTO);\r
+               cScale.add(MANUAL);\r
+               String _scale = data.scale != null ? data.scale.toString() : chartnode.get( ChartPreferences.P_SCALEMODE, ChartPreferences.DEFAULT_SCALEMODE ); \r
+               cScale.setText( _scale );\r
+               GridDataFactory.fillDefaults().span(2, 1).applyTo(cScale);\r
+               \r
+               lMin = new Label(scaleComposite, 0);\r
+               lMin.setText("&Min: ");\r
+               GridDataFactory.fillDefaults().span(1, 1).align(SWT.FILL, SWT.CENTER).applyTo(lMin);\r
+               tMin = new Text(scaleComposite, SWT.BORDER);\r
+               Double _min = data.min;\r
+               if ( _min == null ) _min = chartnode.getDouble( ChartPreferences.P_SCALE_MIN, 0.0);\r
+               tMin.setText( Double.toString(_min) );\r
+               GridDataFactory.fillDefaults().hint(80, SWT.DEFAULT).indent(5, 0).grab(true, false).span(2, 1).applyTo(tMin);\r
+               tMin.addModifyListener(new ModifyListener() {\r
+                   @Override\r
+                   public void modifyText(ModifyEvent e) {\r
+                       data.min = parseDouble(tMin, false, 0.0);\r
+                    if (data.min != null)\r
+                        cScale.setText(MANUAL);\r
+                       validate();\r
+                   }\r
+               });\r
+\r
+               lMax = new Label(scaleComposite, 0);\r
+               lMax.setText("Ma&x: ");\r
+               GridDataFactory.fillDefaults().span(1, 1).align(SWT.FILL, SWT.CENTER).applyTo(lMax);\r
+               tMax = new Text(scaleComposite, SWT.BORDER);\r
+               Double _max = data.max;\r
+               if ( _max==null ) _max = chartnode.getDouble( ChartPreferences.P_SCALE_MAX, 100.0);\r
+               tMax.setText( Double.toString(_max) );\r
+               GridDataFactory.fillDefaults().hint(80, SWT.DEFAULT).indent(5, 0).grab(true, false).span(2, 1).applyTo(tMax);\r
+            tMax.addModifyListener(new ModifyListener() {\r
+                @Override\r
+                public void modifyText(ModifyEvent e) {\r
+                    data.max = parseDouble(tMax, false, 100.0);\r
+                    if (data.max != null)\r
+                        cScale.setText(MANUAL);\r
+                    validate();\r
+                }\r
+            });\r
+        }\r
+\r
+        // 6th line - Subscription: [ Default / others ] [New] \r
+        lSubscription = new Label(c, 0);\r
+        lSubscription.setText("S&ubscription: ");\r
+        gd1.applyTo(lSubscription);\r
+        cSubscription = new Combo(c, SWT.BORDER);\r
+        for (String s : data.subscriptions) cSubscription.add(s);\r
+        gd2.applyTo(cSubscription);\r
+        String _subscription = data.subscription;\r
+        if ( _subscription == null ) _subscription = subscriptionnode.get( SubscriptionPreferences.P_SUBSCRIPTION_DEFAULT, data.subscriptions.length==0 ? "Default" : cSubscription.getItem(0) );\r
+        cSubscription.setText( _subscription );\r
+\r
+        if (!data.binaryMode) {\r
+               // 7th line - Deadband: [deadband] Interval: [interval]\r
+               lDeadband = new Label(c, 0);\r
+               lDeadband.setText("&Deadband: ");\r
+               gd1.applyTo(lDeadband);\r
+               tDeadband = new Text(c, SWT.BORDER);\r
+               Double _deadband = data.deadband;\r
+               if ( _deadband == null ) _deadband = subscriptionnode.getDouble( SubscriptionPreferences.P_SUBSCRIPTION_DEADBAND, SubscriptionPreferences.DEFAULT_SUBSCRIPTION_DEADBAND );\r
+               tDeadband.setText( Double.toString(_deadband) );\r
+               tDeadband.setEditable(data.mutableCollectionSettings);\r
+               GridDataFactory.fillDefaults().hint(110, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tDeadband);\r
+            tDeadband.addModifyListener(new ModifyListener() {\r
+                @Override\r
+                public void modifyText(ModifyEvent e) {\r
+                    data.deadband = parseDouble(tDeadband, false, 0.0);\r
+                    validate();\r
+                }\r
+            });\r
+\r
+               lInterval = new Label(c, 0);\r
+               lInterval.setText("&Interval: ");\r
+               lInterval.setToolTipText("Sampling Interval");\r
+               GridDataFactory.fillDefaults().span(2, 1).applyTo(lInterval);\r
+               tInterval = new Text(c, SWT.BORDER);\r
+               Double _interval = data.interval;\r
+               if ( _interval == null ) _interval = subscriptionnode.getDouble( SubscriptionPreferences.P_SUBSCRIPTION_INTERVAL, SubscriptionPreferences.DEFAULT_SUBSCRIPTION_INTERVAL );\r
+               tInterval.setText( Double.toString(_interval) );\r
+               tInterval.setEditable(data.mutableCollectionSettings);\r
+               GridDataFactory.fillDefaults().hint(110, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tInterval);\r
+            tInterval.addModifyListener(new ModifyListener() {\r
+                @Override\r
+                public void modifyText(ModifyEvent e) {\r
+                    data.interval = parseDouble(tInterval, false, 0.0);\r
+                    validate();\r
+                }\r
+            });\r
+        }\r
+\r
+        // 8th line - Gain: [gain] Bias: [bias]\r
+        if (!data.binaryMode) {\r
+               lGain = new Label(c, 0);\r
+               lGain.setText("&Gain: ");\r
+               gd1.applyTo(lGain);\r
+               tGain = new Text(c, SWT.BORDER);\r
+               Double _gain = data.gain;\r
+               if (_gain == null) _gain = subscriptionnode.getDouble( SubscriptionPreferences.P_SUBSCRIPTION_GAIN, 1.0);\r
+               tGain.setText( Double.toString(_gain) );\r
+               GridDataFactory.fillDefaults().hint(110, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tGain);\r
+            tGain.addModifyListener(new ModifyListener() {\r
+                @Override\r
+                public void modifyText(ModifyEvent e) {\r
+                    data.gain = parseDouble(tGain, false, 1.0);\r
+                    validate();\r
+                }\r
+            });\r
+\r
+               lBias = new Label(c, 0);\r
+               lBias.setText("&Bias: ");\r
+               GridDataFactory.fillDefaults().span(2, 1).applyTo(lBias);\r
+               tBias = new Text(c, SWT.BORDER);\r
+               Double _bias = data.bias;\r
+               if (_bias == null) _bias = subscriptionnode.getDouble( SubscriptionPreferences.P_SUBSCRIPTION_BIAS, 0.0);\r
+               tBias.setText( Double.toString(_bias) );\r
+               GridDataFactory.fillDefaults().hint(110, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tBias);\r
+            tBias.addModifyListener(new ModifyListener() {\r
+                @Override\r
+                public void modifyText(ModifyEvent e) {\r
+                    data.bias = parseDouble(tBias, false, 0.0);\r
+                    validate();\r
+                }\r
+            });\r
+        }\r
+\r
+        // 9th line - Unit: [unit]\r
+        if (!data.binaryMode) {\r
+               lUnit = new Label(c, 0);\r
+               lUnit.setText("U&nit: ");\r
+               gd1.applyTo(lUnit);\r
+               tUnit = new Text(c, SWT.BORDER);\r
+               String _unit = data.unit;\r
+               if (_unit==null) _unit = subscriptionnode.get( SubscriptionPreferences.P_SUBSCRIPTION_UNIT, "");\r
+               tUnit.setText( _unit );\r
+               GridDataFactory.fillDefaults().hint(100, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tUnit);\r
+               // Fill line\r
+            GridDataFactory.fillDefaults().span(5, 1).applyTo(new Label(c, 0));\r
+        }\r
+\r
+        // Disable fields that edit subscription item\r
+        if (!data.hasSubscriptionItem) {\r
+               tLabel.setEnabled( false );\r
+               cSubscription.setEnabled( false );\r
+               tDeadband.setEnabled( false );\r
+               tInterval.setEnabled( false );\r
+               tGain.setEnabled( false );\r
+               tBias.setEnabled( false );\r
+               tUnit.setEnabled( false );\r
+        }\r
+\r
+        // 10th line - Color stroke / color\r
+        if (includeChartSpecificProperties) {\r
+            createStrokeGroup(c);\r
+        }\r
+\r
+        saveAsPrefs = new Button(c, SWT.CHECK);\r
+        saveAsPrefs.setText("Sav&e as new defaults");\r
+        saveAsPrefs.setToolTipText("Sav&e these settings as new defaults");\r
+        // Always unchecked by default.\r
+        saveAsPrefs.setSelection(false);\r
+        GridDataFactory.fillDefaults().hint(100, SWT.DEFAULT).span(9, 1).applyTo(saveAsPrefs);\r
+\r
+        // Error decorations\r
+        Image image = FieldDecorationRegistry.getDefault()\r
+                .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR)\r
+                .getImage();\r
+\r
+        if (!data.binaryMode) {\r
+            if (includeChartSpecificProperties) {\r
+                tMinDecor = createDecoration(tMin, SWT.LEFT | SWT.CENTER, image);\r
+                tMaxDecor = createDecoration(tMax, SWT.LEFT | SWT.CENTER, image);\r
+            }\r
+            tDeadbandDecor = createDecoration(tDeadband, SWT.LEFT | SWT.CENTER, image);\r
+            tIntervalDecor = createDecoration(tInterval, SWT.LEFT | SWT.CENTER, image);\r
+            tGainDecor = createDecoration(tGain, SWT.LEFT | SWT.CENTER, image);\r
+            tBiasDecor = createDecoration(tBias, SWT.LEFT | SWT.CENTER, image);\r
+        }\r
+\r
+        // Ensure that the data structure contains all the values that were\r
+        // initialized into the UI.\r
+        parseUiToData();\r
+\r
+        tLabel.setFocus();\r
+    }\r
+\r
+    private void createStrokeGroup(Composite c) {\r
+        GridDataFactory gd1 = GridDataFactory.fillDefaults().indent(10, 0).align(SWT.FILL, SWT.CENTER).span(1, 1);\r
+\r
+        Group gStroke = new Group(c, 0);\r
+        gStroke.setText("Trend Line Stroke");\r
+        GridLayoutFactory.fillDefaults().margins(8, 8).spacing(10, 10).numColumns(5).applyTo(gStroke);\r
+        GridDataFactory.fillDefaults().span(9, 1).applyTo(gStroke);\r
+\r
+        if (!data.binaryMode) {\r
+            // Custom stroke\r
+            Label lStrokeWidth = new Label(gStroke, 0);\r
+            lStrokeWidth.setText("&Width:");\r
+            gd1.applyTo(lStrokeWidth);\r
+            sStrokeWidth = new Spinner(gStroke, SWT.BORDER);\r
+            sStrokeWidth.setDigits(1);\r
+            sStrokeWidth.setIncrement(5);\r
+            sStrokeWidth.setMinimum(10);\r
+            sStrokeWidth.setMaximum(50);\r
+            GridDataFactory.fillDefaults().indent(10, 0).grab(false, false).span(1, 1).applyTo(sStrokeWidth);\r
+\r
+            if (data.strokeWidth != null) {\r
+                sStrokeWidth.setSelection((int) (data.strokeWidth * 10));\r
+            }\r
+\r
+            sStrokeWidth.addSelectionListener(new SelectionAdapter() {\r
+                @Override\r
+                public void widgetSelected(SelectionEvent e) {\r
+                    float newWidth = ((float) sStrokeWidth.getSelection()) * 0.1f;\r
+                    data.strokeWidth = newWidth;\r
+                }\r
+            });\r
+        }\r
+\r
+        Label lColor = new Label(gStroke, 0);\r
+        lColor.setText("&Color: ");\r
+        gd1.applyTo(lColor);\r
+        colorSelector = new ColorSelector(gStroke);\r
+        GridDataFactory.fillDefaults().indent(10, 0).span(1, 1).grab(false, false).applyTo(colorSelector.getButton());\r
+        final RGB indexColor = toRGB(JarisPaints.getColor(data.index));\r
+        RGB customColor = data.color != null ? toRGB(data.color) : indexColor;\r
+        colorSelector.setColorValue(customColor);\r
+\r
+        final Button bResetColor = new Button(gStroke, SWT.PUSH);\r
+        bResetColor.setText("Reset Color");\r
+        bResetColor.setToolTipText("Reset Color to Item Index Default");\r
+        bResetColor.setEnabled(!indexColor.equals(customColor));\r
+\r
+        colorSelector.addListener(new IPropertyChangeListener() {\r
+            @Override\r
+            public void propertyChange(PropertyChangeEvent event) {\r
+                RGB rgb = colorSelector.getColorValue();\r
+                data.color = new Color(rgb.red, rgb.green, rgb.blue).getColorComponents(new float[4]);\r
+                data.color[3] = 1;\r
+                bResetColor.setEnabled(!indexColor.equals(rgb));\r
+            }\r
+        });\r
+\r
+        bResetColor.addSelectionListener(new SelectionAdapter() {\r
+            @Override\r
+            public void widgetSelected(SelectionEvent e) {\r
+                data.color = null;\r
+                colorSelector.setColorValue(toRGB(JarisPaints.getColor(data.index)));\r
+                bResetColor.setEnabled(false);\r
+            }\r
+        });\r
+    }\r
+\r
+    protected RGB toRGB(float[] color) {\r
+        float r = color[0];\r
+        float g = color[1];\r
+        float b = color[2];\r
+        return new RGB( (int) (r*255+0.5), (int) (g*255+0.5), (int) (b*255+0.5) );\r
+    }\r
+\r
+    protected RGB toRGB(Color color) {\r
+        return new RGB(color.getRed(), color.getGreen(), color.getBlue());\r
+    }\r
+\r
+    protected ControlDecoration createDecoration(Control control, int position, Image image) {\r
+        ControlDecoration d = new ControlDecoration(control, position);\r
+        d.setMarginWidth(2);\r
+        d.setImage(image);\r
+        d.hide();\r
+        return d;\r
+    }\r
+\r
+    protected Double parseDouble(Text text, boolean returnDefault, double defaultValue) {\r
+        if (text == null)\r
+            return null;\r
+        try {\r
+            String s = text.getText();\r
+            s = s.replace(',', '.');\r
+            return Double.valueOf(s);\r
+        } catch ( NumberFormatException nfe ) {\r
+            return returnDefault ? defaultValue : null;\r
+        }\r
+    }\r
+\r
+    protected void parseUiToData() {\r
+        data.label = tLabel.getText();\r
+        if (!data.binaryMode) {\r
+            if (includeChartSpecificProperties) {\r
+                data.min = parseDouble(tMin, true, 0.0);\r
+                data.max = parseDouble(tMax, true, 100.0);\r
+            }\r
+            data.interval = parseDouble(tInterval, true, 0.0);\r
+            data.deadband = parseDouble(tDeadband, true, 0.0);\r
+            data.gain = parseDouble(tGain, true, 1.0);\r
+            data.bias = parseDouble(tBias, true, 0.0);\r
+            data.unit = tUnit.getText();\r
+\r
+            if (includeChartSpecificProperties) {\r
+//                data.drawmode = DrawMode.valueOf( cDrawMode.getText() );\r
+                data.drawmode = DrawMode.Line;\r
+\r
+                if (cScale.getText().equals("Manual")) {\r
+                    data.scale = new Scale.Manual(data.min, data.max);\r
+                } else if (cScale.getText().equals("Auto")) {\r
+                    data.scale = new Scale.Auto();\r
+                }\r
+            }\r
+        }\r
+        data.subscription = cSubscription.getText();\r
+    }\r
+\r
+    @Override\r
+    protected void buttonPressed(int buttonId) {\r
+        if (ChartDialogConstants.APPLY_ID == buttonId) {\r
+            applyPressed();\r
+        } else {\r
+            super.buttonPressed(buttonId);\r
+        }\r
+    }\r
+\r
+    private void applyPressed() {\r
+        if (applyAction != null) {\r
+            parseUiToData();\r
+            if (!baseData.equals(data)) {\r
+                baseData.readFrom(data);\r
+                applyAction.run();\r
+            }\r
+        }\r
+    }\r
+\r
+    @Override\r
+    protected void okPressed() {\r
+        boolean savePrefs = saveAsPrefs.getSelection();\r
+        parseUiToData();\r
+\r
+        if (!data.binaryMode && savePrefs) {\r
+            if (includeChartSpecificProperties) {\r
+                chartnode.put( ChartPreferences.P_DRAWMODE, data.drawmode.name() );\r
+                chartnode.put( ChartPreferences.P_SCALEMODE, data.scale instanceof Scale.Manual ? "Manual" : "Auto" );\r
+                chartnode.putDouble( ChartPreferences.P_SCALE_MIN, data.min );\r
+                chartnode.putDouble( ChartPreferences.P_SCALE_MAX, data.max );\r
+            }\r
+            subscriptionnode.putDouble( SubscriptionPreferences.P_SUBSCRIPTION_DEADBAND, data.deadband );\r
+            subscriptionnode.putDouble( SubscriptionPreferences.P_SUBSCRIPTION_INTERVAL, data.interval );\r
+            subscriptionnode.putDouble( SubscriptionPreferences.P_SUBSCRIPTION_GAIN, data.gain );\r
+            subscriptionnode.putDouble( SubscriptionPreferences.P_SUBSCRIPTION_BIAS, data.bias );\r
+            subscriptionnode.put( SubscriptionPreferences.P_SUBSCRIPTION_UNIT, data.unit );\r
+        }\r
+\r
+        if (savePrefs)\r
+            subscriptionnode.put( SubscriptionPreferences.P_SUBSCRIPTION_DEFAULT, data.subscription );\r
+\r
+        if (applyAction != null && !baseData.equals(data))\r
+            applyAction.run();\r
+        super.okPressed();\r
+    }\r
+\r
+    @Override\r
+    protected void configureShell(Shell newShell) {\r
+        super.configureShell(newShell);\r
+        newShell.setText(\r
+                includeChartSpecificProperties ? "Edit Chart Item"\r
+                                               : "Edit Subscription Item"\r
+                );\r
+    }\r
+\r
+    public void validate() {\r
+        boolean ok = true;\r
+        if (!data.binaryMode) {\r
+            if (includeChartSpecificProperties) {\r
+                setDecoration(tMinDecor, null);\r
+                setDecoration(tMaxDecor, null);\r
+                if (tMin != null && tMax != null) {\r
+                    if (data.min == null || data.max == null) {\r
+                        ok = false;\r
+                        if (data.min == null)\r
+                            setDecoration(tMinDecor, "Invalid non-numeric value");\r
+                        if (data.max == null)\r
+                            setDecoration(tMaxDecor, "Invalid non-numeric value");\r
+                    } else {\r
+                        if (data.min >= data.max) {\r
+                            setDecoration(tMinDecor, "Minimum value must be smaller than maximum value");\r
+                            setDecoration(tMaxDecor, "Maximum value must be larger than minimum value");\r
+                            ok = false;\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+\r
+            ok &= data.interval != null && data.deadband != null && data.bias != null && data.gain != null;\r
+            setDecoration(tIntervalDecor, data.interval == null ? "Invalid non-numeric value" : null);\r
+            if (data.interval != null && data.interval < 0)\r
+                setDecoration(tIntervalDecor, "Sampling interval cannot be negative");\r
+            setDecoration(tDeadbandDecor, data.deadband == null ? "Invalid non-numeric value" : null);\r
+            if (data.deadband != null && data.deadband < 0)\r
+                setDecoration(tDeadbandDecor, "Deadband cannot be negative");\r
+            setDecoration(tGainDecor, data.gain == null ? "Invalid non-numeric value" : null);\r
+            setDecoration(tBiasDecor, data.bias == null ? "Invalid non-numeric value" : null);\r
+        }\r
+        setFinishable(ok);\r
+    }\r
+\r
+    private void setDecoration(ControlDecoration decor, String desc) {\r
+        if (decor == null)\r
+            return;\r
+        if (desc != null) {\r
+            decor.setDescriptionText(desc);\r
+            decor.show();\r
+        } else {\r
+            decor.hide();\r
+        }\r
+    }\r
+\r
+    protected void setFinishable(boolean ok) {\r
+        getButton(OK).setEnabled(ok);\r
+    }\r
+\r
+}\r