| /****************************************************************************** |
| * 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(); |
| } |
| |
| } |