blob: 1e44ce492133f679a33ad8723fc8867e7326a4c2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2012 The University of York, Antonio García-Domínguez.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Dimitrios Kolovos - initial API and implementation
* Antonio García-Domínguez - recreate the menu on every call to getMenu
* (required in Eclipse 4.x), clean up
******************************************************************************/
package org.eclipse.epsilon.ewl.emf;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.epsilon.common.dt.console.EpsilonConsole;
import org.eclipse.epsilon.common.dt.util.EclipseUtil;
import org.eclipse.epsilon.common.dt.util.LogUtil;
import org.eclipse.epsilon.emc.emf.EmfPrettyPrinter;
import org.eclipse.epsilon.emc.emf.EmfUtil;
import org.eclipse.epsilon.emc.emf.InMemoryEmfModel;
import org.eclipse.epsilon.eol.dt.ExtensionPointToolNativeTypeDelegate;
import org.eclipse.epsilon.eol.dt.userinput.JFaceUserInput;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.execute.context.Variable;
import org.eclipse.epsilon.eol.tools.EolSystem;
import org.eclipse.epsilon.ewl.EwlModule;
import org.eclipse.epsilon.ewl.execute.WizardInstance;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.MenuListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
public abstract class AbstractContributeWizardsAction implements IObjectActionDelegate, IMenuCreator, MenuListener {
protected ISelection selection;
protected IWorkbenchPart targetPart;
private List<InMemoryEmfModel> models;
/**
* Constructor for ContributeWizardsAction.
*/
public AbstractContributeWizardsAction() {
super();
}
/**
* @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
*/
@Override
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
this.targetPart = targetPart;
}
/**
* @see IActionDelegate#run(IAction)
*/
@Override
public void run(IAction action) {
// do nothing
}
/**
* @see IActionDelegate#selectionChanged(IAction, ISelection)
*/
@Override
public void selectionChanged(IAction action, ISelection selection) {
this.selection = selection;
action.setMenuCreator(this);
}
@Override
public void dispose() {
if (models != null) {
for (InMemoryEmfModel model : models) {
model.dispose();
}
}
}
@Override
public Menu getMenu(Menu parent) {
Menu wizardsMenu = new Menu(parent);
wizardsMenu.addMenuListener(this);
return wizardsMenu;
}
@Override
public Menu getMenu(Control parent) {
Menu wizardsMenu = new Menu(parent);
wizardsMenu.addMenuListener(this);
return wizardsMenu;
}
@Override
public void menuHidden(MenuEvent e) {
// not interested in this event
}
@Override
public void menuShown(MenuEvent e) {
populateWizardsMenu((Menu)e.widget);
}
protected abstract EObject getEObject(Object selected);
protected abstract EditingDomain getEditingDomain();
protected abstract WorkbenchPartRefresher getWorkbenchPartRefresher();
protected void execute(Command command) {
EditingDomain editingDomain = getEditingDomain();
if (editingDomain != null) {
editingDomain.getCommandStack().execute(command);
}
else {
command.execute();
}
}
private void populateWizardsMenu(Menu wizardsMenu) {
// Clean the menu
for (MenuItem item : wizardsMenu.getItems()) {
item.dispose();
}
List<EObject> eObjects = new ArrayList<>();
List<WizardInstance> applicableWizards = new ArrayList<>();
if ((selection instanceof IStructuredSelection)) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
Iterator<?> it = structuredSelection.iterator();
while (it.hasNext()) {
Object next = it.next();
EObject eObject = getEObject(next);
if (eObject != null) {
eObjects.add(eObject);
}
}
final Set<String> eObjectURIs = getEObjectURIsFor(eObjects);
final List<IConfigurationElement> availableConfigElems = getConfigurationElementsFor(eObjectURIs);
final List<EPackage> ePackages = getExtraPackages(availableConfigElems);
if (!eObjects.isEmpty()) {
ePackages.add(EmfUtil.getTopEPackage(eObjects.get(0)));
}
final Resource mainResource = eObjects.get(0).eResource();
models = new ArrayList<>();
models.add(new InMemoryEmfModel("Model", mainResource, ePackages));
if (getEditingDomain() instanceof AdapterFactoryEditingDomain) {
// AFED is the common superclass of many useful editing domains, such as the GMF DiagramEditingDomain,
// and it gives us access to the other models besides the domain model (such as the .diagram notation
// model).
final AdapterFactoryEditingDomain adapterEDomain = (AdapterFactoryEditingDomain)getEditingDomain();
// Try to give the extra models better names (without collisions)
final Map<String, Integer> usedCounts = new HashMap<>();
for (Resource res : adapterEDomain.getResourceSet().getResources()) {
if (res != mainResource) {
final String modelName = extractModelNameFromExtension(res, usedCounts);
models.add(new InMemoryEmfModel(modelName, res));
}
}
}
for (URI uri : getEwlURIsFor(eObjectURIs, availableConfigElems)) {
EwlModule module = new EwlModule();
try {
module.parse(uri);
module.getContext().setErrorStream(EpsilonConsole.getInstance().getErrorStream());
module.getContext().setOutputStream(EpsilonConsole.getInstance().getDebugStream());
module.getContext().getNativeTypeDelegates().add(new ExtensionPointToolNativeTypeDelegate());
module.getContext().setUserInput(new JFaceUserInput(module.getContext().getPrettyPrinterManager()));
module.getContext().getFrameStack().put(Variable.createReadOnlyVariable("editor", targetPart));
module.getContext().getPrettyPrinterManager().addPrettyPrinter(new EmfPrettyPrinter());
EolSystem system = new EolSystem();
system.setContext(module.getContext());
module.getContext().getFrameStack().put(Variable.createReadOnlyVariable("System", system));
} catch (Exception e) {
LogUtil.log(e);
continue;
}
for (InMemoryEmfModel model : models) {
module.getContext().getModelRepository().addModel(model);
}
Object self = null;
if (eObjects.size() > 1) {
self = eObjects;
}
else if (eObjects.size() == 1){
self = eObjects.get(0);
}
try {
applicableWizards.addAll(module.getWizardsFor(self));
} catch (EolRuntimeException e) {
EpsilonConsole.getInstance().getErrorStream().println(e.toString());
}
}
}
for (final WizardInstance wizard : applicableWizards) {
final MenuItem wizardItem = new MenuItem(wizardsMenu, SWT.NONE);
try {
wizardItem.setText(wizard.getTitle());
} catch (EolRuntimeException e) {
wizardItem.setText("<error> " + wizard.getWizard().getName());
LogUtil.log(e);
}
wizardItem.addSelectionListener(new SelectionListener() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
// do nothing
}
@Override
public void widgetSelected(SelectionEvent e) {
WorkbenchPartRefresher refresher = getWorkbenchPartRefresher();
refresher.setPart(targetPart);
ExecuteWizardInstanceCommand command =
new ExecuteWizardInstanceCommand(wizard, models, refresher);
execute(command);
}
});
}
}
/**
* Extracts the name of the extra model from the extension of the resource URI, while
* avoiding name collisions using a map that counts how many times each name has been
* used.
*/
private String extractModelNameFromExtension(Resource res, final Map<String, Integer> usedCounts) {
String modelName = "Extra";
if (res.getURI() != null && res.getURI().path() != null) {
// Try to use the resource extension for the model name
final String resourcePath = res.getURI().path().trim();
final int dotPosition = resourcePath.lastIndexOf('.');
if (dotPosition != -1) {
final String extension = resourcePath.substring(dotPosition + 1);
if (extension.length() > 0) {
modelName = extension.substring(0, 1).toUpperCase() + extension.substring(1);
}
}
}
// Avoid collisions by appending '2', '3' and so on after the first use
Integer usedCount = usedCounts.get(modelName);
if (usedCount != null) {
usedCount = usedCount + 1;
usedCounts.put(modelName, usedCount);
modelName = modelName + usedCount;
}
else {
usedCounts.put(modelName, 1);
}
return modelName;
}
private IConfigurationElement[] getAllConfigurationElements() {
return Platform.getExtensionRegistry().getConfigurationElementsFor("org.eclipse.epsilon.ewl.emf.wizards");
}
private List<IConfigurationElement> getConfigurationElementsFor(final Set<String> eObjectURIs) {
final List<IConfigurationElement> availableConfigElems = new ArrayList<>();
for (IConfigurationElement configurationElement : getAllConfigurationElements()) {
String namespaceURI = configurationElement.getAttribute("namespaceURI");
if (namespaceURI.equalsIgnoreCase("*") || eObjectURIs.contains(namespaceURI)) {
availableConfigElems.add(configurationElement);
}
}
return availableConfigElems;
}
private Set<String> getEObjectURIsFor(Collection<EObject> eObjects) {
final Set<String> eObjectURIs = new TreeSet<>();
for (EObject eObject : eObjects) {
String eObjectNsURI = EmfUtil.getTopEPackage(eObject).getNsURI();
eObjectURIs.add(eObjectNsURI);
}
return eObjectURIs;
}
private List<URI> getEwlURIsFor(Set<String> eObjectURIs, Collection<IConfigurationElement> availableConfigElems) {
final List<URI> wizardURIs = new ArrayList<>();
for (IConfigurationElement configurationElement : availableConfigElems) {
String pluginId = configurationElement.getDeclaringExtension().getNamespaceIdentifier();
try {
String path = configurationElement.getAttribute("file");
wizardURIs.add(FileLocator.find(Platform.getBundle(pluginId), new Path(path), null).toURI());
} catch (Exception e) {
LogUtil.log(e);
}
}
for (WizardsExtensionPreference preference : WizardsExtensionPreference.getPreferences()) {
String namespaceURI = preference.getNamespaceURI();
if (namespaceURI.equalsIgnoreCase("*") || eObjectURIs.contains(namespaceURI)) {
wizardURIs.add(new File(EclipseUtil.getWorkspaceFileAbsolutePath(preference.getWizards())).toURI());
}
}
return wizardURIs;
}
private List<EPackage> getExtraPackages(Collection<IConfigurationElement> availableConfigElems) {
final List<EPackage> ePackages = new ArrayList<>();
for (IConfigurationElement elem : availableConfigElems) {
final String extraPackages = elem.getAttribute("extraPackages");
if (extraPackages == null) continue;
for (String packageURI : extraPackages.split(",")) {
final EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(packageURI);
if (ePackage != null) {
ePackages.add(ePackage);
}
}
}
for (WizardsExtensionPreference preference : WizardsExtensionPreference.getPreferences()) {
for (String packageURI : preference.getExtraPackages()) {
final EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(packageURI);
if (ePackage != null) {
ePackages.add(ePackage);
}
}
}
return ePackages;
}
}