blob: 602d32faa23c1909898770f455444be8a3697ba9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2012 Red Hat, Inc.
* All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.bpmn2.modeler.core.merrimac.clad;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.bpmn2.BaseElement;
import org.eclipse.bpmn2.Bpmn2Package;
import org.eclipse.bpmn2.modeler.core.Activator;
import org.eclipse.bpmn2.modeler.core.merrimac.Bpmn2PropertyPageRedrawHandler;
import org.eclipse.bpmn2.modeler.core.merrimac.DefaultBusinessObjectDelegate;
import org.eclipse.bpmn2.modeler.core.merrimac.IBusinessObjectDelegate;
import org.eclipse.bpmn2.modeler.core.merrimac.IConstants;
import org.eclipse.bpmn2.modeler.core.model.ModelHandler;
import org.eclipse.bpmn2.modeler.core.preferences.Bpmn2Preferences;
import org.eclipse.bpmn2.modeler.core.preferences.ModelEnablements;
import org.eclipse.bpmn2.modeler.core.runtime.TargetRuntime;
import org.eclipse.bpmn2.modeler.core.utils.ModelUtil;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
import org.eclipse.emf.edit.provider.INotifyChangedListener;
import org.eclipse.emf.transaction.NotificationFilter;
import org.eclipse.emf.transaction.ResourceSetChangeEvent;
import org.eclipse.emf.transaction.ResourceSetListener;
import org.eclipse.emf.transaction.RollbackException;
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
import org.eclipse.emf.validation.model.EvaluationMode;
import org.eclipse.emf.validation.service.IValidator;
import org.eclipse.emf.validation.service.ModelValidationService;
import org.eclipse.graphiti.ui.editor.DiagramEditor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.views.properties.PropertySheet;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
public class ListAndDetailCompositeBase extends Composite implements ResourceSetListener, Adapter {
public final static Bpmn2Package PACKAGE = Bpmn2Package.eINSTANCE;
@Deprecated
// use createModelObject() instead
//public final static Bpmn2Factory FACTORY = Bpmn2ModelerFactory.getInstance();
protected AbstractBpmn2PropertySection propertySection;
protected FormToolkit toolkit;
protected IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore();
protected EObject businessObject;
protected int style;
protected DiagramEditor diagramEditor;
protected TransactionalEditingDomainImpl editingDomain;
protected ModelHandler modelHandler;
protected boolean isPopupDialog;
private IBusinessObjectDelegate boDelegate;
public ListAndDetailCompositeBase(AbstractBpmn2PropertySection section) {
this(section, SWT.NONE);
}
public ListAndDetailCompositeBase(AbstractBpmn2PropertySection section, int style) {
super(section.getParent(), style);
propertySection = section;
toolkit = propertySection.getWidgetFactory();
initialize();
}
public ListAndDetailCompositeBase(Composite parent, int style) {
super(parent, style);
toolkit = new FormToolkit(Display.getCurrent());
this.style = style;
initialize();
}
protected void initialize() {
GridLayout layout = new GridLayout(3, false);
layout.marginWidth = 0;
setLayout(layout);
if (getParent().getLayout() instanceof GridLayout) {
layout = (GridLayout) getParent().getLayout();
setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, layout.numColumns, 1));
}
toolkit.adapt(this);
toolkit.paintBordersFor(this);
}
@Override
public void dispose() {
removeDomainListener();
removeChangeListener(businessObject);
ModelUtil.disposeChildWidgets(this);
super.dispose();
}
protected void addDomainListener() {
if (editingDomain == null) {
if (diagramEditor == null) {
if ((diagramEditor = getDiagramEditor()) == null)
return;
}
editingDomain = (TransactionalEditingDomainImpl)diagramEditor.getEditingDomain();
editingDomain.addResourceSetListener(this);
}
}
protected void removeDomainListener() {
if (editingDomain!=null) {
editingDomain.removeResourceSetListener(this);
}
}
public void setPropertySection(AbstractBpmn2PropertySection section) {
propertySection = section;
}
public AbstractBpmn2PropertySection getPropertySection() {
if (propertySection!=null)
return propertySection;
Composite parent = getParent();
while (parent!=null && !(parent instanceof ListAndDetailCompositeBase))
parent = parent.getParent();
if (parent instanceof ListAndDetailCompositeBase)
return ((ListAndDetailCompositeBase)parent).getPropertySection();
return null;
}
public IBusinessObjectDelegate getBusinessObjectDelegate() {
if (boDelegate==null)
boDelegate = new DefaultBusinessObjectDelegate(editingDomain);
return boDelegate;
}
/**
* This is no longer need since it has been replaced with the
* redraw UIJob in Bpmn2PropertyPageRoot.
* @deprecated
*/
public synchronized void redrawPageAsync() {
redrawPage();
}
protected synchronized boolean needsRedraw() {
return Bpmn2PropertyPageRedrawHandler.needsRedraw(this);
}
public synchronized void redrawPage() {
Bpmn2PropertyPageRedrawHandler.redraw(this);
}
@Override
public void setVisible(boolean visible) {
// No need if already disposed.
if (isDisposed ())
return;
if (getLayoutData() instanceof GridData) {
((GridData)getLayoutData()).exclude = !visible;
}
super.setVisible(visible);
redrawPage();
}
public TabbedPropertySheetPage getTabbedPropertySheetPage() {
if (getPropertySection()!=null)
return getPropertySection().getTabbedPropertySheetPage();
return null;
}
public FormToolkit getToolkit() {
return toolkit;
}
public void setDiagramEditor(DiagramEditor bpmn2Editor) {
this.diagramEditor = bpmn2Editor;
}
public DiagramEditor getDiagramEditor() {
if (diagramEditor!=null)
return diagramEditor;
if (getPropertySection()!=null)
return (DiagramEditor)getPropertySection().getDiagramEditor();
Composite parent = getParent();
while (parent!=null && !(parent instanceof ListAndDetailCompositeBase))
parent = parent.getParent();
if (parent instanceof ListAndDetailCompositeBase)
return diagramEditor = ((ListAndDetailCompositeBase)parent).getDiagramEditor();
IWorkbenchPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart();
if (part instanceof DiagramEditor)
diagramEditor = (DiagramEditor)part;
else if (part instanceof IEditorPart) {
diagramEditor = (DiagramEditor) ((IEditorPart)part).getAdapter(DiagramEditor.class);
}
else if (part instanceof PropertySheet) {
TabbedPropertySheetPage page = (TabbedPropertySheetPage) ((PropertySheet)part).getCurrentPage();
if (page instanceof Bpmn2TabbedPropertySheetPage) {
diagramEditor = ((Bpmn2TabbedPropertySheetPage)page).getDiagramEditor();
}
}
return diagramEditor;
}
protected boolean isModelObjectEnabled(String className, String featureName) {
return getModelEnablements().isEnabled(className, featureName);
}
protected boolean isModelObjectEnabled(EClass eclass, EStructuralFeature feature) {
String className = eclass==null ? null : eclass.getName();
String featureName = feature==null ? null : feature.getName();
return isModelObjectEnabled(className, featureName);
}
protected boolean isModelObjectEnabled(EClass eclass) {
if (eclass!=null)
return isModelObjectEnabled(eclass,null);
return false;
}
protected ModelEnablements getModelEnablements() {
return (ModelEnablements)getDiagramEditor().getAdapter(ModelEnablements.class);
}
/**
* Convenience method for creating and initializing new objects.
*
* @param clazz
* @return
*/
protected <T extends EObject> T createModelObject(Class clazz) {
T object = getBusinessObjectDelegate().createObject(clazz);
return object;
}
public TargetRuntime getTargetRuntime() {
return (TargetRuntime) getDiagramEditor().getAdapter(TargetRuntime.class);
}
public Bpmn2Preferences getPreferences() {
return (Bpmn2Preferences) getDiagramEditor().getAdapter(Bpmn2Preferences.class);
}
/* (non-Javadoc)
* @see org.eclipse.swt.widgets.Widget#setData(java.lang.Object)
*/
@Override
public void setData(Object object) {
if (object instanceof EObject)
setBusinessObject((EObject)object);
}
public void setBusinessObject(EObject object) {
getDiagramEditor();
if (diagramEditor==null)
diagramEditor = ModelUtil.getEditor(object);
addDomainListener();
modelHandler = ModelHandler.getInstance(getDiagramEditor().getDiagramTypeProvider().getDiagram());
removeChangeListener(businessObject);
businessObject = object;
addChangeListener(businessObject);
// Do initial validation to force display of error message if any
validate();
}
protected void addChangeListener(EObject object) {
if (object!=null && !object.eAdapters().contains(this))
object.eAdapters().add(this);
}
protected void removeChangeListener(EObject object) {
if (object!=null && object.eAdapters().contains(this)) {
object.eSetDeliver(false);
object.eAdapters().remove(this);
object.eSetDeliver(true);
}
}
public final EObject getBusinessObject() {
return businessObject;
}
@Override
public NotificationFilter getFilter() {
NotificationFilter filter = null;
// the editor needs to return a "do nothing" filter while a save is in progress
if (diagramEditor!=null)
filter = (NotificationFilter)diagramEditor.getAdapter(NotificationFilter.class);
if (filter==null) {
filter = NotificationFilter.NOT_TOUCH;
}
return filter;
}
@Override
public Command transactionAboutToCommit(ResourceSetChangeEvent event)
throws RollbackException {
// TODO Auto-generated method stub
return null;
}
protected void getAllChildWidgets(Composite parent, List<Control>kids) {
if (parent!=null && !parent.isDisposed()) {
Control[] cs = parent.getChildren();
for (Control c : cs) {
if (c instanceof Composite) {
getAllChildWidgets((Composite)c,kids);
}
if (!c.isDisposed() &&
c.getData(IConstants.NOTIFY_CHANGE_LISTENER_KEY) instanceof INotifyChangedListener) {
kids.add(c);
}
}
}
}
// TODO: Figure out a broader method of detecting model changes.
// This listener is only called AFTER a transaction has committed,
// it will not receive notification of model changes inside a txn.
// So, while this works in the Property Sheet pages, things like
// the ObjectEditingDialog (which makes changes in the current txn)
// will not cause other widgets in the dialog to be notified.
@Override
public void resourceSetChanged(ResourceSetChangeEvent event) {
final List<Notification> notifications = new ArrayList<Notification>();
List<Notification> eventNotifications = event.getNotifications();
NotificationFilter filter = getFilter();
for (int i=eventNotifications.size()-1; i>=0; --i) {
Notification n = eventNotifications.get(i);
// We are only interested in notifications that affect BaseElements
// since the {@link ObjectEditor} children only work with these objects.
if (n.getNotifier() instanceof BaseElement) {
if (filter.matches(n)) {
boolean add = true;
if (n.getFeature() instanceof EStructuralFeature) {
EStructuralFeature f = (EStructuralFeature)n.getFeature();
EClass ec = f.getEContainingClass();
// Attempt to reduce the number of notifications to process:
// notifications for the XMLTypePackage are inconsequential
if (ec.getEPackage()==XMLTypePackage.eINSTANCE)
add = false;
}
for (Notification n2 : notifications) {
if (n2.getNotifier()==n.getNotifier() && n2.getFeature()==n.getFeature()) {
add = false;
break;
}
}
if (add)
{
notifications.add(n);
}
}
}
}
// System.out.println("resource changed: "+this.getClass().getSimpleName()+" "+notifications.size()+" notifications");
// run this in the UI thread
Display.getDefault().asyncExec( new Runnable() {
public void run() {
Composite parent = ListAndDetailCompositeBase.this;
if (!parent.isDisposed()) {
List<Control>kids = new ArrayList<Control>();
try {
AbstractBpmn2PropertySection section = ListAndDetailCompositeBase.this.getPropertySection();
if (section!=null && section.getTabbedPropertySheetPage()!=null) {
parent = (Composite)section.getTabbedPropertySheetPage().getControl();
}
}
catch (Exception e) {
return;
}
boolean firstTime = true;
for (Notification n : notifications) {
if (getFilter().matches(n)) {
if (n.getFeature() instanceof EStructuralFeature) {
// EStructuralFeature f = (EStructuralFeature)n.getFeature();
// EClass ec = (EClass)f.eContainer();
// String et;
// switch (n.getEventType()){
// case Notification.SET: et = "SET"; break;
// case Notification.UNSET: et = "UNSET"; break;
// case Notification.ADD: et = "ADD"; break;
// case Notification.ADD_MANY: et = "ADD_MANY"; break;
// case Notification.REMOVE: et = "REMOVE"; break;
// case Notification.REMOVE_MANY: et = "REMOVE_MANY"; break;
// default: et = "UNKNOWN";
// }
// System.out.println("sending notification: "+
// ec.getEPackage().getName()+":"+ec.getName()+"."+f.getName()+" "+et+" old="+n.getOldStringValue()+" new="+n.getNewStringValue());
if (firstTime) {
getAllChildWidgets(parent, kids);
firstTime = false;
}
for (Control c : kids) {
if (!c.isDisposed() && c.isVisible()) {
INotifyChangedListener listener = (INotifyChangedListener)c.getData(
IConstants.NOTIFY_CHANGE_LISTENER_KEY);
if (listener!=null) {
// System.out.println(" "+listener.getClass().getSimpleName());
listener.notifyChanged(n);
}
}
}
}
}
}
}
}
});
}
/* (non-Javadoc)
* @see org.eclipse.emf.transaction.ResourceSetListener#isAggregatePrecommitListener()
*/
@Override
public boolean isAggregatePrecommitListener() {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see org.eclipse.emf.transaction.ResourceSetListener#isPrecommitOnly()
*/
@Override
public boolean isPrecommitOnly() {
// TODO Auto-generated method stub
return false;
}
/* (non-Javadoc)
* @see org.eclipse.emf.transaction.ResourceSetListener#isPostcommitOnly()
*/
@Override
public boolean isPostcommitOnly() {
// TODO Auto-generated method stub
return false;
}
public void setIsPopupDialog(boolean isPopupDialog) {
this.isPopupDialog = isPopupDialog;
}
public IStatus validate() {
Notification n = new ENotificationImpl((InternalEObject) businessObject, 0, null, null, null, false);
return validate(n);
}
protected IStatus validate(Notification notification) {
IValidator<Notification> validator = ModelValidationService.getInstance().newValidator(EvaluationMode.LIVE);
return validator.validate(notification);
}
@Override
public void notifyChanged(Notification notification) {
validate(notification);
}
@Override
public Notifier getTarget() {
return null;
}
@Override
public void setTarget(Notifier newTarget) {
}
@Override
public boolean isAdapterForType(Object type) {
return false;
}
}