/*******************************************************************************
* Copyright (c) 2009 SpringSource, a divison of VMware, Inc.
* 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:
* SpringSource, a division of VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.virgo.ide.ui.editors;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.zip.ZipFile;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.pde.core.IBaseModel;
import org.eclipse.pde.core.IWritable;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.internal.core.ICoreConstants;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.pde.internal.core.ibundle.IBundleModel;
import org.eclipse.pde.internal.core.plugin.IWritableDelimiter;
import org.eclipse.pde.internal.ui.IPreferenceConstants;
import org.eclipse.pde.internal.ui.PDEPlugin;
import org.eclipse.pde.internal.ui.editor.ISortableContentOutlinePage;
import org.eclipse.pde.internal.ui.editor.JarEntryEditorInput;
import org.eclipse.pde.internal.ui.editor.JarEntryFile;
import org.eclipse.pde.internal.ui.editor.ModelDataTransfer;
import org.eclipse.pde.internal.ui.editor.PDEFormEditor;
import org.eclipse.pde.internal.ui.editor.PDESourcePage;
import org.eclipse.pde.internal.ui.editor.context.InputContextManager;
import org.eclipse.pde.internal.ui.editor.plugin.BundleInputContext;
import org.eclipse.pde.internal.ui.editor.plugin.ManifestEditor;
import org.eclipse.pde.internal.ui.editor.plugin.PluginInputContext;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IURIEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.virgo.ide.eclipse.editors.AbstractPdeFormPage;
import org.eclipse.virgo.ide.facet.core.FacetUtils;
import org.eclipse.virgo.ide.manifest.core.IHeaderConstants;
import org.eclipse.virgo.ide.runtime.core.provisioning.RepositoryUtils;
import org.eclipse.virgo.ide.ui.ServerIdeUiPlugin;
import org.eclipse.virgo.ide.ui.StatusHandler;
import org.eclipse.virgo.kernel.repository.BundleDefinition;
import org.osgi.service.prefs.BackingStoreException;
/**
* @author Christian Dupuis
* @author Leo Dos Santos
* @author Steffen Pingel
*/
public class BundleManifestEditor extends ManifestEditor {
public static String ID_EDITOR = "org.eclipse.virgo.ide.ui.bundlemanifest";
protected boolean fEquinox = true;
protected boolean fShowExtensions = true;
protected IEclipsePreferences fPrefs;
protected List<IBundleManifestSaveListener> saveListeners = new ArrayList<IBundleManifestSaveListener>(3);
/**
* Returns the list of pages for this editor. Public for testing.
*/
public IEditorPart[] getParts() {
ArrayList<IEditorPart> parts = new ArrayList<IEditorPart>(getPageCount());
if (pages != null) {
for (int i = 0; i < pages.size(); i++) {
Object page = pages.get(i);
if (page instanceof IEditorPart) {
parts.add((IEditorPart) page);
}
}
}
return parts.toArray(new IEditorPart[parts.size()]);
}
@Override
protected void addEditorPages() {
try {
BundleOverviewPage overviewPage = new BundleOverviewPage(this);
addPage(overviewPage);
saveListeners.add(overviewPage);
BundleDependenciesPage dependenciesPage = new BundleDependenciesPage(this);
addPage(dependenciesPage);
saveListeners.add(dependenciesPage);
BundleRuntimePage runtimePage = new BundleRuntimePage(this);
addPage(runtimePage);
saveListeners.add(runtimePage);
}
catch (PartInitException e) {
StatusHandler
.log(new Status(IStatus.ERROR, ServerIdeUiPlugin.PLUGIN_ID, "Failed to create editor pages", e));
}
addSourcePage(BundleInputContext.CONTEXT_ID);
}
@Override
protected PDESourcePage createSourcePage(PDEFormEditor editor, String title, String name, String contextId) {
if (contextId.equals(BundleInputContext.CONTEXT_ID)) {
return new SpringBundleSourcePage(editor, title, name);
}
return super.createSourcePage(editor, title, name, contextId);
}
@Override
protected void createResourceContexts(InputContextManager manager, IFileEditorInput input) {
IFile file = input.getFile();
IContainer container = file.getParent();
IFile manifestFile = null;
String name = file.getName().toLowerCase(Locale.ENGLISH);
if (name.endsWith("mf")) { //$NON-NLS-1$
if (container instanceof IFolder) {
container = container.getParent();
}
manifestFile = file;
}
if (manifestFile != null && manifestFile.exists()) {
IEditorInput in = new FileEditorInput(manifestFile);
manager.putContext(in, new SpringBundleInputContext(this, in, file == manifestFile));
}
manager.monitorFile(manifestFile);
fPrefs = new ProjectScope(container.getProject()).getNode(PDECore.PLUGIN_ID);
if (fPrefs != null) {
fShowExtensions = fPrefs.getBoolean(ICoreConstants.EXTENSIONS_PROPERTY, true);
fEquinox = fPrefs.getBoolean(ICoreConstants.EQUINOX_PROPERTY, true);
}
}
@Override
public void doSave(IProgressMonitor monitor) {
super.doSave(monitor);
for (IBundleManifestSaveListener currListener : this.saveListeners) {
currListener.manifestSaved();
}
}
@Override
public boolean isEquinox() {
return fEquinox;
}
@Override
public void monitoredFileAdded(IFile file) {
if (fInputContextManager == null) {
return;
}
String name = file.getName();
if (name.equalsIgnoreCase("MANIFEST.MF")) { //$NON-NLS-1$
if (!fInputContextManager.hasContext(BundleInputContext.CONTEXT_ID)) {
IEditorInput in = new FileEditorInput(file);
fInputContextManager.putContext(in, new SpringBundleInputContext(this, in, false));
}
}
}
/**
* Copy of super method with work-around to maintain compatibility with
* Eclipse 3.4 and 3.5.
*
* @see #createSystemFileContexts(InputContextManager, IEditorInput)
*/
protected void createInputContexts(InputContextManager contextManager) {
IEditorInput input = getEditorInput();
if (input instanceof IFileEditorInput) {
// resource - find the project
createResourceContexts(contextManager, (IFileEditorInput) input);
}
else if (PdeCompatibilityUtil.isSystemFileEditorInput(input)) {
// system file - find the file system folder
createSystemFileContexts(contextManager, input);
}
else if (input instanceof IStorageEditorInput) {
createStorageContexts(contextManager, (IStorageEditorInput) input);
}
else if (input instanceof IURIEditorInput) {
IURIEditorInput uriEditorInput = (IURIEditorInput) input;
try {
IFileStore store = EFS.getStore(uriEditorInput.getURI());
if (!EFS.SCHEME_FILE.equals(store.getFileSystem().getScheme())) {
return;
}
IEditorInput sinput = PdeCompatibilityUtil.createSystemFileEditorInput(uriEditorInput);
if (sinput == null) {
// Eclipse 3.5 or later
sinput = new FileStoreEditorInput(store);
}
createSystemFileContexts(contextManager, sinput);
}
catch (CoreException e) {
return;
}
}
}
/**
* The signature of createSystemFileContexts() has changed between Eclipse
* 3.4 and 3.5. This method serves as a work-around with a more generic
* signature.
*
* @param input either a SystemFileEditorInput or FileStoreEditorInput
*/
protected void createSystemFileContexts(InputContextManager manager, IEditorInput input) {
File file = (File) input.getAdapter(File.class);
if (file == null && input instanceof FileStoreEditorInput) {
file = new File(((IURIEditorInput) input).getURI());
}
if (file == null) {
return;
}
File manifestFile = null;
String name = file.getName().toLowerCase(Locale.ENGLISH);
if (name.equals("manifest.mf")) { //$NON-NLS-1$
manifestFile = file;
}
try {
if (manifestFile != null && manifestFile.exists()) {
IEditorInput in = PdeCompatibilityUtil.createSystemFileEditorInput(manifestFile);
if (in == null) {
// Eclipse 3.5 or later
IFileStore store = EFS.getStore(manifestFile.toURI());
in = new FileStoreEditorInput(store);
}
manager.putContext(in, new SpringBundleInputContext(this, in, file == manifestFile));
}
}
catch (CoreException e) {
PDEPlugin.logException(e);
}
}
@Override
protected void createStorageContexts(InputContextManager manager, IStorageEditorInput input) {
if (input instanceof JarEntryEditorInput) {
createJarEntryContexts(manager, (JarEntryEditorInput) input);
return;
}
String name = input.getName().toLowerCase(Locale.ENGLISH);
if (name.startsWith("manifest.mf")) { //$NON-NLS-1$
manager.putContext(input, new SpringBundleInputContext(this, input, true));
}
}
@Override
protected void createJarEntryContexts(InputContextManager manager, JarEntryEditorInput input) {
IStorage storage = input.getStorage();
ZipFile zip = (ZipFile) storage.getAdapter(ZipFile.class);
try {
if (zip == null) {
return;
}
if (zip.getEntry("META-INF/MANIFEST.MF") != null) { //$NON-NLS-1$
input = new JarEntryEditorInput(new JarEntryFile(zip, "META-INF/MANIFEST.MF")); //$NON-NLS-1$
manager.putContext(input,
new SpringBundleInputContext(this, input, storage.getName().equals("MANIFEST.MF"))); //$NON-NLS-1$
}
}
finally {
try {
if (zip != null) {
zip.close();
}
}
catch (IOException e) {
}
}
}
@Override
protected void setShowExtensions(boolean show) throws BackingStoreException {
if (fPrefs != null) {
fPrefs.putBoolean(ICoreConstants.EXTENSIONS_PROPERTY, show);
fPrefs.flush();
}
fShowExtensions = show;
}
@Override
public boolean showExtensionTabs() {
if (fInputContextManager.hasContext(PluginInputContext.CONTEXT_ID)) {
return true;
}
IBaseModel model = getAggregateModel();
return fShowExtensions && model != null && model.isEditable();
}
@Override
public String getTitle() {
IPluginModelBase model = (IPluginModelBase) getAggregateModel();
if (model == null || !model.isValid()) {
return super.getTitle();
}
String text = getTitleText(model);
if (text == null) {
return super.getTitle();
}
return model.getResourceString(text);
}
private String getTitleText(IPluginModelBase model) {
IPreferenceStore store = PDEPlugin.getDefault().getPreferenceStore();
String pref = store.getString(IPreferenceConstants.PROP_SHOW_OBJECTS);
StringBuilder builder = new StringBuilder();
if (model.getUnderlyingResource() != null) {
if (model.getUnderlyingResource().getName().equals("TEST.MF")) {
builder.append("test: ");
}
else if (model.getUnderlyingResource().getName().equals("template.mf")) {
builder.append("template: ");
}
}
if (FacetUtils.isParProject(getCommonProject())) {
BundleInputContext context = (BundleInputContext) getContextManager().findContext(
BundleInputContext.CONTEXT_ID);
if (context != null) {
IBundleModel bundleModel = (IBundleModel) context.getModel();
if (pref != null && pref.equals(IPreferenceConstants.VALUE_USE_NAMES)) {
builder.append(bundleModel.getBundle().getHeader(IHeaderConstants.PAR_NAME));
}
builder.append(bundleModel.getBundle().getHeader(IHeaderConstants.PAR_SYMBOLICNAME));
}
}
if (pref != null && pref.equals(IPreferenceConstants.VALUE_USE_NAMES)
&& model.getPluginBase().getName() != null) {
builder.append(model.getPluginBase().getName());
}
if (model.getPluginBase().getId() != null) {
builder.append(model.getPluginBase().getId());
}
return builder.toString();
}
@Override
protected ISortableContentOutlinePage createContentOutline() {
return new BundleManifestOutlinePage(this);
}
public static IEditorPart openBundleEditor(String bundle, String version, IProject project) {
return openPluginEditor(RepositoryUtils.getBundleDefinition(bundle, version, project));
}
public static IEditorPart openPluginEditor(BundleDefinition bundleDefinition) {
if (bundleDefinition == null) {
Display.getDefault().beep();
return null;
}
return openPluginEditor(bundleDefinition, false);
}
public static IEditorPart openPluginEditor(Object object, boolean source) {
if (object instanceof BundleDefinition) {
URI file = ((BundleDefinition) object).getLocation();
return openExternalPlugin(new File(file), "META-INF/MANIFEST.MF");
}
return null;
}
// private static IEditorPart openWorkspacePlugin(IFile pluginFile) {
// return openEditor(new FileEditorInput(pluginFile));
// }
public static IEditorPart openExternalPlugin(File location, String filename) {
IEditorInput input = null;
if (location.isFile()) {
try {
ZipFile zipFile = new ZipFile(location);
if (zipFile.getEntry(filename) != null) {
input = new JarEntryEditorInput(new JarEntryFile(zipFile, filename));
}
}
catch (IOException e) {
}
}
else {
File file = new File(location, filename);
if (file.exists()) {
IFileStore store;
try {
store = EFS.getStore(file.toURI());
input = new FileStoreEditorInput(store);
}
catch (CoreException e) {
}
}
}
return openEditor(input);
}
public static IEditorPart openEditor(IEditorInput input) {
if (input != null) {
try {
return PDEPlugin.getActivePage().openEditor(input, BundleManifestEditor.ID_EDITOR);
}
catch (PartInitException e) {
PDEPlugin.logException(e);
}
}
return null;
}
public void contributeToToolbar(IToolBarManager manager) {
// ignore
}
@Override
protected void performGlobalAction(String id) {
ISelection selection = getSelection();
IFormPage page = getActivePageInstance();
if (page instanceof AbstractPdeFormPage) {
boolean handled = ((AbstractPdeFormPage) page).performGlobalAction(id);
if (!handled) {
if (id.equals(ActionFactory.UNDO.getId())) {
fInputContextManager.undo();
return;
}
if (id.equals(ActionFactory.REDO.getId())) {
fInputContextManager.redo();
return;
}
if (id.equals(ActionFactory.CUT.getId()) || id.equals(ActionFactory.COPY.getId())) {
copyToClipboard(selection);
return;
}
}
}
else {
super.performGlobalAction(id);
}
}
private void copyToClipboard(ISelection selection) {
Object[] objects = null;
String textVersion = null;
if (selection instanceof IStructuredSelection) {
IStructuredSelection ssel = (IStructuredSelection) selection;
if (ssel == null || ssel.size() == 0) {
return;
}
objects = ssel.toArray();
StringWriter writer = new StringWriter();
PrintWriter pwriter = new PrintWriter(writer);
Class<?> objClass = null;
for (int i = 0; i < objects.length; i++) {
Object obj = objects[i];
if (objClass == null) {
objClass = obj.getClass();
}
else if (objClass.equals(obj.getClass()) == false) {
return;
}
if (obj instanceof IWritable) {
// Add a customized delimiter in between all serialized
// objects to format the text representation
if ((i != 0) && (obj instanceof IWritableDelimiter)) {
((IWritableDelimiter) obj).writeDelimeter(pwriter);
}
((IWritable) obj).write("", pwriter); //$NON-NLS-1$
}
else if (obj instanceof String) {
// Delimiter is always a newline
pwriter.println((String) obj);
}
}
pwriter.flush();
textVersion = writer.toString();
try {
pwriter.close();
writer.close();
}
catch (IOException e) {
}
}
else if (selection instanceof ITextSelection) {
textVersion = ((ITextSelection) selection).getText();
}
if ((textVersion == null || textVersion.length() == 0) && objects == null) {
return;
}
// set the clipboard contents
Object[] o = null;
Transfer[] t = null;
if (objects == null) {
o = new Object[] { textVersion };
t = new Transfer[] { TextTransfer.getInstance() };
}
else if (textVersion == null || textVersion.length() == 0) {
o = new Object[] { objects };
t = new Transfer[] { ModelDataTransfer.getInstance() };
}
else {
o = new Object[] { objects, textVersion };
t = new Transfer[] { ModelDataTransfer.getInstance(), TextTransfer.getInstance() };
}
getClipboard().setContents(o, t);
}
}