/*******************************************************************************
* Copyright (c) 2010, 2011 Obeo.
* 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:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.docs.intent.bridge.ide.ui;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.eclipse.emf.validation.marker.MarkerUtil;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.mylyn.docs.intent.client.ui.editor.renderers.IEditorRendererExtension;
import org.eclipse.mylyn.docs.intent.client.ui.logger.IntentUiLogger;
import org.eclipse.mylyn.docs.intent.core.modelingunit.ExternalContentReference;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.ResourceTransfer;
/**
* An default {@link IEditorRendererExtension} providing extension do drop {@link IFile}s in the IntentEditor,
* open editors with FileEditorInputs...
*
* @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a>
*/
public class DefaultIDEEditorRendererExtension implements IEditorRendererExtension {
/**
* Constant used to determine the height of the image margin.
*/
private static final int IMAGE_HEIGHT_MARGIN = 5;
/**
* Constant usde to determine the image width.
*/
private static final int IMAGE_WIDTH = 800;
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.client.ui.editor.renderers.IEditorRendererExtension#isRendererFor(org.eclipse.mylyn.docs.intent.core.modelingunit.ExternalContentReference)
*/
public boolean isRendererFor(ExternalContentReference externalContentReference) {
// Can be applied on any external content reference (with low priority)
return true;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.client.ui.editor.renderers.IEditorRendererExtension#openEditor(org.eclipse.mylyn.docs.intent.core.modelingunit.ExternalContentReference)
*/
public boolean openEditor(ExternalContentReference externalContentReference) {
URI resourceToOpenURI = URI.createURI(externalContentReference.getUri().toString().trim());
if ("intent".equals(resourceToOpenURI.scheme())
&& externalContentReference.getExternalContent() != null) {
resourceToOpenURI = EcoreUtil.getURI(externalContentReference.getExternalContent())
.trimFragment();
}
if (resourceToOpenURI.isPlatformResource()) {
String filePath = resourceToOpenURI.trimFragment().toPlatformString(true);
// Step 1: Open editor with a file editor input
IFile resourceFile = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(filePath));
FileEditorInput editorInput = new FileEditorInput(resourceFile);
if ("repomodel".equals(resourceToOpenURI.fileExtension())) {
resourceToOpenURI = resourceToOpenURI.trimFileExtension();
}
IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry()
.getDefaultEditor(resourceToOpenURI.trimFragment().lastSegment());
IEditorPart openedEditor = null;
if (desc != null) {
try {
openedEditor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.openEditor(editorInput, desc.getId());
} catch (PartInitException e) {
IntentUiLogger.logError(e);
}
}
// Step 2: Update selection using a shadow marker
if (openedEditor instanceof IGotoMarker && resourceToOpenURI.hasFragment()) {
IMarker shadowMarker = null;
try {
// We create a shadow marker that will be deleted
shadowMarker = resourceFile.createMarker(MarkerUtil.VALIDATION_MARKER_TYPE);
shadowMarker.setAttribute(EValidator.URI_ATTRIBUTE, resourceToOpenURI.toString());
// Update selection using the gotoMarker method
((IGotoMarker)openedEditor).gotoMarker(shadowMarker);
} catch (CoreException e) {
// Silent catch
e.printStackTrace();
} finally {
if (shadowMarker != null) {
try {
shadowMarker.delete();
} catch (CoreException e) {
// Silent catch
}
}
}
}
return true;
}
return false;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.client.ui.editor.renderers.IEditorRendererExtension#getAdditionalTransfers()
*/
public Collection<Transfer> getAdditionalTransfers() {
// Adding the Resource transfer to be able to directly drop IFiles inside the Intent editor
Collection<Transfer> transfers = new ArrayList<Transfer>();
transfers.add(ResourceTransfer.getInstance());
transfers.add(LocalSelectionTransfer.getTransfer());
return transfers;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.client.ui.editor.renderers.IEditorRendererExtension#getEObjectsFromDropTargetEvent(org.eclipse.swt.dnd.DropTargetEvent)
*/
public Collection<? extends EObject> getEObjectsFromDropTargetEvent(DropTargetEvent event) {
Collection<EObject> eObjects = new LinkedHashSet<EObject>();
try {
Collection<Resource> emfResources = new LinkedHashSet<Resource>();
// If directly dropping an IFile
if (event.data instanceof IResource[]) {
IResource[] droppedResources = (IResource[])event.data;
for (int i = 0; i < droppedResources.length; i++) {
emfResources.add(getEMFResourceFromIResource(droppedResources[i]));
}
} else if (event.data instanceof IStructuredSelection) {
// If dropping a selection of IFiles
Iterator iterator = ((IStructuredSelection)event.data).iterator();
while (iterator.hasNext()) {
Object element = iterator.next();
if (element instanceof IResource) {
emfResources.add(getEMFResourceFromIResource((IResource)element));
}
}
}
for (Resource emfResource : emfResources) {
if (emfResource != null && emfResource.getContents().iterator().hasNext()) {
eObjects.add(emfResource.getContents().iterator().next());
}
}
} catch (IllegalArgumentException e) {
// Nothing to do, the drop event was not valid for this extension
}
return eObjects;
}
/**
* Returns an emfResource corresponding to the given {@link IResource} (if any).
*
* @param iResource
* the {@link IResource} to analyse
* @return an emfResource corresponding to the given {@link IResource}, or null if none find
*/
private Resource getEMFResourceFromIResource(IResource iResource) {
// Try to get the EMF ressource corresponding to this file
URI resourceURI = URI.createPlatformResourceURI(iResource.getFullPath().toString(), true);
try {
return new ResourceSetImpl().getResource(resourceURI, true);
// CHECKSTYLE:OFF
} catch (Exception e) {
// CHECKSTYLE:ON
IntentUiLogger.logError("Could not perform drop of the resource at URI " + resourceURI
+ " because a bridge to represent such files as models is missing", e);
}
return null;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.mylyn.docs.intent.client.ui.editor.renderers.IEditorRendererExtension#getImage(org.eclipse.mylyn.docs.intent.core.modelingunit.ExternalContentReference)
*/
public Image getImage(ExternalContentReference externalContentReference) {
Image image = null;
if (externalContentReference.getExternalContent() != null) {
// Determine string to render
IItemLabelProvider labeProvider = (IItemLabelProvider)new ComposedAdapterFactory(
ComposedAdapterFactory.Descriptor.Registry.INSTANCE).adapt(
externalContentReference.getExternalContent(), IItemLabelProvider.class);
if (labeProvider != null) {
String label = labeProvider.getText(externalContentReference.getExternalContent());
Display display = Display.getDefault();
int fontHeight = new GC(new Image(display, 1, 1)).getFontMetrics().getHeight();
int imageHeight = fontHeight + IMAGE_HEIGHT_MARGIN;
image = new Image(display, IMAGE_WIDTH, imageHeight);
GC gc = new GC(image);
// Render icon
int iconWidth = 5;
gc.setForeground(display.getSystemColor(SWT.COLOR_DARK_GRAY));
Object iconURL = labeProvider.getImage(externalContentReference.getExternalContent());
Image icon = ExtendedImageRegistry.getInstance().getImage(iconURL);
if (icon != null) {
gc.drawImage(icon, 0, 5);
iconWidth += icon.getImageData().width + 2;
}
// Render text
gc.drawText(label, iconWidth, 5);
gc.dispose();
}
}
return image;
}
}