]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.plant3d/src/org/simantics/plant3d/dialog/ComponentSelectionDialog.java
Make component addition dialog resizable and remember last dimensions
[simantics/3d.git] / org.simantics.plant3d / src / org / simantics / plant3d / dialog / ComponentSelectionDialog.java
1 package org.simantics.plant3d.dialog;
2
3 import java.util.Collection;
4 import java.util.HashSet;
5 import java.util.List;
6 import java.util.Set;
7
8 import org.eclipse.jface.dialogs.Dialog;
9 import org.eclipse.jface.dialogs.IDialogConstants;
10 import org.eclipse.jface.dialogs.IDialogSettings;
11 import org.eclipse.jface.layout.GridDataFactory;
12 import org.eclipse.jface.layout.GridLayoutFactory;
13 import org.eclipse.jface.resource.JFaceResources;
14 import org.eclipse.jface.resource.LocalResourceManager;
15 import org.eclipse.jface.resource.ResourceLocator;
16 import org.eclipse.jface.resource.ResourceManager;
17 import org.eclipse.jface.viewers.ISelectionChangedListener;
18 import org.eclipse.jface.viewers.IStructuredSelection;
19 import org.eclipse.jface.viewers.ListViewer;
20 import org.eclipse.jface.viewers.SelectionChangedEvent;
21 import org.eclipse.jface.viewers.StructuredSelection;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.events.KeyAdapter;
24 import org.eclipse.swt.events.KeyEvent;
25 import org.eclipse.swt.events.SelectionAdapter;
26 import org.eclipse.swt.events.SelectionEvent;
27 import org.eclipse.swt.layout.GridData;
28 import org.eclipse.swt.layout.GridLayout;
29 import org.eclipse.swt.widgets.Button;
30 import org.eclipse.swt.widgets.Composite;
31 import org.eclipse.swt.widgets.Control;
32 import org.eclipse.swt.widgets.ExpandBar;
33 import org.eclipse.swt.widgets.ExpandItem;
34 import org.eclipse.swt.widgets.Label;
35 import org.eclipse.swt.widgets.Shell;
36 import org.eclipse.swt.widgets.Text;
37 import org.simantics.db.exception.DatabaseException;
38 import org.simantics.plant3d.Activator;
39 import org.simantics.plant3d.ontology.Plant3D;
40 import org.simantics.plant3d.scenegraph.EndComponent;
41 import org.simantics.plant3d.scenegraph.InlineComponent;
42 import org.simantics.plant3d.scenegraph.Nozzle;
43 import org.simantics.plant3d.scenegraph.PipelineComponent;
44 import org.simantics.plant3d.scenegraph.TurnComponent;
45 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
46 import org.simantics.plant3d.utils.Item;
47 import org.simantics.plant3d.utils.Item.Type;
48 import org.simantics.plant3d.utils.P3DUtil;
49 import org.simantics.utils.ui.ExceptionUtils;
50
51 public class ComponentSelectionDialog extends Dialog implements ISelectionChangedListener {
52
53         private static final String DIALOG = "ComponentSelectionDialog"; //$NON-NLS-1$
54
55         private IDialogSettings dialogSettings;
56
57         private ResourceManager resourceManager;
58
59         private String libUri;
60
61         private Item selected;
62         private Set<PositionType> allowed;
63         private Set<PositionType> filterAllowed;
64         // private boolean positionAdjustment;
65         private PipelineComponent component;
66         private boolean insertAdjustable;
67         private boolean lenghtAdjustable;
68         private PositionType insertPosition = PositionType.NEXT;
69
70         private Double angle;
71         private Double length;
72         private Double rotationAngle;
73
74         private String name;
75         
76         private Text nameText;
77
78         // In-line component
79         private Text lengthText;
80         // Turn component
81         private Text angleText;
82         // Rotated In-line, or turn component.
83         private Text rotationAngleText;
84
85         // Input for new PipeRun
86         private Double diameter;
87         private Double turnRadius;
88
89         private Text diameterText;
90         private Text turnRadiusText;
91
92         // Position selection
93         private Button startButton;
94         private Button middleButton;
95         private Button endButton;
96
97         private boolean inlineSplit = false;
98
99         ListViewer inlineViewer;
100         ListViewer turnViewer;
101         ListViewer endViewer;
102
103         private Set<String> usedNames;
104
105         public ComponentSelectionDialog(Shell parentShell, Set<PositionType> allowed, PipelineComponent component) {
106                 this(parentShell, allowed, component, Plant3D.URIs.Builtin);
107         }
108
109         public ComponentSelectionDialog(Shell parentShell, Set<PositionType> allowed, PipelineComponent component,
110                         String libUri) {
111                 super(parentShell);
112                 this.allowed = allowed;
113                 this.component = component;
114                 filterAllowed = new HashSet<PositionType>();
115                 insertAdjustable = component instanceof InlineComponent ? ((InlineComponent) component).isVariableLength()
116                                 : false;
117                 lenghtAdjustable = false;
118                 this.libUri = libUri;
119
120                 usedNames = new HashSet<>();
121
122                 setShellStyle(getShellStyle() | SWT.RESIZE);
123
124                 IDialogSettings settings = Activator.getDefault().getDialogSettings();
125                 dialogSettings = settings.getSection(DIALOG);
126                 if (dialogSettings == null)
127                         dialogSettings = settings.addNewSection(DIALOG);
128         }
129
130         @Override
131         protected IDialogSettings getDialogBoundsSettings() {
132                 return dialogSettings;
133         }
134
135         @Override
136         protected void configureShell(Shell newShell) {
137                 super.configureShell(newShell);
138                 newShell.setText("Create pipeline component");
139         }
140
141         public void addUsedNames(Collection<String> names) {
142                 usedNames.addAll(names);
143         }
144
145         protected List<Item> getItems(Class<?> c, String libUri) throws DatabaseException {
146                 if (InlineComponent.class.equals(c)) {
147                         return P3DUtil.getInlines(libUri);
148                 } else if (TurnComponent.class.equals(c)) {
149                         return P3DUtil.getTurns(libUri);
150                 } else if (EndComponent.class.equals(c)) {
151                         return P3DUtil.getEnds(libUri);
152                 } else {
153                         return null;
154                 }
155         }
156
157         @Override
158         protected Control createDialogArea(Composite parent) {
159                 resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
160
161                 Composite composite = new Composite(parent, SWT.NONE);
162                 GridLayout layout = new GridLayout(2, false);
163                 layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
164                 layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
165                 layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
166                 layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
167                 composite.setLayout(layout);
168                 composite.setLayoutData(new GridData(GridData.FILL_BOTH));
169                 applyDialogFont(composite);
170
171                 // Grid layout data for fields that grab horizontal space
172                 final GridDataFactory horizFillData = GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP);
173                 
174                 // TODO : we need better classification than inline,turn, and end:
175                 // * fixed length inlines
176                 // * fixed angle turns
177                 // * size changes (requires input for pipe run specs)
178                 // * variable length inlines (input for length)
179                 // * variable angle turns (input for angle)
180                 // * ends
181
182                 List<Item> ends = null;
183                 List<Item> turns = null;
184                 List<Item> inlines = null;
185                 try {
186                         ends = getItems(EndComponent.class, libUri);
187                         turns = getItems(TurnComponent.class, libUri);
188                         inlines = getItems(InlineComponent.class, libUri);
189                 } catch (DatabaseException e) {
190                         Label label = new Label(composite, SWT.NONE);
191                         label.setText("Cannot load pipeline components: " + e.getMessage());
192                         ExceptionUtils.logError(e);
193                         return composite;
194                 }
195                 ends = P3DUtil.filterUserComponents(ends);
196                 turns = P3DUtil.filterUserComponents(turns);
197                 inlines = P3DUtil.filterUserComponents(inlines);
198
199                 ExpandBar expandBar = new ExpandBar(composite, SWT.V_SCROLL);
200
201                 ExpandItem inlineItem = new ExpandItem(expandBar, SWT.NONE);
202                 inlineItem.setText("Inline");
203                 inlineViewer = new ListViewer(expandBar);
204                 inlineViewer.setLabelProvider(new ComponentLabelProvider());
205                 inlineViewer.setContentProvider(new ComponentContentProvider());
206
207                 ExpandItem turnItem = new ExpandItem(expandBar, SWT.NONE);
208                 turnItem.setText("Turn");
209                 turnViewer = new ListViewer(expandBar);
210                 turnViewer.setLabelProvider(new ComponentLabelProvider());
211                 turnViewer.setContentProvider(new ComponentContentProvider());
212
213                 ExpandItem endItem = new ExpandItem(expandBar, SWT.NONE);
214                 endItem.setText("End");
215                 endViewer = new ListViewer(expandBar);
216                 endViewer.setLabelProvider(new ComponentLabelProvider());
217                 endViewer.setContentProvider(new ComponentContentProvider());
218
219                 inlineItem.setControl(inlineViewer.getList());
220                 turnItem.setControl(turnViewer.getList());
221                 endItem.setControl(endViewer.getList());
222
223                 inlineViewer.setInput(inlines);
224                 turnViewer.setInput(turns);
225                 endViewer.setInput(ends);
226
227                 inlineItem.setHeight(inlineViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
228                 turnItem.setHeight(turnViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
229                 endItem.setHeight(endViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
230
231                 inlineViewer.addSelectionChangedListener(this);
232                 turnViewer.addSelectionChangedListener(this);
233                 endViewer.addSelectionChangedListener(this);
234
235                 GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).span(2, 1).applyTo(expandBar);
236                 GridDataFactory.fillDefaults().grab(true, true).minSize(500, 500).hint(500, 500).applyTo(composite);
237
238                 Label label = new Label(composite, SWT.NONE);
239                 label.setText("Position");
240                 Composite buttonComposite = new Composite(composite, SWT.NONE);
241                 startButton = new Button(buttonComposite, SWT.TOGGLE);
242                 middleButton = new Button(buttonComposite, SWT.TOGGLE);
243                 endButton = new Button(buttonComposite, SWT.TOGGLE);
244                 startButton.setImage(resourceManager.createImage(
245                                 ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_start.png").get()));
246                 middleButton.setImage(resourceManager.createImage(
247                                 ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_middle.png").get()));
248                 endButton.setImage(resourceManager.createImage(
249                                 ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_end.png").get()));
250                 startButton.setToolTipText("Overlapping insert");
251                 middleButton.setToolTipText("Cutting insert");
252                 endButton.setToolTipText("Adding insert");
253                 horizFillData.applyTo(buttonComposite);
254                 GridLayoutFactory.fillDefaults().numColumns(3).applyTo(buttonComposite);
255
256                 startButton.setEnabled(false);
257                 middleButton.setEnabled(false);
258                 endButton.setEnabled(false);
259
260                 startButton.addSelectionListener(new SelectionAdapter() {
261                         @Override
262                         public void widgetSelected(SelectionEvent e) {
263                                 updateInsertPosition(PositionType.PREVIOUS);
264                         }
265                 });
266
267                 middleButton.addSelectionListener(new SelectionAdapter() {
268                         @Override
269                         public void widgetSelected(SelectionEvent e) {
270                                 updateInsertPosition(PositionType.SPLIT);
271                         }
272                 });
273                 endButton.addSelectionListener(new SelectionAdapter() {
274                         @Override
275                         public void widgetSelected(SelectionEvent e) {
276                                 updateInsertPosition(PositionType.NEXT);
277                         }
278                 });
279                 endButton.setSelection(true);
280
281                 label = new Label(composite, SWT.NONE);
282                 label.setText("Name");
283                 nameText = new Text(composite, SWT.SINGLE | SWT.BORDER);
284
285                 label = new Label(composite, SWT.NONE);
286                 label.setText("Length");
287                 lengthText = new Text(composite, SWT.SINGLE | SWT.BORDER);
288                 label = new Label(composite, SWT.NONE);
289                 label.setText("Angle");
290                 angleText = new Text(composite, SWT.SINGLE | SWT.BORDER);
291                 label = new Label(composite, SWT.NONE);
292                 label.setText("Rotation angle");
293                 rotationAngleText = new Text(composite, SWT.SINGLE | SWT.BORDER);
294
295                 label = new Label(composite, SWT.NONE);
296                 label.setText("Diameter");
297                 diameterText = new Text(composite, SWT.SINGLE | SWT.BORDER);
298                 label = new Label(composite, SWT.NONE);
299                 label.setText("Turn Radius");
300                 turnRadiusText = new Text(composite, SWT.SINGLE | SWT.BORDER);
301
302                 lengthText.setEnabled(false);
303                 angleText.setEnabled(false);
304                 rotationAngleText.setEnabled(false);
305                 turnRadiusText.setEnabled(false);
306                 diameterText.setEnabled(false);
307
308                 nameText.addKeyListener(new KeyAdapter() {
309                         @Override
310                         public void keyReleased(KeyEvent e) {
311                                 name = nameText.getText();
312                                 validate();
313                         }
314                 });
315                 
316                 lengthText.addKeyListener(new KeyAdapter() {
317                         @Override
318                         public void keyReleased(KeyEvent e) {
319                                 try {
320                                         length = Double.parseDouble(lengthText.getText());
321                                 } catch (NumberFormatException err) {
322                                         length = null;
323                                 }
324                                 validate();
325                         }
326                 });
327
328                 angleText.addKeyListener(new KeyAdapter() {
329                         @Override
330                         public void keyReleased(KeyEvent e) {
331                                 try {
332                                         angle = Double.parseDouble(angleText.getText());
333                                 } catch (NumberFormatException err) {
334                                         angle = null;
335                                 }
336                                 validate();
337                         }
338                 });
339
340                 rotationAngleText.addKeyListener(new KeyAdapter() {
341                         @Override
342                         public void keyReleased(KeyEvent e) {
343                                 try {
344                                         rotationAngle = Double.parseDouble(rotationAngleText.getText());
345                                 } catch (NumberFormatException err) {
346                                         rotationAngle = null;
347                                 }
348                                 validate();
349                         }
350                 });
351
352                 diameterText.addKeyListener(new KeyAdapter() {
353                         @Override
354                         public void keyReleased(KeyEvent e) {
355                                 try {
356                                         diameter = Double.parseDouble(diameterText.getText());
357                                 } catch (NumberFormatException err) {
358                                         diameter = null;
359                                 }
360                                 validate();
361                         }
362                 });
363
364                 turnRadiusText.addKeyListener(new KeyAdapter() {
365                         @Override
366                         public void keyReleased(KeyEvent e) {
367                                 try {
368                                         turnRadius = Double.parseDouble(turnRadiusText.getText());
369                                 } catch (NumberFormatException err) {
370                                         turnRadius = null;
371                                 }
372                                 validate();
373                         }
374                 });
375
376                 horizFillData.applyTo(nameText);
377                 horizFillData.applyTo(lengthText);
378                 horizFillData.applyTo(angleText);
379                 horizFillData.applyTo(rotationAngleText);
380                 horizFillData.applyTo(diameterText);
381                 horizFillData.applyTo(turnRadiusText);
382
383                 if (!allowed.contains(PositionType.NEXT) && !allowed.contains(PositionType.PREVIOUS)) {
384                         turnViewer.getList().setEnabled(false);
385                         endViewer.getList().setEnabled(false);
386                         inlineSplit = true;
387                 }
388
389                 return composite;
390         }
391
392         private void updateInsertPosition(PositionType type) {
393                 if (insertPosition == type)
394                         return;
395                 endButton.setSelection(type == PositionType.NEXT);
396                 middleButton.setSelection(type == PositionType.SPLIT);
397                 startButton.setSelection(type == PositionType.PREVIOUS);
398                 insertPosition = type;
399         }
400
401         @Override
402         public void selectionChanged(SelectionChangedEvent event) {
403                 IStructuredSelection sel = (IStructuredSelection) event.getSelection();
404                 Item i = (Item) sel.getFirstElement();
405                 if (i != null) {
406                         selected = i;
407                         if (event.getSource() == inlineViewer) {
408                                 turnViewer.setSelection(new StructuredSelection());
409                                 endViewer.setSelection(new StructuredSelection());
410                         } else if (event.getSource() == turnViewer) {
411                                 inlineViewer.setSelection(new StructuredSelection());
412                                 endViewer.setSelection(new StructuredSelection());
413                         } else if (event.getSource() == endViewer) {
414                                 inlineViewer.setSelection(new StructuredSelection());
415                                 turnViewer.setSelection(new StructuredSelection());
416                         }
417                         
418                         name = generateUniqueName(selected.getName());
419                         nameText.setText(name);
420                         
421                         validate();
422                 }
423         }
424
425         private void validate() {
426                 filterAllowed.clear();
427                 Set<PositionType> filterAllowed = new HashSet<PositionType>();
428                 boolean ok = true;
429                 if (selected == null) {
430                         ok = false;
431                 } else if (selected.isCode()) {// TODO : instead of disabling the button, we should filter the content.
432                         ok = false;
433                 } else {
434                         lenghtAdjustable = ((selected.getType() == Type.INLINE)
435                                         && (selected.isVariable() || selected.isModifiable()));
436                         if (insertAdjustable) {
437                                 switch (selected.getType()) {
438                                 case END:
439                                         startButton.setEnabled(false);
440                                         middleButton.setEnabled(false);
441                                         endButton.setEnabled(true);
442                                         updateInsertPosition(PositionType.NEXT);
443                                         break;
444                                 case INLINE:
445                                         if (!selected.isVariable()) {
446                                                 startButton.setEnabled(true);
447                                                 middleButton.setEnabled(true);
448                                                 endButton.setEnabled(true);
449                                         } else {
450                                                 startButton.setEnabled(false);
451                                                 middleButton.setEnabled(false);
452                                                 endButton.setEnabled(true);
453                                                 updateInsertPosition(PositionType.NEXT);
454                                         }
455                                         break;
456                                 case NOZZLE:
457                                         startButton.setEnabled(false);
458                                         middleButton.setEnabled(false);
459                                         endButton.setEnabled(true);
460                                         updateInsertPosition(PositionType.NEXT);
461                                         break;
462                                 case TURN:
463                                         startButton.setEnabled(false);
464                                         middleButton.setEnabled(true);
465                                         endButton.setEnabled(true);
466                                         if (insertPosition == PositionType.PREVIOUS)
467                                                 updateInsertPosition(PositionType.NEXT);
468                                         break;
469                                 case EQUIPMENT:
470                                         throw new RuntimeException("Expected component, got equipment " + selected);
471                                 }
472                         } else if (lenghtAdjustable) {
473                                 if (component instanceof InlineComponent) {
474                                         startButton.setEnabled(true);
475                                         middleButton.setEnabled(true);
476                                         endButton.setEnabled(true);
477                                 } else if (component instanceof TurnComponent) {
478                                         startButton.setEnabled(false);
479                                         middleButton.setEnabled(true);
480                                         endButton.setEnabled(true);
481                                         if (insertPosition == PositionType.PREVIOUS)
482                                                 updateInsertPosition(PositionType.NEXT);
483                                 } else if (component instanceof EndComponent || component instanceof Nozzle) {
484                                         startButton.setEnabled(false);
485                                         middleButton.setEnabled(false);
486                                         endButton.setEnabled(true);
487                                         updateInsertPosition(PositionType.NEXT);
488                                 }
489                         } else {
490                                 startButton.setEnabled(false);
491                                 middleButton.setEnabled(false);
492                                 endButton.setEnabled(true);
493                         }
494                         if (selected.isVariable() || selected.isModifiable()) {
495                                 if (selected.getType() == Type.INLINE) {
496                                         filterAllowed.add(PositionType.NEXT);
497                                         filterAllowed.add(PositionType.PREVIOUS);
498                                         if (inlineSplit && selected.isVariable()) {
499                                                 lengthText.setEnabled(false);
500                                                 angleText.setEnabled(false);
501                                                 rotationAngleText.setEnabled(selected.isRotated());
502                                                 ok = false;
503
504                                         } else {
505                                                 lengthText.setEnabled(true);
506                                                 angleText.setEnabled(false);
507                                                 rotationAngleText.setEnabled(selected.isRotated());
508                                                 if (length == null)
509                                                         ok = false;
510                                         }
511                                 } else if (selected.getType() == Type.TURN) {
512                                         filterAllowed.add(PositionType.NEXT);
513                                         filterAllowed.add(PositionType.PREVIOUS);
514                                         lengthText.setEnabled(false);
515                                         angleText.setEnabled(true);
516                                         rotationAngleText.setEnabled(true);
517                                         if (angle == null)
518                                                 ok = false;
519                                 } else {
520                                         // this should not happen, since end components should not have variable, or
521                                         // modifiable flag.
522                                         lengthText.setEnabled(false);
523                                         angleText.setEnabled(false);
524                                         rotationAngleText.setEnabled(false);
525
526                                 }
527                         } else {
528                                 lengthText.setEnabled(false);
529                                 angleText.setEnabled(false);
530                                 rotationAngleText.setEnabled(selected.getType() == Type.TURN || selected.isRotated());
531                         }
532
533                         if (selected.isSizeChange()) {
534                                 turnRadiusText.setEnabled(true);
535                                 diameterText.setEnabled(true);
536                                 if (diameter == null || turnRadius == null)
537                                         ok = false;
538                         } else {
539                                 turnRadiusText.setEnabled(false);
540                                 diameterText.setEnabled(false);
541                         }
542
543                         if (!selected.isVariable()) {
544                                 switch (selected.getType()) {
545                                 case END:
546                                         filterAllowed.add(PositionType.NEXT);
547                                         filterAllowed.add(PositionType.PREVIOUS);
548                                         break;
549                                 case NOZZLE:
550                                 case EQUIPMENT:
551                                         break;
552                                 case INLINE:
553                                         filterAllowed.add(PositionType.NEXT);
554                                         filterAllowed.add(PositionType.PREVIOUS);
555                                         filterAllowed.add(PositionType.SPLIT);
556                                 case TURN:
557                                         filterAllowed.add(PositionType.NEXT);
558                                         filterAllowed.add(PositionType.PREVIOUS);
559                                 }
560                         }
561                 }
562                 for (PositionType t : filterAllowed) {
563                         if (allowed.contains(t))
564                                 this.filterAllowed.add(t);
565                 }
566
567                 if (name.isEmpty() || usedNames.contains(name))
568                         ok = false;
569                 
570                 getButton(OK).setEnabled(ok);
571         }
572
573         private String generateUniqueName(String name) {
574                 int i = 1;
575                 String newName;
576                 while (usedNames.contains((newName = name + "_" + i)))
577                         i++;
578                 return newName;
579         }
580
581         public Item getSelected() {
582                 return selected;
583         }
584         
585         public String getName() {
586                 return name;
587         }
588
589         public Double getAngle() {
590                 return angle;
591         }
592
593         public Double getLength() {
594                 return length;
595         }
596
597         public Double getRotationAngle() {
598                 return rotationAngle;
599         }
600
601         public Double getDiameter() {
602                 return diameter;
603         }
604
605         public Double getTurnRadius() {
606                 return turnRadius;
607         }
608
609         public Set<PositionType> filterAllowed() {
610                 return filterAllowed;
611         }
612
613         public PositionType getInsertPosition() {
614                 return insertPosition;
615         }
616
617         public boolean isInsertAdjustable() {
618                 return insertAdjustable;
619         }
620
621         public boolean isLenghtAdjustable() {
622                 return lenghtAdjustable;
623         }
624
625 }