/****************************************************************************** * Copyright (c) 2002, 2010 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.clipboard; import java.awt.Image; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Stack; import org.eclipse.core.runtime.Assert; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PrecisionPoint; import org.eclipse.draw2d.geometry.PrecisionRectangle; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.gef.ConnectionEditPart; import org.eclipse.gef.EditPart; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.LayerConstants; import org.eclipse.gef.editparts.LayerManager; import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramRootEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.figures.IExpandableFigure; import org.eclipse.gmf.runtime.diagram.ui.image.PartPositionInfo; import org.eclipse.gmf.runtime.diagram.ui.l10n.SharedImages; import org.eclipse.gmf.runtime.diagram.ui.render.util.DiagramImageUtils; import org.eclipse.gmf.runtime.diagram.ui.render.util.PartPositionInfoGenerator; import org.eclipse.gmf.runtime.diagram.ui.services.decorator.Decoration; import org.eclipse.gmf.runtime.draw2d.ui.internal.graphics.ScaledGraphics; import org.eclipse.gmf.runtime.draw2d.ui.mapmode.IMapMode; import org.eclipse.gmf.runtime.draw2d.ui.mapmode.MapModeUtil; import org.eclipse.gmf.runtime.draw2d.ui.render.internal.graphics.RenderedMapModeGraphics; import org.eclipse.gmf.runtime.draw2d.ui.render.internal.graphics.RenderedScaledGraphics; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.graphics.ImageData; /** * Provides the framework to generate SWT and AWT images of a diagram or a * subset of editparts on a diagram. * * @author sshaw * @author Barys Dubauski */ abstract public class DiagramGenerator { private int image_margin = 0; private DiagramEditPart _dgrmEP; private IFigure printableLayer; private Dimension emptyImageSize; private static final int DEFAULT_IMAGE_MARGIN_PIXELS = 10; private static final int DEFAULT_EMPTY_IMAGE_SIZE_PIXELS = 100; /** * Creates a new instance. * * @param dgrmEP * the diagram editpart */ public DiagramGenerator(DiagramEditPart dgrmEP) { this._dgrmEP = dgrmEP; this.printableLayer = LayerManager.Helper.find(_dgrmEP).getLayer(LayerConstants.PRINTABLE_LAYERS); IMapMode mm = getMapMode(); image_margin = mm.DPtoLP(DEFAULT_IMAGE_MARGIN_PIXELS); emptyImageSize = (Dimension) mm.DPtoLP(new Dimension( DEFAULT_EMPTY_IMAGE_SIZE_PIXELS, DEFAULT_EMPTY_IMAGE_SIZE_PIXELS)); } /** * @return DiagramEditPart */ protected DiagramEditPart getDiagramEditPart() { return this._dgrmEP; } /** * Allows hook for the creation of a <code>Graphics</code> object that is * used for the rendering of the diagram. * * @param width * of the clipping area * @param height * of the clipping area * @return Graphics element that is the target for rendering. */ abstract protected Graphics setUpGraphics(int width, int height); /** * Allows hook to dispose of any artifacts around the creation of the * <code>Graphics</code> object used for rendering. * * @param g * Graphics element that is to be disposed. */ protected void disposeGraphics(Graphics g) { g.dispose(); } /** * Creates an image descriptor representing the image rendered from the * diagram. * * @param g * Graphics object where information to form the image descriptor * can be retrieved from. * @return ImageDescriptor representing the image rendered from the diagram. */ abstract protected ImageDescriptor getImageDescriptor(Graphics g); /** * Creates an AWT image for the contents of the diagram editpart. * * @return an image in AWT format */ final public Image createAWTImageForDiagram() { List editparts = getDiagramEditPart().getPrimaryEditParts(); return createAWTImageForParts(editparts); } /** * Creates an AWT image for the list of editparts passed in. * * @param editparts * the list of <code>IGraphicalEditParts</code> that will be * rendered to the Image * @return an image in AWT format */ public Image createAWTImageForParts(List editparts) { org.eclipse.swt.graphics.Rectangle diagramArea = calculateImageRectangle(editparts); return createAWTImageForParts(editparts, diagramArea); } /** * Creates an SWT image descriptor for the contents of the diagram editpart. * * @return an image descriptor for an SWT image */ final public ImageDescriptor createSWTImageDescriptorForDiagram() { List editparts = getDiagramEditPart().getPrimaryEditParts(); return createSWTImageDescriptorForParts(editparts); } /** * Creates an SWT image descriptor for the list of editparts passed in.Any * connections where both the source and target editparts are passed in are * also drawn. * * @param editparts * the list of <code>IGraphicalEditParts</code> that will be * rendered to the Image * @return an image descriptor for an SWT image */ final public ImageDescriptor createSWTImageDescriptorForParts(List editparts) { org.eclipse.swt.graphics.Rectangle sourceRect = calculateImageRectangle(editparts); return createSWTImageDescriptorForParts(editparts, sourceRect); } /** * @return */ protected IMapMode getMapMode() { return MapModeUtil.getMapMode(getDiagramEditPart().getFigure()); } /** * Renders the list of editparts to the graphics object. Any connections * where both the source and target editparts are passed in are also drawn. * * @param graphics * the graphics object on which to draw * @param translateOffset * a <code>Point</code> that the value the * <code>graphics</code> object will be translated by in * relative coordinates. * @param editparts * the list of <code>IGraphicalEditParts</code> that will be * rendered to the graphics object */ final protected void renderToGraphics(Graphics graphics, Point translateOffset, List editparts) { // List sortedEditparts = sortSelection(editparts); graphics.translate((-translateOffset.x), (-translateOffset.y)); graphics.pushState(); List<GraphicalEditPart> connectionsToPaint = new LinkedList<GraphicalEditPart>(); Map decorations = findDecorations(editparts); for (Iterator editPartsItr = editparts.listIterator(); editPartsItr.hasNext();) { IGraphicalEditPart editPart = (IGraphicalEditPart) editPartsItr.next(); // do not paint selected connection part if (editPart instanceof ConnectionEditPart) { connectionsToPaint.add(editPart); } else { connectionsToPaint.addAll(findConnectionsToPaint(editPart)); // paint shape figure IFigure figure = editPart.getFigure(); paintFigure(graphics, figure); paintDecorations(graphics, figure, decorations); } } // paint the connection parts after shape parts paint decorations = findDecorations(connectionsToPaint); for (Iterator<GraphicalEditPart> connItr = connectionsToPaint.iterator(); connItr.hasNext();) { IFigure figure = connItr.next().getFigure(); paintFigure(graphics, figure); paintDecorations(graphics, figure, decorations); } } /** * Collects all connections contained within the given edit part * * @param editPart the container editpart * @return connections within it */ private Collection<ConnectionEditPart> findConnectionsToPaint(IGraphicalEditPart editPart) { /* * Set of node editparts contained within the given editpart */ HashSet<GraphicalEditPart> editParts = new HashSet<GraphicalEditPart>(); /* * All connection editparts that have a source contained within the given editpart */ HashSet<ConnectionEditPart> connectionEPs = new HashSet<ConnectionEditPart>(); /* * Connections contained within the given editpart (or just the connections to paint */ HashSet<ConnectionEditPart> connectionsToPaint = new HashSet<ConnectionEditPart>(); /* * Populate the set of node editparts */ getNestedEditParts(editPart, editParts); /* * Populate the set of connections whose source is within the given editpart */ for (Iterator<GraphicalEditPart> editPartsItr = editParts.iterator(); editPartsItr.hasNext();) { connectionEPs.addAll(getAllConnectionsFrom(editPartsItr.next())); } /* * Create a set of connections constained within the given editpart */ while (!connectionEPs.isEmpty()) { /* * Take the first connection and check whethe there is a path * through that connection that leads to the target contained within * the given editpart */ Stack<ConnectionEditPart> connectionsPath = new Stack<ConnectionEditPart>(); ConnectionEditPart conn = connectionEPs.iterator().next(); connectionEPs.remove(conn); connectionsPath.add(conn); /* * Initialize the target for the current path */ EditPart target = conn.getTarget(); while(connectionEPs.contains(target)) { /* * If the target end is a connection, check if it's one of the * connection's whose target is a connection and within the * given editpart. Append it to the path if it is. Otherwise * check if the target is within the actual connections or nodes * contained within the given editpart */ ConnectionEditPart targetConn = (ConnectionEditPart) target; connectionEPs.remove(targetConn); connectionsPath.add(targetConn); /* * Update the target for the new path */ target = targetConn.getTarget(); } /* * The path is built, check if it's target is a node or a connection * contained within the given editpart */ if (editParts.contains(target) || connectionsToPaint.contains(target)) { connectionsToPaint.addAll(connectionsPath); } } return connectionsToPaint; } /** * Returns all connections orginating from a given editpart. All means that * connections originating from connections that have a source given * editpart will be included * * @param ep the editpart * @return all source connections */ private List<ConnectionEditPart> getAllConnectionsFrom(GraphicalEditPart ep) { LinkedList<ConnectionEditPart> connections = new LinkedList<ConnectionEditPart>(); for (Iterator itr = ep.getSourceConnections().iterator(); itr.hasNext();) { ConnectionEditPart sourceConn = (ConnectionEditPart) itr.next(); connections.add(sourceConn); connections.addAll(getAllConnectionsFrom(sourceConn)); } return connections; } /** * This method is used when a figure needs to be painted to the graphics. * The figure will be translated based on its absolute positioning. * * @param graphics * Graphics object to render figure * @param figure * the figure to be rendered */ private void paintFigure(Graphics graphics, IFigure figure) { if (!figure.isVisible() || figure.getBounds().isEmpty()) return; // Calculate the Relative bounds and absolute bounds Rectangle relBounds = null; if (figure instanceof IExpandableFigure) relBounds = ((IExpandableFigure) figure).getExtendedBounds() .getCopy(); else relBounds = figure.getBounds().getCopy(); Rectangle abBounds = relBounds.getCopy(); DiagramImageUtils.translateTo(abBounds, figure, printableLayer); // Calculate the difference int transX = abBounds.x - relBounds.x; int transY = abBounds.y - relBounds.y; // Paint the figure graphics.pushState(); graphics.translate(transX, transY); figure.paint(graphics); graphics.popState(); graphics.restoreState(); } /** * Find the decorations that adorn the specified <code>editParts</code>. * * @param editparts * the list of <code>IGraphicalEditParts</code> for which to * find decorations * @return a mapping of {@link IFigure}to ({@link Decoration}or * {@link Collection}of decorations}) */ private Map findDecorations(Collection editparts) { // create inverse mapping of figures to edit parts (need this to map // decorations to edit parts) Map figureMap = mapFiguresToEditParts(editparts); Map result = new java.util.HashMap(); if (!editparts.isEmpty()) { IGraphicalEditPart first = (IGraphicalEditPart) editparts.iterator().next(); IFigure decorationLayer = LayerManager.Helper.find(first).getLayer( DiagramRootEditPart.DECORATION_PRINTABLE_LAYER); if (decorationLayer != null) { // compute the figures of the shapes List figures = new java.util.ArrayList(editparts); for (ListIterator iter = figures.listIterator(); iter.hasNext();) { iter.set(((IGraphicalEditPart) iter.next()).getFigure()); } // find the decorations on figures that were selected for (Iterator iter = decorationLayer.getChildren().iterator(); iter .hasNext();) { Object next = iter.next(); if (next instanceof Decoration) { Decoration decoration = (Decoration) next; IFigure owner = decoration.getOwnerFigure(); while (owner != null) { if (figureMap.containsKey(owner)) { Object existing = result.get(owner); if (existing == null) { result.put(owner, decoration); } else if (existing instanceof Collection) { ((Collection) existing).add(decoration); } else { Collection c = new java.util.ArrayList(2); c.add(existing); c.add(decoration); result.put(owner, c); } break; } else { owner = owner.getParent(); } } } } } } return result; } /** * Constructs a mapping of figures to their corresponding edit parts. * * @param editParts * a collection of <code>IGraphicalEditParts</code> * @return a mapping of {@link IFigure}to {@link IGraphicalEditPart} */ private Map mapFiguresToEditParts(Collection editParts) { Map result = new java.util.HashMap(); for (Iterator iter = editParts.iterator(); iter.hasNext();) { IGraphicalEditPart next = (IGraphicalEditPart) iter.next(); result.put(next.getFigure(), next); } return result; } /** * Paints the decorations adorning the specified <code>figure</code>, if * any. * * @param graphics * the graphics to paint on * @param figure * the figure * @param decorations * mapping of figures to decorations, in which we will find the * <code>figure</code>'s decorations */ private void paintDecorations(Graphics graphics, IFigure figure, Map decorations) { Object decoration = decorations.get(figure); if (decoration != null) { if (decoration instanceof Collection) { for (Iterator iter = ((Collection) decoration).iterator(); iter .hasNext();) { paintFigure(graphics, (IFigure) iter.next()); } } else { paintFigure(graphics, (IFigure) decoration); } } } /** * This is a recursive method that search a tree of edit parts looking for * edit parts contained in the open list. If the edit part is found it is * removed from the open list and placed in the closed list. * * @param editPart * @param open * @param closed */ /* * The 2 commented out methods are not being used currently */ // private void sortSelection(GraphicalEditPart editPart, List open, // List closed) { // // // Do nothing if the open list is empty // if (open.isEmpty()) { // return; // } // // // IF the edit part is contained in the open list (we are searching for // // it) // if (open.contains(editPart)) { // // Add the Edit Part to the closed list and remove it from // // the open list // closed.add(editPart); // open.remove(editPart); // } // // for (Iterator iter = editPart.getChildren().iterator(); iter.hasNext();) { // GraphicalEditPart child = (GraphicalEditPart) iter.next(); // sortSelection(child, open, closed); // } // } // // private List sortSelection(List toSort) { // List closed = new ArrayList(toSort.size()); // List open = new ArrayList(toSort.size()); // open.addAll(toSort); // // sortSelection(getDiagramEditPart(), open, closed); // if (!open.isEmpty()) { // closed.addAll(open); // } // // return closed; // } /** * This method is used to obtain the list of child edit parts for shape * compartments. * * @param childEditPart * base edit part to get the list of children editparts * @param editParts * list of nested shape edit parts */ private void getNestedEditParts(IGraphicalEditPart childEditPart, Collection editParts) { for (Iterator iter = childEditPart.getChildren().iterator(); iter .hasNext();) { IGraphicalEditPart child = (IGraphicalEditPart) iter.next(); editParts.add(child); getNestedEditParts(child, editParts); } } /** * Determine the minimal rectangle required to bound the list of editparts. * A margin is used around each of the editpart's figures when calculating * the size. * * @param editparts * the list of <code>IGraphicalEditParts</code> from which * their figure bounds will be used * @return Rectangle the minimal rectangle that can bound the figures of the * list of editparts */ public org.eclipse.swt.graphics.Rectangle calculateImageRectangle( List editparts) { Rectangle rect = DiagramImageUtils.calculateImageRectangle(editparts, getImageMargin(), emptyImageSize); return new org.eclipse.swt.graphics.Rectangle(rect.x, rect.y, rect.width, rect.height); } /** * Get the positional data and the semantic elements for each * <code>ShapeEditPart</code>, <code>ShapeCompartmentEditPart</code>, * and <code>ConnectionEditPart</code> on the diagram. * * @return A list of {@link PartPositionInfo}objects with positional data * and the semantic element for the relevant editparts on the * diagram. */ public List getDiagramPartInfo() { Assert.isNotNull(_dgrmEP); return getDiagramPartInfo(_dgrmEP); } /** * Get the positional data and the semantic elements for each * <code>ShapeEditPart</code>, <code>ShapeCompartmentEditPart</code>, * and <code>ConnectionEditPart</code> on the diagram. * * @param diagramEditPart * The diagram edit part. * @return A list of {@link PartPositionInfo}objects with positional data * and the semantic element for the relevant editparts on the * diagram. */ public List getDiagramPartInfo(DiagramEditPart diagramEditPart) { Map<String, Object> options = new HashMap<String, Object>(); Point origin = DiagramImageUtils.calculateImageRectangle( diagramEditPart.getPrimaryEditParts(), getImageMargin(), emptyImageSize).getLocation(); options.put(PartPositionInfoGenerator.CONNECTION_MARGIN, new Double(getImageMargin() >> 1)); options.put(PartPositionInfoGenerator.DIAGRAM_ORIGIN, origin); return PartPositionInfoGenerator.getDiagramPartInfo(diagramEditPart, options); } public List<PartPositionInfo> getConstrainedDiagramPartInfo(int maxWidth, int maxHeight, boolean useMargins) { return getConstrainedDiagramPartInfo(_dgrmEP, maxWidth, maxHeight, useMargins); } public List<PartPositionInfo> getConstrainedDiagramPartInfo( DiagramEditPart diagramEditPart, int maxWidth, int maxHeight, boolean useMargins) { List<IGraphicalEditPart> children = (List<IGraphicalEditPart>) diagramEditPart .getPrimaryEditParts(); IMapMode mm = getMapMode(); // We will use the diagram generate that was used to generate the image // to figure out the outer-bound rectangle so that we are calculating // the // image positions using the same box as was used to create the image. ConstrainedImageRenderingData data = getConstrainedImageRenderingData( children, maxWidth, maxHeight, useMargins); Rectangle imageRect = data.imageOriginalBounds.getCopy(); mm.DPtoLP(imageRect); if (useMargins) { imageRect.shrink(getImageMargin(), getImageMargin()); } imageRect.performScale(data.scalingFactor); if (useMargins) { imageRect.expand(getImageMargin(), getImageMargin()); } Map<String, Object> options = new HashMap<String, Object>(); options.put(PartPositionInfoGenerator.CONNECTION_MARGIN, new Double(mm.DPtoLP(5))); options.put(PartPositionInfoGenerator.DIAGRAM_ORIGIN, imageRect.getLocation()); options.put(PartPositionInfoGenerator.SCALE_FACTOR, new Double(data.scalingFactor)); return PartPositionInfoGenerator.getDiagramPartInfo(diagramEditPart, options); } /** * @return <code>int</code> value that is the margin around the generated * image in logical coordinates. * @since 1.3 */ public int getImageMargin() { return image_margin; } /** * Sets the image margin value (width of the white frame around the image). * The value must be in logical units. * * @param imageMargin * @since 1.3 */ public void setImageMargin(int imageMargin) { Assert.isTrue(imageMargin >= 0); image_margin = imageMargin; } /** * Generates AWT image of specified editparts on the specified rectangle. * * @param editParts editparts * @param diagramArea clipping rectangle * @return AWT image */ public Image createAWTImageForParts(List editParts, org.eclipse.swt.graphics.Rectangle diagramArea) { return null; } final public ImageDescriptor createSWTImageDescriptorForParts( List editparts, org.eclipse.swt.graphics.Rectangle sourceRect) { // initialize imageDesc to the error icon ImageDescriptor imageDesc = new ImageDescriptor() { /* * (non-Javadoc) * * @see org.eclipse.jface.resource.ImageDescriptor#getImageData() */ public ImageData getImageData() { return SharedImages.get(SharedImages.IMG_ERROR).getImageData(); } }; Graphics graphics = null; try { IMapMode mm = getMapMode(); PrecisionRectangle rect = new PrecisionRectangle(); rect.setX(sourceRect.x); rect.setY(sourceRect.y); rect.setWidth(sourceRect.width); rect.setHeight(sourceRect.height); mm.LPtoDP(rect); // Create the graphics and wrap it with the HiMetric graphics object graphics = setUpGraphics((int) Math.round(rect.preciseWidth), (int) Math.round(rect.preciseHeight)); RenderedMapModeGraphics mapModeGraphics = new RenderedMapModeGraphics( graphics, getMapMode()); renderToGraphics(mapModeGraphics, new Point(sourceRect.x, sourceRect.y), editparts); imageDesc = getImageDescriptor(graphics); } finally { if (graphics != null) disposeGraphics(graphics); } return imageDesc; } /** * Creates an SWT image descriptor for editparts. Editparts are scaled to fit in maxDeviceWidth and maxDeviceHeight * frame * * @param editParts editparts * @param maxDeviceWidth max width for the image * @param maxDeviceHeight max height for the image * @param useMargins true if 10 pisels margins are required to bound the editparts image * @return the image descriptor */ final public ImageDescriptor createConstrainedSWTImageDecriptorForParts( List editParts, int maxDeviceWidth, int maxDeviceHeight, boolean useMargins) { ImageDescriptor imageDesc = new ImageDescriptor() { /* * (non-Javadoc) * * @see org.eclipse.jface.resource.ImageDescriptor#getImageData() */ public ImageData getImageData() { return SharedImages.get(SharedImages.IMG_ERROR).getImageData(); } }; Graphics graphics = null; try { IMapMode mm = getMapMode(); ConstrainedImageRenderingData data = getConstrainedImageRenderingData( editParts, maxDeviceWidth, maxDeviceHeight, useMargins); // Create the graphics and wrap it with the HiMetric graphics object graphics = setUpGraphics(data.imageWidth, data.imageHeight); ScaledGraphics scaledGraphics = new RenderedScaledGraphics(graphics); RenderedMapModeGraphics mapModeGraphics = new RenderedMapModeGraphics( scaledGraphics, getMapMode()); graphics.translate(data.margin, data.margin); mapModeGraphics.scale(data.scalingFactor); Point location = new PrecisionPoint(data.imageOriginalBounds .preciseX(), data.imageOriginalBounds.preciseY()); mm.DPtoLP(location); renderToGraphics(mapModeGraphics, location, editParts); imageDesc = getImageDescriptor(graphics); } finally { if (graphics != null) disposeGraphics(graphics); } return imageDesc; } class ConstrainedImageRenderingData { double scalingFactor; int imageWidth; // in pixels int imageHeight; // in pixels Rectangle imageOriginalBounds; // in pixels int margin; // margins size in pixels } ConstrainedImageRenderingData getConstrainedImageRenderingData( List editParts, int maxDeviceWidth, int maxDeviceHeight, boolean useMargins) { ConstrainedImageRenderingData data = new ConstrainedImageRenderingData(); IMapMode mm = getMapMode(); data.imageOriginalBounds = new PrecisionRectangle(new Rectangle( calculateImageRectangle(editParts))); mm.LPtoDP(data.imageOriginalBounds); int deviceMargins = mm.LPtoDP(getImageMargin()); data.margin = useMargins ? deviceMargins : 0; double xScalingFactor = 1.0, yScalingFactor = xScalingFactor; data.imageOriginalBounds.shrink(deviceMargins, deviceMargins); if (maxDeviceWidth > data.margin) { xScalingFactor = (maxDeviceWidth - data.margin - data.margin) / (data.imageOriginalBounds.preciseWidth()); } if (maxDeviceHeight > data.margin) { yScalingFactor = (maxDeviceHeight - data.margin - data.margin) / (data.imageOriginalBounds.preciseHeight()); } data.scalingFactor = Math.min(Math.min(xScalingFactor, yScalingFactor), 1); data.imageWidth = data.imageOriginalBounds.width + data.margin + data.margin; data.imageHeight = data.imageOriginalBounds.height + data.margin + data.margin; if (data.scalingFactor < 1) { data.imageWidth = (int) Math.round(data.imageOriginalBounds .preciseWidth() * data.scalingFactor) + data.margin + data.margin; data.imageHeight = (int) Math.round(data.imageOriginalBounds .preciseHeight() * data.scalingFactor) + data.margin + data.margin; } else { data.scalingFactor = 1; } return data; } /** * Creates an AWT image for editparts. Editparts are scaled to fit in maxDeviceWidth and maxDeviceHeight * frame * * @param editParts editparts * @param maxDeviceWidth max width for the image * @param maxDeviceHeight max height for the image * @param useMargins true if 10 pisels margins are required to bound the editparts image * @return the image */ public Image createConstrainedAWTImageForParts(List editParts, int maxDeviceWidth, int maxDeviceHeight, boolean useMargins) { return null; } }