blob: 51d5290a49cb9674995bd76905f05e2d931d0b3d [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2006, 2009 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
****************************************************************************/
package org.eclipse.gmf.runtime.diagram.ui.render.actions;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.Request;
import org.eclipse.gef.editparts.LayerManager;
import org.eclipse.gmf.runtime.common.core.util.Log;
import org.eclipse.gmf.runtime.common.core.util.Trace;
import org.eclipse.gmf.runtime.diagram.ui.actions.DiagramAction;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart;
import org.eclipse.gmf.runtime.diagram.ui.internal.editparts.ISurfaceEditPart;
import org.eclipse.gmf.runtime.diagram.ui.render.internal.DiagramUIRenderDebugOptions;
import org.eclipse.gmf.runtime.diagram.ui.render.internal.DiagramUIRenderPlugin;
import org.eclipse.gmf.runtime.diagram.ui.render.internal.DiagramUIRenderStatusCodes;
import org.eclipse.gmf.runtime.diagram.ui.render.internal.dialogs.CopyToImageDialog;
import org.eclipse.gmf.runtime.diagram.ui.render.internal.l10n.DiagramUIRenderMessages;
import org.eclipse.gmf.runtime.diagram.ui.render.util.CopyToHTMLImageUtil;
import org.eclipse.gmf.runtime.diagram.ui.render.util.CopyToImageUtil;
import org.eclipse.gmf.runtime.diagram.ui.render.util.DiagramImageUtils;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
/**
* Action to copy the selected shapes in the diagram or the entire diagram to an
* image file.
*
* @author Anthony Hunter, cmahoney
*/
public class CopyToImageAction
extends DiagramAction {
/**
* the copy diagram to image file dialog used by the action.
*/
private CopyToImageDialog dialog = null;
/**
* Constructor for CopyToImageAction.
*
* @param page
* the page of the workbench for the action
*/
public CopyToImageAction(IWorkbenchPage page) {
super(page);
}
/**
* Initialize with the correct text label, action id, and images.
*/
public void init() {
super.init();
/* set the label for the action */
setText(DiagramUIRenderMessages.CopyToImageAction_Label);
/* set the id */
setId(ActionIds.ACTION_COPY_TO_IMAGE);
/* set the image */
ISharedImages sharedImages = PlatformUI.getWorkbench()
.getSharedImages();
setImageDescriptor(sharedImages
.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
setHoverImageDescriptor(sharedImages
.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
setDisabledImageDescriptor(sharedImages
.getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED));
}
public void run() {
IPath path = null;
String fileName = null;
if (getWorkbenchPart() instanceof IEditorPart) {
IEditorPart editor = (IEditorPart) getWorkbenchPart();
// The editor's input may provide us with an IContainer where
// we should store items related to it.
IContainer container = (IContainer) editor.getEditorInput()
.getAdapter(IContainer.class);
// If there is a container in the workspace and it exists then
// we will use its path to store the image.
if (container != null && container.exists()) {
// The path has to be an absolute filesystem path for this
// use case rather than just the path relative to the workspace
// root.
path = container.getLocation();
}
// Otherwise, we will try to adapt the input to the IFile that
// represents the place where the editor's input file resides.
// We can extrapolate a destination path from this file.
if (path == null) {
IFile file = (IFile) editor.getEditorInput().getAdapter(
IFile.class);
// We can't necessarily assume that the editor input is a file.
if (file != null) {
path = file.getLocation().removeLastSegments(1);
fileName = file.getLocation().removeFileExtension()
.lastSegment();
}
}
}
dialog = new CopyToImageDialog(Display.getCurrent().getActiveShell(),
path, fileName);
runCopyToImageUI(dialog);
}
/**
* Displays the dialog and performs <code>OutOfMemoryError</code> checking
*
* @param dialog the copy to image dialog
*/
private void runCopyToImageUI(CopyToImageDialog dialog) {
if (dialog.open() == CopyToImageDialog.CANCEL) {
return;
}
if (!overwriteExisting()) {
return;
}
Trace
.trace(
DiagramUIRenderPlugin.getInstance(),
"Copy Diagram to " + dialog.getDestination().toOSString() + " as " + dialog.getImageFormat().toString()); //$NON-NLS-1$ //$NON-NLS-2$
final MultiStatus status = new MultiStatus(DiagramUIRenderPlugin
.getPluginId(), DiagramUIRenderStatusCodes.OK,
DiagramUIRenderMessages.CopyToImageAction_Label, null);
IRunnableWithProgress runnable = createRunnable(status);
ProgressMonitorDialog progressMonitorDialog = new ProgressMonitorDialog(
Display.getCurrent().getActiveShell());
try {
progressMonitorDialog.run(false, true, runnable);
} catch (InvocationTargetException e) {
Log.warning(DiagramUIRenderPlugin.getInstance(),
DiagramUIRenderStatusCodes.IGNORED_EXCEPTION_WARNING, e
.getTargetException().getMessage(), e
.getTargetException());
if (e.getTargetException() instanceof OutOfMemoryError) {
if (dialog.exportToHTML()) {
openErrorDialog(DiagramUIRenderMessages.CopyToImageAction_outOfMemoryMessage);
} else {
if (new MessageDialog(dialog.getShell(),
DiagramUIRenderMessages.CopyToImageOutOfMemoryDialog_title,
null,
DiagramUIRenderMessages.CopyToImageOutOfMemoryDialog_message,
MessageDialog.ERROR,
new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 0
).open() == 0) {
runCopyToImageUI(dialog);
}
}
} else if (e.getTargetException() instanceof SWTError) {
/**
* SWT returns an out of handles error when processing large
* diagrams
*/
if (dialog.exportToHTML()) {
openErrorDialog(DiagramUIRenderMessages.CopyToImageAction_outOfMemoryMessage);
} else {
if (new MessageDialog(dialog.getShell(),
DiagramUIRenderMessages.CopyToImageOutOfMemoryDialog_title,
null,
DiagramUIRenderMessages.CopyToImageOutOfMemoryDialog_message,
MessageDialog.ERROR,
new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }, 0
).open() == 0) {
runCopyToImageUI(dialog);
}
}
} else {
openErrorDialog(e.getTargetException().getMessage());
}
return;
} catch (InterruptedException e) {
/* the user pressed cancel */
Log.warning(DiagramUIRenderPlugin.getInstance(),
DiagramUIRenderStatusCodes.IGNORED_EXCEPTION_WARNING, e
.getMessage(), e);
}
if (!status.isOK()) {
openErrorDialog(status.getChildren()[0].getMessage());
}
}
/**
* copy the selected shapes in the diagram to an image file.
*
* @param diagramEditPart
* the diagram editor
* @param list
* list of selected shapes in the diagram
* @param destination
* path to the new image file
* @param imageFormat
* image format to create
* @return the runnable with a progress monitor
*/
private IRunnableWithProgress createRunnable(final MultiStatus status) {
return new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) {
try {
List editparts = getOperationSet();
CopyToImageUtil copyToImageUtil = null;
if (dialog.exportToHTML()) {
copyToImageUtil = new CopyToHTMLImageUtil();
} else {
copyToImageUtil = new CopyToImageUtil();
}
if (editparts.size() == 1
&& editparts.get(0) instanceof DiagramEditPart) {
monitor.beginTask("", 6); //$NON-NLS-1$
monitor.worked(1);
monitor
.setTaskName(NLS
.bind(
DiagramUIRenderMessages.CopyToImageAction_copyingDiagramToImageFileMessage,
dialog.getDestination().toOSString()));
copyToImageUtil.copyToImage(
(DiagramEditPart) editparts.get(0), dialog
.getDestination(), dialog.getImageFormat(),
monitor);
} else {
DiagramImageUtils
.zOrderSort(
editparts,
LayerManager.Helper
.find(getDiagramEditPart())
.getLayer(
LayerConstants.PRINTABLE_LAYERS));
monitor.beginTask("", 6); //$NON-NLS-1$
monitor.worked(1);
monitor
.setTaskName(NLS
.bind(
DiagramUIRenderMessages.CopyToImageAction_copyingSelectedElementsToImageFileMessage,
dialog.getDestination().toOSString()));
copyToImageUtil.copyToImage(getDiagramEditPart(),
editparts, dialog.getDestination(), dialog
.getImageFormat(), monitor);
}
} catch (CoreException e) {
Log.warning(DiagramUIRenderPlugin.getInstance(),
DiagramUIRenderStatusCodes.IGNORED_EXCEPTION_WARNING, e
.getMessage(), e);
status.add(e.getStatus());
} finally {
monitor.done();
}
}
};
}
protected boolean calculateEnabled() {
return !getOperationSet().isEmpty();
}
/**
* display an error dialog
*
* @param message
* cause of the error
*/
private void openErrorDialog(String message) {
MessageDialog
.openError(
Display.getCurrent().getActiveShell(),
DiagramUIRenderMessages.CopyToImageAction_copyToImageErrorDialogTitle,
NLS
.bind(
DiagramUIRenderMessages.CopyToImageAction_copyToImageErrorDialogMessage,
message));
}
/**
* Warn the user with a question dialog if an existing file is going to be
* overwritten and the user has not selected overwrite existing.
*
* @return true of it is ok to continue with the copy to image.
*/
private boolean overwriteExisting() {
if (dialog.overwriteExisting()) {
/**
* the user has selected to overwrite existing
*/
return true;
}
if (!dialog.getDestination().toFile().exists()) {
/**
* the file does not already exist
*/
return true;
}
/**
* ask the user to confirm to overwrite existing file.
*/
return MessageDialog
.openQuestion(
Display.getCurrent().getActiveShell(),
DiagramUIRenderMessages.CopyToImageAction_overwriteExistingConfirmDialogTitle,
NLS
.bind(
DiagramUIRenderMessages.CopyToImageAction_overwriteExistingConfirmDialogMessage,
dialog.getDestination().toOSString()));
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gmf.runtime.diagram.ui.actions.DiagramAction#createOperationSet()
*/
protected List createOperationSet() {
List selection = getSelectedObjects();
if (selection.size() == 1) {
Object editpart = selection.get(0);
if (editpart instanceof DiagramEditPart) {
return selection;
}
if (editpart instanceof ISurfaceEditPart) {
selection = ((ISurfaceEditPart) editpart).getPrimaryEditParts();
}
}
// must contain at least one shape
for (Iterator iter = selection.iterator(); iter.hasNext();) {
Object editpart = iter.next();
if (editpart instanceof ShapeEditPart) {
return selection;
}
}
return Collections.EMPTY_LIST;
}
protected boolean isSelectionListener() {
return true;
}
/**
* This action is not really a <code>DiagramAction</code> as it doesn't
* have a request. The doRun() and calculatedEnabled() have been overwritten
* appropriately.
*/
protected Request createTargetRequest() {
return null;
}
protected void doRun(IProgressMonitor progressMonitor) {
try {
// whatever we are copying belongs to the same editing domain as
// the Diagram
getDiagramEditPart().getEditingDomain().runExclusive(
new Runnable() {
public void run() {
CopyToImageAction.this.run();
}
});
} catch (Exception e) {
Trace.catching(DiagramUIRenderPlugin.getInstance(),
DiagramUIRenderDebugOptions.EXCEPTIONS_CATCHING, getClass(),
"doRun()", //$NON-NLS-1$
e);
}
}
/**
* Subclasses may override to specialize the rendering to an image file.
*
* @return the <code>CopyToImageUtil</code> class to be used.
*/
protected CopyToImageUtil getCopyToImageUtil() {
return new CopyToImageUtil();
}
}