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);
139 public void setLengthFactor(double lengthFactor) {
140 this.lengthFactor = lengthFactor;
144 protected IDialogSettings getDialogBoundsSettings() {
145 return dialogSettings;
149 protected void configureShell(Shell newShell) {
150 super.configureShell(newShell);
151 newShell.setText("Create pipeline component");
154 public void addUsedNames(Collection<String> names) {
155 usedNames.addAll(names);
158 protected List<Item> getItems(Class<?> c, String libUri) throws DatabaseException {
159 Session session = Simantics.getSession();
160 if (InlineComponent.class.equals(c)) {
161 return P3DUtil.getInlines(session, libUri);
162 } else if (TurnComponent.class.equals(c)) {
163 return P3DUtil.getTurns(session, libUri);
164 } else if (EndComponent.class.equals(c)) {
165 return P3DUtil.getEnds(session, libUri);
172 protected Control createDialogArea(Composite parent) {
173 resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent);
175 Composite composite = new Composite(parent, SWT.NONE);
176 GridLayout layout = new GridLayout(2, false);
177 layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
178 layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
179 layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
180 layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
181 composite.setLayout(layout);
182 composite.setLayoutData(new GridData(GridData.FILL_BOTH));
183 applyDialogFont(composite);
185 // Grid layout data for fields that grab horizontal space
186 final GridDataFactory horizFillData = GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP);
188 // TODO : we need better classification than inline,turn, and end:
189 // * fixed length inlines
190 // * fixed angle turns
191 // * size changes (requires input for pipe run specs)
192 // * variable length inlines (input for length)
193 // * variable angle turns (input for angle)
196 List<Item> ends = null;
197 List<Item> turns = null;
198 List<Item> inlines = null;
200 ends = getItems(EndComponent.class, libUri);
201 turns = getItems(TurnComponent.class, libUri);
202 inlines = getItems(InlineComponent.class, libUri);
203 } catch (DatabaseException e) {
204 Label label = new Label(composite, SWT.NONE);
205 label.setText("Cannot load pipeline components: " + e.getMessage());
206 ExceptionUtils.logError(e);
209 ends = P3DUtil.filterUserComponents(ends);
210 turns = P3DUtil.filterUserComponents(turns);
211 inlines = P3DUtil.filterUserComponents(inlines);
213 ExpandBar expandBar = new ExpandBar(composite, SWT.V_SCROLL);
215 ExpandItem inlineItem = new ExpandItem(expandBar, SWT.NONE);
216 inlineItem.setText("Inline");
217 inlineViewer = new ListViewer(expandBar);
218 inlineViewer.setLabelProvider(new ComponentLabelProvider());
219 inlineViewer.setContentProvider(new ComponentContentProvider());
221 ExpandItem turnItem = new ExpandItem(expandBar, SWT.NONE);
222 turnItem.setText("Turn");
223 turnViewer = new ListViewer(expandBar);
224 turnViewer.setLabelProvider(new ComponentLabelProvider());
225 turnViewer.setContentProvider(new ComponentContentProvider());
227 ExpandItem endItem = new ExpandItem(expandBar, SWT.NONE);
228 endItem.setText("End");
229 endViewer = new ListViewer(expandBar);
230 endViewer.setLabelProvider(new ComponentLabelProvider());
231 endViewer.setContentProvider(new ComponentContentProvider());
233 inlineItem.setControl(inlineViewer.getList());
234 turnItem.setControl(turnViewer.getList());
235 endItem.setControl(endViewer.getList());
237 inlineViewer.setInput(inlines);
238 turnViewer.setInput(turns);
239 endViewer.setInput(ends);
241 inlineItem.setHeight(inlineViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
242 turnItem.setHeight(turnViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
243 endItem.setHeight(endViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y);
245 inlineViewer.addSelectionChangedListener(this);
246 turnViewer.addSelectionChangedListener(this);
247 endViewer.addSelectionChangedListener(this);
249 GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).span(2, 1).applyTo(expandBar);
250 GridDataFactory.fillDefaults().grab(true, true).minSize(500, 500).hint(500, 500).applyTo(composite);
252 Label label = new Label(composite, SWT.NONE);
253 label.setText("Position");
254 Composite buttonComposite = new Composite(composite, SWT.NONE);
255 startButton = new Button(buttonComposite, SWT.TOGGLE);
256 middleButton = new Button(buttonComposite, SWT.TOGGLE);
257 endButton = new Button(buttonComposite, SWT.TOGGLE);
258 startButton.setImage(resourceManager.createImage(
259 ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_start.png").get()));
260 middleButton.setImage(resourceManager.createImage(
261 ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_middle.png").get()));
262 endButton.setImage(resourceManager.createImage(
263 ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_end.png").get()));
264 startButton.setToolTipText("Overlapping insert");
265 middleButton.setToolTipText("Cutting insert");
266 endButton.setToolTipText("Adding insert");
267 horizFillData.applyTo(buttonComposite);
268 GridLayoutFactory.fillDefaults().numColumns(3).applyTo(buttonComposite);
270 startButton.setEnabled(false);
271 middleButton.setEnabled(false);
272 endButton.setEnabled(false);
274 startButton.addSelectionListener(new SelectionAdapter() {
276 public void widgetSelected(SelectionEvent e) {
277 updateInsertPosition(PositionType.PREVIOUS);
281 middleButton.addSelectionListener(new SelectionAdapter() {
283 public void widgetSelected(SelectionEvent e) {
284 updateInsertPosition(PositionType.SPLIT);
287 endButton.addSelectionListener(new SelectionAdapter() {
289 public void widgetSelected(SelectionEvent e) {
290 updateInsertPosition(PositionType.NEXT);
293 endButton.setSelection(true);
295 label = new Label(composite, SWT.NONE);
296 label.setText("Name");
297 nameText = new Text(composite, SWT.SINGLE | SWT.BORDER);
299 label = new Label(composite, SWT.NONE);
300 label.setText("Length");
301 lengthText = new Text(composite, SWT.SINGLE | SWT.BORDER);
302 label = new Label(composite, SWT.NONE);
303 label.setText("Angle");
304 angleText = new Text(composite, SWT.SINGLE | SWT.BORDER);
305 label = new Label(composite, SWT.NONE);
306 label.setText("Rotation angle");
307 rotationAngleText = new Text(composite, SWT.SINGLE | SWT.BORDER);
309 label = new Label(composite, SWT.NONE);
310 label.setText("Diameter");
311 diameterText = new Text(composite, SWT.SINGLE | SWT.BORDER);
312 label = new Label(composite, SWT.NONE);
313 label.setText("Wall thickness");
314 thicknessText = new Text(composite, SWT.SINGLE | SWT.BORDER);
315 label = new Label(composite, SWT.NONE);
316 label.setText("Turn radius");
317 turnRadiusText = new Text(composite, SWT.SINGLE | SWT.BORDER);
319 validationLabel = new Label(composite, SWT.NONE);
320 validationLabel.setText("");
322 lengthText.setEnabled(false);
323 angleText.setEnabled(false);
324 rotationAngleText.setEnabled(false);
325 turnRadiusText.setEnabled(false);
326 diameterText.setEnabled(false);
327 thicknessText.setEnabled(false);
329 nameText.addKeyListener(new KeyAdapter() {
331 public void keyReleased(KeyEvent e) {
332 name = nameText.getText();
337 lengthText.addKeyListener(new KeyAdapter() {
339 public void keyReleased(KeyEvent e) {
341 length = Double.parseDouble(lengthText.getText()) / lengthFactor;
342 } catch (NumberFormatException err) {
349 angleText.addKeyListener(new KeyAdapter() {
351 public void keyReleased(KeyEvent e) {
353 angle = Double.parseDouble(angleText.getText());
354 } catch (NumberFormatException err) {
361 rotationAngleText.addKeyListener(new KeyAdapter() {
363 public void keyReleased(KeyEvent e) {
365 rotationAngle = Double.parseDouble(rotationAngleText.getText());
366 } catch (NumberFormatException err) {
367 rotationAngle = null;
373 diameterText.addKeyListener(new KeyAdapter() {
375 public void keyReleased(KeyEvent e) {
377 diameter = Double.parseDouble(diameterText.getText()) / lengthFactor;
378 } catch (NumberFormatException err) {
385 thicknessText.addKeyListener(new KeyAdapter() {
387 public void keyReleased(KeyEvent e) {
389 thickness = Double.parseDouble(thicknessText.getText()) / lengthFactor;
390 } catch (NumberFormatException err) {
397 turnRadiusText.addKeyListener(new KeyAdapter() {
399 public void keyReleased(KeyEvent e) {
401 turnRadius = Double.parseDouble(turnRadiusText.getText()) / lengthFactor;
402 } catch (NumberFormatException err) {
409 horizFillData.applyTo(nameText);
410 horizFillData.applyTo(lengthText);
411 horizFillData.applyTo(angleText);
412 horizFillData.applyTo(rotationAngleText);
413 horizFillData.applyTo(diameterText);
414 horizFillData.applyTo(thicknessText);
415 horizFillData.applyTo(turnRadiusText);
417 GridDataFactory.fillDefaults().span(2, 1).align(SWT.END, SWT.END).grab(true, false).applyTo(validationLabel);
419 if (!allowed.contains(PositionType.NEXT) && !allowed.contains(PositionType.PREVIOUS)) {
420 turnViewer.getList().setEnabled(false);
421 endViewer.getList().setEnabled(false);
428 private void updateInsertPosition(PositionType type) {
429 if (insertPosition == type)
431 endButton.setSelection(type == PositionType.NEXT);
432 middleButton.setSelection(type == PositionType.SPLIT);
433 startButton.setSelection(type == PositionType.PREVIOUS);
434 insertPosition = type;
438 public void selectionChanged(SelectionChangedEvent event) {
439 IStructuredSelection sel = (IStructuredSelection) event.getSelection();
440 Item i = (Item) sel.getFirstElement();
443 if (event.getSource() == inlineViewer) {
444 turnViewer.setSelection(new StructuredSelection());
445 endViewer.setSelection(new StructuredSelection());
446 } else if (event.getSource() == turnViewer) {
447 inlineViewer.setSelection(new StructuredSelection());
448 endViewer.setSelection(new StructuredSelection());
449 } else if (event.getSource() == endViewer) {
450 inlineViewer.setSelection(new StructuredSelection());
451 turnViewer.setSelection(new StructuredSelection());
454 name = generateUniqueName(selected.getName());
455 nameText.setText(name);
461 private void validate() {
462 filterAllowed.clear();
463 Set<PositionType> filterAllowed = new HashSet<PositionType>();
467 if (name.isEmpty() || usedNames.contains(name)) {
471 msg = "Please provide a valid name";
473 msg = "Name \"" + name + "\" is already in use";
477 if (selected == null) {
479 } else if (selected.isCode()) {// TODO : instead of disabling the button, we should filter the content.
482 lenghtAdjustable = ((selected.getType() == Type.INLINE)
483 && (selected.isVariable() || selected.isModifiable()));
484 if (insertAdjustable) {
485 switch (selected.getType()) {
487 startButton.setEnabled(false);
488 middleButton.setEnabled(false);
489 endButton.setEnabled(true);
490 updateInsertPosition(PositionType.NEXT);
493 if (!selected.isVariable()) {
494 startButton.setEnabled(true);
495 middleButton.setEnabled(true);
496 endButton.setEnabled(true);
498 startButton.setEnabled(false);
499 middleButton.setEnabled(false);
500 endButton.setEnabled(true);
501 updateInsertPosition(PositionType.NEXT);
505 startButton.setEnabled(false);
506 middleButton.setEnabled(false);
507 endButton.setEnabled(true);
508 updateInsertPosition(PositionType.NEXT);
511 startButton.setEnabled(false);
512 middleButton.setEnabled(true);
513 endButton.setEnabled(true);
514 if (insertPosition == PositionType.PREVIOUS)
515 updateInsertPosition(PositionType.NEXT);
518 throw new RuntimeException("Expected component, got equipment " + selected);
520 } else if (lenghtAdjustable) {
521 if (component instanceof InlineComponent) {
522 startButton.setEnabled(true);
523 middleButton.setEnabled(true);
524 endButton.setEnabled(true);
525 } else if (component instanceof TurnComponent) {
526 startButton.setEnabled(false);
527 middleButton.setEnabled(true);
528 endButton.setEnabled(true);
529 if (insertPosition == PositionType.PREVIOUS)
530 updateInsertPosition(PositionType.NEXT);
531 } else if (component instanceof EndComponent || component instanceof Nozzle) {
532 startButton.setEnabled(false);
533 middleButton.setEnabled(false);
534 endButton.setEnabled(true);
535 updateInsertPosition(PositionType.NEXT);
538 startButton.setEnabled(false);
539 middleButton.setEnabled(false);
540 endButton.setEnabled(true);
542 if (selected.isVariable() || selected.isModifiable()) {
543 if (selected.getType() == Type.INLINE) {
544 filterAllowed.add(PositionType.NEXT);
545 filterAllowed.add(PositionType.PREVIOUS);
546 if (inlineSplit && selected.isVariable()) {
547 lengthText.setEnabled(false);
548 angleText.setEnabled(false);
549 rotationAngleText.setEnabled(selected.isRotated());
551 if (msg == null) msg = "Cannot split a straight pipe with a straight pipe";
553 lengthText.setEnabled(true);
554 angleText.setEnabled(false);
555 rotationAngleText.setEnabled(selected.isRotated());
556 if (length == null || length <= 0.0) {
558 if (msg == null) msg = "Please provide a valid length";
561 } else if (selected.getType() == Type.TURN) {
562 filterAllowed.add(PositionType.NEXT);
563 filterAllowed.add(PositionType.PREVIOUS);
564 lengthText.setEnabled(false);
565 angleText.setEnabled(true);
566 rotationAngleText.setEnabled(true);
569 if (msg == null) msg = "Please provide a rotation angle";
572 // this should not happen, since end components should not have variable, or
574 lengthText.setEnabled(false);
575 angleText.setEnabled(false);
576 rotationAngleText.setEnabled(false);
580 lengthText.setEnabled(false);
581 angleText.setEnabled(false);
582 rotationAngleText.setEnabled(selected.getType() == Type.TURN || selected.isRotated());
585 if (selected.isSizeChange()) {
586 turnRadiusText.setEnabled(true);
587 diameterText.setEnabled(true);
588 thicknessText.setEnabled(true);
589 if (diameter == null || diameter <= 0.0) {
591 if (msg == null) msg = "Please provide a valid diameter";
593 if (turnRadius == null || diameter != null && turnRadius < diameter / 2) {
595 if (msg == null) msg = "Please provide a valid turn radius";
597 if (thickness == null || thickness < 0.0 || diameter != null && thickness >= diameter / 2) {
599 if (msg == null) msg = "Please provide a valid wall thickness";
602 turnRadiusText.setEnabled(false);
603 diameterText.setEnabled(false);
606 if (!selected.isVariable()) {
607 switch (selected.getType()) {
609 filterAllowed.add(PositionType.NEXT);
610 filterAllowed.add(PositionType.PREVIOUS);
616 filterAllowed.add(PositionType.NEXT);
617 filterAllowed.add(PositionType.PREVIOUS);
618 filterAllowed.add(PositionType.SPLIT);
620 filterAllowed.add(PositionType.NEXT);
621 filterAllowed.add(PositionType.PREVIOUS);
625 for (PositionType t : filterAllowed) {
626 if (allowed.contains(t))
627 this.filterAllowed.add(t);
630 validationLabel.setText(msg != null ? msg : "");
631 validationLabel.requestLayout();
633 getButton(OK).setEnabled(ok);
636 private String generateUniqueName(String name) {
639 while (usedNames.contains((newName = name + "_" + i)))
644 public Item getSelected() {
648 public String getName() {
652 public Double getAngle() {
656 public Double getLength() {
660 public Double getRotationAngle() {
661 return rotationAngle;
664 public Double getDiameter() {
668 public Double getTurnRadius() {
672 public Set<PositionType> filterAllowed() {
673 return filterAllowed;
676 public PositionType getInsertPosition() {
677 return insertPosition;
680 public boolean isInsertAdjustable() {
681 return insertAdjustable;
684 public boolean isLenghtAdjustable() {
685 return lenghtAdjustable;
688 public Double getThickness() {