blob: d9368f9cc9d51ecfd036ce516cbbbe7e21d9efc3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 David A Carlson
* 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:
* David A Carlson (Clinical Cloud Solutions, LLC) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.mdht.uml.fhir.ui.properties;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.commands.operations.IUndoableOperation;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.emf.workspace.AbstractEMFOperation;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.mdht.uml.common.ui.dialogs.DialogLaunchUtil;
import org.eclipse.mdht.uml.common.ui.search.IElementFilter;
import org.eclipse.mdht.uml.common.util.UMLUtil;
import org.eclipse.mdht.uml.fhir.FHIRPackage;
import org.eclipse.mdht.uml.fhir.StructureDefinition;
import org.eclipse.mdht.uml.fhir.TypeChoice;
import org.eclipse.mdht.uml.fhir.common.util.FhirModelUtil;
import org.eclipse.mdht.uml.fhir.ui.Activator;
import org.eclipse.mdht.uml.ui.properties.sections.WrapperAwareModelerPropertySection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertyConstants;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;
/**
* The properties section for a Property TypeChoice list.
*
* @author dcarlson
*/
public class TypeChoiceSection extends WrapperAwareModelerPropertySection {
protected Property umlProperty;
protected TypeChoice typeChoice;
private FHIRTableViewer typeChoiceViewer = null;
private Button addButton = null;
private Button removeButton = null;
private void addChoiceMember() {
try {
TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(typeChoice);
IUndoableOperation operation = new AbstractEMFOperation(editingDomain, "temp") {
@Override
protected IStatus doExecute(IProgressMonitor monitor, IAdaptable info) {
this.setLabel("Add Type Choice");
// search for a StructureDefinition
// add TypeChoice stereotype, if not already applied
// -- move current non-abstract type into choice list
String baseTypeName = umlProperty.getType().getName();
Class type = selectChoiceMember(baseTypeName, "Extension");
if (type != null) {
typeChoice.getTypes().add(type);
}
refresh();
return Status.OK_STATUS;
}
};
execute(operation);
} catch (Exception e) {
throw new RuntimeException(e.getCause());
}
}
protected Class selectChoiceMember(final String hasBaseTypeNames, final String notBaseTypeNames) {
// select a structure definition class
Profile fhirProfile = org.eclipse.uml2.uml.util.UMLUtil.getProfile(FHIRPackage.eINSTANCE.getStructureDefinition().getEPackage(), umlProperty);
if (fhirProfile == null) {
return null;
}
final Stereotype structureDefStereotype = fhirProfile.getOwnedStereotype(org.eclipse.mdht.uml.fhir.FHIRPackage.eINSTANCE.getStructureDefinition().getName());
IElementFilter filter = new IElementFilter() {
public boolean accept(Element element) {
boolean hasStereotype = (element instanceof Class) && element.isStereotypeApplied(structureDefStereotype);
boolean hasBaseType = true;
boolean notBaseType = true;
if (hasStereotype && hasBaseTypeNames != null) {
hasBaseType = false;
String[] names = hasBaseTypeNames.split(",| ");
for (int i = 0; i < names.length; i++) {
boolean isKindOf = FhirModelUtil.isKindOf((Class)element, names[i]);
if (isKindOf) {
hasBaseType = true;
break;
}
}
}
if (hasStereotype && hasBaseType && notBaseTypeNames != null) {
String[] names = notBaseTypeNames.split(",| ");
for (int i = 0; i < names.length; i++) {
boolean isKindOf = FhirModelUtil.isKindOf((Class)element, names[i]);
if (isKindOf) {
notBaseType = false;
break;
}
}
}
return hasStereotype && hasBaseType && notBaseType;
}
};
final Class selectedClass = (Class) DialogLaunchUtil.chooseElement(
filter, UMLUtil.getTopPackage(umlProperty), getPart().getSite().getShell(), null, "Select a type");
return selectedClass;
}
private void removeChoiceMember(final Classifier choiceMember) {
try {
TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(typeChoice);
IUndoableOperation operation = new AbstractEMFOperation(editingDomain, "temp") {
@Override
protected IStatus doExecute(IProgressMonitor monitor, IAdaptable info) {
this.setLabel("Remove Choice Member");
if (typeChoice != null) {
typeChoice.getTypes().remove(choiceMember);
}
refresh();
return Status.OK_STATUS;
}
};
execute(operation);
} catch (Exception e) {
throw new RuntimeException(e.getCause());
}
}
private ModifyListener modifyListener = new ModifyListener() {
public void modifyText(final ModifyEvent event) {
}
};
private FocusListener focusListener = new FocusListener() {
public void focusGained(FocusEvent e) {
// do nothing
}
public void focusLost(FocusEvent event) {
modifyFields();
}
};
private void modifyFields() {
}
@Override
public boolean shouldUseExtraSpace() {
return true;
}
@Override
public void createControls(final Composite parent, final TabbedPropertySheetPage aTabbedPropertySheetPage) {
super.createControls(parent, aTabbedPropertySheetPage);
Composite composite = getWidgetFactory().createGroup(parent, "Type Choice");
FormLayout layout = new FormLayout();
layout.marginWidth = ITabbedPropertyConstants.HSPACE;
layout.marginHeight = ITabbedPropertyConstants.VSPACE;
layout.spacing = ITabbedPropertyConstants.VMARGIN;
composite.setLayout(layout);
addButton = getWidgetFactory().createButton(composite, null, SWT.PUSH);
Image addImage = Activator.getDefault().getBundledImage("icons/full/eview16/add.gif");
addButton.setImage(addImage);
addButton.setToolTipText("Add Type");
addButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
addChoiceMember();
}
});
removeButton = getWidgetFactory().createButton(composite, null, SWT.PUSH);
Image removeImage = Activator.getDefault().getBundledImage("icons/full/eview16/remove.gif");
removeButton.setImage(removeImage);
removeButton.setToolTipText("Delete selected type(s)");
removeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
ISelection selection = typeChoiceViewer.getSelection();
if (selection instanceof IStructuredSelection) {
for (Object selected : ((IStructuredSelection)selection).toList()) {
if (selected instanceof StructureDefinition) {
selected = ((StructureDefinition)selected).getBase_Class();
}
if (selected instanceof Classifier) {
removeChoiceMember((Classifier)selected);
}
}
}
}
});
FormData data = new FormData();
data.left = new FormAttachment(0, 0);
data.top = new FormAttachment(0, 0);
addButton.setLayoutData(data);
data = new FormData();
data.left = new FormAttachment(0, 0);
data.top = new FormAttachment(addButton, 0);
removeButton.setLayoutData(data);
Table table = getWidgetFactory().createTable(composite, SWT.V_SCROLL | SWT.MULTI);
data = new FormData();
data.left = new FormAttachment(addButton, 0);
data.right = new FormAttachment(100, 0);
data.top = new FormAttachment(0, 0);
data.bottom = new FormAttachment(100, 0);
table.setLayoutData(data);
typeChoiceViewer = new FHIRTableViewer(table) {
@Override
protected AdapterFactoryContentProvider createContentProvider(AdapterFactory adapterFactory) {
return new AdapterFactoryContentProvider(adapterFactory) {
@Override
public Object[] getElements(Object object) {
List<Object> choiceMembers = new ArrayList<Object>();
if (typeChoice != null) {
for (Classifier member : typeChoice.getTypes()) {
StructureDefinition structureDef = FhirModelUtil.getStructureDefinition(member);
choiceMembers.add(structureDef != null ? structureDef : member);
}
}
return choiceMembers.toArray();
}
};
}
@Override
protected void createColumns() {
String[] titles = { "Class", "Base Type", "Profile", "Aggregation" };
int[] bounds = { 150, 150, 300, 100 };
TableViewerColumn classColumn = createTableViewerColumn(titles[0], bounds[0], 0);
TableViewerColumn baseTypeColumn = createTableViewerColumn(titles[1], bounds[1], 1);
TableViewerColumn profileColumn = createTableViewerColumn(titles[2], bounds[2], 2);
TableViewerColumn aggregationColumn = createTableViewerColumn(titles[3], bounds[3], 3);
// TODO add editing support for each editable column
}
};
}
@Override
protected boolean isReadOnly() {
if (umlProperty != null) {
TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(umlProperty);
if (editingDomain != null && editingDomain.isReadOnly(umlProperty.eResource())) {
return true;
}
}
return super.isReadOnly();
}
/*
* Override super implementation to allow for objects that are not IAdaptable.
*
* (non-Javadoc)
*
* @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AbstractModelerPropertySection#addToEObjectList(java.lang.Object)
*/
@Override
protected boolean addToEObjectList(Object object) {
boolean added = super.addToEObjectList(object);
if (!added && object instanceof Element) {
getEObjectList().add(object);
added = true;
}
return added;
}
@Override
public void setInput(IWorkbenchPart part, ISelection selection) {
super.setInput(part, selection);
this.umlProperty = null;
this.typeChoice = null;
EObject element = getEObject();
if (element instanceof View) {
element = ((View) element).getElement();
}
if (element instanceof Association) {
element = UMLUtil.getNavigableEnd((Association) element);
}
if (element instanceof Property) {
this.umlProperty = (Property) element;
for (EObject stereoApp : ((Element)element).getStereotypeApplications()) {
if (stereoApp instanceof TypeChoice) {
element = stereoApp;
}
}
}
if (element instanceof TypeChoice) {
this.typeChoice = (TypeChoice) element;
}
}
@Override
public void dispose() {
super.dispose();
}
@Override
public void refresh() {
if (typeChoice == null) {
typeChoiceViewer.setInput(null);
return;
}
typeChoiceViewer.setInput(typeChoice);
}
/**
* Update if necessary, upon receiving the model event.
*
* @see #aboutToBeShown()
* @see #aboutToBeHidden()
* @param notification
* -
* even notification
* @param element
* -
* element that has changed
*/
@Override
public void update(final Notification notification, EObject element) {
if (!isDisposed()) {
postUpdateRequest(new Runnable() {
public void run() {
if (!isDisposed() && !isNotifierDeleted(notification)) {
refresh();
}
}
});
}
}
}