blob: 9d0f03d9f0885493b4ffef875706fadcbc04dff6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2015 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* R.Dvorak and others - QVTo debugger framework
* E.D.Willink - revised API for OCL/QVTi debugger framework
*******************************************************************************/
package org.eclipse.qvtd.debug.ui.launching;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.examples.debug.vm.ui.launching.LaunchingUtils;
import org.eclipse.ocl.pivot.internal.utilities.OCLInternal;
import org.eclipse.ocl.pivot.resource.BasicProjectManager;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.qvtd.debug.launching.QVTiLaunchConstants;
import org.eclipse.qvtd.debug.ui.QVTdDebugUIPlugin;
import org.eclipse.qvtd.pivot.qvtbase.Transformation;
import org.eclipse.qvtd.pivot.qvtimperative.evaluation.QVTiEnvironmentFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
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.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
public abstract class MainTab extends AbstractMainTab implements QVTiLaunchConstants
{
protected class DirectionModifyListener implements ModifyListener
{
@Override
public void modifyText(ModifyEvent e) {
if (!directionModified) {
directionModified = true;
updateLaunchConfigurationDialog();
}
}
}
protected class TransformationModifyListener implements ModifyListener
{
@Override
public void modifyText(ModifyEvent e) {
if (!txModified) {
txModified = true;
updateLaunchConfigurationDialog();
}
}
}
protected Text txPath;
protected Button txBrowseWS;
protected Button txBrowseFile;
protected Group inputsGroup;
protected Group outputsGroup;
private Composite directionGroup;
protected Combo modeCombo;
protected Combo directionCombo;
protected Button partialCheckButton;
private Group intermediatesGroup;
/**
* Internal flag to suppress redundant recursive updates while initializing controls.
*/
protected boolean initializing = false;
private boolean updating = false;
private boolean txModified = false;
private Transformation transformation = null;
private boolean directionModified = false;
private boolean groupsModified = false;
protected void addListeners() {
txPath.addModifyListener(new TransformationModifyListener());
}
@Override
public boolean canSave() {
assert !initializing;
ResourceSet resourceSet = getEnvironmentFactory().getResourceSet();
URIConverter uriConverter = resourceSet.getURIConverter();
String txName = txPath.getText().trim();
URI txURI = URI.createURI(txName, true);
boolean txExists = uriConverter.exists(txURI, null);
if (!txExists){
setErrorMessage("Transformation '" + txName + "' does not exist");
return false;
}
if (inputsGroup != null) {
Control[] children = inputsGroup.getChildren();
for (int i = 0; i < children.length; i++) {
ParameterRow row = (ParameterRow)children[i];
String name = row.name.getText();
String path = row.path.getText();
URI inURI = URI.createURI(path, true);
boolean inExists = uriConverter.exists(inURI, null);
if (!inExists){
setErrorMessage("Input '" + name + "': '" + path + "' does not exist");
return false;
}
}
}
if (outputsGroup != null) {
Control[] children = outputsGroup.getChildren();
for (int i = 0; i < children.length; i++) {
ParameterRow row = (ParameterRow)children[i];
String name = row.name.getText();
String path = row.path.getText();
URI outURI = URI.createURI(path, true);
boolean outExists = uriConverter.exists(outURI.trimSegments(1), null);
if (!outExists){
setErrorMessage("Output '" + name + "': '" + path + "' uses non-existent parent folder");
return false;
}
}
}
setErrorMessage(null);
return true;
}
@SuppressWarnings("null")
public void createControl(Composite parent) {
Composite control = createForm(parent);
addListeners();
LaunchingUtils.prepareBrowseWorkspaceButton(txBrowseWS, txPath, false);
LaunchingUtils.prepareBrowseFileSystemButton(txBrowseFile, txPath, false);
updateParametersGroup(inputsGroup, SWT.NONE, EMPTY_MAP);
updateParametersGroup(outputsGroup, SWT.SAVE, EMPTY_MAP);
control.setBounds(0, 0, 300, 300);
control.layout();
control.pack();
}
protected void createDirectionGroup(Group txGroup) {
directionGroup = new Composite(txGroup, SWT.NONE);
GridLayout gl_directionGroup = new GridLayout(5, false);
gl_directionGroup.marginWidth = 0;
gl_directionGroup.marginHeight = 0;
directionGroup.setLayout(gl_directionGroup);
directionGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
Label modeLabel = new Label(directionGroup, SWT.NONE);
modeLabel.setSize(31, 15);
modeLabel.setText("Mode");
modeCombo = new Combo(directionGroup, SWT.NONE);
modeCombo.setToolTipText("Whether the execution\n- checks that the output corresponds to the input\n- creates new output model elements\n- updates existing model elements where possible ");
modeCombo.setItems(new String[] {"CHECK", "ENFORCE - CREATE", "ENFORCE - UPDATE"});
modeCombo.select(0);
Label directionLabel = new Label(directionGroup, SWT.NONE);
directionLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));
directionLabel.setText("Direction");
directionCombo = new Combo(directionGroup, SWT.NONE);
directionCombo.setToolTipText("The enforceable output domain defining the direction of a multi-directional trnsformation");
directionCombo.setItems(new String[] {"NONE"});
directionCombo.select(0);
partialCheckButton = new Button(directionGroup, SWT.CHECK);
partialCheckButton.setToolTipText("Whether the input may be part of a larger model, or must be the whole model.");
partialCheckButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));
partialCheckButton.setText("Partial Model");
}
/**
* @wbp.parser.entryPoint
*/
public Composite createForm(Composite parent) {
Composite control = new Composite(parent, SWT.NONE);
setControl(control);
control.setLayout(new GridLayout(1, false));
control.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
Group txGroup = new Group(control, SWT.NONE);
txGroup.setToolTipText("The transformation selection and its directional configuration ");
txGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
txGroup.setText("Transformation");
txGroup.setLayout(new GridLayout(3, false));
txPath = new Text(txGroup, SWT.BORDER);
txPath.setToolTipText("The transformation to execute");
GridData gd_txPath = new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1);
gd_txPath.minimumWidth = 100;
txPath.setLayoutData(gd_txPath);
txBrowseWS = new Button(txGroup, SWT.NONE);
txBrowseWS.setText("Browse Workspace...");
txBrowseFile = new Button(txGroup, SWT.NONE);
txBrowseFile.setText("Browse File...");
createDirectionGroup(txGroup);
inputsGroup = new Group(control, SWT.NONE);
inputsGroup.setToolTipText("The models bound to each input domain");
inputsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
inputsGroup.setText("Inputs");
inputsGroup.setLayout(new GridLayout(1, false));
outputsGroup = new Group(control, SWT.NONE);
outputsGroup.setToolTipText("The models bound to each output domain");
outputsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
outputsGroup.setText("Outputs");
outputsGroup.setLayout(new GridLayout(1, false));
intermediatesGroup = new Group(control, SWT.NONE);
intermediatesGroup.setToolTipText("The intermediate models nd files");
intermediatesGroup.setLayout(new GridLayout(1, false));
intermediatesGroup.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
intermediatesGroup.setText("Intermediates");
return control;
}
protected String getDefaultPath(@NonNull Group group, String name) {
if (name != null) {
for (Control child : group.getChildren()) {
if (child instanceof ParameterRow) {
ParameterRow row = (ParameterRow)child;
if (name.equals(row.name.getText())) {
return row.path.getText();
}
}
}
}
return "";
}
protected @NonNull QVTiEnvironmentFactory getEnvironmentFactory() {
OCLInternal ocl2 = ocl;
if (ocl2 == null) {
ocl = ocl2 = OCLInternal.newInstance(new QVTiEnvironmentFactory(BasicProjectManager.createDefaultProjectManager(), null));
}
return (QVTiEnvironmentFactory) ocl2.getEnvironmentFactory();
}
@Override
public Image getImage() {
return QVTdDebugUIPlugin.getDefault().createImage("icons/QVTiModelFile.gif");
}
public void initializeFrom(ILaunchConfiguration configuration) {
assert !initializing;
try {
initializing = true;
if (configuration != null) {
initializeInternal(configuration);
}
} catch (CoreException e) {
//Ignore
} finally {
initializing = false;
txModified = true;
updateLaunchConfigurationDialog();
}
}
protected void initializeInternal(@NonNull ILaunchConfiguration configuration) throws CoreException {
txPath.setText(configuration.getAttribute(TX_KEY, ""));
Map<String, String> inMap = configuration.getAttribute(IN_KEY, EMPTY_MAP);
Map<String, String> outMap = configuration.getAttribute(OUT_KEY, EMPTY_MAP);
if (inMap != null) {
updateParametersGroup(ClassUtil.nonNullState(inputsGroup), SWT.NONE, inMap);
// refreshParametersGroup(ClassUtil.nonNullState(inputsGroup), SWT.NONE, inMap);
}
if (outMap != null) {
updateParametersGroup(ClassUtil.nonNullState(outputsGroup), SWT.SAVE, outMap);
// refreshParametersGroup(ClassUtil.nonNullState(outputsGroup), SWT.SAVE, outMap);
}
}
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
configuration.setAttribute(TX_KEY, txPath.getText());
Map<String, String> inputMap = new HashMap<String, String>();
for (Control child : inputsGroup.getChildren()) {
if (child instanceof ParameterRow) {
ParameterRow row = (ParameterRow)child;
inputMap.put(row.name.getText(), row.path.getText());
}
}
configuration.setAttribute(IN_KEY, inputMap);
Map<String, String> outputMap = new HashMap<String, String>();
for (Control child : outputsGroup.getChildren()) {
if (child instanceof ParameterRow) {
ParameterRow row = (ParameterRow)child;
outputMap.put(row.name.getText(), row.path.getText());
}
}
configuration.setAttribute(OUT_KEY, outputMap);
}
protected void refreshParametersGroup(@NonNull Group group, int style, @NonNull Map<String, String> map) {
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys);
Control[] children = group.getChildren();
for (int i = 0; i < children.length; i++) {
ParameterRow row = (ParameterRow)children[i];
String text = row.name.getText();
String path = map.get(text);
if (path != null) {
row.path.setText(path);
}
}
group.layout();
}
protected void setDefaults(@NonNull ILaunchConfigurationWorkingCopy configuration, @NonNull IFile iFile) {
configuration.setAttribute(TX_KEY, iFile.getFullPath().toString());
configuration.setAttribute(IN_KEY, EMPTY_MAP);
configuration.setAttribute(OUT_KEY, EMPTY_MAP);
}
@Override
public void updateLaunchConfigurationDialog() {
if (!initializing &&!updating) {
updating = true;
try {
if (txModified) {
if (txPath.isDisposed()) {
return;
}
String txName = txPath.getText().trim();
@SuppressWarnings("null")@NonNull URI txURI = URI.createURI(txName, true);
try {
transformation = updateTransformation(txURI);
directionModified = true;
}
catch (Throwable ex) {
setErrorMessage("Failed to load '" + txName + "': " + ex.toString());
return;
}
txModified = false;
}
Transformation transformation2 = transformation;
if (transformation2 == null) {
return;
}
if (directionModified) {
updateDirection(transformation2);
directionModified = false;
groupsModified = true;
}
if (groupsModified) {
if (txPath.isDisposed()) {
return;
}
Map<String, String> inputMap = new HashMap<String, String>();
Map<String, String> outputMap = new HashMap<String, String>();
updateGroups(transformation2, inputMap, outputMap);
@SuppressWarnings("null")@NonNull Group inputsGroup2 = inputsGroup;
@SuppressWarnings("null")@NonNull Group outputsGroup2 = outputsGroup;
for (String inputName : inputMap.keySet()) {
inputMap.put(inputName, getDefaultPath(inputsGroup2, inputName));
}
for (String outputName : outputMap.keySet()) {
outputMap.put(outputName, getDefaultPath(outputsGroup2, outputName));
}
updateParametersGroup(inputsGroup2, SWT.NONE, inputMap);
updateParametersGroup(outputsGroup2, SWT.SAVE, outputMap);
groupsModified = false;
}
}
finally {
super.updateLaunchConfigurationDialog();
updating = false;
}
}
}
protected abstract void updateDirection(@NonNull Transformation tansformation);
protected abstract void updateGroups(@NonNull Transformation tansformation, @NonNull Map<String, String> inputMap, @NonNull Map<String, String> outputMap);
protected void updateParametersGroup(@NonNull Group group, int style, @NonNull Map<String, String> map) {
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys);
Control[] children = group.getChildren();
int iMax = Math.min(children.length, keys.size());
int i = 0;
for (; i < iMax; i++) {
ParameterRow row = (ParameterRow)children[i];
String string = keys.get(i);
row.name.setText(string);
row.path.setText(map.get(string));
}
for (; i < keys.size(); i++) {
@SuppressWarnings("null")@NonNull String string = keys.get(i);
@SuppressWarnings("null")@NonNull String parameterPath = map.get(string);
new ParameterRow(this, group, style, string, parameterPath);
}
for (; i < children.length; i++) {
children[i].dispose();
}
group.layout();
}
protected abstract @NonNull Transformation updateTransformation(@NonNull URI txURI) throws IOException;
}