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