/******************************************************************************* * Copyright (c) 2011 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.ui.property; import java.util.Collection; import java.util.List; import org.eclipse.bpmn2.BaseElement; import org.eclipse.bpmn2.modeler.core.Bpmn2Preferences; import org.eclipse.bpmn2.modeler.core.utils.ModelUtil; import org.eclipse.bpmn2.modeler.ui.editor.BPMN2Editor; import org.eclipse.bpmn2.provider.Bpmn2ItemProviderAdapterFactory; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.edit.command.CommandParameter; import org.eclipse.emf.edit.provider.ItemProviderAdapter; import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider; import org.eclipse.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.ResourceSetChangeEvent; import org.eclipse.emf.transaction.ResourceSetListenerImpl; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.graphiti.mm.pictograms.PictogramElement; import org.eclipse.graphiti.ui.services.GraphitiUi; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Tree; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.forms.widgets.ExpandableComposite; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; @SuppressWarnings("unchecked") public class ImprovedAdvancedPropertiesComposite extends Composite { private final FormToolkit toolkit = new FormToolkit(Display.getCurrent()); private EObject be; private final TreeViewer treeViewer; private TabbedPropertySheetPage aTabbedPropertySheetPage; private BPMN2Editor diagramEditor; private final MainPropertiesComposite mainPropertiesComposite; private Bpmn2Preferences prefs; private TransactionalEditingDomain domain; private DomainListener domainListener; class DomainListener extends ResourceSetListenerImpl { @Override public void resourceSetChanged(ResourceSetChangeEvent event) { List<Notification> notifications = event.getNotifications(); for (Notification notification : notifications) { treeViewer.refresh(notification.getNotifier(), true); } } } /** * Create the composite. * * @param parent * @param style */ public ImprovedAdvancedPropertiesComposite(Composite parent, int style) { super(parent, style); addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { toolkit.dispose(); } }); toolkit.adapt(this); toolkit.paintBordersFor(this); FillLayout fillLayout = new FillLayout(SWT.HORIZONTAL); fillLayout.spacing = 2; fillLayout.marginHeight = 3; fillLayout.marginWidth = 3; setLayout(fillLayout); SashForm sashForm = new SashForm(this, SWT.NONE); sashForm.setSashWidth(5); toolkit.adapt(sashForm); toolkit.paintBordersFor(sashForm); Section sctnProperties = toolkit.createSection(sashForm, ExpandableComposite.TITLE_BAR); toolkit.paintBordersFor(sctnProperties); sctnProperties.setText("Properties"); Composite composite = toolkit.createComposite(sctnProperties, SWT.NONE); toolkit.paintBordersFor(composite); sctnProperties.setClient(composite); composite.setLayout(new GridLayout(1, false)); treeViewer = new TreeViewer(composite, SWT.BORDER); Tree tree = treeViewer.getTree(); tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2)); toolkit.paintBordersFor(tree); treeViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { mainPropertiesComposite.setEObject(diagramEditor, getSelectedBaseElement()); aTabbedPropertySheetPage.resizeScrolledComposite(); } }); treeViewer.setContentProvider(new PropertyTreeContentProvider(this)); treeViewer.setLabelProvider(new AdapterFactoryLabelProvider(AbstractBpmn2PropertiesComposite.ADAPTER_FACTORY)); Section sctnEditors = toolkit.createSection(sashForm, ExpandableComposite.TITLE_BAR); toolkit.paintBordersFor(sctnEditors); sctnEditors.setText("Attributes"); mainPropertiesComposite = new MainPropertiesComposite(sctnEditors, SWT.NONE); sctnEditors.setClient(mainPropertiesComposite); toolkit.adapt(mainPropertiesComposite); toolkit.paintBordersFor(mainPropertiesComposite); sashForm.setWeights(new int[] { 1, 1 }); } public void setEObject(BPMN2Editor diagramEditor, EObject be) { if (domain != null && domainListener != null) { domain.removeResourceSetListener(domainListener); } this.diagramEditor = diagramEditor; this.be = be; domain = diagramEditor.getEditingDomain(); domainListener = new DomainListener(); domain.addResourceSetListener(domainListener); treeViewer.setInput(be); prefs = Bpmn2Preferences.getPreferences(diagramEditor.getModelFile().getProject()); } public void setSheetPage(TabbedPropertySheetPage aTabbedPropertySheetPage) { this.aTabbedPropertySheetPage = aTabbedPropertySheetPage; MenuManager manager = new MenuManager("#PropertiesMenu"); manager.setRemoveAllWhenShown(true); manager.addMenuListener(new IMenuListener() { @Override public void menuAboutToShow(IMenuManager manager) { ImprovedAdvancedPropertiesComposite.this.buildMenu((MenuManager) manager); } }); Tree tree = treeViewer.getTree(); Menu menu = manager.createContextMenu(tree); tree.setMenu(menu); aTabbedPropertySheetPage.getSite().registerContextMenu("#PropertiesMenu", manager, treeViewer); } protected void buildMenu(MenuManager manager) { EObject selectedElem = getSelectedBaseElement(); createElementProperties(manager, selectedElem); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); if (selectedElem != null) { manager.add(createRemoveAction(selectedElem)); } manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); createRootProperties(manager); } private void createRootProperties(MenuManager menuManager) { MenuManager manager = new MenuManager("Add Root Property"); menuManager.add(manager); createMenuItems(manager, "", be, true); } private void createElementProperties(MenuManager manager, EObject baseElement) { if (baseElement != null) { createMenuItems(manager, "Add ", baseElement, false); } } private void createMenuItems(MenuManager manager, String prefix, EObject baseElement, boolean root) { ItemProviderAdapter itemProviderAdapter = (ItemProviderAdapter) new Bpmn2ItemProviderAdapterFactory().adapt( baseElement, ItemProviderAdapter.class); Collection<CommandParameter> desc = (Collection<CommandParameter>) itemProviderAdapter.getNewChildDescriptors( baseElement, diagramEditor.getEditingDomain(), null); EList<EReference> eAllContainments = baseElement.eClass().getEAllContainments(); for (CommandParameter command : desc) { EStructuralFeature feature = (EStructuralFeature) command.feature; EObject commandValue = (EObject) command.value; if (root) { if (eAllContainments.contains(feature) && prefs.isEnabled(commandValue.eClass()) && prefs.isEnabled(commandValue.eClass(), feature)) { Object value = baseElement.eGet(feature); String name = PropertyUtil.deCamelCase(commandValue.eClass().getName()); Action item = createMenuItemFor(prefix + name, baseElement, (EReference) feature, command.value); item.setEnabled(value == null || value instanceof EList); manager.add(item); } } else { if (eAllContainments.contains(feature) && prefs.isEnabled(baseElement.eClass(), feature)) { Object value = baseElement.eGet(feature); String name = PropertyUtil.deCamelCase(commandValue.eClass().getName()); Action item = createMenuItemFor(prefix + name, baseElement, (EReference) feature, command.value); item.setEnabled(value == null || value instanceof EList); manager.add(item); } } } } private Action createMenuItemFor(String prefix, final EObject baseElement, final EReference eReference, final Object value) { return new Action(prefix) { @Override public void run() { TransactionalEditingDomain domain = diagramEditor.getEditingDomain(); domain.getCommandStack().execute(new RecordingCommand(domain) { @Override protected void doExecute() { createNewProperty(baseElement, eReference); } private void createNewProperty(final EObject baseElement, final EReference eReference) { Object eGet = baseElement.eGet(eReference); if (value instanceof BaseElement) { BaseElement e = ((BaseElement) value); if (e.getId() == null) { // e.setId(EcoreUtil.generateUUID()); ModelUtil.setID(e,baseElement.eResource()); } } if (eGet instanceof EList) { ((EList) eGet).add(value); } else { baseElement.eSet(eReference, value); } treeViewer.refresh(true); } }); } }; } private EObject getSelectedBaseElement() { ISelection selection = treeViewer.getSelection(); EObject baseElement = null; if (selection instanceof IStructuredSelection) { Object firstElement = ((IStructuredSelection) selection).getFirstElement(); if (firstElement instanceof EObject) { baseElement = (EObject) firstElement; } } return baseElement; } private Action createRemoveAction(final EObject baseElement) { return new Action("Remove") { @SuppressWarnings("restriction") @Override public void run() { if (baseElement == null) { treeViewer.refresh(true); return; } final EObject container = baseElement.eContainer(); final Object eGet = container.eGet(baseElement.eContainingFeature()); TransactionalEditingDomain domain = diagramEditor.getEditingDomain(); domain.getCommandStack().execute(new RecordingCommand(domain) { @SuppressWarnings("rawtypes") @Override protected void doExecute() { List<PictogramElement> pictogramElements = GraphitiUi.getLinkService().getPictogramElements( diagramEditor.getDiagramTypeProvider().getDiagram(), baseElement); if (eGet instanceof EList) { ((EList) eGet).remove(baseElement); } else { container.eUnset(baseElement.eContainingFeature()); } for (PictogramElement pictogramElement : pictogramElements) { // TODO: check if we need to update the diagram manually or will the autoupdate do // it // UpdateContext context = new UpdateContext(pictogramElement); // IUpdateFeature updateFeature = diagramEditor.getDiagramTypeProvider() // .getFeatureProvider().getUpdateFeature(context); // context.putProperty("deleted", baseElement); // if (updateFeature != null) { // updateFeature.update(context); // } pictogramElement.getLink().getBusinessObjects().clear(); } treeViewer.refresh(true); } }); } }; } }