blob: 70bc88be4935e8243d29e32352500087d8baed6e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2017 BestSolution.at and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
* Dmitry Spiridenok <d.spiridenok@gmail.com> - Bug 408712
* Marco Descher <marco@descher.at> - Bug 434371
* Olivier Prouvost <olivier.prouvost@opcoach.com> Bug 485723, Bug 436836
******************************************************************************/
package org.eclipse.e4.internal.tools.wizards.model;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.e4.internal.tools.Messages;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.pde.core.build.IBuildEntry;
import org.eclipse.pde.core.plugin.IExtensionsModelFactory;
import org.eclipse.pde.core.plugin.IMatchRules;
import org.eclipse.pde.core.plugin.IPluginAttribute;
import org.eclipse.pde.core.plugin.IPluginElement;
import org.eclipse.pde.core.plugin.IPluginExtension;
import org.eclipse.pde.core.plugin.IPluginExtensionPoint;
import org.eclipse.pde.core.plugin.IPluginImport;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.IPluginObject;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.eclipse.pde.internal.core.build.WorkspaceBuildModel;
import org.eclipse.pde.internal.core.bundle.BundlePluginModel;
import org.eclipse.pde.internal.core.bundle.WorkspaceBundlePluginModel;
import org.eclipse.pde.internal.core.project.PDEProject;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWizard;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.ISetSelectionTarget;
@SuppressWarnings("restriction")
public abstract class BaseApplicationModelWizard extends Wizard implements INewWizard {
private NewModelFilePage page;
private ISelection selection;
protected IWorkbench workbench;
/**
* Constructor for NewApplicationModelWizard.
*/
public BaseApplicationModelWizard() {
super();
setNeedsProgressMonitor(true);
}
/**
* Adding the page to the wizard.
*/
@Override
public void addPages() {
page = createWizardPage(selection);
addPage(page);
}
protected abstract NewModelFilePage createWizardPage(ISelection selection);
public abstract String getDefaultFileName();
@Override
public boolean performFinish() {
try {
// Remember the file.
//
final IFile modelFile = getModelFile();
if (modelFile.exists()) {
final boolean continueWithExistingFile = handleFileExist();
if (!continueWithExistingFile) {
return true;
}
}
// Do the work within an operation.
//
final WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor progressMonitor) {
try {
// Create a resource set
//
final ResourceSet resourceSet = new ResourceSetImpl();
// Get the URI of the model file.
//
final URI fileURI = URI.createPlatformResourceURI(modelFile.getFullPath().toString(), true);
// Create a resource for this file.
//
final Resource resource = resourceSet.createResource(fileURI);
final EObject rootObject = createInitialModel();
if (rootObject == null) {
throw new IllegalArgumentException(Messages.BaseApplicationModelWizard_ModelRootMustNotBeNull);
}
// If target file already exists, load its content
//
if (modelFile.exists()) {
resource.load(null);
mergeWithExistingFile(resource, rootObject);
} else {
// If target model is empty (file just created)
// => add as is
resource.getContents().add(rootObject);
}
// Save the contents of the resource to the file system.
//
final Map<Object, Object> options = new HashMap<>();
resource.save(options);
adjustBuildPropertiesFile(modelFile);
adjustDependencies(modelFile);
} catch (final Exception exception) {
throw new RuntimeException(exception);
} finally {
progressMonitor.done();
}
}
};
getContainer().run(false, false, operation);
// Select the new file resource in the current view.
//
final IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow();
final IWorkbenchPage page = workbenchWindow.getActivePage();
final IWorkbenchPart activePart = page.getActivePart();
if (activePart instanceof ISetSelectionTarget) {
final ISelection targetSelection = new StructuredSelection(modelFile);
getShell().getDisplay()
.asyncExec(() -> ((ISetSelectionTarget) activePart).selectReveal(targetSelection));
}
// Open an editor on the new file.
//
try {
page.openEditor(new FileEditorInput(modelFile),
workbench.getEditorRegistry().getDefaultEditor(modelFile.getFullPath().toString()).getId());
} catch (final PartInitException exception) {
MessageDialog.openError(workbenchWindow.getShell(), "Could not init editor", exception.getMessage()); //$NON-NLS-1$
return false;
}
return true;
} catch (final Exception exception) {
exception.printStackTrace();
MessageDialog.openError(getShell(), Messages.BaseApplicationModelWizard_Error, exception.getMessage());
return false;
}
}
/**
* @return if the wizard should continue in case the file already exists
*/
protected boolean handleFileExist() {
MessageDialog.openInformation(getShell(), Messages.BaseApplicationModelWizard_FileExists,
Messages.BaseApplicationModelWizard_TheFileAlreadyExists);
return false;
}
/**
* Creates the rootObject of the new model file. Must not be null.
*
* @return The root {@link EObject}
*/
protected abstract EObject createInitialModel();
protected IFile getModelFile() throws CoreException {
final String containerName = page.getContainerName();
final String fileName = page.getFileName();
final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
final IResource resource = root.findMember(new Path(containerName));
if (!resource.exists() || !(resource instanceof IContainer)) {
throwCoreException("Container \"" + containerName //$NON-NLS-1$
+ "\" does not exist."); //$NON-NLS-1$
}
final IContainer container = (IContainer) resource;
return container.getFile(new Path(fileName));
}
private void throwCoreException(String message) throws CoreException {
final IStatus status = new Status(IStatus.ERROR, "org.eclipse.e4.tools.emf.editor3x", IStatus.OK, message, //$NON-NLS-1$
null);
throw new CoreException(status);
}
/**
* We will accept the selection in the workbench to see if we can initialize
* from it.
*
* @see IWorkbenchWizard#init(IWorkbench, IStructuredSelection)
*/
@Override
public void init(IWorkbench workbench, IStructuredSelection selection) {
this.workbench = workbench;
this.selection = selection;
}
/**
* Adds other file to the build.properties file.
*/
private void adjustBuildPropertiesFile(IFile file) throws CoreException {
final IProject project = file.getProject();
final IFile buildPropertiesFile = PDEProject.getBuildProperties(project);
if (buildPropertiesFile.exists()) {
final WorkspaceBuildModel model = new WorkspaceBuildModel(buildPropertiesFile);
final IBuildEntry entry = model.getBuild().getEntry(IBuildEntry.BIN_INCLUDES);
final String token = file.getProjectRelativePath().toString();
if (!entry.contains(token)) {
entry.addToken(token);
}
model.save();
}
}
/**
* Callback hook to allow for after-file-creation modifications. Default
* implementation does nothing.
*
* @param file
* the file created by the wizard
*/
protected void adjustDependencies(IFile file) {
}
/**
* Add the required dependencies (org.eclipse.e4.ui.model.workbench) and
* register fragment.e4xmi at the required extension point
* (org.eclipse.e4.workbench.model)
*/
protected void adjustFragmentDependencies(IFile file) {
final IProject project = file.getProject();
final IFile pluginXml = PDEProject.getPluginXml(project);
final IFile manifest = PDEProject.getManifest(project);
final WorkspaceBundlePluginModel fModel = new WorkspaceBundlePluginModel(manifest, pluginXml);
try {
addWorkbenchDependencyIfRequired(fModel);
registerWithExtensionPointIfRequired(project, fModel, file);
} catch (final CoreException e) {
e.printStackTrace();
MessageDialog.openError(getShell(), Messages.BaseApplicationModelWizard_Error, e.getMessage());
}
}
private void addWorkbenchDependencyIfRequired(WorkspaceBundlePluginModel fModel) throws CoreException {
final IPluginImport[] imports = fModel.getPluginBase().getImports();
final String WORKBENCH_IMPORT_ID = "org.eclipse.e4.ui.model.workbench"; //$NON-NLS-1$
for (final IPluginImport iPluginImport : imports) {
if (WORKBENCH_IMPORT_ID.equalsIgnoreCase(iPluginImport.getId())) {
return;
}
}
String version = ""; //$NON-NLS-1$
final IPluginModelBase findModel = PluginRegistry.findModel(WORKBENCH_IMPORT_ID);
if (findModel != null) {
final BundleDescription bundleDescription = findModel.getBundleDescription();
if (bundleDescription != null) {
version = bundleDescription.getVersion().toString().replaceFirst("\\.qualifier$", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
}
final IPluginImport workbenchImport = fModel.getPluginFactory().createImport();
workbenchImport.setId(WORKBENCH_IMPORT_ID);
workbenchImport.setVersion(version);
workbenchImport.setMatch(IMatchRules.GREATER_OR_EQUAL);
fModel.getPluginBase().add(workbenchImport);
fModel.save();
}
/**
* Register the fragment.e4xmi with the org.eclipse.e4.workbench.model
* extension point, if there is not already a fragment registered.
*/
private void registerWithExtensionPointIfRequired(IProject project, WorkspaceBundlePluginModel fModel, IFile file)
throws CoreException {
final String WORKBENCH_MODEL_EP_ID = "org.eclipse.e4.workbench.model"; //$NON-NLS-1$
final String FRAGMENT = "fragment"; //$NON-NLS-1$
// Fix bug #436836 : the received fModel is an empty plugin model
// without extension.
// We must copy extensions found in registry plugin model into it
// The registry plugin model is read only and must be copied inside the
// new extension value..
final BundlePluginModel registryModel = (BundlePluginModel) PluginRegistry.findModel(project.getName());
// The registry Model is not modifiable and may be contains some
// existing extensions.
// Must copy them in the new created fModel
for (final IPluginExtension e : registryModel.getPluginBase().getExtensions()) {
final IPluginExtension clonedExtens = copyExtension(fModel.getFactory(), e);
fModel.getPluginBase().add(clonedExtens);
}
// Fix 485723 Must do the same for extension points
for (final IPluginExtensionPoint ep : registryModel.getPluginBase().getExtensionPoints()) {
final IPluginExtensionPoint clonedExtensionPoint = copyExtensionPoint(fModel.getFactory(), ep);
fModel.getPluginBase().add(clonedExtensionPoint);
}
// Can now check if we must add this extension (may be already inside).
final IPluginExtension[] extensions = fModel.getPluginBase().getExtensions();
for (final IPluginExtension iPluginExtension : extensions) {
if (WORKBENCH_MODEL_EP_ID.equalsIgnoreCase(iPluginExtension.getPoint())) {
final IPluginObject[] children = iPluginExtension.getChildren();
for (final IPluginObject child : children) {
if (FRAGMENT.equalsIgnoreCase(child.getName())) {
return;
}
}
}
}
final IPluginExtension extPointFragmentRegister = fModel.getPluginFactory().createExtension();
final IPluginElement element = extPointFragmentRegister.getModel().getFactory()
.createElement(extPointFragmentRegister);
element.setName(FRAGMENT);
element.setAttribute("uri", file.getName()); //$NON-NLS-1$
// Bug 538922 set default value of apply to always
element.setAttribute("apply", "always"); //$NON-NLS-1$ //$NON-NLS-2$
extPointFragmentRegister.setId(project.getName() + "." + FRAGMENT); //$NON-NLS-1$
extPointFragmentRegister.setPoint(WORKBENCH_MODEL_EP_ID);
extPointFragmentRegister.add(element);
fModel.getPluginBase().add(extPointFragmentRegister);
fModel.save();
}
// Used to Fix bug #436836
private IPluginExtension copyExtension(IExtensionsModelFactory factory, final IPluginExtension ext) {
try {
final IPluginExtension clonedExt = factory.createExtension();
clonedExt.setPoint(ext.getPoint());
final IPluginObject[] _children = ext.getChildren();
for (final IPluginObject elt : _children) {
if (elt instanceof IPluginElement) {
final IPluginElement ipe = (IPluginElement) elt;
final IPluginElement clonedElt = copyExtensionElement(factory, ipe, ext);
clonedExt.add(clonedElt);
}
}
return clonedExt;
} catch (final Exception e) {
e.printStackTrace();
}
return null;
}
// Used to Fix bug #485723
private IPluginExtensionPoint copyExtensionPoint(IExtensionsModelFactory factory, final IPluginExtensionPoint ep) {
try {
final IPluginExtensionPoint clonedExtPt = factory.createExtensionPoint();
clonedExtPt.setId(ep.getId());
clonedExtPt.setName(ep.getName());
clonedExtPt.setSchema(ep.getSchema());
return clonedExtPt;
} catch (final Exception e) {
e.printStackTrace();
}
return null;
}
// Used to Fix bug #436836
private IPluginElement copyExtensionElement(IExtensionsModelFactory factory, final IPluginElement elt,
final IPluginObject parent) {
try {
final IPluginElement clonedElt = factory.createElement(parent);
clonedElt.setName(elt.getName());
for (final IPluginAttribute a : elt.getAttributes()) {
clonedElt.setAttribute(a.getName(), a.getValue());
}
for (final IPluginObject e : elt.getChildren()) {
if (e instanceof IPluginElement) {
final IPluginElement ipe = (IPluginElement) e;
final IPluginElement copyExtensionElement = copyExtensionElement(factory, ipe, clonedElt);
clonedElt.add(copyExtensionElement);
}
}
return clonedElt;
} catch (final Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @param resource
* @param rootObject
*/
protected void mergeWithExistingFile(Resource resource, EObject rootObject) {
// do nothing
}
}