]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.charts/src/org/simantics/charts/ui/ChartAndSubscriptionItemDialog.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.charts / src / org / simantics / charts / ui / ChartAndSubscriptionItemDialog.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
3  * Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.charts.ui;
13
14 import java.awt.Color;
15
16 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
17 import org.eclipse.core.runtime.preferences.InstanceScope;
18 import org.eclipse.jface.dialogs.Dialog;
19 import org.eclipse.jface.fieldassist.ControlDecoration;
20 import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
21 import org.eclipse.jface.layout.GridDataFactory;
22 import org.eclipse.jface.layout.GridLayoutFactory;
23 import org.eclipse.jface.preference.ColorSelector;
24 import org.eclipse.jface.util.IPropertyChangeListener;
25 import org.eclipse.jface.util.PropertyChangeEvent;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.events.ModifyEvent;
28 import org.eclipse.swt.events.ModifyListener;
29 import org.eclipse.swt.events.SelectionAdapter;
30 import org.eclipse.swt.events.SelectionEvent;
31 import org.eclipse.swt.graphics.Image;
32 import org.eclipse.swt.graphics.RGB;
33 import org.eclipse.swt.widgets.Button;
34 import org.eclipse.swt.widgets.Combo;
35 import org.eclipse.swt.widgets.Composite;
36 import org.eclipse.swt.widgets.Control;
37 import org.eclipse.swt.widgets.Group;
38 import org.eclipse.swt.widgets.Label;
39 import org.eclipse.swt.widgets.Shell;
40 import org.eclipse.swt.widgets.Spinner;
41 import org.eclipse.swt.widgets.Text;
42 import org.simantics.charts.preference.ChartPreferences;
43 import org.simantics.charts.query.ChartAndSubscriptionItemData;
44 import org.simantics.databoard.util.URIStringUtils;
45 import org.simantics.modeling.preferences.SubscriptionPreferences;
46 import org.simantics.trend.configuration.Scale;
47 import org.simantics.trend.configuration.TrendItem.DrawMode;
48 import org.simantics.trend.impl.JarisPaints;
49
50 /**
51  * ChartAndSubscriptionItemDialog is a dialog that has the following property
52  * queries:
53  *   Chart name  (Read only)
54  *   Variable    (Read only)
55  *   Label
56  *   Draw Mode   (Enumeration)
57  *   Scale, min, max ( Enum, int, int)
58  *   Subscription ( Text )
59  *   Deadband, Interval, Gain, Bias, Unit (Double)
60  *   Stroke settings (width, color)
61  * 
62  * If the dialog is opened in binary mode the content is more stripped.
63  *   Chart name
64  *   Variable
65  *   Label
66  *   Subscription
67  *   Stroke settings
68  * 
69  * @author toni.kalajainen
70  */
71 public class ChartAndSubscriptionItemDialog extends Dialog {
72
73     private static final String MANUAL = "Manual";
74     private static final String AUTO = "Auto";
75
76     // UI
77     Label lChart, lRVI, lLabel, lDrawMode, lScale, lMin, lMax, lSubscription, lDeadband, lInterval, lGain, lBias, lUnit;
78     Text tRVI, tLabel, tDeadband, tInterval, tGain, tBias, tUnit;
79     Combo cSubscription;
80     Button saveAsPrefs;
81
82     // chart specific, not initialized, if includeChartSpecificProperties=false
83     Text tChart, tMin, tMax;
84     Combo cDrawMode, cScale;
85     Spinner sStrokeWidth;
86     ColorSelector colorSelector;
87
88     // Input error decorations
89     ControlDecoration tMinDecor;
90     ControlDecoration tMaxDecor;
91     ControlDecoration tDeadbandDecor;
92     ControlDecoration tIntervalDecor;
93     ControlDecoration tGainDecor;
94     ControlDecoration tBiasDecor;
95
96     //
97     ChartAndSubscriptionItemData baseData = new ChartAndSubscriptionItemData();
98     ChartAndSubscriptionItemData data;
99
100     final Runnable applyAction;
101
102     IEclipsePreferences chartnode; // chart specific, not initialized, if includeChartSpecificProperties=false
103     IEclipsePreferences subscriptionnode;
104     boolean includeChartSpecificProperties;
105
106     public ChartAndSubscriptionItemDialog(Shell parentShell, ChartAndSubscriptionItemData data, boolean includeChartSpecificProperties) {
107         this(parentShell, data, includeChartSpecificProperties, null);
108     }
109
110     public ChartAndSubscriptionItemDialog(Shell parentShell, ChartAndSubscriptionItemData data, boolean includeChartSpecificProperties, Runnable applyAction) {
111         super(parentShell);
112         this.data = data;
113         this.baseData.readFrom(data);
114         this.includeChartSpecificProperties = includeChartSpecificProperties;
115         this.applyAction = applyAction;
116
117         if(includeChartSpecificProperties)
118             chartnode = InstanceScope.INSTANCE.getNode( ChartPreferences.P_NODE );
119         subscriptionnode = InstanceScope.INSTANCE.getNode( SubscriptionPreferences.P_NODE );
120
121         setShellStyle(SWT.RESIZE | SWT.TITLE | SWT.CLOSE | SWT.BORDER);
122     }
123
124     @Override
125     protected Control createContents(Composite parent) {
126         Control c = super.createContents(parent);
127         validate();
128         return c;
129     }
130
131     @Override
132     protected void createButtonsForButtonBar(Composite parent) {
133         if (applyAction != null)
134             createButton(parent, ChartDialogConstants.APPLY_ID, ChartDialogConstants.APPLY_LABEL, true);
135         super.createButtonsForButtonBar(parent);
136     }
137
138     public void setInput(ChartAndSubscriptionItemData data) {
139         // TODO: implement so that this reinitializes the UI of the dialog according to the new specified data
140     }
141
142     protected void disposeDialogAreaContents() {
143         Composite area = (Composite) dialogArea;
144         for (Control child : area.getChildren())
145             child.dispose();
146     }
147
148     @Override
149     protected Control createDialogArea(Composite parent) {
150         Composite c = (Composite) super.createDialogArea(parent);
151         GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(9).applyTo(c);
152         createDialogAreaContents(c);
153         return c;
154     }
155
156     protected void createDialogAreaContents(Composite c) {
157         GridDataFactory gd1 = GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(1, 1);
158         GridDataFactory gd2 = GridDataFactory.fillDefaults().grab(true, false).indent(5, 0).span(8, 1);
159
160         // 1st line - Chart: [chart name]
161         if(includeChartSpecificProperties) {
162             lChart = new Label(c, 0);
163             lChart.setText("Chart:");
164             gd1.applyTo(lChart);
165             tChart = new Text(c, SWT.BORDER | SWT.READ_ONLY);
166             //tChart.setEnabled( false );
167             if ( data.chartName != null ) tChart.setText( data.chartName );
168             gd2.applyTo(tChart);
169         }
170
171         // 2nd line - Variable Reference: [chart item label]
172         lRVI = new Label(c, 0);
173         lRVI.setText("Variable: ");
174         gd1.applyTo(lRVI);
175         tRVI = new Text(c, SWT.BORDER | SWT.READ_ONLY);
176         //tRVI.setEnabled(false);
177         if ( data.variableReference!=null ) tRVI.setText(URIStringUtils.unescape( data.variableReference ));
178         gd2.applyTo(tRVI);
179
180         // 3rd line - Label: [chart item label]
181         lLabel = new Label(c, 0);
182         lLabel.setText("&Label: ");
183         gd1.applyTo(lLabel);
184         tLabel = new Text(c, SWT.BORDER);
185         if ( data.label!=null ) tLabel.setText(data.label);
186         gd2.applyTo(tLabel);
187
188 //        if (!data.binaryMode) {
189 //              // 4th line - DrawMode: [ drop-down-list V ]
190 //              lDrawMode = new Label(c, 0);
191 //              lDrawMode.setText("DrawMode :");
192 //              gd1.applyTo(lDrawMode);
193 //              cDrawMode = new Combo(c, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
194 //              for (DrawMode dm : DrawMode.values()) cDrawMode.add( dm.name() );
195 //              String _drawmode = data.drawmode!=null ? data.drawmode.toString() : chartnode.get( ChartPreferences.P_DRAWMODE, ChartPreferences.DEFAULT_DRAWMODE ); 
196 //              cDrawMode.setText( _drawmode );
197 //              gd2.applyTo(cDrawMode);
198 //        }
199
200         if (!data.binaryMode && includeChartSpecificProperties) {
201                 // 5th line - Scale: [ Auto/Manual ] Min: [ ## ] Max: [ ## ]
202                 lScale = new Label(c, 0);
203                 lScale.setText("&Scale: ");
204                 gd1.applyTo(lScale);
205
206                 Composite scaleComposite = new Composite(c, 0);
207                 gd2.applyTo(scaleComposite);
208                 GridLayoutFactory.fillDefaults().numColumns(8).applyTo(scaleComposite);
209
210                 cScale = new Combo(scaleComposite, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
211                 cScale.add(AUTO);
212                 cScale.add(MANUAL);
213                 String _scale = data.scale != null ? data.scale.toString() : chartnode.get( ChartPreferences.P_SCALEMODE, ChartPreferences.DEFAULT_SCALEMODE ); 
214                 cScale.setText( _scale );
215                 GridDataFactory.fillDefaults().span(2, 1).applyTo(cScale);
216                 
217                 lMin = new Label(scaleComposite, 0);
218                 lMin.setText("&Min: ");
219                 GridDataFactory.fillDefaults().span(1, 1).align(SWT.FILL, SWT.CENTER).applyTo(lMin);
220                 tMin = new Text(scaleComposite, SWT.BORDER);
221                 Double _min = data.min;
222                 if ( _min == null ) _min = chartnode.getDouble( ChartPreferences.P_SCALE_MIN, 0.0);
223                 tMin.setText( Double.toString(_min) );
224                 GridDataFactory.fillDefaults().hint(80, SWT.DEFAULT).indent(5, 0).grab(true, false).span(2, 1).applyTo(tMin);
225                 tMin.addModifyListener(new ModifyListener() {
226                     @Override
227                     public void modifyText(ModifyEvent e) {
228                         data.min = parseDouble(tMin, false, 0.0);
229                     if (data.min != null)
230                         cScale.setText(MANUAL);
231                         validate();
232                     }
233                 });
234
235                 lMax = new Label(scaleComposite, 0);
236                 lMax.setText("Ma&x: ");
237                 GridDataFactory.fillDefaults().span(1, 1).align(SWT.FILL, SWT.CENTER).applyTo(lMax);
238                 tMax = new Text(scaleComposite, SWT.BORDER);
239                 Double _max = data.max;
240                 if ( _max==null ) _max = chartnode.getDouble( ChartPreferences.P_SCALE_MAX, 100.0);
241                 tMax.setText( Double.toString(_max) );
242                 GridDataFactory.fillDefaults().hint(80, SWT.DEFAULT).indent(5, 0).grab(true, false).span(2, 1).applyTo(tMax);
243             tMax.addModifyListener(new ModifyListener() {
244                 @Override
245                 public void modifyText(ModifyEvent e) {
246                     data.max = parseDouble(tMax, false, 100.0);
247                     if (data.max != null)
248                         cScale.setText(MANUAL);
249                     validate();
250                 }
251             });
252         }
253
254         // 6th line - Subscription: [ Default / others ] [New] 
255         lSubscription = new Label(c, 0);
256         lSubscription.setText("S&ubscription: ");
257         gd1.applyTo(lSubscription);
258         cSubscription = new Combo(c, SWT.BORDER);
259         for (String s : data.subscriptions) cSubscription.add(s);
260         gd2.applyTo(cSubscription);
261         String _subscription = data.subscription;
262         if ( _subscription == null ) _subscription = subscriptionnode.get( SubscriptionPreferences.P_SUBSCRIPTION_DEFAULT, data.subscriptions.length==0 ? "Default" : cSubscription.getItem(0) );
263         cSubscription.setText( _subscription );
264
265         if (!data.binaryMode) {
266                 // 7th line - Deadband: [deadband] Interval: [interval]
267                 lDeadband = new Label(c, 0);
268                 lDeadband.setText("&Deadband: ");
269                 gd1.applyTo(lDeadband);
270                 tDeadband = new Text(c, SWT.BORDER);
271                 Double _deadband = data.deadband;
272                 if ( _deadband == null ) _deadband = subscriptionnode.getDouble( SubscriptionPreferences.P_SUBSCRIPTION_DEADBAND, SubscriptionPreferences.DEFAULT_SUBSCRIPTION_DEADBAND );
273                 tDeadband.setText( Double.toString(_deadband) );
274                 tDeadband.setEditable(data.mutableCollectionSettings);
275                 GridDataFactory.fillDefaults().hint(110, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tDeadband);
276             tDeadband.addModifyListener(new ModifyListener() {
277                 @Override
278                 public void modifyText(ModifyEvent e) {
279                     data.deadband = parseDouble(tDeadband, false, 0.0);
280                     validate();
281                 }
282             });
283
284                 lInterval = new Label(c, 0);
285                 lInterval.setText("&Interval: ");
286                 lInterval.setToolTipText("Sampling Interval");
287                 GridDataFactory.fillDefaults().span(2, 1).applyTo(lInterval);
288                 tInterval = new Text(c, SWT.BORDER);
289                 Double _interval = data.interval;
290                 if ( _interval == null ) _interval = subscriptionnode.getDouble( SubscriptionPreferences.P_SUBSCRIPTION_INTERVAL, SubscriptionPreferences.DEFAULT_SUBSCRIPTION_INTERVAL );
291                 tInterval.setText( Double.toString(_interval) );
292                 tInterval.setEditable(data.mutableCollectionSettings);
293                 GridDataFactory.fillDefaults().hint(110, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tInterval);
294             tInterval.addModifyListener(new ModifyListener() {
295                 @Override
296                 public void modifyText(ModifyEvent e) {
297                     data.interval = parseDouble(tInterval, false, 0.0);
298                     validate();
299                 }
300             });
301         }
302
303         // 8th line - Gain: [gain] Bias: [bias]
304         if (!data.binaryMode) {
305                 lGain = new Label(c, 0);
306                 lGain.setText("&Gain: ");
307                 gd1.applyTo(lGain);
308                 tGain = new Text(c, SWT.BORDER);
309                 Double _gain = data.gain;
310                 if (_gain == null) _gain = subscriptionnode.getDouble( SubscriptionPreferences.P_SUBSCRIPTION_GAIN, 1.0);
311                 tGain.setText( Double.toString(_gain) );
312                 GridDataFactory.fillDefaults().hint(110, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tGain);
313             tGain.addModifyListener(new ModifyListener() {
314                 @Override
315                 public void modifyText(ModifyEvent e) {
316                     data.gain = parseDouble(tGain, false, 1.0);
317                     validate();
318                 }
319             });
320
321                 lBias = new Label(c, 0);
322                 lBias.setText("&Bias: ");
323                 GridDataFactory.fillDefaults().span(2, 1).applyTo(lBias);
324                 tBias = new Text(c, SWT.BORDER);
325                 Double _bias = data.bias;
326                 if (_bias == null) _bias = subscriptionnode.getDouble( SubscriptionPreferences.P_SUBSCRIPTION_BIAS, 0.0);
327                 tBias.setText( Double.toString(_bias) );
328                 GridDataFactory.fillDefaults().hint(110, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tBias);
329             tBias.addModifyListener(new ModifyListener() {
330                 @Override
331                 public void modifyText(ModifyEvent e) {
332                     data.bias = parseDouble(tBias, false, 0.0);
333                     validate();
334                 }
335             });
336         }
337
338         // 9th line - Unit: [unit]
339         if (!data.binaryMode) {
340                 lUnit = new Label(c, 0);
341                 lUnit.setText("U&nit: ");
342                 gd1.applyTo(lUnit);
343                 tUnit = new Text(c, SWT.BORDER);
344                 String _unit = data.unit;
345                 if (_unit==null) _unit = subscriptionnode.get( SubscriptionPreferences.P_SUBSCRIPTION_UNIT, "");
346                 tUnit.setText( _unit );
347                 GridDataFactory.fillDefaults().hint(100, SWT.DEFAULT).indent(5, 0).span(3, 1).applyTo(tUnit);
348                 // Fill line
349             GridDataFactory.fillDefaults().span(5, 1).applyTo(new Label(c, 0));
350         }
351
352         // Disable fields that edit subscription item
353         if (!data.hasSubscriptionItem) {
354                 tLabel.setEnabled( false );
355                 cSubscription.setEnabled( false );
356                 tDeadband.setEnabled( false );
357                 tInterval.setEnabled( false );
358                 tGain.setEnabled( false );
359                 tBias.setEnabled( false );
360                 tUnit.setEnabled( false );
361         }
362
363         // 10th line - Color stroke / color
364         if (includeChartSpecificProperties) {
365             createStrokeGroup(c);
366         }
367
368         saveAsPrefs = new Button(c, SWT.CHECK);
369         saveAsPrefs.setText("Sav&e as new defaults");
370         saveAsPrefs.setToolTipText("Sav&e these settings as new defaults");
371         // Always unchecked by default.
372         saveAsPrefs.setSelection(false);
373         GridDataFactory.fillDefaults().hint(100, SWT.DEFAULT).span(9, 1).applyTo(saveAsPrefs);
374
375         // Error decorations
376         Image image = FieldDecorationRegistry.getDefault()
377                 .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR)
378                 .getImage();
379
380         if (!data.binaryMode) {
381             if (includeChartSpecificProperties) {
382                 tMinDecor = createDecoration(tMin, SWT.LEFT | SWT.CENTER, image);
383                 tMaxDecor = createDecoration(tMax, SWT.LEFT | SWT.CENTER, image);
384             }
385             tDeadbandDecor = createDecoration(tDeadband, SWT.LEFT | SWT.CENTER, image);
386             tIntervalDecor = createDecoration(tInterval, SWT.LEFT | SWT.CENTER, image);
387             tGainDecor = createDecoration(tGain, SWT.LEFT | SWT.CENTER, image);
388             tBiasDecor = createDecoration(tBias, SWT.LEFT | SWT.CENTER, image);
389         }
390
391         // Ensure that the data structure contains all the values that were
392         // initialized into the UI.
393         parseUiToData();
394
395         tLabel.setFocus();
396     }
397
398     private void createStrokeGroup(Composite c) {
399         GridDataFactory gd1 = GridDataFactory.fillDefaults().indent(10, 0).align(SWT.FILL, SWT.CENTER).span(1, 1);
400
401         Group gStroke = new Group(c, 0);
402         gStroke.setText("Trend Line Stroke");
403         GridLayoutFactory.fillDefaults().margins(8, 8).spacing(10, 10).numColumns(5).applyTo(gStroke);
404         GridDataFactory.fillDefaults().span(9, 1).applyTo(gStroke);
405
406         if (!data.binaryMode) {
407             // Custom stroke
408             Label lStrokeWidth = new Label(gStroke, 0);
409             lStrokeWidth.setText("&Width:");
410             gd1.applyTo(lStrokeWidth);
411             sStrokeWidth = new Spinner(gStroke, SWT.BORDER);
412             sStrokeWidth.setDigits(1);
413             sStrokeWidth.setIncrement(5);
414             sStrokeWidth.setMinimum(10);
415             sStrokeWidth.setMaximum(50);
416             GridDataFactory.fillDefaults().indent(10, 0).grab(false, false).span(1, 1).applyTo(sStrokeWidth);
417
418             if (data.strokeWidth != null) {
419                 sStrokeWidth.setSelection((int) (data.strokeWidth * 10));
420             }
421
422             sStrokeWidth.addSelectionListener(new SelectionAdapter() {
423                 @Override
424                 public void widgetSelected(SelectionEvent e) {
425                     float newWidth = ((float) sStrokeWidth.getSelection()) * 0.1f;
426                     data.strokeWidth = newWidth;
427                 }
428             });
429         }
430
431         Label lColor = new Label(gStroke, 0);
432         lColor.setText("&Color: ");
433         gd1.applyTo(lColor);
434         colorSelector = new ColorSelector(gStroke);
435         GridDataFactory.fillDefaults().indent(10, 0).span(1, 1).grab(false, false).applyTo(colorSelector.getButton());
436         final RGB indexColor = toRGB(JarisPaints.getColor(data.index));
437         RGB customColor = data.color != null ? toRGB(data.color) : indexColor;
438         colorSelector.setColorValue(customColor);
439
440         final Button bResetColor = new Button(gStroke, SWT.PUSH);
441         bResetColor.setText("Reset Color");
442         bResetColor.setToolTipText("Reset Color to Item Index Default");
443         bResetColor.setEnabled(!indexColor.equals(customColor));
444
445         colorSelector.addListener(new IPropertyChangeListener() {
446             @Override
447             public void propertyChange(PropertyChangeEvent event) {
448                 RGB rgb = colorSelector.getColorValue();
449                 data.color = new Color(rgb.red, rgb.green, rgb.blue).getColorComponents(new float[4]);
450                 data.color[3] = 1;
451                 bResetColor.setEnabled(!indexColor.equals(rgb));
452             }
453         });
454
455         bResetColor.addSelectionListener(new SelectionAdapter() {
456             @Override
457             public void widgetSelected(SelectionEvent e) {
458                 data.color = null;
459                 colorSelector.setColorValue(toRGB(JarisPaints.getColor(data.index)));
460                 bResetColor.setEnabled(false);
461             }
462         });
463     }
464
465     protected RGB toRGB(float[] color) {
466         float r = color[0];
467         float g = color[1];
468         float b = color[2];
469         return new RGB( (int) (r*255+0.5), (int) (g*255+0.5), (int) (b*255+0.5) );
470     }
471
472     protected RGB toRGB(Color color) {
473         return new RGB(color.getRed(), color.getGreen(), color.getBlue());
474     }
475
476     protected ControlDecoration createDecoration(Control control, int position, Image image) {
477         ControlDecoration d = new ControlDecoration(control, position);
478         d.setMarginWidth(2);
479         d.setImage(image);
480         d.hide();
481         return d;
482     }
483
484     protected Double parseDouble(Text text, boolean returnDefault, double defaultValue) {
485         if (text == null)
486             return null;
487         try {
488             String s = text.getText();
489             s = s.replace(',', '.');
490             return Double.valueOf(s);
491         } catch ( NumberFormatException nfe ) {
492             return returnDefault ? defaultValue : null;
493         }
494     }
495
496     protected void parseUiToData() {
497         data.label = tLabel.getText();
498         if (!data.binaryMode) {
499             if (includeChartSpecificProperties) {
500                 data.min = parseDouble(tMin, true, 0.0);
501                 data.max = parseDouble(tMax, true, 100.0);
502             }
503             data.interval = parseDouble(tInterval, true, 0.0);
504             data.deadband = parseDouble(tDeadband, true, 0.0);
505             data.gain = parseDouble(tGain, true, 1.0);
506             data.bias = parseDouble(tBias, true, 0.0);
507             data.unit = tUnit.getText();
508
509             if (includeChartSpecificProperties) {
510 //                data.drawmode = DrawMode.valueOf( cDrawMode.getText() );
511                 data.drawmode = DrawMode.Line;
512
513                 if (cScale.getText().equals("Manual")) {
514                     data.scale = new Scale.Manual(data.min, data.max);
515                 } else if (cScale.getText().equals("Auto")) {
516                     data.scale = new Scale.Auto();
517                 }
518             }
519         }
520         data.subscription = cSubscription.getText();
521     }
522
523     @Override
524     protected void buttonPressed(int buttonId) {
525         if (ChartDialogConstants.APPLY_ID == buttonId) {
526             applyPressed();
527         } else {
528             super.buttonPressed(buttonId);
529         }
530     }
531
532     private void applyPressed() {
533         if (applyAction != null) {
534             parseUiToData();
535             if (!baseData.equals(data)) {
536                 baseData.readFrom(data);
537                 applyAction.run();
538             }
539         }
540     }
541
542     @Override
543     protected void okPressed() {
544         boolean savePrefs = saveAsPrefs.getSelection();
545         parseUiToData();
546
547         if (!data.binaryMode && savePrefs) {
548             if (includeChartSpecificProperties) {
549                 chartnode.put( ChartPreferences.P_DRAWMODE, data.drawmode.name() );
550                 chartnode.put( ChartPreferences.P_SCALEMODE, data.scale instanceof Scale.Manual ? "Manual" : "Auto" );
551                 chartnode.putDouble( ChartPreferences.P_SCALE_MIN, data.min );
552                 chartnode.putDouble( ChartPreferences.P_SCALE_MAX, data.max );
553             }
554             subscriptionnode.putDouble( SubscriptionPreferences.P_SUBSCRIPTION_DEADBAND, data.deadband );
555             subscriptionnode.putDouble( SubscriptionPreferences.P_SUBSCRIPTION_INTERVAL, data.interval );
556             subscriptionnode.putDouble( SubscriptionPreferences.P_SUBSCRIPTION_GAIN, data.gain );
557             subscriptionnode.putDouble( SubscriptionPreferences.P_SUBSCRIPTION_BIAS, data.bias );
558             subscriptionnode.put( SubscriptionPreferences.P_SUBSCRIPTION_UNIT, data.unit );
559         }
560
561         if (savePrefs)
562             subscriptionnode.put( SubscriptionPreferences.P_SUBSCRIPTION_DEFAULT, data.subscription );
563
564         if (applyAction != null && !baseData.equals(data))
565             applyAction.run();
566         super.okPressed();
567     }
568
569     @Override
570     protected void configureShell(Shell newShell) {
571         super.configureShell(newShell);
572         newShell.setText(
573                 includeChartSpecificProperties ? "Edit Chart Item"
574                                                : "Edit Subscription Item"
575                 );
576     }
577
578     public void validate() {
579         boolean ok = true;
580         if (!data.binaryMode) {
581             if (includeChartSpecificProperties) {
582                 setDecoration(tMinDecor, null);
583                 setDecoration(tMaxDecor, null);
584                 if (tMin != null && tMax != null) {
585                     if (data.min == null || data.max == null) {
586                         ok = false;
587                         if (data.min == null)
588                             setDecoration(tMinDecor, "Invalid non-numeric value");
589                         if (data.max == null)
590                             setDecoration(tMaxDecor, "Invalid non-numeric value");
591                     } else {
592                         if (data.min >= data.max) {
593                             setDecoration(tMinDecor, "Minimum value must be smaller than maximum value");
594                             setDecoration(tMaxDecor, "Maximum value must be larger than minimum value");
595                             ok = false;
596                         }
597                     }
598                 }
599             }
600
601             ok &= data.interval != null && data.deadband != null && data.bias != null && data.gain != null;
602             setDecoration(tIntervalDecor, data.interval == null ? "Invalid non-numeric value" : null);
603             if (data.interval != null && data.interval < 0)
604                 setDecoration(tIntervalDecor, "Sampling interval cannot be negative");
605             setDecoration(tDeadbandDecor, data.deadband == null ? "Invalid non-numeric value" : null);
606             if (data.deadband != null && data.deadband < 0)
607                 setDecoration(tDeadbandDecor, "Deadband cannot be negative");
608             setDecoration(tGainDecor, data.gain == null ? "Invalid non-numeric value" : null);
609             setDecoration(tBiasDecor, data.bias == null ? "Invalid non-numeric value" : null);
610         }
611         setFinishable(ok);
612     }
613
614     private void setDecoration(ControlDecoration decor, String desc) {
615         if (decor == null)
616             return;
617         if (desc != null) {
618             decor.setDescriptionText(desc);
619             decor.show();
620         } else {
621             decor.hide();
622         }
623     }
624
625     protected void setFinishable(boolean ok) {
626         getButton(OK).setEnabled(ok);
627     }
628
629 }