| /** |
| * <copyright> |
| * |
| * Copyright (c) 2012, 2014 E.D.Willink 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: |
| * E.D.Willink - Initial API and implementation |
| * Obeo - Enable export and re-use CompleteOCL files for validation |
| * |
| * </copyright> |
| */ |
| package org.eclipse.ocl.examples.xtext.completeocl.ui.commands; |
| |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceStatus; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.emf.common.ui.dialogs.DiagnosticDialog; |
| import org.eclipse.emf.common.util.BasicDiagnostic; |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.common.util.WrappedException; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.provider.EcoreEditPlugin; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.edit.domain.EditingDomain; |
| import org.eclipse.emf.edit.domain.IEditingDomainProvider; |
| import org.eclipse.emf.edit.ui.action.LoadResourceAction.LoadResourceDialog; |
| import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.ocl.examples.domain.elements.DomainPackage; |
| import org.eclipse.ocl.examples.pivot.Element; |
| import org.eclipse.ocl.examples.pivot.ParserException; |
| import org.eclipse.ocl.examples.pivot.Type; |
| import org.eclipse.ocl.examples.pivot.ecore.Ecore2Pivot; |
| import org.eclipse.ocl.examples.pivot.manager.MetaModelManager; |
| import org.eclipse.ocl.examples.pivot.manager.MetaModelManagerResourceSetAdapter; |
| import org.eclipse.ocl.examples.pivot.utilities.BaseResource; |
| import org.eclipse.ocl.examples.pivot.utilities.PivotUtil; |
| import org.eclipse.ocl.examples.pivot.validation.PivotEObjectValidator; |
| import org.eclipse.ocl.examples.xtext.completeocl.CompleteOCLStandaloneSetup; |
| import org.eclipse.ocl.examples.xtext.completeocl.internal.registry.CompleteOCLRegistry; |
| import org.eclipse.ocl.examples.xtext.completeocl.ui.CompleteOCLUiModule; |
| import org.eclipse.ocl.examples.xtext.completeocl.ui.messages.CompleteOCLUIMessages; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.dnd.DND; |
| import org.eclipse.swt.dnd.DropTarget; |
| import org.eclipse.swt.dnd.DropTargetAdapter; |
| import org.eclipse.swt.dnd.DropTargetEvent; |
| import org.eclipse.swt.dnd.FileTransfer; |
| import org.eclipse.swt.dnd.Transfer; |
| 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.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.ISources; |
| import org.eclipse.ui.dialogs.ElementListSelectionDialog; |
| import org.eclipse.ui.handlers.HandlerUtil; |
| import org.eclipse.ui.part.ResourceTransfer; |
| import org.eclipse.xtext.resource.XtextResource; |
| import org.eclipse.xtext.ui.editor.XtextEditor; |
| import org.eclipse.xtext.ui.editor.model.IXtextDocument; |
| import org.eclipse.xtext.util.concurrent.IUnitOfWork; |
| |
| |
| /** |
| * A LoadCompleteOCLResourceHandler supports the OCL->Load Document command. |
| * |
| * It provides a pop-up dialog with DND capability for a Complete OCL document to be installed in the |
| * ResourceSet associated with the invoking selection. |
| */ |
| public class LoadCompleteOCLResourceHandler extends AbstractHandler |
| { |
| protected class ResourceDialog extends LoadResourceDialog |
| { |
| public class URIDropTargetListener extends DropTargetAdapter |
| { |
| @Override |
| public void dragEnter(DropTargetEvent e) { |
| e.detail = DND.DROP_LINK; |
| } |
| |
| @Override |
| public void dragOperationChanged(DropTargetEvent e) { |
| e.detail = DND.DROP_LINK; |
| } |
| |
| @Override |
| public void drop(DropTargetEvent event) { |
| Object data = event.data; |
| if (data == null) { |
| event.detail = DND.DROP_NONE; |
| return; |
| } |
| if (data instanceof IResource[]) { |
| StringBuilder s = new StringBuilder(); |
| for (IResource resource : (IResource[])data) { |
| if (s.length() > 0) { |
| s.append(" "); |
| } |
| s.append(URI.createPlatformResourceURI(resource.getFullPath().toString(), true)); |
| } |
| uriField.setText(s.toString()); |
| } |
| else if (data instanceof String[]) { |
| StringBuilder s = new StringBuilder(); |
| for (String resource : (String[])data) { |
| if (s.length() > 0) { |
| s.append(" "); |
| } |
| s.append(URI.createFileURI(resource)); |
| } |
| uriField.setText(s.toString()); |
| } |
| else { |
| uriField.setText(((String) data)); |
| } |
| } |
| } |
| |
| protected final Shell parent; |
| protected final @NonNull ResourceSet resourceSet; |
| private DropTarget target; |
| private Set<URI> registeredURIsForResourceSet; |
| |
| protected ResourceDialog(Shell parent, EditingDomain domain, @NonNull ResourceSet resourceSet) { |
| super(parent, domain); |
| this.parent = parent; |
| this.resourceSet = resourceSet; |
| int shellStyle = getShellStyle(); |
| int newShellStyle = shellStyle & ~(SWT.APPLICATION_MODAL | SWT.PRIMARY_MODAL | SWT.SYSTEM_MODAL); |
| setShellStyle(newShellStyle); |
| } |
| |
| @Override |
| protected void configureShell(Shell shell) { |
| super.configureShell(shell); |
| shell.setText("Load Complete OCL Document"); |
| } |
| |
| @Override |
| protected Control createContents(Composite parent) { |
| Control control = super.createContents(parent); |
| int operations = /*DND.DROP_MOVE |*/ DND.DROP_COPY | DND.DROP_LINK; |
| target = new DropTarget(uriField, operations); |
| target.setTransfer(new Transfer[] {ResourceTransfer.getInstance(), FileTransfer.getInstance()}); |
| target.addDropListener(new URIDropTargetListener()); |
| return control; |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| Composite createDialogArea = (Composite) super.createDialogArea(parent); |
| |
| // Button composite is the first children and we are expected to retrieve it as such... |
| Composite buttonComposite = (Composite)createDialogArea.getChildren()[0]; |
| |
| Button browseRegisteredOCLFiles = new Button(buttonComposite, SWT.PUSH); |
| browseRegisteredOCLFiles.setText(CompleteOCLUIMessages.LoadCompleteOCLResource_browseOCLFiles); |
| prepareBrowseRegisteredOCLFiles(browseRegisteredOCLFiles); |
| registeredURIsForResourceSet = CompleteOCLRegistry.getRegisteredResourceURIs(resourceSet); |
| if (registeredURIsForResourceSet.isEmpty()) { |
| browseRegisteredOCLFiles.setEnabled(false); |
| } else { |
| browseRegisteredOCLFiles.setEnabled(true); |
| } |
| |
| { |
| FormData data = new FormData(); |
| Control [] children = buttonComposite.getChildren(); |
| data.right = new FormAttachment(children[0], -CONTROL_OFFSET); |
| browseRegisteredOCLFiles.setLayoutData(data); |
| } |
| |
| Label helpLabel = new Label(createDialogArea, SWT.CENTER); |
| helpLabel.setText("You may Drag and Drop from an Eclipse or Operating System Explorer."); |
| { |
| FormData data = new FormData(); |
| data.top = new FormAttachment(uriField, 2 * CONTROL_OFFSET); // Separator is at 1 * CONTROL_OFFSET |
| data.left = new FormAttachment(0, CONTROL_OFFSET); |
| data.right = new FormAttachment(100, -CONTROL_OFFSET); |
| helpLabel.setLayoutData(data); |
| } |
| |
| return createDialogArea; |
| } |
| |
| private void prepareBrowseRegisteredOCLFiles(Button browseRegisteredOCLFiles) { |
| browseRegisteredOCLFiles.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent event) { |
| RegisteredOCLFilesDialog registeredOCLFilesDialog = new RegisteredOCLFilesDialog(getShell()); |
| registeredOCLFilesDialog.open(); |
| Object[] result = registeredOCLFilesDialog.getResult(); |
| if (result != null) { |
| StringBuffer uris = new StringBuffer(); |
| |
| for (int i = 0, length = result.length; i < length; i++) { |
| uris.append(result[i]); |
| uris.append(" "); |
| } |
| uriField.setText((uriField.getText() + " " + uris.toString()).trim()); |
| } |
| } |
| }); |
| } |
| |
| private class RegisteredOCLFilesDialog extends ElementListSelectionDialog |
| { |
| public RegisteredOCLFilesDialog(Shell parent) { |
| super(parent, new LabelProvider() { |
| @Override |
| public Image getImage(Object element) { |
| return ExtendedImageRegistry.getInstance().getImage(EcoreEditPlugin.INSTANCE.getImage("full/obj16/EPackage")); |
| } |
| }); |
| |
| setMultipleSelection(true); |
| setMessage(CompleteOCLUIMessages.LoadCompleteOCLResource_SelectRegisteredOCLFileURI); |
| setFilter("*"); |
| setTitle(CompleteOCLUIMessages.LoadCompleteOCLResource_OCLFileSelection_label); |
| } |
| |
| @Override |
| protected Control createDialogArea(Composite parent) |
| { |
| Composite result = (Composite)super.createDialogArea(parent); |
| URI[] uris = registeredURIsForResourceSet.toArray(new URI[registeredURIsForResourceSet.size()]); |
| Arrays.sort(uris, new URIComparator()); |
| setListElements(uris); |
| return result; |
| } |
| } |
| |
| /** |
| * Generate a popup to display a primaryMessage and optionally a detailMessage too. |
| * @param primaryMessage |
| * @param detailMessage |
| * @return |
| */ |
| protected boolean error(@NonNull String primaryMessage, @Nullable String detailMessage) { |
| Shell shell = parent; |
| if (detailMessage != null) { |
| Diagnostic diagnostic = new BasicDiagnostic(Diagnostic.ERROR, "source", 0, detailMessage, null); |
| DiagnosticDialog.open(shell, title, primaryMessage, diagnostic); |
| } |
| else { |
| MessageDialog.openInformation(shell, title, primaryMessage); |
| } |
| return false; |
| } |
| |
| @Override |
| public int open() { |
| try { |
| return super.open(); |
| } |
| catch (Throwable e) { |
| @SuppressWarnings("null")@NonNull String primaryMessage = String.valueOf(e.getMessage()); |
| error(primaryMessage, null); |
| return CANCEL; |
| } |
| finally { |
| if (target != null) { |
| target.dispose(); |
| target = null; |
| } |
| } |
| } |
| |
| @Override |
| protected boolean processResources() { |
| Helper helper = new Helper(resourceSet) { |
| @Override |
| protected boolean error(@NonNull String primaryMessage, @Nullable String detailMessage) { |
| return ResourceDialog.this.error(primaryMessage, detailMessage); |
| } |
| }; |
| |
| if (!helper.loadMetaModels()) { |
| return false; |
| } |
| // |
| // Load all the documents |
| // |
| for (URI oclURI : getURIs()) { |
| assert oclURI != null; |
| try { |
| if (!helper.loadDocument(oclURI)) { |
| return false; |
| }; |
| } |
| catch (Throwable e) { |
| IStatus status = new Status(IStatus.ERROR, CompleteOCLUiModule.PLUGIN_ID, e.getLocalizedMessage(), e); |
| ErrorDialog.openError(parent, "OCL->Load Document Failure", "Failed to load '" + oclURI + "'", status); |
| return false; |
| } |
| } |
| helper.installPackages(); |
| return true; |
| } |
| |
| @Override |
| protected boolean processResource(Resource resource) { |
| throw new UnsupportedOperationException(); // Never happens since processResources overridden. |
| } |
| } |
| |
| public static abstract class Helper // Functionality subject to JUnit exercising |
| { |
| protected final @NonNull ResourceSet resourceSet; |
| protected final @NonNull MetaModelManager metaModelManager; |
| protected final @NonNull Set<EPackage> mmPackages; |
| |
| public Helper(@NonNull ResourceSet resourceSet) { |
| this.resourceSet = resourceSet; |
| MetaModelManagerResourceSetAdapter adapter = MetaModelManagerResourceSetAdapter.getAdapter(resourceSet, null); // ?? Shared global MMM |
| this.metaModelManager = adapter.getMetaModelManager(); |
| this.mmPackages = new HashSet<EPackage>(); |
| } |
| |
| public boolean loadMetaModels() { |
| for (Resource resource : resourceSet.getResources()) { |
| assert resource != null; |
| Ecore2Pivot ecore2Pivot = Ecore2Pivot.findAdapter(resource, metaModelManager); |
| if (ecore2Pivot == null) { // Pivot has its own validation |
| for (TreeIterator<EObject> tit = resource.getAllContents(); tit.hasNext(); ) { |
| EObject eObject = tit.next(); |
| EClass eClass = eObject.eClass(); |
| if (eClass != null) { |
| EPackage mmPackage = eClass.getEPackage(); |
| if (mmPackage != null) { |
| mmPackages.add(mmPackage); |
| } |
| } |
| } |
| } |
| } |
| Set<Resource> mmResources = new HashSet<Resource>(); |
| for (EPackage mmPackage : mmPackages) { |
| Resource mmResource = EcoreUtil.getRootContainer(mmPackage).eResource(); |
| if (mmResource != null) { |
| mmResources.add(mmResource); |
| } |
| } |
| for (Resource mmResource : mmResources) { |
| assert mmResource != null; |
| try { |
| Element pivotRoot = metaModelManager.loadResource(mmResource, null); |
| if (pivotRoot != null) { |
| List<org.eclipse.emf.ecore.resource.Resource.Diagnostic> errors = pivotRoot.eResource().getErrors(); |
| assert errors != null; |
| String message = PivotUtil.formatResourceDiagnostics(errors, "", "\n"); |
| if (message != null) { |
| return error("Failed to load Pivot from '" + mmResource.getURI(), message); |
| } |
| } |
| else { |
| return error("Failed to load Pivot from '" + mmResource.getURI(), ""); |
| } |
| } catch (ParserException e) { |
| return error("Failed to load Pivot from '" + mmResource.getURI(), e.getMessage()); |
| } |
| } |
| return true; |
| } |
| |
| protected abstract boolean error(@NonNull String primaryMessage, @Nullable String detailMessage); |
| |
| public void installPackages() { |
| // |
| // Install validation for all the complemented packages |
| // |
| PivotEObjectValidator.install(resourceSet, metaModelManager); |
| for (EPackage mmPackage : mmPackages) { |
| assert mmPackage != null; |
| PivotEObjectValidator.install(mmPackage); |
| } |
| } |
| |
| public boolean loadDocument(@NonNull URI oclURI) { |
| Resource resource = loadResource(oclURI); |
| if (resource == null) { |
| return false; |
| } |
| // |
| // Identify the packages which the Complete OCL document complements. |
| // |
| for (TreeIterator<EObject> tit = resource.getAllContents(); tit.hasNext(); ) { |
| EObject eObject = tit.next(); |
| if (eObject instanceof org.eclipse.ocl.examples.pivot.Package) { |
| DomainPackage aPackage = metaModelManager.getPrimaryPackage((org.eclipse.ocl.examples.pivot.Package)eObject); |
| if (eObject instanceof org.eclipse.ocl.examples.pivot.Package) { |
| EPackage mmPackage = (EPackage) ((org.eclipse.ocl.examples.pivot.Package)aPackage).getETarget(); |
| if (mmPackage != null) { |
| mmPackages.add(mmPackage); |
| } |
| } |
| } |
| else if (eObject instanceof Type) { |
| tit.prune(); |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Load the Xtext resource from oclURI, then convert it to a pivot representation and return it. |
| * Return null after invoking error() to display any errors in a pop-up. |
| */ |
| public Resource loadResource(@NonNull URI oclURI) { |
| BaseResource xtextResource = null; |
| CompleteOCLStandaloneSetup.init(); |
| try { |
| xtextResource = (BaseResource) resourceSet.getResource(oclURI, true); |
| } |
| catch (WrappedException e) { |
| URI retryURI = null; |
| Throwable cause = e.getCause(); |
| if (cause instanceof CoreException) { |
| IStatus status = ((CoreException)cause).getStatus(); |
| if ((status.getCode() == IResourceStatus.RESOURCE_NOT_FOUND) && status.getPlugin().equals(ResourcesPlugin.PI_RESOURCES)) { |
| if (oclURI.isPlatformResource()) { |
| retryURI = URI.createPlatformPluginURI(oclURI.toPlatformString(false), false); |
| } |
| } |
| } |
| if (retryURI != null) { |
| xtextResource = (BaseResource) resourceSet.getResource(retryURI, true); |
| } |
| else { |
| throw e; |
| } |
| } |
| List<org.eclipse.emf.ecore.resource.Resource.Diagnostic> errors = xtextResource.getErrors(); |
| assert errors != null; |
| String message = PivotUtil.formatResourceDiagnostics(errors, "", "\n"); |
| if (message != null) { |
| error("Failed to load '" + oclURI, message); |
| return null; |
| } |
| Resource asResource = xtextResource.getASResource(metaModelManager); |
| errors = asResource.getErrors(); |
| assert errors != null; |
| message = PivotUtil.formatResourceDiagnostics(errors, "", "\n"); |
| if (message != null) { |
| error("Failed to load Pivot from '" + oclURI, message); |
| return null; |
| } |
| return asResource; |
| } |
| } |
| |
| public static class URIComparator implements Comparator<URI> { |
| public int compare(URI o1, URI o2) { |
| return o1.toString().compareTo(o2.toString()); |
| } |
| } |
| |
| public @Nullable Object execute(ExecutionEvent event) throws ExecutionException { |
| Object applicationContext = event.getApplicationContext(); |
| EditingDomain editingDomain = getEditingDomain(applicationContext); |
| ResourceSet resourceSet = getResourceSet(applicationContext); |
| // System.out.println("execute " + event); |
| Object shell = HandlerUtil.getVariable(applicationContext, ISources.ACTIVE_SHELL_NAME); |
| if (!(shell instanceof Shell)) { |
| return null; |
| } |
| if (resourceSet != null) { |
| ResourceDialog dialog = new ResourceDialog((Shell)shell, editingDomain, resourceSet); |
| dialog.open(); |
| } |
| return null; |
| } |
| |
| public static @Nullable EditingDomain getEditingDomain(@Nullable Object evaluationContext) { |
| Object o = HandlerUtil.getVariable(evaluationContext, ISources.ACTIVE_EDITOR_NAME); |
| if (!(o instanceof IEditorPart)) { |
| return null; |
| } |
| IEditingDomainProvider editor = (IEditingDomainProvider) ((IEditorPart)o).getAdapter(IEditingDomainProvider.class); |
| if (editor == null) { |
| return null; |
| } |
| EditingDomain editingDomain = editor.getEditingDomain(); |
| if (editingDomain == null) { |
| return null; |
| } |
| return editingDomain; |
| } |
| |
| public static @Nullable ResourceSet getResourceSet(@Nullable Object evaluationContext) { |
| Object o = HandlerUtil.getVariable(evaluationContext, ISources.ACTIVE_EDITOR_NAME); |
| if (!(o instanceof IEditorPart)) { |
| return null; |
| } |
| IEditingDomainProvider editingDomainProvider = (IEditingDomainProvider) ((IEditorPart)o).getAdapter(IEditingDomainProvider.class); |
| if (editingDomainProvider != null) { |
| EditingDomain editingDomain = editingDomainProvider.getEditingDomain(); |
| if (editingDomain == null) { |
| return null; |
| } |
| ResourceSet resourceSet = editingDomain.getResourceSet(); |
| return resourceSet; |
| } |
| XtextEditor xtextEditor = (XtextEditor) ((IEditorPart)o).getAdapter(XtextEditor.class); |
| if (xtextEditor != null) { |
| IXtextDocument document = xtextEditor.getDocument(); |
| ResourceSet resourceSet = document.readOnly(new IUnitOfWork<ResourceSet, XtextResource>() { |
| public ResourceSet exec(XtextResource xtextResource) { |
| if (xtextResource == null) { |
| return null; |
| } |
| MetaModelManager metaModelManager = PivotUtil.findMetaModelManager(xtextResource); |
| if (metaModelManager != null) { |
| return metaModelManager.getExternalResourceSet(); |
| } |
| else { |
| return xtextResource.getResourceSet(); |
| } |
| } |
| }); |
| return resourceSet; |
| } |
| return null; |
| } |
| |
| @Override |
| public void setEnabled(Object evaluationContext) { |
| // System.out.println("setEnabled " + evaluationContext); |
| setBaseEnabled(getResourceSet(evaluationContext) != null); |
| } |
| } |