//------------------------------------------------------------------------------ // Copyright (c) 2005, 2006 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 implementation //------------------------------------------------------------------------------ package org.eclipse.epf.library.layout.diagram; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.TexturePaint; import java.awt.geom.Line2D; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; import java.awt.image.IndexColorModel; import java.awt.image.WritableRaster; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Properties; import javax.imageio.ImageIO; import javax.swing.JPanel; import org.eclipse.core.runtime.Platform; import org.eclipse.epf.common.utils.I18nUtil; import org.eclipse.epf.common.utils.ImageUtil; import org.eclipse.epf.library.LibraryPlugin; import org.eclipse.epf.library.LibraryResources; import org.eclipse.epf.library.configuration.ConfigurationHelper; import org.eclipse.epf.library.diagram.providers.DiagramIconProviderManager; import org.eclipse.epf.library.layout.IElementLayout; import org.eclipse.epf.library.layout.elements.RoleLayout; import org.eclipse.epf.library.preferences.LibraryPreferences; import org.eclipse.epf.library.prefs.PreferenceUtil; import org.eclipse.epf.publish.layout.LayoutPlugin; import org.eclipse.epf.uma.MethodElement; import org.eclipse.epf.uma.Role; import org.eclipse.epf.uma.Task; import org.eclipse.epf.uma.WorkProduct; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Display; /** * Renders the Role diagram using Java2D and saves it as a JPEG file. * * @author Kelvin Low * @author Jinhua Xi * @since 1.0 */ public class RoleDiagramPublisher { private static final String DEFAULT_FONT_NAME = "Arial"; //$NON-NLS-1$ private static final int DEFAULT_FONT_SIZE = 10; private static final int DEFAULT_X_MARGIN = 200; // The maximum width of the generated image. private int maxImageWidth = 1024; // The maximum height of the generated image. private int maxImageHeight = 2048; // The border width. private int borderWidth = 10; // The border height. private int borderHeight = 10; // The additional spacing before the left-most Task and/or Work Product // image. private int xMargin = 240; // The horizontal spacing between the element images. private int xSpacing; // The vertical spacing between the element images. private int ySpacing; // The maximun number of text lines for the element labels. private int maxTextLines; // The image width private int imageWidth = 32; // The image height private int imageHeight = 32; private int linePadding = 12; private Font textFont = null; private Properties xslParams = null; private Image shapeImage = null; /** * Creates a new <code>ImagePublisher</code>. */ public RoleDiagramPublisher() { // Select the font for rendering the element names. String fontName; int fontSize; fontName = getFontName(); if (SWT.getPlatform().equals(Platform.WS_WIN32)) { fontSize = I18nUtil.getInt( LibraryResources.roleDiagramFont_size_win32, DEFAULT_FONT_SIZE); } else { fontSize = I18nUtil.getInt(LibraryResources.roleDiagramFont_size, DEFAULT_FONT_SIZE); } if (fontName.startsWith("[")) { //$NON-NLS-1$ fontName = DEFAULT_FONT_NAME; } textFont = new Font(fontName, Font.PLAIN, fontSize); xMargin = I18nUtil.getInt(LibraryResources.roleDiagram_xMargin, DEFAULT_X_MARGIN); xSpacing = LibraryPreferences.getRoleDiagramHorizontalSpacing(); ySpacing = LibraryPreferences.getRoleDiagramVerticalSpacing(); maxTextLines = LibraryPreferences.getRoleDiagramMaximumTextLines(); try { xslParams = LayoutPlugin.getDefault().getProperties( "/layout/xsl/resources.properties"); //$NON-NLS-1$ } catch (IOException e) { } } private String getFontName() { String fontName; if (Platform.getNL().startsWith("ja")) { //$NON-NLS-1$ if (SWT.getPlatform().equals(Platform.WS_WIN32)) { fontName = LibraryResources.roleDiagramFont_name_win32_ja; } else { fontName = LibraryResources.roleDiagramFont_name_ja; } } else if (Platform.getNL().startsWith("ko")) { //$NON-NLS-1$ if (SWT.getPlatform().equals(Platform.WS_WIN32)) { fontName = LibraryResources.roleDiagramFont_name_win32_ko; } else { fontName = LibraryResources.roleDiagramFont_name_ko; } } else if (Platform.getNL().startsWith("zh_TW")) { //$NON-NLS-1$ if (SWT.getPlatform().equals(Platform.WS_WIN32)) { fontName = LibraryResources.roleDiagramFont_name_win32_zh_TW; } else { fontName = LibraryResources.roleDiagramFont_name_zh_TW; } } else if (Platform.getNL().startsWith("zh")) { //$NON-NLS-1$ if (SWT.getPlatform().equals(Platform.WS_WIN32)) { fontName = LibraryResources.roleDiagramFont_name_win32_zh; } else { fontName = LibraryResources.roleDiagramFont_name_zh; } } else { if (SWT.getPlatform().equals(Platform.WS_WIN32)) { fontName = LibraryResources.roleDiagramFont_name_win32; } else { fontName = LibraryResources.roleDiagramFont_name; } } return fontName; } /** * Generates the Role Diagram HTML source for the given role. * * @param role * The Role element. * @param path * The publish path. * @return A <code>MethodElementDiagram</code> object associated with the * published diagram. */ public MethodElementDiagram publish(RoleLayout roleLayout, File path) { Role role = (Role) roleLayout.getElement(); if (role == null) { throw new IllegalArgumentException(); } try { MethodElementDiagram elementDiagram = new MethodElementDiagram(role); String publishDir = roleLayout.getLayoutMgr().getPublishDir(); String mapName = roleLayout.getDisplayName(); if (mapName == null || mapName.length() == 0) { mapName = "Unknown"; //$NON-NLS-1$ } else { mapName = mapName.replace(' ', '_'); } HTMLMap htmlMap = new HTMLMap(mapName); elementDiagram.setHTMLMap(htmlMap); // Create the AWT JPanel for rendering the diagram. JPanel panel = new JPanel(); // Create the output BufferedImage. BufferedImage outputImage = new BufferedImage(maxImageWidth, maxImageHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = (Graphics2D) outputImage.getGraphics(); // Switch on anti-aliasing. g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.fillRect(0, 0, maxImageWidth, maxImageHeight); // Set the stroke for drawing the association lines. g2d.setStroke(new BasicStroke(1.25f)); g2d.setColor(Color.BLACK); int xOffset = xSpacing / 2; // Renders the Tasks performed by the Role. List tasks = roleLayout.getPerforms(); int totalTasks = tasks != null ? tasks.size() : 0; Point taskStartPoint = new Point(borderWidth + xMargin, borderHeight); Point taskEndPoint = new Point(borderWidth + xMargin, borderHeight); int x = taskStartPoint.x; int y = taskStartPoint.y; int tasksEndX = 0; if (totalTasks > 0) { int taskNo = 1; for (Iterator i = tasks.iterator(); i.hasNext(); taskNo++) { Task task = (Task) i.next(); IElementLayout taskLayout = roleLayout.getLayoutMgr() .getLayout(task, true); String taskName = taskLayout.getDisplayName(); String imageFile = publishDir + taskLayout.getDiagramiconUrl(); try { BufferedImage taskImage = null; Image taskShapeIcon = getShapeIcon(task); if (taskShapeIcon != null) { taskImage = convertToAWT(taskShapeIcon.getImageData()); } else { taskImage = ImageUtil.getBufferedImage(imageFile, panel); } int taskWidth = imageWidth; //taskImage.getWidth(); int taskHeight = imageHeight; // taskImage.getHeight(); if (taskNo == 1) { taskEndPoint.x += taskWidth; taskEndPoint.y += taskHeight; tasksEndX = taskEndPoint.x; } Rectangle taskImageRect = new Rectangle(x, y, taskWidth, taskHeight); TexturePaint taskPaint = new TexturePaint(taskImage, taskImageRect); g2d.setPaint(taskPaint); g2d.fill(taskImageRect); if (taskName != null) { ImageUtil.drawText(g2d, taskName, textFont, Color.BLACK, x - xOffset, taskEndPoint.y, taskWidth + xSpacing, maxTextLines); } String href = taskLayout.getFilePath(roleLayout) + taskLayout.getFileName(".html"); //$NON-NLS-1$ HTMLArea htmlArea = new HTMLArea(task.getGuid(), href, "rect", taskImageRect, taskName); //$NON-NLS-1$ htmlMap.addArea(htmlArea); if (x + taskWidth > tasksEndX) { tasksEndX = x + taskWidth; } if (i.hasNext()) { int xIncrement = taskWidth + xSpacing; x += xIncrement; taskEndPoint.x += xIncrement; if ((x + xIncrement + xOffset + borderWidth) > maxImageWidth) { x = taskStartPoint.x; int yIncrement = taskHeight + ySpacing; y += yIncrement; taskEndPoint.y += yIncrement; taskEndPoint.x = taskStartPoint.x + taskWidth; } } } catch (Exception e) { LibraryPlugin.getDefault().getLogger().logError(e); } } } // Renders the Work Products that the Role is responsible for. List workProducts = roleLayout.getResponsibleFor(); int totalWorkProducts = workProducts != null ? workProducts.size() : 0; Point workProductStartPoint = new Point(taskStartPoint.x, borderHeight); Point workProductEndPoint = new Point(taskStartPoint.x, borderHeight); if (totalTasks > 0 && totalWorkProducts > 0) { workProductStartPoint.y = taskEndPoint.y + ySpacing + ySpacing / 2; workProductEndPoint.y = workProductStartPoint.y; } else if (totalTasks > 0) { workProductEndPoint.y = taskEndPoint.y + borderHeight; } x = workProductStartPoint.x; y = workProductStartPoint.y; int workProductsEndX = 0; if (totalWorkProducts > 0) { int workProductNo = 1; for (Iterator i = workProducts.iterator(); i.hasNext(); workProductNo++) { WorkProduct workProduct = (WorkProduct) i.next(); IElementLayout wpLayout = roleLayout.getLayoutMgr() .getLayout(workProduct, true); String workProductName = wpLayout.getDisplayName(); String imageFile = publishDir + wpLayout.getDiagramiconUrl(); try { BufferedImage workProductImage = null; Image wpShapeIcon = getShapeIcon(workProduct); if (wpShapeIcon != null) { workProductImage = convertToAWT(wpShapeIcon.getImageData()); } else { workProductImage = ImageUtil.getBufferedImage(imageFile, panel); } int workProductWidth = imageWidth; // workProductImage.getWidth(); int workProductHeight = imageHeight; // workProductImage.getHeight(); if (workProductNo == 1) { workProductEndPoint.x += workProductWidth; workProductEndPoint.y += workProductHeight; workProductsEndX = workProductEndPoint.x; } Rectangle workProductImageRect = new Rectangle(x, y, workProductWidth, workProductHeight); TexturePaint workProductPaint = new TexturePaint( workProductImage, workProductImageRect); g2d.setPaint(workProductPaint); g2d.fill(workProductImageRect); if (workProductName != null) { ImageUtil.drawText(g2d, workProductName, textFont, Color.BLACK, x - xOffset, workProductEndPoint.y, workProductWidth + xSpacing, maxTextLines); } String href = wpLayout.getFilePath(roleLayout) + wpLayout.getFileName(".html"); //$NON-NLS-1$ HTMLArea htmlArea = new HTMLArea(workProduct.getGuid(), href, "rect", workProductImageRect, workProductName); //$NON-NLS-1$ htmlMap.addArea(htmlArea); if (x + workProductWidth > workProductsEndX) { workProductsEndX = x + workProductWidth; } if (i.hasNext()) { int xIncrement = workProductWidth + xSpacing; x += xIncrement; workProductEndPoint.x += xIncrement; if ((x + xIncrement + xOffset + borderWidth) > maxImageWidth) { x = workProductStartPoint.x; int yIncrement = workProductHeight + ySpacing; y += yIncrement; workProductEndPoint.y += yIncrement; workProductEndPoint.x = workProductStartPoint.x + workProductWidth; } } } catch (Exception e) { LibraryPlugin.getDefault().getLogger().logError(e); } } } // Render the Role. Point roleStartPoint = new Point(xOffset - 5, borderHeight); Point roleEndPoint = roleStartPoint; try { String roleName = roleLayout.getDisplayName(); String imageFile = publishDir + roleLayout.getDiagramiconUrl(); BufferedImage roleImage = null; Image roleShapeIcon = getShapeIcon(role); if (roleShapeIcon != null) { roleImage = convertToAWT(roleShapeIcon.getImageData()); } else { roleImage = ImageUtil.getBufferedImage(imageFile, panel); } // scale image to 32x32 int roleWidth = imageWidth; //roleImage.getWidth(); int roleHeight = imageHeight; // roleImage.getHeight(); x = xOffset - 5; y = borderHeight; roleEndPoint.x += roleWidth; roleEndPoint.y += roleHeight; if (totalWorkProducts > 0) { y = borderHeight + (workProductEndPoint.y - taskStartPoint.y - roleHeight) / 2; // Render the "responsible for" association line. Point startPoint = new Point(x + roleWidth + linePadding / 2, y + roleHeight / 2); int lineEndPoint = workProductStartPoint.x - linePadding; if (lineEndPoint > (DEFAULT_X_MARGIN - xSpacing / 2)) { lineEndPoint = (DEFAULT_X_MARGIN - xSpacing / 2); } Point endPoint = new Point(workProductStartPoint.x - linePadding, workProductStartPoint.y + (workProductEndPoint.y - workProductStartPoint.y) / 2); renderAssociation(g2d, startPoint, endPoint, getLabel("roleDiagramResponsibleFor_text"), textFont, Color.BLACK); } else if (totalTasks > 0) { y = borderHeight + (taskEndPoint.y - taskStartPoint.y - roleHeight) / 2; } roleStartPoint.y = y; roleEndPoint.y = y + roleHeight; if (totalTasks > 0) { // Render the "performs" association line. Point startPoint = new Point(x + roleWidth + linePadding / 2, y + roleHeight / 2); int lineEndPoint = taskStartPoint.x - linePadding; if (lineEndPoint > (DEFAULT_X_MARGIN - xSpacing / 2)) { lineEndPoint = (DEFAULT_X_MARGIN - xSpacing / 2); } Point endPoint = new Point(lineEndPoint, borderHeight + (taskEndPoint.y - taskStartPoint.y) / 2); renderAssociation(g2d, startPoint, endPoint, getLabel("roleDiagramPerforms_text"), // LibraryResources.roleDiagramPerforms_text, textFont, Color.BLACK); } Rectangle roleImageRect = new Rectangle(x, y, roleWidth, roleHeight); TexturePaint rolePaint = new TexturePaint(roleImage, roleImageRect); g2d.setPaint(rolePaint); g2d.fill(roleImageRect); if (roleName != null) { ImageUtil.drawText(g2d, roleName, textFont, Color.BLACK, x - xOffset, y + roleHeight, roleWidth + xSpacing, maxTextLines); } } catch (Exception e) { LibraryPlugin.getDefault().getLogger().logError(e); } // Calculate the optimal width and height for the rendered image. int optimalWidth = Math.max(tasksEndX, workProductsEndX) + borderWidth; optimalWidth = Math.max(optimalWidth, roleEndPoint.x + borderWidth); optimalWidth = Math.min(optimalWidth, maxImageWidth); int optimalHeight = workProductEndPoint.y + borderHeight; optimalHeight = Math.max(optimalHeight, roleEndPoint.y + borderHeight); optimalWidth += xOffset; optimalHeight += (maxTextLines * 10); optimalHeight = Math.min(optimalHeight, maxImageHeight); BufferedImage optimalImage = outputImage.getSubimage(0, 0, optimalWidth, optimalHeight); // Save the image as a JPEG file. File jpgFile = new File(path, roleLayout.getFilePath() + roleLayout.getFileName(".jpg")); //$NON-NLS-1$ File parentFolder = jpgFile.getParentFile(); if (!parentFolder.exists()) { parentFolder.mkdirs(); } ImageIO.write(optimalImage, "jpg", jpgFile); //$NON-NLS-1$ elementDiagram.setImageFileName(jpgFile.getName()); return elementDiagram; } catch (Exception e) { LibraryPlugin.getDefault().getLogger().logError(e); return null; } } /** * Renders the association line. * * @param g2d * The Graphics2D context. * @param startPoint * The start point of the line. * @param endPoint * The end point of the line. * @param name * The association name. * @param font * The font for rendering the association name. * @param color * the color for rendering the association name. */ protected void renderAssociation(Graphics2D g2d, Point startPoint, Point endPoint, String name, Font font, Color color) { g2d.draw(new Line2D.Double(startPoint.x, startPoint.y, endPoint.x, endPoint.y)); int textX = startPoint.x + (endPoint.x - startPoint.x) / 2 - 40; int textY = startPoint.y + (endPoint.y - startPoint.y) / 2 - 5; if (startPoint.y != endPoint.y) { g2d.setColor(Color.WHITE); g2d.fillRect(textX, textY, 80, 10); } else { textY -= 10; } ImageUtil.drawText(g2d, name, font, color, textX, textY, 80, 3); } private Image getShapeIcon(MethodElement element) { final MethodElement e = element; if (ConfigurationHelper.serverMode) { return DiagramIconProviderManager.getInstance().getIcon( e, false); } // add display.async since it's getting called from non-ui thread Display.getDefault().syncExec(new Runnable() { public void run() { Image img = DiagramIconProviderManager.getInstance().getIcon( e, false); shapeImage = img; } }); if (shapeImage != null) { return shapeImage; } return null; } /** * Converts swt imagedata into awt buffered image * @param data * @return */ private BufferedImage convertToAWT(ImageData data) { ColorModel colorModel = null; PaletteData palette = data.palette; if (palette.isDirect) { colorModel = new DirectColorModel(data.depth, palette.redMask, palette.greenMask, palette.blueMask); BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height), false, null); WritableRaster raster = bufferedImage.getRaster(); int[] pixelArray = new int[3]; for (int y = 0; y < data.height; y++) { for (int x = 0; x < data.width; x++) { int pixel = data.getPixel(x, y); RGB rgb = palette.getRGB(pixel); pixelArray[0] = rgb.red; pixelArray[1] = rgb.green; pixelArray[2] = rgb.blue; raster.setPixels(x, y, 1, 1, pixelArray); } } return bufferedImage; } else { RGB[] rgbs = palette.getRGBs(); byte[] red = new byte[rgbs.length]; byte[] green = new byte[rgbs.length]; byte[] blue = new byte[rgbs.length]; for (int i = 0; i < rgbs.length; i++) { RGB rgb = rgbs[i]; red[i] = (byte) rgb.red; green[i] = (byte) rgb.green; blue[i] = (byte) rgb.blue; } if (data.transparentPixel != -1) { colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue, data.transparentPixel); } else { colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue); } BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height), false, null); WritableRaster raster = bufferedImage.getRaster(); int[] pixelArray = new int[1]; for (int y = 0; y < data.height; y++) { for (int x = 0; x < data.width; x++) { int pixel = data.getPixel(x, y); pixelArray[0] = pixel; raster.setPixel(x, y, pixelArray); } } return bufferedImage; } } private String getLabel(String key) { String label = PreferenceUtil.getLabel(key); if (label == null) { label = xslParams.getProperty(key); if ( label == null ) { System.out.println("Can't find property entry for " + key); //$NON-NLS-1$ label = key; } } return label; } }