blob: e2653872cd0f80ee1c8bc13638e9228a64c69ad5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency
* 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:
* Pierre Allard,
* Regent L'Archeveque,
* Olivier L. Larouche - initial API and implementation
*
* SPDX-License-Identifier: EPL-1.0
*
*******************************************************************************/
package org.eclipse.apogy.core.invocator.ui.composites;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.apogy.common.emf.ApogyCommonEMFFactory;
import org.eclipse.apogy.common.emf.ApogyCommonEMFPackage;
import org.eclipse.apogy.common.emf.EObjectReference;
import org.eclipse.apogy.common.emf.FeaturePathAdapter;
import org.eclipse.apogy.common.emf.impl.FeaturePathAdapterCustomImpl;
import org.eclipse.apogy.common.emf.transaction.ApogyCommonTransactionFacade;
import org.eclipse.apogy.core.invocator.ApogyCoreInvocatorFacade;
import org.eclipse.apogy.core.invocator.ApogyCoreInvocatorPackage;
import org.eclipse.apogy.core.invocator.OperationCall;
import org.eclipse.apogy.core.invocator.OperationCallsList;
import org.eclipse.apogy.core.invocator.ui.wizards.OperationCallWizard;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.core.databinding.conversion.Converter;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.databinding.viewers.ViewerProperties;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
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.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
public class OperationCallsListComposite extends ScrolledComposite {
private DataBindingContext m_currentDataBindings;
private final ComposedAdapterFactory adapterFactory = new ComposedAdapterFactory(
ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
private OperationCallsList operationCallsList;
private List<FeaturePathAdapter> featurePathAdapters;
private TableViewer tableViewer;
private Button btnDelete;
private Button btnNew;
private Button btnInvoke;
public OperationCallsListComposite(Composite parent, int style) {
super(parent, style);
setLayout(new GridLayout(1, true));
setExpandHorizontal(true);
setExpandVertical(true);
addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
if (OperationCallsListComposite.this.m_currentDataBindings != null) {
OperationCallsListComposite.this.m_currentDataBindings.dispose();
}
if (OperationCallsListComposite.this.operationCallsList != null) {
for (FeaturePathAdapter adapter : OperationCallsListComposite.this.featurePathAdapters) {
adapter.dispose();
}
}
}
});
Composite composite = new Composite(this, SWT.NONE);
composite.setLayout(new GridLayout(2, false));
this.tableViewer = new TableViewer(composite, SWT.BORDER | SWT.FULL_SELECTION);
Table table = this.tableViewer.getTable();
table.setHeaderVisible(true);
table.setLinesVisible(true);
table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 4));
this.tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
newSelection(event.getSelection());
}
});
TableColumn tblclmnName = new TableColumn(table, SWT.NONE);
tblclmnName.setText("Name");
TableColumn tblclmnFeature = new TableColumn(table, SWT.NONE);
tblclmnFeature.setText("Feature");
TableColumn tblclmnCommand = new TableColumn(table, SWT.NONE);
tblclmnCommand.setText("Command");
this.btnInvoke = new Button(composite, SWT.None);
this.btnInvoke.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1));
this.btnInvoke.setText("Invoke");
this.btnInvoke.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
final OperationCall opsCall = (OperationCall) OperationCallsListComposite.this.tableViewer
.getStructuredSelection().getFirstElement();
Job job = new Job(ApogyCoreInvocatorFacade.INSTANCE.getOperationCallString(opsCall)) {
@Override
protected IStatus run(IProgressMonitor monitor) {
ApogyCoreInvocatorFacade.INSTANCE.exec(opsCall);
return Status.OK_STATUS;
}
};
job.schedule();
}
});
Label label = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL);
label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1));
this.btnNew = new Button(composite, SWT.NONE);
this.btnNew.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1));
this.btnNew.setText("New");
this.btnNew.setEnabled(false);
this.btnNew.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
OperationCallWizard newOperationCallWizard = new OperationCallWizard(
OperationCallsListComposite.this.operationCallsList) {
@Override
public boolean performFinish() {
getOperationCall().eResource().getResourceSet().getResources()
.remove(getOperationCall().eResource());
TransactionUtil.disconnectFromEditingDomain(getOperationCall().eResource());
/**
* Needs to be executed in a asyncExec because of the databinding and the
* ObservableListContentProvider.
*/
getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
ApogyCommonTransactionFacade.INSTANCE.basicAdd(
OperationCallsListComposite.this.operationCallsList,
ApogyCoreInvocatorPackage.Literals.OPERATION_CALL_CONTAINER__OPERATION_CALLS,
getOperationCall());
}
});
OperationCallsListComposite.this.tableViewer
.setSelection(new StructuredSelection(getOperationCall()));
packColumns();
return true;
}
};
WizardDialog dialog = new WizardDialog(getShell(), newOperationCallWizard);
dialog.open();
}
});
this.btnDelete = new Button(composite, SWT.NONE);
this.btnDelete.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
this.btnDelete.setText("Delete");
this.btnDelete.setEnabled(false);
this.btnDelete.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ApogyCommonTransactionFacade.INSTANCE.basicRemove(OperationCallsListComposite.this.operationCallsList,
ApogyCoreInvocatorPackage.Literals.OPERATION_CALL_CONTAINER__OPERATION_CALLS,
getSelectedOperationCall());
}
});
setContent(composite);
setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
this.m_currentDataBindings = initDataBindingsCustom();
}
/**
* Returns the selected {@link OperationCall}.
*
* @return Reference to the selected {@link OperationCall}.
*/
public OperationCall getSelectedOperationCall() {
return (OperationCall) this.tableViewer.getStructuredSelection().getFirstElement();
}
/**
* This method is called when a new selection is made in the parentComposite.
*
* @param selection Reference to the selection.
*/
protected void newSelection(ISelection selection) {
}
/**
* This methods packs the columns to adjust their widths
*/
private void packColumns() {
if (!this.tableViewer.isBusy()) {
getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
for (TableColumn column : OperationCallsListComposite.this.tableViewer.getTable().getColumns()) {
column.pack();
}
}
});
}
}
protected void refreshViewer() {
if (!this.tableViewer.isBusy()) {
getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
OperationCallsListComposite.this.tableViewer.refresh();
packColumns();
}
});
}
}
/**
* Sets the {@link OperationCallsList} in the parentComposite
*
* @param operationCallsList
*/
public void setOperationCallsList(OperationCallsList operationCallsList) {
if (this.operationCallsList != null) {
for (FeaturePathAdapter adapter : getFeaturePathAdapters()) {
adapter.dispose();
}
}
this.operationCallsList = operationCallsList;
if (this.operationCallsList.getOperationCalls() != null) {
EObjectReference eObjectReference = ApogyCommonEMFFactory.eINSTANCE.createEObjectReference();
eObjectReference.setEObject(operationCallsList);
this.tableViewer.setInput(eObjectReference);
this.btnNew.setEnabled(true);
packColumns();
} else {
this.tableViewer.setInput(null);
}
for (FeaturePathAdapter adapter : getFeaturePathAdapters()) {
adapter.init(operationCallsList);
}
}
public OperationCallsList getOperationCallsList() {
return this.operationCallsList;
}
/**
* Sets the background colors of the {@link OperationCall}s. If no color is
* specified for an {@link OperationCall}, the color will be set to white.
*
* @param map
*/
public void setBackgroudColor(Map<OperationCall, Integer> map) {
for (TableItem item : this.tableViewer.getTable().getItems()) {
Color color = null;
if (map.containsKey(item.getData())) {
color = getDisplay().getSystemColor(map.get(item.getData()));
}
if (color == null) {
color = getDisplay().getSystemColor(SWT.COLOR_WHITE);
}
item.setBackground(color);
}
}
private List<FeaturePathAdapter> getFeaturePathAdapters() {
if (this.featurePathAdapters == null) {
this.featurePathAdapters = new ArrayList<>();
this.featurePathAdapters.add(new FeaturePathAdapterCustomImpl() {
@Override
public void notifyChanged(Notification msg) {
refreshViewer();
}
@Override
public List<? extends EStructuralFeature> getFeatureList() {
List<EStructuralFeature> featurePath = new ArrayList<EStructuralFeature>();
featurePath.add(ApogyCoreInvocatorPackage.Literals.OPERATION_CALL_CONTAINER__OPERATION_CALLS);
featurePath.add(ApogyCommonEMFPackage.Literals.NAMED__NAME);
return featurePath;
}
});
this.featurePathAdapters.add(new FeaturePathAdapterCustomImpl() {
@Override
public void notifyChanged(Notification msg) {
refreshViewer();
}
@Override
public List<? extends EStructuralFeature> getFeatureList() {
List<EStructuralFeature> featurePath = new ArrayList<EStructuralFeature>();
featurePath.add(ApogyCoreInvocatorPackage.Literals.OPERATION_CALL_CONTAINER__OPERATION_CALLS);
featurePath.add(ApogyCoreInvocatorPackage.Literals.OPERATION_CALL__EOPERATION);
return featurePath;
}
});
this.featurePathAdapters.add(new FeaturePathAdapterCustomImpl() {
@Override
public void notifyChanged(Notification msg) {
refreshViewer();
OperationCallsListComposite.this.newSelection(null);
}
@Override
public List<? extends EStructuralFeature> getFeatureList() {
List<EStructuralFeature> featurePath = new ArrayList<EStructuralFeature>();
featurePath.add(ApogyCoreInvocatorPackage.Literals.OPERATION_CALL_CONTAINER__OPERATION_CALLS);
featurePath.add(ApogyCoreInvocatorPackage.Literals.VARIABLE_FEATURE_REFERENCE__VARIABLE);
featurePath.add(ApogyCommonEMFPackage.Literals.NAMED__NAME);
return featurePath;
}
});
this.featurePathAdapters.add(new FeaturePathAdapterCustomImpl() {
@Override
public void notifyChanged(Notification msg) {
refreshViewer();
OperationCallsListComposite.this.newSelection(null);
}
@Override
public List<? extends EStructuralFeature> getFeatureList() {
List<EStructuralFeature> featurePath = new ArrayList<EStructuralFeature>();
featurePath.add(ApogyCoreInvocatorPackage.Literals.OPERATION_CALL_CONTAINER__OPERATION_CALLS);
featurePath.add(ApogyCoreInvocatorPackage.Literals.VARIABLE_FEATURE_REFERENCE__FEATURE_ROOT);
return featurePath;
}
});
this.featurePathAdapters.add(new FeaturePathAdapterCustomImpl() {
@Override
public void notifyChanged(Notification msg) {
refreshViewer();
OperationCallsListComposite.this.newSelection(null);
}
@Override
public List<? extends EStructuralFeature> getFeatureList() {
List<EStructuralFeature> featurePath = new ArrayList<EStructuralFeature>();
featurePath.add(ApogyCoreInvocatorPackage.Literals.OPERATION_CALL_CONTAINER__OPERATION_CALLS);
featurePath.add(
ApogyCoreInvocatorPackage.Literals.VARIABLE_FEATURE_REFERENCE__TYPE_MEMBER_REFERENCE_LIST_ELEMENT);
return featurePath;
}
});
this.featurePathAdapters.add(new FeaturePathAdapterCustomImpl() {
@Override
public void notifyChanged(Notification msg) {
refreshViewer();
OperationCallsListComposite.this.newSelection(null);
}
@Override
public List<? extends EStructuralFeature> getFeatureList() {
List<EStructuralFeature> featurePath = new ArrayList<EStructuralFeature>();
featurePath.add(ApogyCoreInvocatorPackage.Literals.OPERATION_CALL_CONTAINER__OPERATION_CALLS);
featurePath.add(ApogyCoreInvocatorPackage.Literals.OPERATION_CALL__ARGUMENTS_LIST);
featurePath.add(ApogyCoreInvocatorPackage.Literals.ARGUMENTS_LIST__ARGUMENTS);
return featurePath;
}
});
}
return this.featurePathAdapters;
}
protected DataBindingContext initDataBindingsCustom() {
DataBindingContext bindingContext = new DataBindingContext();
this.tableViewer.setContentProvider(new ControllerBindingsContentProvider(this.adapterFactory));
this.tableViewer.setLabelProvider(new ControllerBindingsLabelProvider(this.adapterFactory));
/**
* Invoke button enabling bindings.
*/
IObservableValue<?> observeSingleSelectionTableViewer = ViewerProperties.singleSelection()
.observe(this.tableViewer);
IObservableValue<?> observeEnabledBtnInvokeObserveWidget = WidgetProperties.enabled().observe(this.btnInvoke);
bindingContext.bindValue(observeEnabledBtnInvokeObserveWidget, observeSingleSelectionTableViewer,
new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER),
new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE)
.setConverter(new Converter(OperationCall.class, Boolean.class) {
@Override
public Object convert(Object fromObject) {
if (fromObject instanceof OperationCall) {
return Diagnostician.INSTANCE.validate((EObject) fromObject)
.getSeverity() == Diagnostic.OK;
} else {
return false;
}
}
}));
/**
* Delete button enabling bindings.
*/
IObservableValue<?> observeEnabledBtnDeleteObserveWidget = WidgetProperties.enabled().observe(this.btnDelete);
bindingContext.bindValue(observeEnabledBtnDeleteObserveWidget, observeSingleSelectionTableViewer,
new UpdateValueStrategy(UpdateValueStrategy.POLICY_NEVER),
new UpdateValueStrategy(UpdateValueStrategy.POLICY_UPDATE)
.setConverter(new Converter(Object.class, Boolean.class) {
@Override
public Object convert(Object fromObject) {
return fromObject != null;
}
}));
return bindingContext;
}
/**
* Label provider for the TreeViewer
*/
private class ControllerBindingsLabelProvider extends AdapterFactoryLabelProvider implements ITableLabelProvider {
public ControllerBindingsLabelProvider(AdapterFactory adapterFactory) {
super(adapterFactory);
}
private final static int NAME_COLUMN_ID = 0;
private final static int FEATURE_COLUMN_ID = 1;
private final static int COMMAND_COLUMN_ID = 2;
@Override
public String getColumnText(Object object, int columnIndex) {
String str = "<undefined>";
if (object instanceof OperationCall) {
OperationCall operationCall = (OperationCall) object;
switch (columnIndex) {
case NAME_COLUMN_ID:
str = operationCall.getName() == null ? "<unnamed>" : operationCall.getName();
break;
case FEATURE_COLUMN_ID:
str = ApogyCoreInvocatorFacade.INSTANCE.getOperationCallString(operationCall);
if (str.contains("#")) {
str = str.substring(0, str.indexOf("#"));
}
break;
case COMMAND_COLUMN_ID:
str = ApogyCoreInvocatorFacade.INSTANCE.getEOperationString(operationCall.getArgumentsList(),
operationCall.getEOperation());
str = str.substring(1, str.length());
break;
}
}
return str;
}
@Override
public Image getColumnImage(Object object, int columnIndex) {
return null;
}
}
/**
* Content provider for the TreeViewer
*/
private class ControllerBindingsContentProvider extends AdapterFactoryContentProvider {
public ControllerBindingsContentProvider(AdapterFactory adapterFactory) {
super(adapterFactory);
}
@Override
public Object[] getElements(Object object) {
if (object instanceof EObjectReference) {
return ((OperationCallsList) ((EObjectReference) object).getEObject()).getOperationCalls().toArray();
}
return null;
}
@Override
public Object[] getChildren(Object object) {
return null;
}
}
}