package org.simantics.plant3d.dialog; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.resource.ResourceLocator; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ListViewer; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.ExpandBar; import org.eclipse.swt.widgets.ExpandItem; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.simantics.db.exception.DatabaseException; import org.simantics.plant3d.Activator; import org.simantics.plant3d.ontology.Plant3D; import org.simantics.plant3d.scenegraph.EndComponent; import org.simantics.plant3d.scenegraph.InlineComponent; import org.simantics.plant3d.scenegraph.Nozzle; import org.simantics.plant3d.scenegraph.PipelineComponent; import org.simantics.plant3d.scenegraph.TurnComponent; import org.simantics.plant3d.scenegraph.controlpoint.PipeControlPoint.PositionType; import org.simantics.plant3d.utils.Item; import org.simantics.plant3d.utils.Item.Type; import org.simantics.plant3d.utils.P3DUtil; import org.simantics.utils.ui.ExceptionUtils; public class ComponentSelectionDialog extends Dialog implements ISelectionChangedListener { private static final String DIALOG = "ComponentSelectionDialog"; //$NON-NLS-1$ private IDialogSettings dialogSettings; private double lengthFactor = 1.0; private ResourceManager resourceManager; private String libUri; private Item selected; private Set allowed; private Set filterAllowed; // private boolean positionAdjustment; private PipelineComponent component; private boolean insertAdjustable; private boolean lenghtAdjustable; private PositionType insertPosition = PositionType.NEXT; private Double angle; private Double length; private Double rotationAngle; private String name; private Text nameText; // In-line component private Text lengthText; // Turn component private Text angleText; // Rotated In-line, or turn component. private Text rotationAngleText; // Input for new PipeRun private Double diameter; private Double turnRadius; private Text diameterText; private Text turnRadiusText; // Position selection private Button startButton; private Button middleButton; private Button endButton; private boolean inlineSplit = false; ListViewer inlineViewer; ListViewer turnViewer; ListViewer endViewer; private Set usedNames; public ComponentSelectionDialog(Shell parentShell, Set allowed, PipelineComponent component) { this(parentShell, allowed, component, Plant3D.URIs.Builtin); } public ComponentSelectionDialog(Shell parentShell, Set allowed, PipelineComponent component, String libUri) { super(parentShell); this.allowed = allowed; this.component = component; filterAllowed = new HashSet(); insertAdjustable = component instanceof InlineComponent ? ((InlineComponent) component).isVariableLength() : false; lenghtAdjustable = false; this.libUri = libUri; usedNames = new HashSet<>(); setShellStyle(getShellStyle() | SWT.RESIZE); IDialogSettings settings = Activator.getDefault().getDialogSettings(); dialogSettings = settings.getSection(DIALOG); if (dialogSettings == null) dialogSettings = settings.addNewSection(DIALOG); } public void setLengthFactor(double lengthFactor) { this.lengthFactor = lengthFactor; } @Override protected IDialogSettings getDialogBoundsSettings() { return dialogSettings; } @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setText("Create pipeline component"); } public void addUsedNames(Collection names) { usedNames.addAll(names); } protected List getItems(Class c, String libUri) throws DatabaseException { if (InlineComponent.class.equals(c)) { return P3DUtil.getInlines(libUri); } else if (TurnComponent.class.equals(c)) { return P3DUtil.getTurns(libUri); } else if (EndComponent.class.equals(c)) { return P3DUtil.getEnds(libUri); } else { return null; } } @Override protected Control createDialogArea(Composite parent) { resourceManager = new LocalResourceManager(JFaceResources.getResources(), parent); Composite composite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(2, false); layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN); layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING); layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING); composite.setLayout(layout); composite.setLayoutData(new GridData(GridData.FILL_BOTH)); applyDialogFont(composite); // Grid layout data for fields that grab horizontal space final GridDataFactory horizFillData = GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.TOP); // TODO : we need better classification than inline,turn, and end: // * fixed length inlines // * fixed angle turns // * size changes (requires input for pipe run specs) // * variable length inlines (input for length) // * variable angle turns (input for angle) // * ends List ends = null; List turns = null; List inlines = null; try { ends = getItems(EndComponent.class, libUri); turns = getItems(TurnComponent.class, libUri); inlines = getItems(InlineComponent.class, libUri); } catch (DatabaseException e) { Label label = new Label(composite, SWT.NONE); label.setText("Cannot load pipeline components: " + e.getMessage()); ExceptionUtils.logError(e); return composite; } ends = P3DUtil.filterUserComponents(ends); turns = P3DUtil.filterUserComponents(turns); inlines = P3DUtil.filterUserComponents(inlines); ExpandBar expandBar = new ExpandBar(composite, SWT.V_SCROLL); ExpandItem inlineItem = new ExpandItem(expandBar, SWT.NONE); inlineItem.setText("Inline"); inlineViewer = new ListViewer(expandBar); inlineViewer.setLabelProvider(new ComponentLabelProvider()); inlineViewer.setContentProvider(new ComponentContentProvider()); ExpandItem turnItem = new ExpandItem(expandBar, SWT.NONE); turnItem.setText("Turn"); turnViewer = new ListViewer(expandBar); turnViewer.setLabelProvider(new ComponentLabelProvider()); turnViewer.setContentProvider(new ComponentContentProvider()); ExpandItem endItem = new ExpandItem(expandBar, SWT.NONE); endItem.setText("End"); endViewer = new ListViewer(expandBar); endViewer.setLabelProvider(new ComponentLabelProvider()); endViewer.setContentProvider(new ComponentContentProvider()); inlineItem.setControl(inlineViewer.getList()); turnItem.setControl(turnViewer.getList()); endItem.setControl(endViewer.getList()); inlineViewer.setInput(inlines); turnViewer.setInput(turns); endViewer.setInput(ends); inlineItem.setHeight(inlineViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y); turnItem.setHeight(turnViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y); endItem.setHeight(endViewer.getList().computeSize(SWT.DEFAULT, SWT.DEFAULT).y); inlineViewer.addSelectionChangedListener(this); turnViewer.addSelectionChangedListener(this); endViewer.addSelectionChangedListener(this); GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).span(2, 1).applyTo(expandBar); GridDataFactory.fillDefaults().grab(true, true).minSize(500, 500).hint(500, 500).applyTo(composite); Label label = new Label(composite, SWT.NONE); label.setText("Position"); Composite buttonComposite = new Composite(composite, SWT.NONE); startButton = new Button(buttonComposite, SWT.TOGGLE); middleButton = new Button(buttonComposite, SWT.TOGGLE); endButton = new Button(buttonComposite, SWT.TOGGLE); startButton.setImage(resourceManager.createImage( ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_start.png").get())); middleButton.setImage(resourceManager.createImage( ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_middle.png").get())); endButton.setImage(resourceManager.createImage( ResourceLocator.imageDescriptorFromBundle(Activator.PLUGIN_ID, "icons/insert_end.png").get())); startButton.setToolTipText("Overlapping insert"); middleButton.setToolTipText("Cutting insert"); endButton.setToolTipText("Adding insert"); horizFillData.applyTo(buttonComposite); GridLayoutFactory.fillDefaults().numColumns(3).applyTo(buttonComposite); startButton.setEnabled(false); middleButton.setEnabled(false); endButton.setEnabled(false); startButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateInsertPosition(PositionType.PREVIOUS); } }); middleButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateInsertPosition(PositionType.SPLIT); } }); endButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateInsertPosition(PositionType.NEXT); } }); endButton.setSelection(true); label = new Label(composite, SWT.NONE); label.setText("Name"); nameText = new Text(composite, SWT.SINGLE | SWT.BORDER); label = new Label(composite, SWT.NONE); label.setText("Length"); lengthText = new Text(composite, SWT.SINGLE | SWT.BORDER); label = new Label(composite, SWT.NONE); label.setText("Angle"); angleText = new Text(composite, SWT.SINGLE | SWT.BORDER); label = new Label(composite, SWT.NONE); label.setText("Rotation angle"); rotationAngleText = new Text(composite, SWT.SINGLE | SWT.BORDER); label = new Label(composite, SWT.NONE); label.setText("Diameter"); diameterText = new Text(composite, SWT.SINGLE | SWT.BORDER); label = new Label(composite, SWT.NONE); label.setText("Turn Radius"); turnRadiusText = new Text(composite, SWT.SINGLE | SWT.BORDER); lengthText.setEnabled(false); angleText.setEnabled(false); rotationAngleText.setEnabled(false); turnRadiusText.setEnabled(false); diameterText.setEnabled(false); nameText.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { name = nameText.getText(); validate(); } }); lengthText.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { try { length = Double.parseDouble(lengthText.getText()) / lengthFactor; } catch (NumberFormatException err) { length = null; } validate(); } }); angleText.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { try { angle = Double.parseDouble(angleText.getText()); } catch (NumberFormatException err) { angle = null; } validate(); } }); rotationAngleText.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { try { rotationAngle = Double.parseDouble(rotationAngleText.getText()); } catch (NumberFormatException err) { rotationAngle = null; } validate(); } }); diameterText.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { try { diameter = Double.parseDouble(diameterText.getText()) / lengthFactor; } catch (NumberFormatException err) { diameter = null; } validate(); } }); turnRadiusText.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { try { turnRadius = Double.parseDouble(turnRadiusText.getText()) / lengthFactor; } catch (NumberFormatException err) { turnRadius = null; } validate(); } }); horizFillData.applyTo(nameText); horizFillData.applyTo(lengthText); horizFillData.applyTo(angleText); horizFillData.applyTo(rotationAngleText); horizFillData.applyTo(diameterText); horizFillData.applyTo(turnRadiusText); if (!allowed.contains(PositionType.NEXT) && !allowed.contains(PositionType.PREVIOUS)) { turnViewer.getList().setEnabled(false); endViewer.getList().setEnabled(false); inlineSplit = true; } return composite; } private void updateInsertPosition(PositionType type) { if (insertPosition == type) return; endButton.setSelection(type == PositionType.NEXT); middleButton.setSelection(type == PositionType.SPLIT); startButton.setSelection(type == PositionType.PREVIOUS); insertPosition = type; } @Override public void selectionChanged(SelectionChangedEvent event) { IStructuredSelection sel = (IStructuredSelection) event.getSelection(); Item i = (Item) sel.getFirstElement(); if (i != null) { selected = i; if (event.getSource() == inlineViewer) { turnViewer.setSelection(new StructuredSelection()); endViewer.setSelection(new StructuredSelection()); } else if (event.getSource() == turnViewer) { inlineViewer.setSelection(new StructuredSelection()); endViewer.setSelection(new StructuredSelection()); } else if (event.getSource() == endViewer) { inlineViewer.setSelection(new StructuredSelection()); turnViewer.setSelection(new StructuredSelection()); } name = generateUniqueName(selected.getName()); nameText.setText(name); validate(); } } private void validate() { filterAllowed.clear(); Set filterAllowed = new HashSet(); boolean ok = true; if (selected == null) { ok = false; } else if (selected.isCode()) {// TODO : instead of disabling the button, we should filter the content. ok = false; } else { lenghtAdjustable = ((selected.getType() == Type.INLINE) && (selected.isVariable() || selected.isModifiable())); if (insertAdjustable) { switch (selected.getType()) { case END: startButton.setEnabled(false); middleButton.setEnabled(false); endButton.setEnabled(true); updateInsertPosition(PositionType.NEXT); break; case INLINE: if (!selected.isVariable()) { startButton.setEnabled(true); middleButton.setEnabled(true); endButton.setEnabled(true); } else { startButton.setEnabled(false); middleButton.setEnabled(false); endButton.setEnabled(true); updateInsertPosition(PositionType.NEXT); } break; case NOZZLE: startButton.setEnabled(false); middleButton.setEnabled(false); endButton.setEnabled(true); updateInsertPosition(PositionType.NEXT); break; case TURN: startButton.setEnabled(false); middleButton.setEnabled(true); endButton.setEnabled(true); if (insertPosition == PositionType.PREVIOUS) updateInsertPosition(PositionType.NEXT); break; case EQUIPMENT: throw new RuntimeException("Expected component, got equipment " + selected); } } else if (lenghtAdjustable) { if (component instanceof InlineComponent) { startButton.setEnabled(true); middleButton.setEnabled(true); endButton.setEnabled(true); } else if (component instanceof TurnComponent) { startButton.setEnabled(false); middleButton.setEnabled(true); endButton.setEnabled(true); if (insertPosition == PositionType.PREVIOUS) updateInsertPosition(PositionType.NEXT); } else if (component instanceof EndComponent || component instanceof Nozzle) { startButton.setEnabled(false); middleButton.setEnabled(false); endButton.setEnabled(true); updateInsertPosition(PositionType.NEXT); } } else { startButton.setEnabled(false); middleButton.setEnabled(false); endButton.setEnabled(true); } if (selected.isVariable() || selected.isModifiable()) { if (selected.getType() == Type.INLINE) { filterAllowed.add(PositionType.NEXT); filterAllowed.add(PositionType.PREVIOUS); if (inlineSplit && selected.isVariable()) { lengthText.setEnabled(false); angleText.setEnabled(false); rotationAngleText.setEnabled(selected.isRotated()); ok = false; } else { lengthText.setEnabled(true); angleText.setEnabled(false); rotationAngleText.setEnabled(selected.isRotated()); if (length == null) ok = false; } } else if (selected.getType() == Type.TURN) { filterAllowed.add(PositionType.NEXT); filterAllowed.add(PositionType.PREVIOUS); lengthText.setEnabled(false); angleText.setEnabled(true); rotationAngleText.setEnabled(true); if (angle == null) ok = false; } else { // this should not happen, since end components should not have variable, or // modifiable flag. lengthText.setEnabled(false); angleText.setEnabled(false); rotationAngleText.setEnabled(false); } } else { lengthText.setEnabled(false); angleText.setEnabled(false); rotationAngleText.setEnabled(selected.getType() == Type.TURN || selected.isRotated()); } if (selected.isSizeChange()) { turnRadiusText.setEnabled(true); diameterText.setEnabled(true); if (diameter == null || turnRadius == null) ok = false; } else { turnRadiusText.setEnabled(false); diameterText.setEnabled(false); } if (!selected.isVariable()) { switch (selected.getType()) { case END: filterAllowed.add(PositionType.NEXT); filterAllowed.add(PositionType.PREVIOUS); break; case NOZZLE: case EQUIPMENT: break; case INLINE: filterAllowed.add(PositionType.NEXT); filterAllowed.add(PositionType.PREVIOUS); filterAllowed.add(PositionType.SPLIT); case TURN: filterAllowed.add(PositionType.NEXT); filterAllowed.add(PositionType.PREVIOUS); } } } for (PositionType t : filterAllowed) { if (allowed.contains(t)) this.filterAllowed.add(t); } if (name.isEmpty() || usedNames.contains(name)) ok = false; getButton(OK).setEnabled(ok); } private String generateUniqueName(String name) { int i = 1; String newName; while (usedNames.contains((newName = name + "_" + i))) i++; return newName; } public Item getSelected() { return selected; } public String getName() { return name; } public Double getAngle() { return angle; } public Double getLength() { return length; } public Double getRotationAngle() { return rotationAngle; } public Double getDiameter() { return diameter; } public Double getTurnRadius() { return turnRadius; } public Set filterAllowed() { return filterAllowed; } public PositionType getInsertPosition() { return insertPosition; } public boolean isInsertAdjustable() { return insertAdjustable; } public boolean isLenghtAdjustable() { return lenghtAdjustable; } }