EditDimensionsDialog.java
/**
* Copyright (c) 2004-2025 Carnegie Mellon University and others. (see Contributors file).
* All Rights Reserved.
*
* NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE
* OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
* MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
* SPDX-License-Identifier: EPL-2.0
*
* Created, in part, with funding and support from the United States Government. (see Acknowledgments file).
*
* This program includes and/or can make use of certain third party source code, object code, documentation and other
* files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system
* configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and
* conditions contained in any such Third Party Software or separate license file distributed with such Third Party
* Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici-
* aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li-
* censes only apply to the Third Party Software and not any other portion of this program or this program as a whole.
*/
package org.osate.ge.aadl2.ui.internal.dialogs;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
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.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.ui.PlatformUI;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.XtextResourceSet;
import org.osate.aadl2.Aadl2Package;
import org.osate.aadl2.AadlInteger;
import org.osate.aadl2.ArrayDimension;
import org.osate.aadl2.ArraySize;
import org.osate.aadl2.NamedElement;
import org.osate.aadl2.Property;
import org.osate.aadl2.PropertyConstant;
import org.osate.ge.aadl2.ui.AadlModelAccessUtil;
public class EditDimensionsDialog extends TitleAreaDialog {
private final IProject projectContext; // Project for determining what may be referenced.
private boolean allowMultipleDimensions;
private List<ArrayDimension> dimensions = new ArrayList<ArrayDimension>();
private List<ArrayDimension> modifiedDimensions; // Stores the modified dimensions after the user selected Ok
private ListViewer dimensionListViewer;
private Button addBtn;
private Button modifyBtn;
private Button deleteBtn;
private Button upBtn;
private Button downBtn;
public EditDimensionsDialog(final Shell parentShell, final IProject projectContext, List<ArrayDimension> initialDimensions, boolean allowMultipleDimensions) {
super(parentShell);
setShellStyle(getShellStyle() | SWT.RESIZE);
this.projectContext = projectContext;
this.allowMultipleDimensions = allowMultipleDimensions;
// Make a copy of the initial dimensions
dimensions.addAll(EcoreUtil.copyAll(initialDimensions));
}
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.setText("Modify Dimensions");
shell.setMinimumSize(425, 500);
}
@Override
public void create() {
super.create();
setTitle("Array Dimensions");
}
@Override
protected Control createDialogArea(final Composite parent) {
final Composite area = (Composite)super.createDialogArea(parent);
// Create basic panel
final Composite container = new Composite(area, SWT.NONE);
container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
container.setLayout(new GridLayout(2, false));
// Left Pane
final Composite leftPane = new Composite(container, SWT.NONE);
leftPane.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
leftPane.setLayout(new RowLayout(SWT.VERTICAL));
final org.eclipse.swt.widgets.List dimensionList = new org.eclipse.swt.widgets.List(leftPane, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL);
dimensionList.setLayoutData(new RowData(300, 300));
dimensionListViewer = new ListViewer(dimensionList);
dimensionListViewer.setContentProvider(new ArrayContentProvider());
dimensionListViewer.setLabelProvider(new LabelProvider() {
@Override
public String getText(final Object element) {
final ArrayDimension dim = (ArrayDimension)element;
final ArraySize dimSize = dim.getSize();
final String txt;
if(dimSize == null) {
txt = "[]";
} else if(dimSize.getSizeProperty() != null) {
if(dimSize.getSizeProperty() instanceof Property) {
txt = "[" + ((Property)dimSize.getSizeProperty()).getQualifiedName() + "]";
} else if(dimSize.getSizeProperty() instanceof PropertyConstant) {
txt = "[" + ((PropertyConstant)dimSize.getSizeProperty()).getQualifiedName() + "]";
} else {
txt = "[<Unsupported case>]";
}
} else {
txt = "[" + dimSize.getSize() + "]";
}
return txt;
}
});
dimensionListViewer.addSelectionChangedListener(event -> refreshWidgetEnabledStates());
dimensionListViewer.addDoubleClickListener(event -> showModifySelectedDimensionDialog());
dimensionListViewer.setInput(dimensions);
addBtn = new Button(leftPane, SWT.PUSH);
addBtn.setText("Add");
addBtn.setToolTipText("Add a new array dimension.");
addBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
final Aadl2Package pkg = Aadl2Package.eINSTANCE;
final ArrayDimension newDim = (ArrayDimension)pkg.getEFactoryInstance().create(pkg.getArrayDimension());
dimensions.add(newDim);
dimensionListViewer.refresh();
dimensionListViewer.setSelection(new StructuredSelection(newDim));
}
});
// Right Pane
final Composite rightPane = new Composite(container, SWT.NONE);
rightPane.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
final RowLayout rightPaneLayout = new RowLayout(SWT.VERTICAL);
rightPaneLayout.fill = true;
rightPane.setLayout(rightPaneLayout);
modifyBtn = new Button(rightPane, SWT.PUSH);
modifyBtn.setText("Modify...");
modifyBtn.setToolTipText("Modify the array dimension.");
modifyBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
showModifySelectedDimensionDialog();
}
});
deleteBtn = new Button(rightPane, SWT.PUSH);
deleteBtn.setText("Delete");
deleteBtn.setToolTipText("Delete the array dimension.");
deleteBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
if(MessageDialog.openQuestion(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Confirm Delete", "Are you sure you want to delete this dimension?")) {
final ArrayDimension dim = getSelectedDimension();
dimensions.remove(dim);
dimensionListViewer.refresh();
refreshWidgetEnabledStates();
}
}
});
upBtn = new Button(rightPane, SWT.PUSH);
upBtn.setText("Up");
upBtn.setToolTipText("Move the array dimension up.");
upBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
final ArrayDimension dim = getSelectedDimension();
final int index = dimensions.indexOf(dim);
if(index > 0) {
dimensions.remove(index);
dimensions.add(index-1, dim);
}
dimensionListViewer.refresh();
refreshWidgetEnabledStates();
}
});
downBtn = new Button(rightPane, SWT.PUSH);
downBtn.setText("Down");
downBtn.setToolTipText("Move the array dimension down.");
downBtn.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
final ArrayDimension dim = getSelectedDimension();
final int index = dimensions.indexOf(dim);
if(index != -1) {
dimensions.remove(index);
dimensions.add(index+1, dim);
}
dimensionListViewer.refresh();
refreshWidgetEnabledStates();
}
});
refreshWidgetEnabledStates();
return area;
}
private void showModifySelectedDimensionDialog() {
final ArrayDimension dim = getSelectedDimension();
if(dim != null) {
// Show the editor dimension dialog. If the user selects OK, it will modify the passed in object.
final EditDimensionDialog dlg = new EditDimensionDialog(EditDimensionsDialog.this.getShell(),
projectContext, dim);
if(dlg.open() == Window.CANCEL) {
return;
}
dimensionListViewer.refresh();
refreshWidgetEnabledStates();
}
}
private ArrayDimension getSelectedDimension() {
final StructuredSelection selection = (StructuredSelection)dimensionListViewer.getSelection();
final ArrayDimension dim = (ArrayDimension)selection.getFirstElement();
return dim;
}
private void refreshWidgetEnabledStates() {
final ArrayDimension dim = getSelectedDimension();
final int dimIndex = dimensions.indexOf(dim);
addBtn.setEnabled(dimensions.size() == 0 || allowMultipleDimensions);
modifyBtn.setEnabled(dim != null);
deleteBtn.setEnabled(dim != null);
upBtn.setEnabled(dim != null && dimIndex >= 1);
downBtn.setEnabled(dim != null && dimIndex < (dimensions.size()-1));
}
@Override
public void okPressed() {
// Make a copy of the selected dimensions
modifiedDimensions = new ArrayList<ArrayDimension>();
modifiedDimensions.addAll(EcoreUtil.copyAll(dimensions));
super.okPressed();
}
public List<ArrayDimension> getDimensions() {
return modifiedDimensions;
}
// Dialog for modifying a single dimension. Modifies the object passed to it.
public static class EditDimensionDialog extends Dialog {
private static String unspecifiedTxt = "Unspecified";
private static String numberTxt = "Number";
private static String propertyConstantTxt = "Property Constant";
private static String unsupportedTypeTxt = "Unsupported Type";
private final IProject projectContext;
private final ArrayDimension dimension;
private Composite detailsPane;
private RowData visibleRowData = new RowData();
private RowData hiddenRowData = new RowData();
private Combo typeCmb;
private Composite numberPane;
private Spinner numberValue;
private Composite propertyConstantPane;
private ComboViewer propertyConstantCmb;
public EditDimensionDialog(final Shell parentShell, final IProject projectContext,
final ArrayDimension dimension) {
super(parentShell);
this.projectContext = projectContext;
this.dimension = dimension;
visibleRowData.exclude = false;
hiddenRowData.exclude = true;
}
@Override
protected void configureShell(Shell shell) {
super.configureShell(shell);
shell.setText("Modify Dimension");
}
@Override
protected Control createDialogArea(final Composite parent) {
final Composite area = (Composite)super.createDialogArea(parent);
// Create basic panel
final Composite container = new Composite(area, SWT.NONE);
container.setLayout(new RowLayout(SWT.VERTICAL));
// Type Combo Box
typeCmb = new Combo(container, SWT.DROP_DOWN | SWT.READ_ONLY);
typeCmb.add(unspecifiedTxt);
typeCmb.add(numberTxt);
typeCmb.add(propertyConstantTxt);
typeCmb.setText(getTypeText(dimension));
typeCmb.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent e) {
updateWidgetVisibility();
}
});
detailsPane = new Composite(container, SWT.NONE);
detailsPane.setLayout(new StackLayout());
// Number Pane
numberPane = new Composite(detailsPane, SWT.NONE);
numberPane.setLayout(new RowLayout(SWT.HORIZONTAL));
final Label numberLbl = new Label(numberPane, SWT.NONE);
numberLbl.setText("Size:");
numberValue = new Spinner(numberPane, SWT.NONE);
final IElementComparer namedElementComparer = new IElementComparer() {
@Override
public boolean equals(final Object a, final Object b) {
if(a instanceof NamedElement && b instanceof NamedElement && ((NamedElement) a).getQualifiedName() != null) {
return ((NamedElement)a).getQualifiedName().equalsIgnoreCase(((NamedElement)b).getQualifiedName());
}
return a.equals(b);
}
@Override
public int hashCode(Object element) {
return element.hashCode();
}
};
// Property Constant Pane
propertyConstantPane = new Composite(detailsPane, SWT.NONE);
propertyConstantPane.setLayout(new RowLayout(SWT.HORIZONTAL));
propertyConstantCmb = new ComboViewer(propertyConstantPane, SWT.DROP_DOWN | SWT.READ_ONLY);
propertyConstantCmb.setContentProvider(new ArrayContentProvider());
propertyConstantCmb.setLabelProvider(new ElementLabelProvider());
propertyConstantCmb.setComparator(new ViewerComparator());
propertyConstantCmb.setInput(getValidPropertyConstants());
propertyConstantCmb.setComparer(namedElementComparer);
// Set initial values
final ArraySize dimSize = dimension.getSize();
if (dimSize != null) {
if (dimSize.getSizeProperty() == null) {
numberValue.setSelection((int) dimSize.getSize());
} else if (dimSize.getSizeProperty() instanceof PropertyConstant) {
propertyConstantCmb.setSelection(new StructuredSelection(dimSize.getSizeProperty()));
}
}
updateWidgetVisibility();
return area;
}
private List<PropertyConstant> getValidPropertyConstants() {
final XtextResourceSet rs = new XtextResourceSet();
final List<PropertyConstant> results = new ArrayList<PropertyConstant>();
for (final IEObjectDescription objDesc : AadlModelAccessUtil.getAllEObjectsByType(projectContext,
Aadl2Package.eINSTANCE.getPropertyConstant())) {
final PropertyConstant propConst = (PropertyConstant)rs.getEObject(EcoreUtil.getURI(objDesc.getEObjectOrProxy()), true);
if(propConst != null && propConst.getPropertyType() instanceof AadlInteger) {
results.add(propConst);
}
}
return results;
}
private void updateWidgetVisibility() {
final String type = typeCmb.getText();
final StackLayout detailsLayout = (StackLayout)detailsPane.getLayout();
if(numberTxt.equals(type)) {
detailsLayout.topControl = numberPane;
} else if(propertyConstantTxt.equals(type)) {
detailsLayout.topControl = propertyConstantPane;
} else {
detailsLayout.topControl = null;
}
detailsPane.layout();
}
private static String getTypeText(final ArrayDimension dim) {
final ArraySize size = dim.getSize();
if(size == null) {
return unspecifiedTxt;
} else if(size.getSizeProperty() == null) {
return numberTxt;
} else if(size.getSizeProperty() instanceof PropertyConstant) {
return propertyConstantTxt;
} else {
return unsupportedTypeTxt;
}
}
@Override
public void okPressed() {
final String type = typeCmb.getText();
// Modify the dimension based on the user's selection
if(unspecifiedTxt.equals(type)) {
dimension.setSize(null);
} else if(numberTxt.equals(type)) {
dimension.createSize().setSize(numberValue.getSelection());
} else if(propertyConstantTxt.equals(type)) {
final StructuredSelection propConstSelection = (StructuredSelection)propertyConstantCmb.getSelection();
final PropertyConstant propConst = (PropertyConstant)propConstSelection.getFirstElement();
if(propConst != null) {
dimension.setSize(null);
dimension.createSize().setSizeProperty(propConst);
}
}
super.okPressed();
}
}
}