1 package org.simantics.charts.ui;
4 import java.text.Format;
5 import java.util.ArrayList;
9 import org.eclipse.core.runtime.IStatus;
10 import org.eclipse.core.runtime.Status;
11 import org.eclipse.jface.dialogs.Dialog;
12 import org.eclipse.jface.fieldassist.ControlDecoration;
13 import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
14 import org.eclipse.jface.layout.GridDataFactory;
15 import org.eclipse.jface.layout.GridLayoutFactory;
16 import org.eclipse.jface.preference.ColorSelector;
17 import org.eclipse.jface.viewers.ArrayContentProvider;
18 import org.eclipse.jface.viewers.DoubleClickEvent;
19 import org.eclipse.jface.viewers.IDoubleClickListener;
20 import org.eclipse.jface.viewers.ISelection;
21 import org.eclipse.jface.viewers.LabelProvider;
22 import org.eclipse.jface.viewers.ListViewer;
23 import org.eclipse.swt.SWT;
24 import org.eclipse.swt.events.KeyAdapter;
25 import org.eclipse.swt.events.KeyEvent;
26 import org.eclipse.swt.events.ModifyEvent;
27 import org.eclipse.swt.events.ModifyListener;
28 import org.eclipse.swt.events.SelectionAdapter;
29 import org.eclipse.swt.events.SelectionEvent;
30 import org.eclipse.swt.graphics.Image;
31 import org.eclipse.swt.graphics.RGB;
32 import org.eclipse.swt.widgets.Button;
33 import org.eclipse.swt.widgets.Combo;
34 import org.eclipse.swt.widgets.Composite;
35 import org.eclipse.swt.widgets.Control;
36 import org.eclipse.swt.widgets.Group;
37 import org.eclipse.swt.widgets.Label;
38 import org.eclipse.swt.widgets.Scale;
39 import org.eclipse.swt.widgets.Shell;
40 import org.eclipse.swt.widgets.Text;
41 import org.simantics.Simantics;
42 import org.simantics.charts.Activator;
43 import org.simantics.charts.query.ChartAndSubscriptionItemData;
44 import org.simantics.charts.query.ChartAndSubscriptionItemReadQuery;
45 import org.simantics.charts.ui.ChartData.ItemKey;
46 import org.simantics.db.exception.DatabaseException;
47 import org.simantics.modeling.ui.chart.property.ChartComposite;
48 import org.simantics.trend.configuration.TrendItem;
49 import org.simantics.trend.configuration.YAxisMode;
50 import org.simantics.trend.impl.Plot;
51 import org.simantics.utils.format.TimeFormat;
52 import org.simantics.utils.ui.ISelectionUtils;
55 * Dialog for chart properties:
61 * Scroll Increment: [--|--] n%
62 * Axis Mode: [Single/Multi]
63 * [ ] Hairline Tracks Experiment Time
65 * --- Styling ------------------------------------------
66 * | [ ] Background Vertical Gradient {color1} {color2} |
67 * | [ ] Show Grid {grid color} |
68 * | [ ] Show Milestones |
69 * ------------------------------------------------------
71 * --- Item visibility ---------------
73 * | ----------- -------------- |
76 * | ----------- -------------- |
77 * -----------------------------------
80 * @author toni.kalajainen@semantum.fi
81 * @author Tuukka Lehtonen
83 public class ChartDialog extends Dialog {
85 private static final RGB DEFAULT_BG_COLOR1 = toRGB(Plot.PLOT_AREA_BG_GRADIENT_COLOR_BOTTOM.getColorComponents(new float[3]), null);
86 private static final RGB DEFAULT_BG_COLOR2 = toRGB(Plot.PLOT_AREA_BG_GRADIENT_COLOR_TOP.getColorComponents(new float[3]), null);
87 private static final RGB DEFAULT_GRID_COLOR = toRGB(Plot.GRID_LINE_COLOR.getColorComponents(new float[3]), null);
89 Format timeFormat = new TimeFormat(100, 3);
92 Label lName, lStartTime, lLength, lScrollIncrement, lAxisMode;
93 Text tName, tStartTime, tLength;
96 Button bBackgroundGradient;
97 ColorSelector backgroundColor1;
98 ColorSelector backgroundColor2;
100 ColorSelector gridColor;
102 Button bTrackExperimentTime;
103 ListViewer lVisibleItems;
104 ListViewer lHiddenItems;
106 ControlDecoration tStartTimeDecor;
107 ControlDecoration tLengthDecor;
109 final ChartData baseData = new ChartData();
110 final ChartData data;
111 final Runnable applyAction;
114 * Set when a chart item dialog has previously been opened by this dialog.
116 ChartAndSubscriptionItemDialog currentItemDialog = null;
118 public ChartDialog(Shell parentShell, ChartData data, Runnable applyAction) {
121 this.baseData.readFrom(data);
122 this.applyAction = applyAction;
123 setShellStyle(SWT.RESIZE | SWT.TITLE | SWT.CLOSE | SWT.BORDER);
127 protected void createButtonsForButtonBar(Composite parent) {
128 if (applyAction != null)
129 createButton(parent, ChartDialogConstants.APPLY_ID, ChartDialogConstants.APPLY_LABEL, true);
130 super.createButtonsForButtonBar(parent);
134 protected Control createDialogArea(Composite parent) {
135 Composite c = (Composite) super.createDialogArea(parent);
136 GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(9).applyTo(c);
137 createDialogAreaContents(c);
141 protected void createDialogAreaContents(Composite c) {
142 GridDataFactory gd1 = GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(1, 1);
143 GridDataFactory gd2 = GridDataFactory.fillDefaults().indent(5, 0).grab(true, false).span(8, 1);
145 // 1st line - Chart: [chart name]
146 lName = new Label(c, 0);
147 lName.setText("&Name:");
149 tName = new Text(c, SWT.BORDER);
150 tName.setEnabled( true );
151 if ( data.name != null ) tName.setText( data.name );
154 // 2nd line - start time + length
155 Label l = new Label(c, 0);
156 l.setText("Chart Time Window Preference (Auto-scale)");
157 GridDataFactory.fillDefaults().span(9, 1).applyTo(l);
159 lStartTime = new Label(c, 0);
160 lStartTime.setText("&Time Start:");
161 gd1.applyTo(lStartTime);
162 tStartTime = new Text(c, SWT.BORDER);
163 tStartTime.setToolTipText("Chart Window Fixed Start Time in Seconds or Yy Dd HH:mm:ss.ddd");
164 if ( data.timeStart!=null ) {
165 String str = timeFormat.format(data.timeStart);
166 tStartTime.setText(str);
168 gd2.applyTo(tStartTime);
169 tStartTime.addModifyListener(new ModifyListener() {
171 public void modifyText(ModifyEvent e) {
172 data.timeStart = parseTime(tStartTime, false, 0.0);
177 lLength = new Label(c, 0);
178 lLength.setText("&Length:");
179 gd1.applyTo(lLength);
180 tLength = new Text(c, SWT.BORDER);
181 tLength.setToolTipText("Chart Window Fixed Time Axis Length in Seconds or Yy Dd HH:mm:ss.ddd");
182 if ( data.timeLength!=null ) {
183 String str = timeFormat.format(data.timeLength);
184 tLength.setText(str);
186 gd2.applyTo(tLength);
187 tLength.addModifyListener(new ModifyListener() {
189 public void modifyText(ModifyEvent e) {
190 data.timeLength = parseTime(tLength, false, 0.0);
195 // 3rd line - Increment scrollbar
196 lScrollIncrement = new Label(c, 0);
197 lScrollIncrement.setText("Scroll Increment:");
198 gd1.applyTo(lScrollIncrement);
199 sIncrement = new Scale(c, SWT.HORIZONTAL);
200 sIncrement.setMinimum(1);
201 sIncrement.setMaximum(100);
202 sIncrement.setIncrement(10);
203 sIncrement.setPageIncrement(10);
204 if (data.timeIncrement!=null) {
205 sIncrement.setSelection( (int) (double) data.timeIncrement );
207 gd2.copy().span(7, 1).applyTo(sIncrement);
208 final Text sIncrementText = new Text(c, SWT.READ_ONLY | SWT.RIGHT);
209 gd1.copy().hint(35, SWT.DEFAULT).applyTo(sIncrementText);
210 sIncrement.addSelectionListener(new SelectionAdapter() {
212 public void widgetSelected(SelectionEvent e) {
213 sIncrementText.setText(sIncrement.getSelection() + " %");
216 sIncrementText.setText(sIncrement.getSelection() + " %");
218 // 4th line -- AxisMode + Milestone
219 lAxisMode = new Label(c, 0);
220 lAxisMode.setText("A&xis Mode:");
221 gd1.applyTo(lAxisMode);
222 cAxisMode = new Combo(c, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
223 GridDataFactory.fillDefaults().indent(5, 0).span(1, 1).applyTo(cAxisMode);
224 cAxisMode.add("Single");
225 cAxisMode.add("Multi");
226 String _mode = data.axisMode==YAxisMode.SingleAxis ? "Single" : "Multi";
227 cAxisMode.setText( _mode );
229 GridDataFactory.fillDefaults().span(7, 1).applyTo(new Label(c, 0));
231 bTrackExperimentTime = new Button(c, SWT.CHECK);
232 bTrackExperimentTime.setText("Ha&irline Tracks Experiment Time");
233 bTrackExperimentTime.setSelection( data.trackExperimentTime );
234 GridDataFactory.fillDefaults().span(9, 1).applyTo(bTrackExperimentTime);
236 // Styling group begins
238 Group gStyling = new Group(c, 0);
239 gStyling.setText("Styling");
240 GridDataFactory.fillDefaults().indent(0, 5).grab(true, true).span(9, 1).applyTo(gStyling);
241 GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(4).applyTo(gStyling);
243 // Background color settings
245 bBackgroundGradient = new Button(gStyling, SWT.CHECK);
246 bBackgroundGradient.setText("&Background Vertical Gradient");
247 bBackgroundGradient.setToolTipText("Solid Color or Vertical Gradient");
248 bBackgroundGradient.setSelection(data.backgroundGradient);
249 bBackgroundGradient.addSelectionListener(new SelectionAdapter() {
251 public void widgetSelected(SelectionEvent e) {
252 data.backgroundGradient = bBackgroundGradient.getSelection();
253 setBackgroundGradient(data.backgroundGradient);
256 GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(bBackgroundGradient);
258 backgroundColor1 = new ColorSelector(gStyling);
259 backgroundColor2 = new ColorSelector(gStyling);
260 backgroundColor1.getButton().setToolTipText("Select Gradient Bottom Color");
261 backgroundColor2.getButton().setToolTipText("Select Gradient Top Color");
262 GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(backgroundColor1.getButton());
263 GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(backgroundColor2.getButton());
264 backgroundColor1.setColorValue(toRGB(data.backgroundColor1, DEFAULT_BG_COLOR1));
265 backgroundColor2.setColorValue(toRGB(data.backgroundColor2, DEFAULT_BG_COLOR2));
266 setBackgroundGradient(data.backgroundGradient);
268 Button bResetBackgroundColors = new Button(gStyling, SWT.PUSH);
269 bResetBackgroundColors.setText("Reset");
270 bResetBackgroundColors.setToolTipText("Reset Background Color to Default");
271 bResetBackgroundColors.addSelectionListener(new SelectionAdapter() {
272 public void widgetSelected(SelectionEvent e) {
273 backgroundColor1.setColorValue(toRGB(null, DEFAULT_BG_COLOR1));
274 backgroundColor2.setColorValue(toRGB(null, DEFAULT_BG_COLOR2));
281 bShowGrid = new Button(gStyling, SWT.CHECK);
282 bShowGrid.setText("Show &Grid");
283 bShowGrid.setToolTipText("Toggle Background Grid Visibility");
284 bShowGrid.setSelection(data.showGrid);
285 GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(bShowGrid);
287 gridColor = new ColorSelector(gStyling);
288 gridColor.getButton().setToolTipText("Select Grid Color");
289 GridDataFactory.fillDefaults().indent(0, 0).span(1, 1).grab(false, false).applyTo(gridColor.getButton());
290 gridColor.setColorValue(toRGB(data.gridColor, DEFAULT_GRID_COLOR));
292 Button bResetGridColor = new Button(gStyling, SWT.PUSH);
293 bResetGridColor.setText("Reset");
294 bResetGridColor.setToolTipText("Reset Grid Color to Default");
295 bResetGridColor.addSelectionListener(new SelectionAdapter() {
296 public void widgetSelected(SelectionEvent e) {
297 gridColor.setColorValue(toRGB(null, DEFAULT_GRID_COLOR));
304 GridDataFactory.fillDefaults().span(1, 1).applyTo(new Label(gStyling, 0));
305 bMilestones = new Button(gStyling, SWT.CHECK);
306 bMilestones.setText("Show &Milestones");
307 bMilestones.setToolTipText("Toggle Milestone Event Visibility");
308 bMilestones.setSelection( data.showMilestones );
309 GridDataFactory.fillDefaults().indent(0, 0).span(4, 1).applyTo(bMilestones);
312 // Item visibility group begins
314 Group gItemVisibility = new Group(c, 0);
315 gItemVisibility.setText("Item Visibility");
316 GridDataFactory.fillDefaults().indent(0, 5).grab(true, true).span(9, 1).applyTo(gItemVisibility);
317 GridLayoutFactory.fillDefaults().margins(8, 8).numColumns(3).applyTo(gItemVisibility);
319 Label visible = new Label(gItemVisibility, 0);
320 visible.setText("Visible");
321 GridDataFactory.fillDefaults().grab(true, false).applyTo(visible);
322 new Label(gItemVisibility, 0);
323 Label hidden = new Label(gItemVisibility, 0);
324 hidden.setText("Hidden");
325 GridDataFactory.fillDefaults().grab(true, false).applyTo(hidden);
327 lVisibleItems = new ListViewer(gItemVisibility, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
328 GridDataFactory.fillDefaults().hint(200, 200).grab(true, true).applyTo(lVisibleItems.getControl());
329 Composite addRemoveButtons = new Composite(gItemVisibility, 0);
330 GridLayoutFactory.fillDefaults().numColumns(1).applyTo(addRemoveButtons);
331 GridDataFactory.fillDefaults().grab(false, true).span(1, 1).applyTo(addRemoveButtons);
332 Button hideButton = new Button(addRemoveButtons, SWT.PUSH);
333 hideButton.setText("&Hide \u2192");
334 GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(hideButton);
335 Button showButton = new Button(addRemoveButtons, SWT.PUSH);
336 showButton.setText("\u2190 &Show");
337 GridDataFactory.fillDefaults().grab(true, false).span(1, 1).applyTo(showButton);
338 lHiddenItems = new ListViewer(gItemVisibility, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
339 GridDataFactory.fillDefaults().hint(200, 200).grab(true, true).applyTo(lHiddenItems.getControl());
341 lVisibleItems.addDoubleClickListener(new OpenChartItemProperties());
342 lVisibleItems.setContentProvider(new ItemContentProvider(false));
343 lHiddenItems.addDoubleClickListener(new OpenChartItemProperties());
344 lHiddenItems.setContentProvider(new ItemContentProvider(true));
345 lVisibleItems.setLabelProvider(new ItemLabeler());
346 lHiddenItems.setLabelProvider(new ItemLabeler());
347 lVisibleItems.setInput(data);
348 lHiddenItems.setInput(data);
350 lVisibleItems.getList().addKeyListener(new SelectAllListener(lVisibleItems));
351 lHiddenItems.getList().addKeyListener(new SelectAllListener(lHiddenItems));
352 showButton.addSelectionListener(new ShowHideListener(false));
353 hideButton.addSelectionListener(new ShowHideListener(true));
355 Image image = FieldDecorationRegistry.getDefault()
356 .getFieldDecoration(FieldDecorationRegistry.DEC_ERROR)
359 tStartTimeDecor = createDecoration(tStartTime, SWT.LEFT | SWT.CENTER, image);
360 tLengthDecor = createDecoration(tLength, SWT.LEFT | SWT.CENTER, image);
363 class ShowHideListener extends SelectionAdapter {
364 private boolean hide;
366 public ShowHideListener(boolean hide) {
371 public void widgetSelected(SelectionEvent e) {
372 ISelection selection = hide ? lVisibleItems.getSelection() : lHiddenItems.getSelection();
373 Set<ItemKey> selected = ISelectionUtils.filterSetSelection(selection, ItemKey.class);
374 if (!selected.isEmpty()) {
376 data.hiddenItems.addAll(selected);
378 data.hiddenItems.removeAll(selected);
380 lVisibleItems.refresh();
381 lHiddenItems.refresh();
386 static class SelectAllListener extends KeyAdapter {
387 private ListViewer list;
389 public SelectAllListener(ListViewer list) {
394 public void keyPressed(KeyEvent e) {
395 if (e.stateMask == SWT.CTRL && e.keyCode == 'a') {
396 list.getList().selectAll();
401 class ItemContentProvider extends ArrayContentProvider {
402 private final boolean expectedHidden;
404 public ItemContentProvider(boolean expectedHidden) {
405 this.expectedHidden = expectedHidden;
409 public Object[] getElements(Object inputElement) {
410 List<Object> result = new ArrayList<>();
411 for (ItemKey item : data.allItems.keySet())
412 if (data.hiddenItems.contains(item) == expectedHidden)
414 return result.toArray();
418 private void setBackgroundGradient(boolean backgroundGradient) {
419 backgroundColor2.setEnabled(backgroundGradient);
420 backgroundColor1.getButton().setToolTipText(backgroundGradient ? "Select Gradient Bottom Color" : "Select Solid Color");
423 protected Double parseTime(Text text, boolean returnDefault, double defaultValue) {
426 String s = text.getText();
427 Double time = ChartComposite.START_VALIDATOR.parse(s);
429 return returnDefault ? defaultValue : null;
433 protected ControlDecoration createDecoration(Control control, int position, Image image) {
434 ControlDecoration d = new ControlDecoration(control, position);
441 class ItemLabeler extends LabelProvider {
443 public String getText(Object element) {
444 ItemKey item = (ItemKey) element;
445 TrendItem ti = data.allItems.get(item);
450 protected void parseUiToData() {
451 data.name = tName.getText();
452 data.backgroundColor1 = toColorComponents( backgroundColor1.getColorValue() );
453 data.backgroundColor2 = toColorComponents( backgroundColor2.getColorValue() );
454 data.showGrid = bShowGrid.getSelection();
455 data.gridColor = toColorComponents( gridColor.getColorValue() );
456 data.showMilestones = bMilestones.getSelection();
457 data.trackExperimentTime = bTrackExperimentTime.getSelection();
458 data.axisMode = cAxisMode.getSelectionIndex()==0?YAxisMode.SingleAxis:YAxisMode.MultiAxis;
459 data.timeIncrement = (double) sIncrement.getSelection();
460 data.timeLength = ChartComposite.LENGTH_VALIDATOR.parse(tLength.getText());
461 data.timeStart = ChartComposite.START_VALIDATOR.parse(tStartTime.getText());
465 protected void buttonPressed(int buttonId) {
466 if (ChartDialogConstants.APPLY_ID == buttonId) {
469 super.buttonPressed(buttonId);
473 private void applyPressed() {
474 if (applyAction != null) {
476 if (!baseData.equals(data)) {
477 baseData.readFrom(data);
484 protected void okPressed() {
486 if (applyAction != null && !baseData.equals(data))
492 protected void configureShell(Shell newShell) {
493 super.configureShell(newShell);
494 newShell.setText("Edit Chart");
497 public void validate() {
498 String startTimeError = ChartComposite.START_VALIDATOR.isValid(tStartTime.getText());
499 String lengthError = ChartComposite.LENGTH_VALIDATOR.isValid(tLength.getText());
500 setDecoration(tStartTimeDecor, startTimeError);
501 setDecoration(tLengthDecor, lengthError);
502 boolean ok = startTimeError == null && lengthError == null;
506 private void setDecoration(ControlDecoration decor, String desc) {
510 decor.setDescriptionText(desc);
517 protected void setFinishable(boolean ok) {
518 getButton(OK).setEnabled(ok);
521 private static RGB toRGB(float[] components, RGB defaultValue) {
522 if (components == null || components.length < 3)
524 Color c = new Color(components[0], components[1], components[2]);
525 return new RGB(c.getRed(), c.getGreen(), c.getBlue());
528 private static float[] toColorComponents(RGB rgb) {
529 return new Color(rgb.red, rgb.green, rgb.blue).getColorComponents(new float[3]);
532 class OpenChartItemProperties implements IDoubleClickListener {
534 public void doubleClick(DoubleClickEvent event) {
535 final ItemKey item = ISelectionUtils.filterSingleSelection(event.getSelection(), ItemKey.class);
539 final ChartAndSubscriptionItemData data = Simantics.getSession().syncRequest(
540 new ChartAndSubscriptionItemReadQuery(item.resource.getResource()));
541 if (currentItemDialog != null && currentItemDialog.getShell() != null && !currentItemDialog.getShell().isDisposed()) {
542 // TODO: reinitialize existing dialog with the specified data.
543 // Close current dialog before opening new one.
544 currentItemDialog.close();
546 currentItemDialog = ChartDoubleClickHandler.openChartItemPropertiesDialog(
547 event.getViewer().getControl().getShell(),
548 item.resource.getResource(),
551 } catch (DatabaseException e) {
552 Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Problems opening chart item property dialog."));