1 package org.simantics.plant3d.dialog;
3 import java.util.Collection;
4 import java.util.HashSet;
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.Simantics;
38 import org.simantics.db.Session;
39 import org.simantics.db.exception.DatabaseException;
40 import org.simantics.plant3d.Activator;
41 import org.simantics.plant3d.ontology.Plant3D;
42 import org.simantics.plant3d.scenegraph.EndComponent;
43 import org.simantics.plant3d.scenegraph.InlineComponent;
44 import org.simantics.plant3d.scenegraph.Nozzle;
45 import org.simantics.plant3d.scenegraph.PipelineComponent;
46 import org.simantics.plant3d.scenegraph.TurnComponent;
47 import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType;
48 import org.simantics.plant3d.utils.Item;
49 import org.simantics.plant3d.utils.Item.Type;
50 import org.simantics.plant3d.utils.P3DUtil;
51 import org.simantics.utils.ui.ExceptionUtils;
53 public class ComponentSelectionDialog extends Dialog implements ISelectionChangedListener {
55 private static final String DIALOG = "ComponentSelectionDialog"; //$NON-NLS-1$
57 private IDialogSettings dialogSettings;
59 private double lengthFactor = 1.0;
61 private ResourceManager resourceManager;
63 private String libUri;
65 private Item selected;
66 private Set<PositionType> allowed;
67 private Set<PositionType> filterAllowed;
68 // private boolean positionAdjustment;
69 private PipelineComponent component;
70 private boolean insertAdjustable;
71 private boolean lenghtAdjustable;
72 private PositionType insertPosition = PositionType.NEXT;
75 private Double length;
76 private Double rotationAngle;
80 private Text nameText;
83 private Text lengthText;
85 private Text angleText;
86 // Rotated In-line, or turn component.
87 private Text rotationAngleText;
89 // Input for new PipeRun
90 private Double diameter;
91 private Double thickness;
92 private Double turnRadius;
94 private Text diameterText;
95 private Text thicknessText;
96 private Text turnRadiusText;
98 // Validation message label
99 private Label validationLabel;
101 // Position selection
102 private Button startButton;
103 private Button middleButton;
104 private Button endButton;
106 private boolean inlineSplit = false;
108 ListViewer inlineViewer;
109 ListViewer turnViewer;
110 ListViewer endViewer;
112 private Set<String> usedNames;
114 public ComponentSelectionDialog(Shell parentShell, Set<PositionType> allowed, PipelineComponent component) {
115 this(parentShell, allowed, component, Plant3D.URIs.Builtin);
118 public ComponentSelectionDialog(Shell parentShell, Set<PositionType> allowed, PipelineComponent component,
121 this.allowed = allowed;
122 this.component = component;
123 filterAllowed = new HashSet<PositionType>();
124 insertAdjustable = component instanceof InlineComponent ? ((InlineComponent) component).isVariableLength()
126 lenghtAdjustable = false;
127 this.libUri = libUri;
129 usedNames = new HashSet<>();
131 setShellStyle(getShellStyle() | SWT.RESIZE);
133 IDialogSettings settings = Activator.getDefault().getDialogSettings();
134 dialogSettings = settings.getSection(DIALOG);
135 if (dialogSettings == null)
136 dialogSettings = settings.addNewSection(DIALOG);
138 if (component.getNext() != null && component.getPrevious() != null)
139 insertPosition = PositionType.PREVIOUS;
142 public void setLengthFactor(double lengthFactor) {
143 this.lengthFactor = lengthFactor;
147 protected IDialogSettings getDialogBoundsSettings() {
148 return dialogSettings;
152 protected void configureShell(Shell newShell) {
153 super.configureShell(newShell);
154 newShell.setText("Create pipeline component");
157 public void addUsedNames(Collection<String> names) {
158 usedNames.addAll(names);
161 protected List<Item> getItems(Class<?> c, String libUri) throws DatabaseException {
162 Session session = Simantics.getSession();
163 if (InlineComponent.class.equals(c)) {
164 return P3DUtil.getInlines(session, libUri);
165 } else if (TurnComponent.class.equals(c)) {
166 return P3DUtil.getTurns(session, libUri);
167 } else if (EndComponent.class.equals(c)) {
168 return P3DUtil.getEnds(session, libUri);
175 protected Control createDialogArea(Composite parent) {
176 resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
178 Composite composite = new Composite(parent, SWT.NONE);
179 GridLayout layout = new GridLayout(2, false);
180 layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
181 layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
182 layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
183 layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
184 composite.setLayout(layout);
185 composite.setLayoutData(new GridData(GridData.FILL_BOTH));
186 applyDialogFont(composite);
188 // Grid layout data for fields that grab horizontal space
189 final GridDataFactory horizFillData = GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP);
191 // TODO : we need better classification than inline,turn, and end:
192 // * fixed length inlines
193 // * fixed angle turns
194 // * size changes (requires input for pipe run specs)
195 // * variable length inlines (input for length)
196 // * variable angle turns (input for angle)
199 List<Item> ends = null;
200 List<Item> turns = null;
201 List<Item> inlines = null;
203 ends = getItems(EndComponent.class, libUri);
204 turns = getItems(TurnComponent.class, libUri);
205 inlines = getItems(InlineComponent.class, libUri);
206 } catch (DatabaseException e) {
207 Label label = new Label(composite, SWT.NONE);
208 label.setText("Cannot load pipeline components: " + e.getMessage());
209 ExceptionUtils.logError(e);
212 ends = P3DUtil.filterUserComponents(ends);
213 turns = P3DUtil.filterUserComponents(turns);
214 inlines = P3DUtil.filterUserComponents(inlines);
216 ExpandBar expandBar = new ExpandBar(composite, SWT.V_SCROLL);
218 ExpandItem inlineItem = new ExpandItem(expandBar, SWT.NONE);
219 inlineItem.setText("Inline");
220 inlineViewer = new ListViewer(expandBar);
221 inlineViewer.setLabelProvider(new ComponentLabelProvider());
222 inlineViewer.setContentProvider(new ComponentContentProvider());
224 ExpandItem turnItem = new ExpandItem(expandBar, SWT.NONE);
225 turnItem.setText("Turn");
226 turnViewer = new ListViewer(expandBar);
227 turnViewer.setLabelProvider(new ComponentLabelProvider());
228 turnViewer.setContentProvider(new ComponentContentProvider());
230 ExpandItem endItem = new ExpandItem(expandBar, SWT.NONE);
231 endItem.setText("End");
232 endViewer = new ListViewer(expandBar);
233 endViewer.setLabelProvider(new ComponentLabelProvider());
234 endViewer.setContentProvider(new ComponentContentProvider());
236 inlineItem.setControl(inlineViewer.getList());
237 turnItem.setControl(turnViewer.getList());
238 endItem.setControl(endViewer.getList());
240 inlineViewer.setInput(inlines);
241 turnViewer.setInput(turns);
242 endViewer.setInput(ends);
244 inlineItem.setHeight(inlineViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
245 turnItem.setHeight(turnViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
246 endItem.setHeight(endViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
248 inlineViewer.addSelectionChangedListener(this);
249 turnViewer.addSelectionChangedListener(this);
250 endViewer.addSelectionChangedListener(this);
252 GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).span(2, 1).applyTo(expandBar);
253 GridDataFactory.fillDefaults().grab(true, true).minSize(500, 500).hint(500, 500).applyTo(composite);
255 Label label = new Label(composite, SWT.NONE);
256 label.setText("Position");
257 Composite buttonComposite = new Composite(composite, SWT.NONE);
258 startButton = new Button(buttonComposite, SWT.TOGGLE);
259 middleButton = new Button(buttonComposite, SWT.TOGGLE);
260 endButton = new Button(buttonComposite, SWT.TOGGLE);
261 startButton.setImage(resourceManager.createImage(
262 ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_start.png").get()));
263 middleButton.setImage(resourceManager.createImage(
264 ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_middle.png").get()));
265 endButton.setImage(resourceManager.createImage(
266 ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_end.png").get()));
267 startButton.setToolTipText("Overlapping insert");
268 middleButton.setToolTipText("Cutting insert");
269 endButton.setToolTipText("Adding insert");
270 horizFillData.applyTo(buttonComposite);
271 GridLayoutFactory.fillDefaults().numColumns(3).applyTo(buttonComposite);
273 startButton.setSelection(insertPosition == PositionType.PREVIOUS);
274 middleButton.setSelection(insertPosition == PositionType.SPLIT);
275 endButton.setSelection(insertPosition == PositionType.NEXT);
277 startButton.setEnabled(false);
278 middleButton.setEnabled(false);
279 endButton.setEnabled(false);
281 startButton.addSelectionListener(new SelectionAdapter() {
283 public void widgetSelected(SelectionEvent e) {
284 updateInsertPosition(PositionType.PREVIOUS);
288 middleButton.addSelectionListener(new SelectionAdapter() {
290 public void widgetSelected(SelectionEvent e) {
291 updateInsertPosition(PositionType.SPLIT);
294 endButton.addSelectionListener(new SelectionAdapter() {
296 public void widgetSelected(SelectionEvent e) {
297 updateInsertPosition(PositionType.NEXT);
301 label = new Label(composite, SWT.NONE);
302 label.setText("Name");
303 nameText = new Text(composite, SWT.SINGLE | SWT.BORDER);
305 label = new Label(composite, SWT.NONE);
306 label.setText("Length");
307 lengthText = new Text(composite, SWT.SINGLE | SWT.BORDER);
308 label = new Label(composite, SWT.NONE);
309 label.setText("Angle");
310 angleText = new Text(composite, SWT.SINGLE | SWT.BORDER);
311 label = new Label(composite, SWT.NONE);
312 label.setText("Rotation angle");
313 rotationAngleText = new Text(composite, SWT.SINGLE | SWT.BORDER);
315 label = new Label(composite, SWT.NONE);
316 label.setText("Diameter");
317 diameterText = new Text(composite, SWT.SINGLE | SWT.BORDER);
318 label = new Label(composite, SWT.NONE);
319 label.setText("Wall thickness");
320 thicknessText = new Text(composite, SWT.SINGLE | SWT.BORDER);
321 label = new Label(composite, SWT.NONE);
322 label.setText("Turn radius");
323 turnRadiusText = new Text(composite, SWT.SINGLE | SWT.BORDER);
325 validationLabel = new Label(composite, SWT.NONE);
326 validationLabel.setText("");
328 lengthText.setEnabled(false);
329 angleText.setEnabled(false);
330 rotationAngleText.setEnabled(false);
331 turnRadiusText.setEnabled(false);
332 diameterText.setEnabled(false);
333 thicknessText.setEnabled(false);
335 nameText.addKeyListener(new KeyAdapter() {
337 public void keyReleased(KeyEvent e) {
338 name = nameText.getText();
343 lengthText.addKeyListener(new KeyAdapter() {
345 public void keyReleased(KeyEvent e) {
347 length = Double.parseDouble(lengthText.getText()) / lengthFactor;
348 } catch (NumberFormatException err) {
355 angleText.addKeyListener(new KeyAdapter() {
357 public void keyReleased(KeyEvent e) {
359 angle = Double.parseDouble(angleText.getText());
360 } catch (NumberFormatException err) {
367 rotationAngleText.addKeyListener(new KeyAdapter() {
369 public void keyReleased(KeyEvent e) {
371 rotationAngle = Double.parseDouble(rotationAngleText.getText());
372 } catch (NumberFormatException err) {
373 rotationAngle = null;
379 diameterText.addKeyListener(new KeyAdapter() {
381 public void keyReleased(KeyEvent e) {
383 diameter = Double.parseDouble(diameterText.getText()) / lengthFactor;
384 } catch (NumberFormatException err) {
391 thicknessText.addKeyListener(new KeyAdapter() {
393 public void keyReleased(KeyEvent e) {
395 thickness = Double.parseDouble(thicknessText.getText()) / lengthFactor;
396 } catch (NumberFormatException err) {
403 turnRadiusText.addKeyListener(new KeyAdapter() {
405 public void keyReleased(KeyEvent e) {
407 turnRadius = Double.parseDouble(turnRadiusText.getText()) / lengthFactor;
408 } catch (NumberFormatException err) {
415 horizFillData.applyTo(nameText);
416 horizFillData.applyTo(lengthText);
417 horizFillData.applyTo(angleText);
418 horizFillData.applyTo(rotationAngleText);
419 horizFillData.applyTo(diameterText);
420 horizFillData.applyTo(thicknessText);
421 horizFillData.applyTo(turnRadiusText);
423 GridDataFactory.fillDefaults().span(2, 1).align(SWT.END, SWT.END).grab(true, false).applyTo(validationLabel);
425 if (!allowed.contains(PositionType.NEXT) && !allowed.contains(PositionType.PREVIOUS)) {
426 turnViewer.getList().setEnabled(false);
427 endViewer.getList().setEnabled(false);
434 private void updateInsertPosition(PositionType type) {
435 if (insertPosition == type)
437 startButton.setSelection(type == PositionType.PREVIOUS);
438 middleButton.setSelection(type == PositionType.SPLIT);
439 endButton.setSelection(type == PositionType.NEXT);
440 insertPosition = type;
444 public void selectionChanged(SelectionChangedEvent event) {
445 IStructuredSelection sel = (IStructuredSelection) event.getSelection();
446 Item i = (Item) sel.getFirstElement();
449 if (event.getSource() == inlineViewer) {
450 turnViewer.setSelection(new StructuredSelection());
451 endViewer.setSelection(new StructuredSelection());
452 } else if (event.getSource() == turnViewer) {
453 inlineViewer.setSelection(new StructuredSelection());
454 endViewer.setSelection(new StructuredSelection());
455 } else if (event.getSource() == endViewer) {
456 inlineViewer.setSelection(new StructuredSelection());
457 turnViewer.setSelection(new StructuredSelection());
460 name = generateUniqueName(selected.getName());
461 nameText.setText(name);
467 private void validate() {
468 filterAllowed.clear();
469 Set<PositionType> filterAllowed = new HashSet<PositionType>();
473 if (name.isEmpty() || usedNames.contains(name)) {
477 msg = "Please provide a valid name";
479 msg = "Name \"" + name + "\" is already in use";
483 if (selected == null) {
485 } else if (selected.isCode()) {// TODO : instead of disabling the button, we should filter the content.
488 lenghtAdjustable = ((selected.getType() == Type.INLINE)
489 && (selected.isVariable() || selected.isModifiable()));
491 if (component.getNext() != null && component.getPrevious() != null) {
492 // We are inserting to a fully connected variable length component
493 // only allow insertion within the component
494 startButton.setEnabled(false);
495 middleButton.setEnabled(false);
496 endButton.setEnabled(false);
497 updateInsertPosition(PositionType.PREVIOUS);
498 } else if (insertAdjustable) {
499 switch (selected.getType()) {
501 startButton.setEnabled(false);
502 middleButton.setEnabled(false);
503 endButton.setEnabled(true);
504 updateInsertPosition(PositionType.NEXT);
507 if (!selected.isVariable()) {
508 startButton.setEnabled(true);
509 middleButton.setEnabled(true);
510 endButton.setEnabled(true);
512 startButton.setEnabled(false);
513 middleButton.setEnabled(false);
514 endButton.setEnabled(true);
515 updateInsertPosition(PositionType.NEXT);
519 startButton.setEnabled(false);
520 middleButton.setEnabled(false);
521 endButton.setEnabled(true);
522 updateInsertPosition(PositionType.NEXT);
525 startButton.setEnabled(false);
526 middleButton.setEnabled(true);
527 endButton.setEnabled(true);
528 if (insertPosition == PositionType.PREVIOUS)
529 updateInsertPosition(PositionType.NEXT);
532 throw new RuntimeException("Expected component, got equipment " + selected);
534 } else if (lenghtAdjustable) {
535 if (component instanceof InlineComponent) {
536 startButton.setEnabled(true);
537 middleButton.setEnabled(true);
538 endButton.setEnabled(true);
539 } else if (component instanceof TurnComponent) {
540 startButton.setEnabled(false);
541 middleButton.setEnabled(true);
542 endButton.setEnabled(true);
543 if (insertPosition == PositionType.PREVIOUS)
544 updateInsertPosition(PositionType.NEXT);
545 } else if (component instanceof EndComponent || component instanceof Nozzle) {
546 startButton.setEnabled(false);
547 middleButton.setEnabled(false);
548 endButton.setEnabled(true);
549 updateInsertPosition(PositionType.NEXT);
552 startButton.setEnabled(false);
553 middleButton.setEnabled(false);
554 endButton.setEnabled(true);
556 if (selected.isVariable() || selected.isModifiable()) {
557 if (selected.getType() == Type.INLINE) {
558 filterAllowed.add(PositionType.NEXT);
559 filterAllowed.add(PositionType.PREVIOUS);
560 if (inlineSplit && selected.isVariable()) {
561 lengthText.setEnabled(false);
562 angleText.setEnabled(false);
563 rotationAngleText.setEnabled(selected.isRotated());
565 if (msg == null) msg = "Cannot split a straight pipe with a straight pipe";
567 lengthText.setEnabled(true);
568 angleText.setEnabled(false);
569 rotationAngleText.setEnabled(selected.isRotated());
570 if (length == null || length <= 0.0) {
572 if (msg == null) msg = "Please provide a valid length";
575 } else if (selected.getType() == Type.TURN) {
576 filterAllowed.add(PositionType.NEXT);
577 filterAllowed.add(PositionType.PREVIOUS);
578 lengthText.setEnabled(false);
579 angleText.setEnabled(true);
580 rotationAngleText.setEnabled(true);
583 if (msg == null) msg = "Please provide a turn angle";
586 // this should not happen, since end components should not have variable, or
588 lengthText.setEnabled(false);
589 angleText.setEnabled(false);
590 rotationAngleText.setEnabled(false);
594 lengthText.setEnabled(false);
595 angleText.setEnabled(false);
596 rotationAngleText.setEnabled(selected.getType() == Type.TURN || selected.isRotated());
599 if (selected.isSizeChange()) {
600 turnRadiusText.setEnabled(true);
601 diameterText.setEnabled(true);
602 thicknessText.setEnabled(true);
603 if (diameter == null || diameter <= 0.0) {
605 if (msg == null) msg = "Please provide a valid diameter";
607 if (turnRadius == null || diameter != null && turnRadius < diameter / 2) {
609 if (msg == null) msg = "Please provide a valid turn radius";
611 if (thickness == null || thickness < 0.0 || diameter != null && thickness >= diameter / 2) {
613 if (msg == null) msg = "Please provide a valid wall thickness";
616 turnRadiusText.setEnabled(false);
617 diameterText.setEnabled(false);
620 if (!selected.isVariable()) {
621 switch (selected.getType()) {
623 filterAllowed.add(PositionType.NEXT);
624 filterAllowed.add(PositionType.PREVIOUS);
630 filterAllowed.add(PositionType.NEXT);
631 filterAllowed.add(PositionType.PREVIOUS);
632 filterAllowed.add(PositionType.SPLIT);
634 filterAllowed.add(PositionType.NEXT);
635 filterAllowed.add(PositionType.PREVIOUS);
639 for (PositionType t : filterAllowed) {
640 if (allowed.contains(t))
641 this.filterAllowed.add(t);
644 validationLabel.setText(msg != null ? msg : "");
645 validationLabel.requestLayout();
647 getButton(OK).setEnabled(ok);
650 private String generateUniqueName(String name) {
653 while (usedNames.contains((newName = name + "_" + i)))
658 public Item getSelected() {
662 public String getName() {
666 public Double getAngle() {
670 public Double getLength() {
674 public Double getRotationAngle() {
675 return rotationAngle;
678 public Double getDiameter() {
682 public Double getTurnRadius() {
686 public Set<PositionType> filterAllowed() {
687 return filterAllowed;
690 public PositionType getInsertPosition() {
691 return insertPosition;
694 public boolean isInsertAdjustable() {
695 return insertAdjustable;
698 public boolean isLenghtAdjustable() {
699 return lenghtAdjustable;
702 public Double getThickness() {