blob: 95624db273c32a612ed9d577d970bf02f757c1f9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2011 IBM Corporation 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:
* IBM Corporation - initial API and implementation
* EclipseSource Corporation - ongoing enhancements
*******************************************************************************/
package org.eclipse.pde.internal.ui.wizards.product;
import java.lang.reflect.InvocationTargetException;
import java.util.Locale;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.IBaseModel;
import org.eclipse.pde.core.plugin.*;
import org.eclipse.pde.internal.core.TargetPlatformHelper;
import org.eclipse.pde.internal.core.iproduct.*;
import org.eclipse.pde.internal.core.iproduct.IProduct;
import org.eclipse.pde.internal.core.plugin.WorkspacePluginModelBase;
import org.eclipse.pde.internal.core.product.SplashInfo;
import org.eclipse.pde.internal.core.text.plugin.PluginElementNode;
import org.eclipse.pde.internal.ui.PDEPlugin;
import org.eclipse.pde.internal.ui.PDEUIMessages;
import org.eclipse.pde.internal.ui.util.*;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.branding.IProductConstants;
public class ProductDefinitionOperation extends BaseManifestOperation {
private String fProductId;
private String fApplication;
private IProduct fProduct;
protected IProject fProject;
private UpdateSplashHandlerAction fUpdateSplashAction;
private RemoveSplashHandlerBindingAction fRemoveSplashAction;
private UpdateSplashProgressOperation fUpdateSplashProgressOperation;
public ProductDefinitionOperation(IProduct product, String pluginId, String productId, String application, Shell shell) {
super(shell, pluginId);
fProductId = productId;
fApplication = application;
fProduct = product;
fProject = null;
}
public ProductDefinitionOperation(IProduct product, String pluginId, String productId, String application, Shell shell, IProject project) {
super(shell, pluginId);
fProductId = productId;
fApplication = application;
fProduct = product;
// Needed for splash handler updates (file copying)
fProject = project;
}
protected String getFormattedPackageName(String id) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < id.length(); i++) {
char ch = id.charAt(i);
if (buffer.length() == 0) {
if (Character.isJavaIdentifierStart(ch))
buffer.append(Character.toLowerCase(ch));
} else {
if (Character.isJavaIdentifierPart(ch) || ch == '.')
buffer.append(ch);
}
}
return buffer.toString().toLowerCase(Locale.ENGLISH);
}
protected String createTargetPackage() {
// Package name addition to create a location for containing
// any classes required by the splash handlers.
String packageName = getFormattedPackageName(fPluginId);
// Unqualifed
if (packageName.length() == 0) {
return ISplashHandlerConstants.F_UNQUALIFIED_EXTENSION_ID;
}
// Qualified
return packageName + '.' + ISplashHandlerConstants.F_UNQUALIFIED_EXTENSION_ID;
}
/**
* @return fully-qualified class (with package)
*/
private String createAttributeValueClass() {
String targetPackage = createTargetPackage();
String targetClass = createTargetClass();
// Ensure target class is defined
if (targetClass == null) {
return null;
}
return targetPackage + "." + //$NON-NLS-1$
targetClass;
}
/**
* @return unqualified class
*/
private String createTargetClass() {
// Get the splash handler type
String splashHandlerType = getSplashHandlerType();
// Ensure splash handler type was specfied
if (splashHandlerType == null) {
return null;
}
// Update the class name depending on the splash screen type
for (int i = 0; i < ISplashHandlerConstants.F_SPLASH_SCREEN_TYPE_CHOICES.length; i++) {
String choice = ISplashHandlerConstants.F_SPLASH_SCREEN_TYPE_CHOICES[i][0];
if (splashHandlerType.equals(choice)) {
return ISplashHandlerConstants.F_SPLASH_SCREEN_CLASSES[i];
}
}
return null;
}
/**
* @return splash screen type qualified with package name
*/
private String createAttributeValueID() {
// Create the ID based on the splash screen type
return createTargetPackage() + "." + //$NON-NLS-1$
getSplashHandlerType();
}
private UpdateSplashProgressOperation getUpdateSplashProgressOperation() {
if (fUpdateSplashProgressOperation == null) {
fUpdateSplashProgressOperation = new UpdateSplashProgressOperation();
} else {
fUpdateSplashProgressOperation.reset();
}
return fUpdateSplashProgressOperation;
}
private void updateSplashProgress(IPluginModelBase model, IProgressMonitor monitor) throws CoreException {
// Sanity checks
if (fProject == null) {
return;
} else if (model == null) {
return;
} else if (monitor == null) {
return;
}
// Get the action
UpdateSplashProgressOperation operation = getUpdateSplashProgressOperation();
operation.setModel(model);
operation.setShowProgress(isProgressDefined());
operation.setProject(fProject);
operation.setProductID(fProduct.getProductId());
operation.setPluginID(fPluginId);
// Execute the action
operation.run(monitor);
}
private boolean isProgressDefined() {
// Get the splash info from the model
ISplashInfo info = fProduct.getProduct().getSplashInfo();
// Ensure splash info was defined
if (info == null) {
return false;
}
// Ensure splash progress was defined
return info.isDefinedGeometry();
}
private String getSplashHandlerType() {
// Get the splash info from the model
ISplashInfo info = fProduct.getProduct().getSplashInfo();
// Ensure splash info was defined
if (info == null) {
return null;
}
// Ensure splash type was defined
if (info.isDefinedSplashHandlerType() == false) {
return null;
}
return info.getFieldSplashHandlerType();
}
private void updateSplashHandler(IPluginModelBase model, IProgressMonitor monitor) throws CoreException {
// Copy the applicable splash handler artifacts and perform parameter
// substitution (like in templates plug-in)
// Artifacts may include code, images and extension point schemas
updateSplashHandlerFiles(model, monitor);
// Update the plug-in model with the applicable splash handler extension
// and extension point related mark-up
updateSplashHandlerModel(model, monitor);
}
private void updateSplashHandlerFiles(IPluginModelBase model, IProgressMonitor monitor) throws CoreException {
// If the project is not defined, abort this operation
if (fProject == null) {
return;
}
// Get the splash handler type
String splashHandlerType = getSplashHandlerType();
// If the splash handler type was not defined, abort this operation
if (splashHandlerType == null) {
return;
}
// Create and configure the template file generator
// Note: Plug-in ID must be passed in separately from model, because
// the underlying model does not contain the ID (even when it is
// a workspace model)
TemplateFileGenerator generator = new TemplateFileGenerator(fProject, model, fPluginId, createTargetPackage(), createTargetClass(), splashHandlerType);
// Generate the necessary files
generator.generateFiles(monitor);
}
private void updateSplashHandlerModel(IPluginModelBase model, IProgressMonitor monitor) throws CoreException {
// Get the splash handler type
String splashHandlerType = getSplashHandlerType();
// If the splash handler type is not defined, abort this operation
if (splashHandlerType == null) {
runRemoveSplashAction(model, monitor);
} else {
runUpdateSplashAction(model, monitor, splashHandlerType);
}
}
private void runRemoveSplashAction(IPluginModelBase model, IProgressMonitor monitor) throws CoreException {
// Create the remove splash handler action
fRemoveSplashAction = new RemoveSplashHandlerBindingAction();
// Configure the action
fRemoveSplashAction.setFieldProductID(fProduct.getProductId());
fRemoveSplashAction.setFieldTargetPackage(createTargetPackage());
fRemoveSplashAction.setModel(model);
fRemoveSplashAction.setMonitor(monitor);
// Execute the action
fRemoveSplashAction.run();
// If an core exception was thrown and caught, release it
fRemoveSplashAction.hasException();
}
private void runUpdateSplashAction(IPluginModelBase model, IProgressMonitor monitor, String splashHandlerType) throws CoreException {
// Create the update splash handler action
fUpdateSplashAction = new UpdateSplashHandlerAction();
// Configure the action
String id = createAttributeValueID();
fUpdateSplashAction.setFieldID(id);
fUpdateSplashAction.setFieldClass(createAttributeValueClass());
fUpdateSplashAction.setFieldSplashID(id);
fUpdateSplashAction.setFieldProductID(fProduct.getProductId());
fUpdateSplashAction.setFieldTemplate(splashHandlerType);
fUpdateSplashAction.setFieldPluginID(fPluginId);
fUpdateSplashAction.setModel(model);
fUpdateSplashAction.setMonitor(monitor);
// Execute the action
fUpdateSplashAction.run();
// If an core exception was thrown and caught, release it
fUpdateSplashAction.hasException();
}
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
IFile file = getFile();
if (!file.exists()) {
createNewFile(file, monitor);
} else {
modifyExistingFile(file, monitor);
}
updateSingleton(monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
}
private void createNewFile(IFile file, IProgressMonitor monitor) throws CoreException {
WorkspacePluginModelBase model = (WorkspacePluginModelBase) getModel(file);
IPluginBase base = model.getPluginBase();
base.setSchemaVersion(TargetPlatformHelper.getSchemaVersion());
base.add(createExtension(model));
// Update the splash handler. Update plug-in model and copy files
updateSplashHandler(model, monitor);
// Update splash progress. Update plug-in model and copy files
updateSplashProgress(model, monitor);
model.save();
}
private IPluginExtension createExtension(IPluginModelBase model) throws CoreException {
IPluginExtension extension = model.getFactory().createExtension();
extension.setPoint("org.eclipse.core.runtime.products"); //$NON-NLS-1$
extension.setId(fProductId);
extension.add(createExtensionContent(extension));
return extension;
}
private IPluginElement createExtensionContent(IPluginExtension extension) throws CoreException {
IPluginElement element = extension.getModel().getFactory().createElement(extension);
element.setName("product"); //$NON-NLS-1$
element.setAttribute("name", fProduct.getName()); //$NON-NLS-1$
element.setAttribute("application", fApplication); //$NON-NLS-1$
IPluginElement child = createElement(element, IProductConstants.WINDOW_IMAGES, getWindowImagesString());
if (child != null)
element.add(child);
child = createElement(element, IProductConstants.ABOUT_TEXT, getAboutText());
if (child != null)
element.add(child);
child = createElement(element, IProductConstants.ABOUT_IMAGE, getAboutImage());
if (child != null)
element.add(child);
child = createElement(element, IProductConstants.STARTUP_FOREGROUND_COLOR, getForegroundColor());
if (child != null)
element.add(child);
child = createElement(element, IProductConstants.STARTUP_PROGRESS_RECT, getProgressRect());
if (child != null)
element.add(child);
child = createElement(element, IProductConstants.STARTUP_MESSAGE_RECT, getMessageRect());
if (child != null)
element.add(child);
child = createElement(element, IProductConstants.PREFERENCE_CUSTOMIZATION, getPreferenceCustomization());
if (child != null)
element.add(child);
return element;
}
private IPluginElement createElement(IPluginElement parent, String name, String value) throws CoreException {
IPluginElement element = null;
if (value != null && value.length() > 0) {
element = parent.getModel().getFactory().createElement(parent);
element.setName("property"); //$NON-NLS-1$
element.setAttribute("name", name); //$NON-NLS-1$
element.setAttribute("value", value); //$NON-NLS-1$
}
return element;
}
private String getAboutText() {
IAboutInfo info = fProduct.getAboutInfo();
if (info != null) {
String text = info.getText();
return text == null || text.length() == 0 ? null : text;
}
return null;
}
private String getAboutImage() {
IAboutInfo info = fProduct.getAboutInfo();
return info != null ? getURL(info.getImagePath()) : null;
}
private String getURL(String location) {
if (location == null || location.trim().length() == 0)
return null;
IPath path = new Path(location);
if (!path.isAbsolute())
return location;
String projectName = path.segment(0);
IProject project = PDEPlugin.getWorkspace().getRoot().getProject(projectName);
if (project.exists()) {
IPluginModelBase model = PluginRegistry.findModel(project);
if (model != null) {
String id = model.getPluginBase().getId();
if (fPluginId.equals(id))
return path.removeFirstSegments(1).toString();
return "platform:/plugin/" + id + "/" + path.removeFirstSegments(1); //$NON-NLS-1$ //$NON-NLS-2$
}
}
return location;
}
private String getFullyQualifiedURL(String location) {
if (location == null || location.trim().length() == 0)
return null;
IPath path = new Path(location);
if (!path.isAbsolute())
return location;
String projectName = path.segment(0);
IProject project = PDEPlugin.getWorkspace().getRoot().getProject(projectName);
if (project.exists()) {
IPluginModelBase model = PluginRegistry.findModel(project);
if (model != null) {
String id = model.getPluginBase().getId();
return "platform:/plugin/" + id + "/" + path.removeFirstSegments(1); //$NON-NLS-1$ //$NON-NLS-2$
}
}
return location;
}
private String getWindowImagesString() {
IWindowImages images = fProduct.getWindowImages();
StringBuffer buffer = new StringBuffer();
if (images != null) {
for (int i = 0; i < IWindowImages.TOTAL_IMAGES; i++) {
String image = getURL(images.getImagePath(i));
if (image != null) {
if (buffer.length() > 0)
buffer.append(","); //$NON-NLS-1$
buffer.append(image);
}
}
}
return buffer.length() == 0 ? null : buffer.toString();
}
private String getForegroundColor() {
ISplashInfo info = fProduct.getSplashInfo();
return info != null ? info.getForegroundColor() : null;
}
private String getProgressRect() {
ISplashInfo info = fProduct.getSplashInfo();
return info != null ? SplashInfo.getGeometryString(info.getProgressGeometry()) : null;
}
private String getMessageRect() {
ISplashInfo info = fProduct.getSplashInfo();
return info != null ? SplashInfo.getGeometryString(info.getMessageGeometry()) : null;
}
private String getPreferenceCustomization() {
IPreferencesInfo info = fProduct.getPreferencesInfo();
if (info != null) {
String text = info.getPreferenceCustomizationPath();
return text == null || text.length() == 0 ? null : getFullyQualifiedURL(text);
}
return null;
}
private void modifyExistingFile(IFile file, IProgressMonitor monitor) throws CoreException {
IStatus status = PDEPlugin.getWorkspace().validateEdit(new IFile[] {file}, getShell());
if (status.getSeverity() != IStatus.OK)
throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.pde.ui", IStatus.ERROR, NLS.bind(PDEUIMessages.ProductDefinitionOperation_readOnly, fPluginId), null)); //$NON-NLS-1$
ModelModification mod = new ModelModification(file) {
protected void modifyModel(IBaseModel model, IProgressMonitor monitor) throws CoreException {
if (!(model instanceof IPluginModelBase))
return;
IPluginExtension extension = findProductExtension((IPluginModelBase) model);
if (extension == null)
insertNewExtension((IPluginModelBase) model);
else
modifyExistingExtension(extension);
// Update the splash handler. Update plug-in model and copy files
updateSplashHandler((IPluginModelBase) model, monitor);
// Update splash progress. Update plug-in model and copy files
updateSplashProgress((IPluginModelBase) model, monitor);
}
};
PDEModelUtility.modifyModel(mod, monitor);
}
private IPluginExtension findProductExtension(IPluginModelBase model) {
IPluginExtension[] extensions = model.getPluginBase().getExtensions();
for (int i = 0; i < extensions.length; i++) {
String point = extensions[i].getPoint();
String id = extensions[i].getId();
if (fProductId.equals(id) && "org.eclipse.core.runtime.products".equals(point)) { //$NON-NLS-1$
return extensions[i];
}
}
return null;
}
private void insertNewExtension(IPluginModelBase model) throws CoreException {
IPluginExtension extension = createExtension(model);
model.getPluginBase().add(extension);
}
private void modifyExistingExtension(IPluginExtension extension) throws CoreException {
if (extension.getChildCount() == 0) {
insertNewProductElement(extension);
return;
}
PluginElementNode element = (PluginElementNode) extension.getChildren()[0];
if (!"product".equals(element.getName())) { //$NON-NLS-1$
insertNewProductElement(extension);
return;
}
element.setAttribute("application", fApplication); //$NON-NLS-1$
element.setAttribute("name", fProduct.getName()); //$NON-NLS-1$
synchronizeChild(element, IProductConstants.APP_NAME, fProduct.getName());
synchronizeChild(element, IProductConstants.ABOUT_IMAGE, getAboutImage());
synchronizeChild(element, IProductConstants.ABOUT_TEXT, getAboutText());
synchronizeChild(element, IProductConstants.WINDOW_IMAGES, getWindowImagesString());
synchronizeChild(element, IProductConstants.STARTUP_FOREGROUND_COLOR, getForegroundColor());
synchronizeChild(element, IProductConstants.STARTUP_MESSAGE_RECT, getMessageRect());
synchronizeChild(element, IProductConstants.STARTUP_PROGRESS_RECT, getProgressRect());
synchronizeChild(element, IProductConstants.PREFERENCE_CUSTOMIZATION, getPreferenceCustomization());
}
private void synchronizeChild(IPluginElement element, String propertyName, String value) throws CoreException {
IPluginElement child = null;
IPluginObject[] children = element.getChildren();
for (int i = 0; i < children.length; i++) {
IPluginElement candidate = (IPluginElement) children[i];
if (candidate.getName().equals("property")) { //$NON-NLS-1$
IPluginAttribute attr = candidate.getAttribute("name"); //$NON-NLS-1$
if (attr != null && attr.getValue().equals(propertyName)) {
child = candidate;
break;
}
}
}
if (child != null && value == null)
element.remove(child);
if (value == null)
return;
if (child == null) {
child = element.getModel().getFactory().createElement(element);
child.setName("property"); //$NON-NLS-1$
element.add(child);
}
child.setAttribute("value", value); //$NON-NLS-1$
child.setAttribute("name", propertyName); //$NON-NLS-1$
}
private void insertNewProductElement(IPluginExtension extension) throws CoreException {
IPluginElement element = createExtensionContent(extension);
extension.add(element);
}
}