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