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