From 9d7b57493a0b0593fb43a54af523dfc09061f848 Mon Sep 17 00:00:00 2001 From: lijiarao Date: Tue, 5 Sep 2023 17:58:13 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E6=B5=81=E7=A8=8B=E5=9B=BE=EF=BC=8C?= =?UTF-8?q?=E4=BC=9A=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- laws-modules/pom.xml | 9 +- .../activiti/config/ActivitiConfig.java | 34 + .../config/DefaultProcessDiagramCanvas.java | 2097 ----------------- .../DefaultProcessDiagramGenerator.java | 1604 ------------- .../config/MultiInstanceTaskHandler.java | 29 + .../jero/modules/activiti/config/MyGen.java | 17 + .../activiti/config/WorkflowConstants.java | 130 + .../activiti/controller/AController.java | 71 +- .../activiti/service/ProcessService.java | 4 +- .../service/impl/ProcessServiceImpl.java | 380 ++- .../image/CustomProcessDiagramCanvas.java | 1294 ++-------- .../image/CustomProcessDiagramGenerator.java | 1118 +++------ .../image/ICustomProcessDiagramGenerator.java | 60 +- .../modules/activiti/util/CamundaTag.java | 58 + .../modules/activiti/util/ConversionUtil.java | 178 ++ .../modules/activiti/util/NamespaceName.java | 34 + .../main/resources/bpmn/企标制修订流程.bpmn | 457 ++++ .../com/jero/JeroSystemSingleApplication.java | 5 +- pom.xml | 2 +- 19 files changed, 1676 insertions(+), 5905 deletions(-) create mode 100644 laws-modules/src/main/java/com/jero/modules/activiti/config/ActivitiConfig.java delete mode 100644 laws-modules/src/main/java/com/jero/modules/activiti/config/DefaultProcessDiagramCanvas.java delete mode 100644 laws-modules/src/main/java/com/jero/modules/activiti/config/DefaultProcessDiagramGenerator.java create mode 100644 laws-modules/src/main/java/com/jero/modules/activiti/config/MultiInstanceTaskHandler.java create mode 100644 laws-modules/src/main/java/com/jero/modules/activiti/config/MyGen.java create mode 100644 laws-modules/src/main/java/com/jero/modules/activiti/config/WorkflowConstants.java create mode 100644 laws-modules/src/main/java/com/jero/modules/activiti/util/CamundaTag.java create mode 100644 laws-modules/src/main/java/com/jero/modules/activiti/util/ConversionUtil.java create mode 100644 laws-modules/src/main/java/com/jero/modules/activiti/util/NamespaceName.java create mode 100644 laws-modules/src/main/resources/bpmn/企标制修订流程.bpmn diff --git a/laws-modules/pom.xml b/laws-modules/pom.xml index c79bb71f..3f456a4b 100644 --- a/laws-modules/pom.xml +++ b/laws-modules/pom.xml @@ -30,16 +30,9 @@ laws-base-generater ${jero.version} - - - org.activiti.dependencies - activiti-dependencies - ${activiti.version} - pom - org.activiti - activiti-spring-boot-starter + activiti-spring-boot-starter-rest-api ${activiti.version} diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/config/ActivitiConfig.java b/laws-modules/src/main/java/com/jero/modules/activiti/config/ActivitiConfig.java new file mode 100644 index 00000000..64b34801 --- /dev/null +++ b/laws-modules/src/main/java/com/jero/modules/activiti/config/ActivitiConfig.java @@ -0,0 +1,34 @@ +package com.jero.modules.activiti.config; + +import com.jero.modules.activiti.service.impl.image.ICustomProcessDiagramGenerator; +import org.activiti.engine.impl.form.DoubleFormType; +import org.activiti.spring.SpringProcessEngineConfiguration; +import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer; +import org.springframework.beans.factory.annotation.Autowired; + + +/** + * @author liJiaRao + * @date 2023-09-05 17:53 + */ +public class ActivitiConfig implements ProcessEngineConfigurationConfigurer { + @Autowired + private ICustomProcessDiagramGenerator customProcessDiagramGenerator; + @Autowired + private DoubleFormType doubleFormType; + + /** + * 解決工作流生成图片乱码问题 + * + * @param processEngineConfiguration + */ + @Override + public void configure(SpringProcessEngineConfiguration processEngineConfiguration) { + int[] result = {}; + processEngineConfiguration.setActivityFontName("宋体"); + processEngineConfiguration.setAnnotationFontName("宋体"); + processEngineConfiguration.setLabelFontName("宋体"); + processEngineConfiguration.setProcessDiagramGenerator(customProcessDiagramGenerator); + } + +} diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/config/DefaultProcessDiagramCanvas.java b/laws-modules/src/main/java/com/jero/modules/activiti/config/DefaultProcessDiagramCanvas.java deleted file mode 100644 index 2c7c87d7..00000000 --- a/laws-modules/src/main/java/com/jero/modules/activiti/config/DefaultProcessDiagramCanvas.java +++ /dev/null @@ -1,2097 +0,0 @@ -package com.jero.modules.activiti.config; - - -import org.activiti.bpmn.model.AssociationDirection; -import org.activiti.bpmn.model.EventSubProcess; -import org.activiti.bpmn.model.GraphicInfo; -import org.activiti.bpmn.model.Transaction; -import org.activiti.image.exception.ActivitiImageException; -import org.activiti.image.impl.ProcessDiagramSVGGraphics2D; -import org.activiti.image.impl.icon.*; -import org.apache.batik.dom.GenericDOMImplementation; -import org.apache.batik.svggen.SVGGraphics2DIOException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.Document; - -import javax.imageio.ImageIO; -import java.awt.*; -import java.awt.font.FontRenderContext; -import java.awt.font.LineBreakMeasurer; -import java.awt.font.TextAttribute; -import java.awt.font.TextLayout; -import java.awt.geom.*; -import java.awt.image.BufferedImage; -import java.io.*; -import java.text.AttributedCharacterIterator; -import java.text.AttributedString; -import java.util.ArrayList; -import java.util.List; -/** - * @author liJiaRao - * @date 2023-08-04 11:18 - */ -/** - 1. Represents a canvas on which BPMN 2.0 constructs can be drawn. - 2.

- 3. @see org.activiti.image.impl.DefaultProcessDiagramGenerator - */ -public class DefaultProcessDiagramCanvas { - - protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultProcessDiagramCanvas.class); - - public enum SHAPE_TYPE { - Rectangle, - Rhombus, - Ellipse - } - - // Predefined sized - protected static final int ARROW_WIDTH = 5; - protected static final int CONDITIONAL_INDICATOR_WIDTH = 16; - protected static final int DEFAULT_INDICATOR_WIDTH = 10; - protected static final int MARKER_WIDTH = 12; - protected static final int FONT_SIZE = 11; - protected static final int FONT_SPACING = 2; - protected static final int TEXT_PADDING = 3; - protected static final int ANNOTATION_TEXT_PADDING = 7; - //protected static final int ARROW_WIDTH = 5; - //protected static final int CONDITIONAL_INDICATOR_WIDTH = 13; - //protected static final int DEFAULT_INDICATOR_WIDTH = 8; - //protected static final int MARKER_WIDTH = 6; - //protected static final int FONT_SIZE = 8; - //protected static final int FONT_SPACING = 1; - //protected static final int TEXT_PADDING = 2; - //protected static final int ANNOTATION_TEXT_PADDING = 4; - protected static final int LINE_HEIGHT = FONT_SIZE + FONT_SPACING; - - // Colors - protected static Color TASK_BOX_COLOR = new Color(249, - 249, - 249); - protected static Color SUBPROCESS_BOX_COLOR = new Color(255, - 255, - 255); - protected static Color EVENT_COLOR = new Color(255, - 255, - 255); - protected static Color CONNECTION_COLOR = new Color(88, - 88, - 88); - protected static Color CONDITIONAL_INDICATOR_COLOR = new Color(255, - 255, - 255); - protected static Color HIGHLIGHT_COLOR = Color.GREEN; // 已流转高亮节点颜色 - protected static Color FINISHHIGHLIGHT_COLOR = Color.decode("#F68535") ; // 当前节点颜色 - protected static Color LABEL_COLOR = new Color(112, - 146, - 190); - protected static Color TASK_BORDER_COLOR = new Color(187, - 187, - 187); - protected static Color EVENT_BORDER_COLOR = new Color(88, - 88, - 88); - protected static Color SUBPROCESS_BORDER_COLOR = new Color(0, - 0, - 0); - - // Fonts - protected static Font LABEL_FONT = null; - protected static Font ANNOTATION_FONT = null; - - // Strokes - protected static Stroke THICK_TASK_BORDER_STROKE = new BasicStroke(3.0f); // 流程节点圆圈大小 - protected static Stroke GATEWAY_TYPE_STROKE = new BasicStroke(3.0f); - protected static Stroke END_EVENT_STROKE = new BasicStroke(3.0f); // 结束节点圆圈大小 - protected static Stroke MULTI_INSTANCE_STROKE = new BasicStroke(1.3f); - protected static Stroke EVENT_SUBPROCESS_STROKE = new BasicStroke(1.0f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 1.0f, - new float[]{1.0f}, - 0.0f); - protected static Stroke NON_INTERRUPTING_EVENT_STROKE = new BasicStroke(1.0f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 1.0f, - new float[]{4.0f, 3.0f}, - 0.0f); - protected static Stroke HIGHLIGHT_FLOW_STROKE = new BasicStroke(1.3f); - protected static Stroke ANNOTATION_STROKE = new BasicStroke(2.0f); - protected static Stroke ASSOCIATION_STROKE = new BasicStroke(2.0f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 1.0f, - new float[]{2.0f, 2.0f}, - 0.0f); - - // icons - protected static int ICON_PADDING = 5; - protected static TaskIconType USERTASK_IMAGE; - protected static TaskIconType SCRIPTTASK_IMAGE; - protected static TaskIconType SERVICETASK_IMAGE; - protected static TaskIconType RECEIVETASK_IMAGE; - protected static TaskIconType SENDTASK_IMAGE; - protected static TaskIconType MANUALTASK_IMAGE; - protected static TaskIconType BUSINESS_RULE_TASK_IMAGE; - - protected static IconType TIMER_IMAGE; - protected static IconType COMPENSATE_THROW_IMAGE; - protected static IconType COMPENSATE_CATCH_IMAGE; - protected static IconType ERROR_THROW_IMAGE; - protected static IconType ERROR_CATCH_IMAGE; - protected static IconType MESSAGE_CATCH_IMAGE; - protected static IconType SIGNAL_CATCH_IMAGE; - protected static IconType SIGNAL_THROW_IMAGE; - - protected int canvasWidth = -1; - protected int canvasHeight = -1; - protected int minX = -1; - protected int minY = -1; - protected ProcessDiagramSVGGraphics2D g; - protected FontMetrics fontMetrics; - protected boolean closed; - protected BufferedImage processDiagram; - protected ClassLoader customClassLoader; - protected String activityFontName = "宋体"; - protected String labelFontName = "宋体"; - protected String annotationFontName = "宋体"; - - /** - * Creates an empty canvas with given width and height. - *

- * Allows to specify minimal boundaries on the left and upper side of the - * canvas. This is useful for diagrams that have white space there. - * Everything beneath these minimum values will be cropped. - * It's also possible to pass a specific font name and a class loader for the icon images. - */ - public DefaultProcessDiagramCanvas(int width, - int height, - int minX, - int minY, - String activityFontName, - String labelFontName, - String annotationFontName) { - - this.canvasWidth = width; - this.canvasHeight = height; - this.minX = minX; - this.minY = minY; - if (activityFontName != null) { - this.activityFontName = activityFontName; - } - if (labelFontName != null) { - this.labelFontName = labelFontName; - } - if (annotationFontName != null) { - this.annotationFontName = annotationFontName; - } - - initialize(); - } - - public DefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { - this.canvasWidth = width; - this.canvasHeight = height; - this.minX = minX; - this.minY = minY; - if(activityFontName != null) { - this.activityFontName = activityFontName; - } - - if(labelFontName != null) { - this.labelFontName = labelFontName; - } - - if(annotationFontName != null) { - this.annotationFontName = annotationFontName; - } - - this.customClassLoader = customClassLoader; - this.initialize(imageType); - } - - /** - * Creates an empty canvas with given width and height. - *

- * Allows to specify minimal boundaries on the left and upper side of the - * canvas. This is useful for diagrams that have white space there (eg - * Signavio). Everything beneath these minimum values will be cropped. - * @param minX Hint that will be used when generating the image. Parts that fall - * below minX on the horizontal scale will be cropped. - * @param minY Hint that will be used when generating the image. Parts that fall - * below minX on the horizontal scale will be cropped. - */ - public DefaultProcessDiagramCanvas(int width, - int height, - int minX, - int minY) { - this.canvasWidth = width; - this.canvasHeight = height; - this.minX = minX; - this.minY = minY; - - initialize(); - } - - public void initialize(String imageType) { - if("png".equalsIgnoreCase(imageType)) { - this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 2); - } else { - this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 1); - } - - // Get a DOMImplementation. - DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); - - // Create an instance of org.w3c.dom.Document. - String svgNS = "http://www.w3.org/2000/svg"; - Document document = domImpl.createDocument(svgNS, - "svg", - null); - - // Create an instance of the SVG Generator.` - this.g = new ProcessDiagramSVGGraphics2D(document); - - this.g.setSVGCanvasSize(new Dimension(this.canvasWidth, this.canvasHeight)); - - this.g.setBackground(new Color(255, - 255, - 255, - 0)); - this.g.clearRect(0, - 0, - canvasWidth, - canvasHeight); - - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - g.setPaint(Color.black); - - Font font = new Font(activityFontName, - Font.BOLD, - FONT_SIZE); - g.setFont(font); - this.fontMetrics = g.getFontMetrics(); - - LABEL_FONT = new Font(labelFontName, - Font.ITALIC, - 10); - ANNOTATION_FONT = new Font(annotationFontName, - Font.PLAIN, - FONT_SIZE); - - USERTASK_IMAGE = new UserTaskIconType(); - SCRIPTTASK_IMAGE = new ScriptTaskIconType(); - SERVICETASK_IMAGE = new ServiceTaskIconType(); - RECEIVETASK_IMAGE = new ReceiveTaskIconType(); - SENDTASK_IMAGE = new SendTaskIconType(); - MANUALTASK_IMAGE = new ManualTaskIconType(); - BUSINESS_RULE_TASK_IMAGE = new BusinessRuleTaskIconType(); - - TIMER_IMAGE = new TimerIconType(); - COMPENSATE_THROW_IMAGE = new CompensateThrowIconType(); - COMPENSATE_CATCH_IMAGE = new CompensateIconType(); - ERROR_THROW_IMAGE = new ErrorThrowIconType(); - ERROR_CATCH_IMAGE = new ErrorIconType(); - MESSAGE_CATCH_IMAGE = new MessageIconType(); - SIGNAL_THROW_IMAGE = new SignalThrowIconType(); - SIGNAL_CATCH_IMAGE = new SignalIconType(); - } - - public void initialize() { - // Get a DOMImplementation. - DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); - - // Create an instance of org.w3c.dom.Document. - String svgNS = "http://www.w3.org/2000/svg"; - Document document = domImpl.createDocument(svgNS, - "svg", - null); - - // Create an instance of the SVG Generator. - this.g = new ProcessDiagramSVGGraphics2D(document); - - this.g.setSVGCanvasSize(new Dimension(this.canvasWidth, this.canvasHeight)); - - this.g.setBackground(new Color(255, - 255, - 255, - 0)); - this.g.clearRect(0, - 0, - canvasWidth, - canvasHeight); - - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - g.setPaint(Color.black); - - Font font = new Font(activityFontName, - Font.BOLD, - FONT_SIZE); - g.setFont(font); - this.fontMetrics = g.getFontMetrics(); - - LABEL_FONT = new Font(labelFontName, - Font.ITALIC, - 10); - ANNOTATION_FONT = new Font(annotationFontName, - Font.PLAIN, - FONT_SIZE); - - USERTASK_IMAGE = new UserTaskIconType(); - SCRIPTTASK_IMAGE = new ScriptTaskIconType(); - SERVICETASK_IMAGE = new ServiceTaskIconType(); - RECEIVETASK_IMAGE = new ReceiveTaskIconType(); - SENDTASK_IMAGE = new SendTaskIconType(); - MANUALTASK_IMAGE = new ManualTaskIconType(); - BUSINESS_RULE_TASK_IMAGE = new BusinessRuleTaskIconType(); - - TIMER_IMAGE = new TimerIconType(); - COMPENSATE_THROW_IMAGE = new CompensateThrowIconType(); - COMPENSATE_CATCH_IMAGE = new CompensateIconType(); - ERROR_THROW_IMAGE = new ErrorThrowIconType(); - ERROR_CATCH_IMAGE = new ErrorIconType(); - MESSAGE_CATCH_IMAGE = new MessageIconType(); - SIGNAL_THROW_IMAGE = new SignalThrowIconType(); - SIGNAL_CATCH_IMAGE = new SignalIconType(); - } - - /** - * Generates an image of what currently is drawn on the canvas. - *

- * Throws an {@link ActivitiImageException} when {@link #close()} is already - * called. - */ - public InputStream generateImage() { - if (closed) { - throw new ActivitiImageException("ProcessDiagramGenerator already closed"); - } - - try { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - Writer out; - out = new OutputStreamWriter(stream, - "UTF-8"); - g.stream(out, - true); - return new ByteArrayInputStream(stream.toByteArray()); - } catch (UnsupportedEncodingException | SVGGraphics2DIOException e) { - throw new ActivitiImageException("Error while generating process image", - e); - } - } - - /** - * Closes the canvas which dissallows further drawing and releases graphical - * resources. - */ - public void close() { - g.dispose(); - closed = true; - } - - public void drawNoneStartEvent(String id, - GraphicInfo graphicInfo) { - drawStartEvent(id, - graphicInfo, - null); - } - - public void drawTimerStartEvent(String id, - GraphicInfo graphicInfo) { - drawStartEvent(id, - graphicInfo, - TIMER_IMAGE); - } - - public void drawSignalStartEvent(String id, - GraphicInfo graphicInfo) { - drawStartEvent(id, - graphicInfo, - SIGNAL_CATCH_IMAGE); - } - - public void drawMessageStartEvent(String id, - GraphicInfo graphicInfo) { - drawStartEvent(id, - graphicInfo, - MESSAGE_CATCH_IMAGE); - } - - public void drawStartEvent(String id, - GraphicInfo graphicInfo, - IconType icon) { - Paint originalPaint = g.getPaint(); - g.setPaint(EVENT_COLOR); - Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), - graphicInfo.getY(), - graphicInfo.getWidth(), - graphicInfo.getHeight()); - g.fill(circle); - g.setPaint(EVENT_BORDER_COLOR); - g.draw(circle); - g.setPaint(originalPaint); - - // calculate coordinates to center image - if (icon != null) { - int imageX = (int) Math.round(graphicInfo.getX() + (graphicInfo.getWidth() / 2) - (icon.getWidth() / 2)); - int imageY = (int) Math.round(graphicInfo.getY() + (graphicInfo.getHeight() / 2) - (icon.getHeight() / 2)); - - icon.drawIcon(imageX, - imageY, - ICON_PADDING, - g); - } - - // set element's id - g.setCurrentGroupId(id); - } - - public void drawNoneEndEvent(String id, - String name, - GraphicInfo graphicInfo) { - Paint originalPaint = g.getPaint(); - Stroke originalStroke = g.getStroke(); - g.setPaint(EVENT_COLOR); - Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), - graphicInfo.getY(), - graphicInfo.getWidth(), - graphicInfo.getHeight()); - g.fill(circle); - g.setPaint(EVENT_BORDER_COLOR); - g.setStroke(END_EVENT_STROKE); - g.draw(circle); - g.setStroke(originalStroke); - g.setPaint(originalPaint); - - // set element's id - g.setCurrentGroupId(id); - - drawLabel(name, - graphicInfo); - } - - public void drawErrorEndEvent(String id, - String name, - GraphicInfo graphicInfo) { - drawNoneEndEvent(id, - name, - graphicInfo); - - int imageX = (int) (graphicInfo.getX() + (graphicInfo.getWidth() / 4)); - int imageY = (int) (graphicInfo.getY() + (graphicInfo.getHeight() / 4)); - - ERROR_THROW_IMAGE.drawIcon(imageX, - imageY, - ICON_PADDING, - g); - } - - public void drawErrorStartEvent(String id, - GraphicInfo graphicInfo) { - drawNoneStartEvent(id, - graphicInfo); - - int imageX = (int) (graphicInfo.getX() + (graphicInfo.getWidth() / 4)); - int imageY = (int) (graphicInfo.getY() + (graphicInfo.getHeight() / 4)); - - ERROR_THROW_IMAGE.drawIcon(imageX, - imageY, - ICON_PADDING, - g); - } - - public void drawCatchingEvent(String id, - GraphicInfo graphicInfo, - boolean isInterrupting, - IconType icon, - String eventType) { - - // event circles - Ellipse2D outerCircle = new Ellipse2D.Double(graphicInfo.getX(), - graphicInfo.getY(), - graphicInfo.getWidth(), - graphicInfo.getHeight()); - int innerCircleSize = 4; - int innerCircleX = (int) graphicInfo.getX() + innerCircleSize; - int innerCircleY = (int) graphicInfo.getY() + innerCircleSize; - int innerCircleWidth = (int) graphicInfo.getWidth() - (2 * innerCircleSize); - int innerCircleHeight = (int) graphicInfo.getHeight() - (2 * innerCircleSize); - Ellipse2D innerCircle = new Ellipse2D.Double(innerCircleX, - innerCircleY, - innerCircleWidth, - innerCircleHeight); - - Paint originalPaint = g.getPaint(); - Stroke originalStroke = g.getStroke(); - g.setPaint(EVENT_COLOR); - g.fill(outerCircle); - - g.setPaint(EVENT_BORDER_COLOR); - if (!isInterrupting) { - g.setStroke(NON_INTERRUPTING_EVENT_STROKE); - } - g.draw(outerCircle); - g.setStroke(originalStroke); - g.setPaint(originalPaint); - g.draw(innerCircle); - - if (icon != null) { - // calculate coordinates to center image - int imageX = (int) (graphicInfo.getX() + (graphicInfo.getWidth() / 2) - (icon.getWidth() / 2)); - int imageY = (int) (graphicInfo.getY() + (graphicInfo.getHeight() / 2) - (icon.getHeight() / 2)); - if ("timer".equals(eventType)) { - // move image one pixel to center timer image - imageX++; - imageY++; - } - icon.drawIcon(imageX, - imageY, - ICON_PADDING, - g); - } - - // set element's id - g.setCurrentGroupId(id); - } - - public void drawCatchingCompensateEvent(String id, - String name, - GraphicInfo graphicInfo, - boolean isInterrupting) { - drawCatchingCompensateEvent(id, - graphicInfo, - isInterrupting); - drawLabel(name, - graphicInfo); - } - - public void drawCatchingCompensateEvent(String id, - GraphicInfo graphicInfo, - boolean isInterrupting) { - - drawCatchingEvent(id, - graphicInfo, - isInterrupting, - COMPENSATE_CATCH_IMAGE, - "compensate"); - } - - public void drawCatchingTimerEvent(String id, - String name, - GraphicInfo graphicInfo, - boolean isInterrupting) { - drawCatchingTimerEvent(id, - graphicInfo, - isInterrupting); - drawLabel(name, - graphicInfo); - } - - public void drawCatchingTimerEvent(String id, - GraphicInfo graphicInfo, - boolean isInterrupting) { - drawCatchingEvent(id, - graphicInfo, - isInterrupting, - TIMER_IMAGE, - "timer"); - } - - public void drawCatchingErrorEvent(String id, - String name, - GraphicInfo graphicInfo, - boolean isInterrupting) { - drawCatchingErrorEvent(id, - graphicInfo, - isInterrupting); - drawLabel(name, - graphicInfo); - } - - public void drawCatchingErrorEvent(String id, - GraphicInfo graphicInfo, - boolean isInterrupting) { - - drawCatchingEvent(id, - graphicInfo, - isInterrupting, - ERROR_CATCH_IMAGE, - "error"); - } - - public void drawCatchingSignalEvent(String id, - String name, - GraphicInfo graphicInfo, - boolean isInterrupting) { - drawCatchingSignalEvent(id, - graphicInfo, - isInterrupting); - drawLabel(name, - graphicInfo); - } - - public void drawCatchingSignalEvent(String id, - GraphicInfo graphicInfo, - boolean isInterrupting) { - drawCatchingEvent(id, - graphicInfo, - isInterrupting, - SIGNAL_CATCH_IMAGE, - "signal"); - } - - public void drawCatchingMessageEvent(String id, - GraphicInfo graphicInfo, - boolean isInterrupting) { - - drawCatchingEvent(id, - graphicInfo, - isInterrupting, - MESSAGE_CATCH_IMAGE, - "message"); - } - - public void drawCatchingMessageEvent(String id, - String name, - GraphicInfo graphicInfo, - boolean isInterrupting) { - drawCatchingEvent(id, - graphicInfo, - isInterrupting, - MESSAGE_CATCH_IMAGE, - "message"); - - drawLabel(name, - graphicInfo); - } - - public void drawThrowingCompensateEvent(String id, - GraphicInfo graphicInfo) { - drawCatchingEvent(id, - graphicInfo, - true, - COMPENSATE_THROW_IMAGE, - "compensate"); - } - - public void drawThrowingSignalEvent(String id, - GraphicInfo graphicInfo) { - drawCatchingEvent(id, - graphicInfo, - true, - SIGNAL_THROW_IMAGE, - "signal"); - } - - public void drawThrowingNoneEvent(String id, - GraphicInfo graphicInfo) { - drawCatchingEvent(id, - graphicInfo, - true, - null, - "none"); - } - - public void drawSequenceflow(int srcX, - int srcY, - int targetX, - int targetY, - boolean conditional) { - drawSequenceflow(srcX, - srcY, - targetX, - targetY, - conditional, - false); - } - - public void drawSequenceflow(int srcX, - int srcY, - int targetX, - int targetY, - boolean conditional, - boolean highLighted) { - Paint originalPaint = g.getPaint(); - if (highLighted) { - g.setPaint(HIGHLIGHT_COLOR); - } - - Line2D.Double line = new Line2D.Double(srcX, - srcY, - targetX, - targetY); - g.draw(line); - drawArrowHead(line); - - if (conditional) { - drawConditionalSequenceFlowIndicator(line); - } - - if (highLighted) { - g.setPaint(originalPaint); - } - } - - public void drawSequenceflow(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, boolean highLighted, double scaleFactor) { - this.drawConnection(xPoints, yPoints, conditional, isDefault, "sequenceFlow", AssociationDirection.ONE, highLighted, scaleFactor); - } - - public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType, AssociationDirection associationDirection, boolean highLighted, double scaleFactor) { - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - this.g.setPaint(CONNECTION_COLOR); - if(connectionType.equals("association")) { - this.g.setStroke(ASSOCIATION_STROKE); - } else if(highLighted) { - this.g.setPaint(HIGHLIGHT_COLOR); - this.g.setStroke(HIGHLIGHT_FLOW_STROKE); - } - - for(int i = 1; i < xPoints.length; ++i) { - Integer sourceX = Integer.valueOf(xPoints[i - 1]); - Integer sourceY = Integer.valueOf(yPoints[i - 1]); - Integer targetX = Integer.valueOf(xPoints[i]); - Integer targetY = Integer.valueOf(yPoints[i]); - Line2D.Double line = new Line2D.Double((double)sourceX.intValue(), (double)sourceY.intValue(), (double)targetX.intValue(), (double)targetY.intValue()); - this.g.draw(line); - } - - Line2D.Double line; - if(isDefault) { - line = new Line2D.Double((double)xPoints[0], (double)yPoints[0], (double)xPoints[1], (double)yPoints[1]); - this.drawDefaultSequenceFlowIndicator(line); - } - - if(conditional) { - line = new Line2D.Double((double)xPoints[0], (double)yPoints[0], (double)xPoints[1], (double)yPoints[1]); - this.drawConditionalSequenceFlowIndicator(line); - } - - if(associationDirection.equals(AssociationDirection.ONE) || associationDirection.equals(AssociationDirection.BOTH)) { - line = new Line2D.Double((double)xPoints[xPoints.length - 2], (double)yPoints[xPoints.length - 2], (double)xPoints[xPoints.length - 1], (double)yPoints[xPoints.length - 1]); - this.drawArrowHead(line); - } - - if(associationDirection.equals(AssociationDirection.BOTH)) { - line = new Line2D.Double((double)xPoints[1], (double)yPoints[1], (double)xPoints[0], (double)yPoints[0]); - this.drawArrowHead(line); - } - - this.g.setPaint(originalPaint); - this.g.setStroke(originalStroke); - } - - public void drawAssociation(int[] xPoints, - int[] yPoints, - AssociationDirection associationDirection, - boolean highLighted) { - boolean conditional = false; - boolean isDefault = false; - drawConnection(xPoints, - yPoints, - conditional, - isDefault, - "association", - associationDirection, - highLighted); - } - - public void drawSequenceflow(int[] xPoints, - int[] yPoints, - boolean conditional, - boolean isDefault, - boolean highLighted) { - drawConnection(xPoints, - yPoints, - conditional, - isDefault, - "sequenceFlow", - AssociationDirection.ONE, - highLighted); - } - - public void drawConnection(int[] xPoints, - int[] yPoints, - boolean conditional, - boolean isDefault, - String connectionType, - AssociationDirection associationDirection, - boolean highLighted) { - - Paint originalPaint = g.getPaint(); - Stroke originalStroke = g.getStroke(); - - g.setPaint(CONNECTION_COLOR); - if ("association".equals(connectionType)) { - g.setStroke(ASSOCIATION_STROKE); - } else if (highLighted) { - g.setPaint(HIGHLIGHT_COLOR); - g.setStroke(HIGHLIGHT_FLOW_STROKE); - } - - for (int i = 1; i < xPoints.length; i++) { - Integer sourceX = xPoints[i - 1]; - Integer sourceY = yPoints[i - 1]; - Integer targetX = xPoints[i]; - Integer targetY = yPoints[i]; - Line2D.Double line = new Line2D.Double(sourceX, - sourceY, - targetX, - targetY); - g.draw(line); - } - - if (isDefault) { - Line2D.Double line = new Line2D.Double(xPoints[0], - yPoints[0], - xPoints[1], - yPoints[1]); - drawDefaultSequenceFlowIndicator(line); - } - - if (conditional) { - Line2D.Double line = new Line2D.Double(xPoints[0], - yPoints[0], - xPoints[1], - yPoints[1]); - drawConditionalSequenceFlowIndicator(line); - } - - if (associationDirection.equals(AssociationDirection.ONE) || associationDirection.equals(AssociationDirection.BOTH)) { - Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], - yPoints[xPoints.length - 2], - xPoints[xPoints.length - 1], - yPoints[xPoints.length - 1]); - drawArrowHead(line); - } - if (associationDirection.equals(AssociationDirection.BOTH)) { - Line2D.Double line = new Line2D.Double(xPoints[1], - yPoints[1], - xPoints[0], - yPoints[0]); - drawArrowHead(line); - } - g.setPaint(originalPaint); - g.setStroke(originalStroke); - } - - public void drawSequenceflowWithoutArrow(int srcX, - int srcY, - int targetX, - int targetY, - boolean conditional) { - drawSequenceflowWithoutArrow(srcX, - srcY, - targetX, - targetY, - conditional, - false); - } - - public void drawSequenceflowWithoutArrow(int srcX, - int srcY, - int targetX, - int targetY, - boolean conditional, - boolean highLighted) { - Paint originalPaint = g.getPaint(); - if (highLighted) { - g.setPaint(HIGHLIGHT_COLOR); - } - - Line2D.Double line = new Line2D.Double(srcX, - srcY, - targetX, - targetY); - g.draw(line); - - if (conditional) { - drawConditionalSequenceFlowIndicator(line); - } - - if (highLighted) { - g.setPaint(originalPaint); - } - } - - public void drawArrowHead(Line2D.Double line) { - int doubleArrowWidth = (int) (2 * ARROW_WIDTH); - if (doubleArrowWidth == 0) { - doubleArrowWidth = 2; - } - Polygon arrowHead = new Polygon(); - arrowHead.addPoint(0, - 0); - int arrowHeadPoint = (int) (-ARROW_WIDTH); - if (arrowHeadPoint == 0) { - arrowHeadPoint = -1; - } - arrowHead.addPoint(arrowHeadPoint, - -doubleArrowWidth); - arrowHeadPoint = (int) (ARROW_WIDTH); - if (arrowHeadPoint == 0) { - arrowHeadPoint = 1; - } - arrowHead.addPoint(arrowHeadPoint, - -doubleArrowWidth); - - AffineTransform transformation = new AffineTransform(); - transformation.setToIdentity(); - double angle = Math.atan2(line.y2 - line.y1, - line.x2 - line.x1); - transformation.translate(line.x2, - line.y2); - transformation.rotate((angle - Math.PI / 2d)); - - AffineTransform originalTransformation = g.getTransform(); - g.setTransform(transformation); - g.fill(arrowHead); - g.setTransform(originalTransformation); - } - - public void drawDefaultSequenceFlowIndicator(Line2D.Double line) { - double length = DEFAULT_INDICATOR_WIDTH; - double halfOfLength = length / 2; - double f = 8; - Line2D.Double defaultIndicator = new Line2D.Double(-halfOfLength, - 0, - halfOfLength, - 0); - - double angle = Math.atan2(line.y2 - line.y1, - line.x2 - line.x1); - double dx = f * Math.cos(angle); - double dy = f * Math.sin(angle); - double x1 = line.x1 + dx; - double y1 = line.y1 + dy; - - AffineTransform transformation = new AffineTransform(); - transformation.setToIdentity(); - transformation.translate(x1, - y1); - transformation.rotate((angle - 3 * Math.PI / 4)); - - AffineTransform originalTransformation = g.getTransform(); - g.setTransform(transformation); - g.draw(defaultIndicator); - - g.setTransform(originalTransformation); - } - - public void drawConditionalSequenceFlowIndicator(Line2D.Double line) { - int horizontal = (int) (CONDITIONAL_INDICATOR_WIDTH * 0.7); - int halfOfHorizontal = horizontal / 2; - int halfOfVertical = CONDITIONAL_INDICATOR_WIDTH / 2; - - Polygon conditionalIndicator = new Polygon(); - conditionalIndicator.addPoint(0, - 0); - conditionalIndicator.addPoint(-halfOfHorizontal, - halfOfVertical); - conditionalIndicator.addPoint(0, - CONDITIONAL_INDICATOR_WIDTH); - conditionalIndicator.addPoint(halfOfHorizontal, - halfOfVertical); - - AffineTransform transformation = new AffineTransform(); - transformation.setToIdentity(); - double angle = Math.atan2(line.y2 - line.y1, - line.x2 - line.x1); - transformation.translate(line.x1, - line.y1); - transformation.rotate((angle - Math.PI / 2d)); - - AffineTransform originalTransformation = g.getTransform(); - g.setTransform(transformation); - g.draw(conditionalIndicator); - - Paint originalPaint = g.getPaint(); - g.setPaint(CONDITIONAL_INDICATOR_COLOR); - g.fill(conditionalIndicator); - - g.setPaint(originalPaint); - g.setTransform(originalTransformation); - } - - public void drawTask(TaskIconType icon, - String id, - String name, - GraphicInfo graphicInfo) { - drawTask(id, - name, - graphicInfo); - - icon.drawIcon((int) graphicInfo.getX(), - (int) graphicInfo.getY(), - ICON_PADDING, - g); - } - - public void drawTask(String id, - String name, - GraphicInfo graphicInfo) { - drawTask(id, - name, - graphicInfo, - false); - } - - public void drawPoolOrLane(String id, - String name, - GraphicInfo graphicInfo) { - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - g.drawRect(x, - y, - width, - height); - - // Add the name as text, vertical - if (name != null && name.length() > 0) { - // Include some padding - int availableTextSpace = height - 6; - - // Create rotation for derived font - AffineTransform transformation = new AffineTransform(); - transformation.setToIdentity(); - transformation.rotate(270 * Math.PI / 180); - - Font currentFont = g.getFont(); - Font theDerivedFont = currentFont.deriveFont(transformation); - g.setFont(theDerivedFont); - - String truncated = fitTextToWidth(name, - availableTextSpace); - int realWidth = fontMetrics.stringWidth(truncated); - - g.drawString(truncated, - x + 2 + fontMetrics.getHeight(), - 3 + y + availableTextSpace - (availableTextSpace - realWidth) / 2); - g.setFont(currentFont); - } - - // set element's id - g.setCurrentGroupId(id); - } - - protected void drawTask(String id, - String name, - GraphicInfo graphicInfo, - boolean thickBorder) { - Paint originalPaint = g.getPaint(); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - // Create a new gradient paint for every task box, gradient depends on x and y and is not relative - g.setPaint(TASK_BOX_COLOR); - - int arcR = 6; - if (thickBorder) { - arcR = 3; - } - - // shape - RoundRectangle2D rect = new RoundRectangle2D.Double(x, - y, - width, - height, - arcR, - arcR); - g.fill(rect); - g.setPaint(TASK_BORDER_COLOR); - - if (thickBorder) { - Stroke originalStroke = g.getStroke(); - g.setStroke(THICK_TASK_BORDER_STROKE); - g.draw(rect); - g.setStroke(originalStroke); - } else { - g.draw(rect); - } - - g.setPaint(originalPaint); - // text - if (name != null && name.length() > 0) { - int boxWidth = width - (2 * TEXT_PADDING); - int boxHeight = height - 16 - ICON_PADDING - ICON_PADDING - MARKER_WIDTH - 2 - 2; - int boxX = x + width / 2 - boxWidth / 2; - int boxY = y + height / 2 - boxHeight / 2 + ICON_PADDING + ICON_PADDING - 2 - 2; - - drawMultilineCentredText(name, - boxX, - boxY, - boxWidth, - boxHeight); - - - } - - // set element's id - g.setCurrentGroupId(id); - } - - protected void drawMultilineCentredText(String text, - int x, - int y, - int boxWidth, - int boxHeight) { - drawMultilineText(text, - x, - y, - boxWidth, - boxHeight, - true); - } - - protected void drawMultilineAnnotationText(String text, - int x, - int y, - int boxWidth, - int boxHeight) { - drawMultilineText(text, - x, - y, - boxWidth, - boxHeight, - false); - } - - protected void drawMultilineText(String text, - int x, - int y, - int boxWidth, - int boxHeight, - boolean centered) { - // Create an attributed string based in input text - AttributedString attributedString = new AttributedString(text); - attributedString.addAttribute(TextAttribute.FONT, - g.getFont()); - attributedString.addAttribute(TextAttribute.FOREGROUND, - Color.black); - - AttributedCharacterIterator characterIterator = attributedString.getIterator(); - - int currentHeight = 0; - // Prepare a list of lines of text we'll be drawing - List layouts = new ArrayList(); - String lastLine = null; - - LineBreakMeasurer measurer = new LineBreakMeasurer(characterIterator, - g.getFontRenderContext()); - - TextLayout layout = null; - // while (measurer.getPosition() < characterIterator.getEndIndex() && currentHeight <= boxHeight) { - while (measurer.getPosition() < characterIterator.getEndIndex()) { - - int previousPosition = measurer.getPosition(); - - // Request next layout - layout = measurer.nextLayout(boxWidth); - - int height = ((Float) (layout.getDescent() + layout.getAscent() + layout.getLeading())).intValue(); - if (currentHeight + height > boxHeight) { - // The line we're about to add should NOT be added anymore, append three dots to previous one instead - // to indicate more text is truncated - if (!layouts.isEmpty()) { - layouts.remove(layouts.size() - 1); - - if (lastLine.length() >= 4) { - lastLine = lastLine.substring(0, - lastLine.length() - 4) + "..."; - } - layouts.add(new TextLayout(lastLine, - g.getFont(), - g.getFontRenderContext())); - } else { - // at least, draw one line - // even if text does not fit - // in order to avoid empty box - layouts.add(layout); - currentHeight += height; - } - break; - } else { - layouts.add(layout); - lastLine = text.substring(previousPosition, - measurer.getPosition()); - currentHeight += height; - } - } - int currentY = y + (centered ? ((boxHeight - currentHeight) / 2) : 0); - int currentX = 0; - - // Actually draw the lines - for (TextLayout textLayout : layouts) { - - currentY += textLayout.getAscent(); - currentX = x + (centered ? ((boxWidth - ((Double) textLayout.getBounds().getWidth()).intValue()) / 2) : 0); - - textLayout.draw(g, - currentX, - currentY); - currentY += textLayout.getDescent() + textLayout.getLeading(); - } - } - - protected String fitTextToWidth(String original, - int width) { - String text = original; - - // remove length for "..." - int maxWidth = width - 10; - - while (fontMetrics.stringWidth(text + "...") > maxWidth && text.length() > 0) { - text = text.substring(0, - text.length() - 1); - } - - if (!text.equals(original)) { - text = text + "..."; - } - - return text; - } - - public void drawUserTask(String id, - String name, - GraphicInfo graphicInfo) { - drawTask(USERTASK_IMAGE, - id, - name, - graphicInfo); - } - - public void drawScriptTask(String id, - String name, - GraphicInfo graphicInfo) { - drawTask(SCRIPTTASK_IMAGE, - id, - name, - graphicInfo); - } - - public void drawServiceTask(String id, - String name, - GraphicInfo graphicInfo) { - drawTask(SERVICETASK_IMAGE, - id, - name, - graphicInfo); - } - - public void drawReceiveTask(String id, - String name, - GraphicInfo graphicInfo) { - drawTask(RECEIVETASK_IMAGE, - id, - name, - graphicInfo); - } - - public void drawSendTask(String id, - String name, - GraphicInfo graphicInfo) { - drawTask(SENDTASK_IMAGE, - id, - name, - graphicInfo); - } - - public void drawManualTask(String id, - String name, - GraphicInfo graphicInfo) { - drawTask(MANUALTASK_IMAGE, - id, - name, - graphicInfo); - } - - public void drawBusinessRuleTask(String id, - String name, - GraphicInfo graphicInfo) { - drawTask(BUSINESS_RULE_TASK_IMAGE, - id, - name, - graphicInfo); - } - - public void drawExpandedSubProcess(String id, - String name, - GraphicInfo graphicInfo, - Class type) { - RoundRectangle2D rect = new RoundRectangle2D.Double(graphicInfo.getX(), - graphicInfo.getY(), - graphicInfo.getWidth(), - graphicInfo.getHeight(), - 8, - 8); - - if (type.equals(EventSubProcess.class)) { - Stroke originalStroke = g.getStroke(); - g.setStroke(EVENT_SUBPROCESS_STROKE); - g.draw(rect); - g.setStroke(originalStroke); - } else if (type.equals(Transaction.class)) { - RoundRectangle2D outerRect = new RoundRectangle2D.Double(graphicInfo.getX()-3, - graphicInfo.getY()-3, - graphicInfo.getWidth()+6, - graphicInfo.getHeight()+6, - 8, - 8); - - Paint originalPaint = g.getPaint(); - g.setPaint(SUBPROCESS_BOX_COLOR); - g.fill(outerRect); - g.setPaint(SUBPROCESS_BORDER_COLOR); - g.draw(outerRect); - g.setPaint(SUBPROCESS_BOX_COLOR); - g.fill(rect); - g.setPaint(SUBPROCESS_BORDER_COLOR); - g.draw(rect); - g.setPaint(originalPaint); - } else { - Paint originalPaint = g.getPaint(); - g.setPaint(SUBPROCESS_BOX_COLOR); - g.fill(rect); - g.setPaint(SUBPROCESS_BORDER_COLOR); - g.draw(rect); - g.setPaint(originalPaint); - } - - if (name != null && !name.isEmpty()) { - String text = fitTextToWidth(name, - (int) graphicInfo.getWidth()); - g.drawString(text, - (int) graphicInfo.getX() + 10, - (int) graphicInfo.getY() + 15); - } - - // set element's id - g.setCurrentGroupId(id); - } - - public void drawCollapsedSubProcess(String id, - String name, - GraphicInfo graphicInfo, - Boolean isTriggeredByEvent) { - drawCollapsedTask(id, - name, - graphicInfo, - false); - } - - public void drawCollapsedCallActivity(String id, - String name, - GraphicInfo graphicInfo) { - drawCollapsedTask(id, - name, - graphicInfo, - true); - } - - protected void drawCollapsedTask(String id, - String name, - GraphicInfo graphicInfo, - boolean thickBorder) { - // The collapsed marker is now visualized separately - drawTask(id, - name, - graphicInfo, - thickBorder); - } - - public void drawCollapsedMarker(int x, - int y, - int width, - int height) { - // rectangle - int rectangleWidth = MARKER_WIDTH; - int rectangleHeight = MARKER_WIDTH; - Rectangle rect = new Rectangle(x + (width - rectangleWidth) / 2, - y + height - rectangleHeight - 3, - rectangleWidth, - rectangleHeight); - g.draw(rect); - - // plus inside rectangle - Line2D.Double line = new Line2D.Double(rect.getCenterX(), - rect.getY() + 2, - rect.getCenterX(), - rect.getMaxY() - 2); - g.draw(line); - line = new Line2D.Double(rect.getMinX() + 2, - rect.getCenterY(), - rect.getMaxX() - 2, - rect.getCenterY()); - g.draw(line); - } - - public void drawActivityMarkers(int x, - int y, - int width, - int height, - boolean multiInstanceSequential, - boolean multiInstanceParallel, - boolean collapsed) { - if (collapsed) { - if (!multiInstanceSequential && !multiInstanceParallel) { - drawCollapsedMarker(x, - y, - width, - height); - } else { - drawCollapsedMarker(x - MARKER_WIDTH / 2 - 2, - y, - width, - height); - if (multiInstanceSequential) { - drawMultiInstanceMarker(true, - x + MARKER_WIDTH / 2 + 2, - y, - width, - height); - } else { - drawMultiInstanceMarker(false, - x + MARKER_WIDTH / 2 + 2, - y, - width, - height); - } - } - } else { - if (multiInstanceSequential) { - drawMultiInstanceMarker(true, - x, - y, - width, - height); - } else if (multiInstanceParallel) { - drawMultiInstanceMarker(false, - x, - y, - width, - height); - } - } - } - - public void drawGateway(GraphicInfo graphicInfo) { - Polygon rhombus = new Polygon(); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - - rhombus.addPoint(x, - y + (height / 2)); - rhombus.addPoint(x + (width / 2), - y + height); - rhombus.addPoint(x + width, - y + (height / 2)); - rhombus.addPoint(x + (width / 2), - y); - g.draw(rhombus); - } - - public void drawParallelGateway(String id, - GraphicInfo graphicInfo) { - // rhombus - drawGateway(graphicInfo); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - - // plus inside rhombus - Stroke orginalStroke = g.getStroke(); - g.setStroke(GATEWAY_TYPE_STROKE); - Line2D.Double line = new Line2D.Double(x + 10, - y + height / 2, - x + width - 10, - y + height / 2); // horizontal - g.draw(line); - line = new Line2D.Double(x + width / 2, - y + height - 10, - x + width / 2, - y + 10); // vertical - g.draw(line); - g.setStroke(orginalStroke); - - // set element's id - g.setCurrentGroupId(id); - } - - public void drawExclusiveGateway(String id, - GraphicInfo graphicInfo) { - // rhombus - drawGateway(graphicInfo); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - - int quarterWidth = width / 4; - int quarterHeight = height / 4; - - // X inside rhombus - Stroke orginalStroke = g.getStroke(); - g.setStroke(GATEWAY_TYPE_STROKE); - Line2D.Double line = new Line2D.Double(x + quarterWidth + 3, - y + quarterHeight + 3, - x + 3 * quarterWidth - 3, - y + 3 * quarterHeight - 3); - g.draw(line); - line = new Line2D.Double(x + quarterWidth + 3, - y + 3 * quarterHeight - 3, - x + 3 * quarterWidth - 3, - y + quarterHeight + 3); - g.draw(line); - g.setStroke(orginalStroke); - - // set element's id - g.setCurrentGroupId(id); - } - - public void drawInclusiveGateway(String id, - GraphicInfo graphicInfo) { - // rhombus - drawGateway(graphicInfo); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - - int diameter = width / 2; - - // circle inside rhombus - Stroke orginalStroke = g.getStroke(); - g.setStroke(GATEWAY_TYPE_STROKE); - Ellipse2D.Double circle = new Ellipse2D.Double(((width - diameter) / 2) + x, - ((height - diameter) / 2) + y, - diameter, - diameter); - g.draw(circle); - g.setStroke(orginalStroke); - - // set element's id - g.setCurrentGroupId(id); - } - - public void drawEventBasedGateway(String id, - GraphicInfo graphicInfo) { - // rhombus - drawGateway(graphicInfo); - - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - - double scale = .6; - - GraphicInfo eventInfo = new GraphicInfo(); - eventInfo.setX(x + width * (1 - scale) / 2); - eventInfo.setY(y + height * (1 - scale) / 2); - eventInfo.setWidth(width * scale); - eventInfo.setHeight(height * scale); - drawCatchingEvent(null, - eventInfo, - true, - null, - "eventGateway"); - - double r = width / 6.; - - // create pentagon (coords with respect to center) - int topX = (int) (.95 * r); // top right corner - int topY = (int) (-.31 * r); - int bottomX = (int) (.59 * r); // bottom right corner - int bottomY = (int) (.81 * r); - - int[] xPoints = new int[]{0, topX, bottomX, -bottomX, -topX}; - int[] yPoints = new int[]{-(int) r, topY, bottomY, bottomY, topY}; - Polygon pentagon = new Polygon(xPoints, - yPoints, - 5); - pentagon.translate(x + width / 2, - y + width / 2); - - // draw - g.drawPolygon(pentagon); - - // set element's id - g.setCurrentGroupId(id); - } - - public void drawMultiInstanceMarker(boolean sequential, - int x, - int y, - int width, - int height) { - int rectangleWidth = MARKER_WIDTH; - int rectangleHeight = MARKER_WIDTH; - int lineX = x + (width - rectangleWidth) / 2; - int lineY = y + height - rectangleHeight - 3; - - Stroke orginalStroke = g.getStroke(); - g.setStroke(MULTI_INSTANCE_STROKE); - - if (sequential) { - g.draw(new Line2D.Double(lineX, - lineY, - lineX + rectangleWidth, - lineY)); - g.draw(new Line2D.Double(lineX, - lineY + rectangleHeight / 2, - lineX + rectangleWidth, - lineY + rectangleHeight / 2)); - g.draw(new Line2D.Double(lineX, - lineY + rectangleHeight, - lineX + rectangleWidth, - lineY + rectangleHeight)); - } else { - g.draw(new Line2D.Double(lineX, - lineY, - lineX, - lineY + rectangleHeight)); - g.draw(new Line2D.Double(lineX + rectangleWidth / 2, - lineY, - lineX + rectangleWidth / 2, - lineY + rectangleHeight)); - g.draw(new Line2D.Double(lineX + rectangleWidth, - lineY, - lineX + rectangleWidth, - lineY + rectangleHeight)); - } - - g.setStroke(orginalStroke); - } - - public void drawHighLight(int x, - int y, - int width, - int height) { - Paint originalPaint = g.getPaint(); - Stroke originalStroke = g.getStroke(); - - g.setPaint(HIGHLIGHT_COLOR); - g.setStroke(THICK_TASK_BORDER_STROKE); - - RoundRectangle2D rect = new RoundRectangle2D.Double(x, - y, - width, - height, - 20, - 20); - g.draw(rect); - - g.setPaint(originalPaint); - g.setStroke(originalStroke); - } - - public void drawHighLight(int x, int y, int width, int height, Color color) { - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - this.g.setPaint(color); - this.g.setStroke(THICK_TASK_BORDER_STROKE); - RoundRectangle2D rect = new RoundRectangle2D.Double((double)x, (double)y, (double)width, (double)height, 20.0D, 20.0D); - this.g.draw(rect); - this.g.setPaint(originalPaint); - this.g.setStroke(originalStroke); - } - - public void drawHighLightEvent(int x, int y, int width, int height, Color color) { - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - Ellipse2D.Double circle = new Ellipse2D.Double(x, y, width, height); - this.g.setStroke(THICK_TASK_BORDER_STROKE); - this.g.setPaint(color); - this.g.draw(circle); - this.g.setPaint(originalPaint); - this.g.setStroke(originalStroke); - } - - public void drawHighLightGateway(int x, int y, int width, int height, Color color){ - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - Polygon rhombus = new Polygon(); - this.g.setPaint(color); - rhombus.addPoint(x, y + (height / 2)); - rhombus.addPoint(x + (width / 2), y + height); - rhombus.addPoint(x + width, y + (height / 2)); - rhombus.addPoint(x + (width / 2), y); - this.g.draw(rhombus); - this.g.setPaint(originalPaint); - this.g.setStroke(originalStroke); - } - - public void drawHighLightTask(int x, int y, int width, int height, Color color) { - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - this.g.setPaint(color); - this.g.setStroke(THICK_TASK_BORDER_STROKE); - RoundRectangle2D rect = new RoundRectangle2D.Double((double)x, (double)y, (double)width, (double)height, 10.0D, 10.0D); - this.g.draw(rect); - this.g.setPaint(originalPaint); - this.g.setStroke(originalStroke); - } - - public void drawHighLightSubProcess(int x, int y, int width, int height, Color color) { - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - this.g.setPaint(color); - this.g.setStroke(THICK_TASK_BORDER_STROKE); - RoundRectangle2D rect = new RoundRectangle2D.Double(x + 1, y + 1,width - 2, height - 2, 5.0D, 5.0D); - this.g.draw(rect); - this.g.setPaint(originalPaint); - this.g.setStroke(originalStroke); - } - - public void drawTextAnnotation(String id, - String text, - GraphicInfo graphicInfo) { - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - - Font originalFont = g.getFont(); - Stroke originalStroke = g.getStroke(); - - g.setFont(ANNOTATION_FONT); - - Path2D path = new Path2D.Double(); - x += .5; - int lineLength = 18; - path.moveTo(x + lineLength, - y); - path.lineTo(x, - y); - path.lineTo(x, - y + height); - path.lineTo(x + lineLength, - y + height); - - path.lineTo(x + lineLength, - y + height - 1); - path.lineTo(x + 1, - y + height - 1); - path.lineTo(x + 1, - y + 1); - path.lineTo(x + lineLength, - y + 1); - path.closePath(); - - g.draw(path); - - int boxWidth = width - (2 * ANNOTATION_TEXT_PADDING); - int boxHeight = height - (2 * ANNOTATION_TEXT_PADDING); - int boxX = x + width / 2 - boxWidth / 2; - int boxY = y + height / 2 - boxHeight / 2; - - if (text != null && !text.isEmpty()) { - drawMultilineAnnotationText(text, - boxX, - boxY, - boxWidth, - boxHeight); - } - - // restore originals - g.setFont(originalFont); - g.setStroke(originalStroke); - - // set element's id - g.setCurrentGroupId(id); - } - - public void drawLabel(String text, - GraphicInfo graphicInfo) { - drawLabel(text, - graphicInfo, - true); - } - - public void drawLabel(String text, - GraphicInfo graphicInfo, - boolean centered) { - float interline = 1.0f; - - // text - if (text != null && text.length() > 0) { - Paint originalPaint = g.getPaint(); - Font originalFont = g.getFont(); - - g.setPaint(SUBPROCESS_BORDER_COLOR); - g.setFont(LABEL_FONT); - - int wrapWidth = 100; - int textY = (int) graphicInfo.getY(); - - // TODO: use drawMultilineText() - AttributedString as = new AttributedString(text); - as.addAttribute(TextAttribute.FOREGROUND, - g.getPaint()); - as.addAttribute(TextAttribute.FONT, - g.getFont()); - AttributedCharacterIterator aci = as.getIterator(); - FontRenderContext frc = new FontRenderContext(null, - true, - false); - LineBreakMeasurer lbm = new LineBreakMeasurer(aci, - frc); - - while (lbm.getPosition() < text.length()) { - TextLayout tl = lbm.nextLayout(wrapWidth); - textY += tl.getAscent(); - Rectangle2D bb = tl.getBounds(); - double tX = graphicInfo.getX(); - if (centered) { - tX += (int) (graphicInfo.getWidth() / 2 - bb.getWidth() / 2); - } - tl.draw(g, - (float) tX, - textY); - textY += tl.getDescent() + tl.getLeading() + (interline - 1.0f) * tl.getAscent(); - } - - // restore originals - g.setFont(originalFont); - g.setPaint(originalPaint); - } - } - - /** - * This method makes coordinates of connection flow better. - * @param sourceShapeType - * @param targetShapeType - * @param sourceGraphicInfo - * @param targetGraphicInfo - * @param graphicInfoList - */ - public List connectionPerfectionizer(SHAPE_TYPE sourceShapeType, - SHAPE_TYPE targetShapeType, - GraphicInfo sourceGraphicInfo, - GraphicInfo targetGraphicInfo, - List graphicInfoList) { - Shape shapeFirst = createShape(sourceShapeType, - sourceGraphicInfo); - Shape shapeLast = createShape(targetShapeType, - targetGraphicInfo); - - if (graphicInfoList != null && graphicInfoList.size() > 0) { - GraphicInfo graphicInfoFirst = graphicInfoList.get(0); - GraphicInfo graphicInfoLast = graphicInfoList.get(graphicInfoList.size() - 1); - if (shapeFirst != null) { - graphicInfoFirst.setX(shapeFirst.getBounds2D().getCenterX()); - graphicInfoFirst.setY(shapeFirst.getBounds2D().getCenterY()); - } - if (shapeLast != null) { - graphicInfoLast.setX(shapeLast.getBounds2D().getCenterX()); - graphicInfoLast.setY(shapeLast.getBounds2D().getCenterY()); - } - - Point p = null; - - if (shapeFirst != null) { - Line2D.Double lineFirst = new Line2D.Double(graphicInfoFirst.getX(), - graphicInfoFirst.getY(), - graphicInfoList.get(1).getX(), - graphicInfoList.get(1).getY()); - p = getIntersection(shapeFirst, - lineFirst); - if (p != null) { - graphicInfoFirst.setX(p.getX()); - graphicInfoFirst.setY(p.getY()); - } - } - - if (shapeLast != null) { - Line2D.Double lineLast = new Line2D.Double(graphicInfoLast.getX(), - graphicInfoLast.getY(), - graphicInfoList.get(graphicInfoList.size() - 2).getX(), - graphicInfoList.get(graphicInfoList.size() - 2).getY()); - p = getIntersection(shapeLast, - lineLast); - if (p != null) { - graphicInfoLast.setX(p.getX()); - graphicInfoLast.setY(p.getY()); - } - } - } - - return graphicInfoList; - } - - /** - * This method creates shape by type and coordinates. - * @param shapeType - * @param graphicInfo - * @return Shape - */ - private static Shape createShape(SHAPE_TYPE shapeType, - GraphicInfo graphicInfo) { - if (SHAPE_TYPE.Rectangle.equals(shapeType)) { - // source is rectangle - return new Rectangle2D.Double(graphicInfo.getX(), - graphicInfo.getY(), - graphicInfo.getWidth(), - graphicInfo.getHeight()); - } else if (SHAPE_TYPE.Rhombus.equals(shapeType)) { - // source is rhombus - Path2D.Double rhombus = new Path2D.Double(); - rhombus.moveTo(graphicInfo.getX(), - graphicInfo.getY() + graphicInfo.getHeight() / 2); - rhombus.lineTo(graphicInfo.getX() + graphicInfo.getWidth() / 2, - graphicInfo.getY() + graphicInfo.getHeight()); - rhombus.lineTo(graphicInfo.getX() + graphicInfo.getWidth(), - graphicInfo.getY() + graphicInfo.getHeight() / 2); - rhombus.lineTo(graphicInfo.getX() + graphicInfo.getWidth() / 2, - graphicInfo.getY()); - rhombus.lineTo(graphicInfo.getX(), - graphicInfo.getY() + graphicInfo.getHeight() / 2); - rhombus.closePath(); - return rhombus; - } else if (SHAPE_TYPE.Ellipse.equals(shapeType)) { - // source is ellipse - return new Ellipse2D.Double(graphicInfo.getX(), - graphicInfo.getY(), - graphicInfo.getWidth(), - graphicInfo.getHeight()); - } - // unknown source element, just do not correct coordinates - return null; - } - - /** - * This method returns intersection point of shape border and line. - * @param shape - * @param line - * @return Point - */ - private static Point getIntersection(Shape shape, - Line2D.Double line) { - if (shape instanceof Ellipse2D) { - return getEllipseIntersection(shape, - line); - } else if (shape instanceof Rectangle2D || shape instanceof Path2D) { - return getShapeIntersection(shape, - line); - } else { - // something strange - return null; - } - } - - /** - * This method calculates ellipse intersection with line - * @param shape Bounds of this shape used to calculate parameters of inscribed into this bounds ellipse. - * @param line - * @return Intersection point - */ - private static Point getEllipseIntersection(Shape shape, - Line2D.Double line) { - double angle = Math.atan2(line.y2 - line.y1, - line.x2 - line.x1); - double x = shape.getBounds2D().getWidth() / 2 * Math.cos(angle) + shape.getBounds2D().getCenterX(); - double y = shape.getBounds2D().getHeight() / 2 * Math.sin(angle) + shape.getBounds2D().getCenterY(); - Point p = new Point(); - p.setLocation(x, - y); - return p; - } - - /** - * This method calculates shape intersection with line. - * @param shape - * @param line - * @return Intersection point - */ - private static Point getShapeIntersection(Shape shape, - Line2D.Double line) { - PathIterator it = shape.getPathIterator(null); - double[] coords = new double[6]; - double[] pos = new double[2]; - Line2D.Double l = new Line2D.Double(); - while (!it.isDone()) { - int type = it.currentSegment(coords); - switch (type) { - case PathIterator.SEG_MOVETO: - pos[0] = coords[0]; - pos[1] = coords[1]; - break; - case PathIterator.SEG_LINETO: - l = new Line2D.Double(pos[0], - pos[1], - coords[0], - coords[1]); - if (line.intersectsLine(l)) { - return getLinesIntersection(line, - l); - } - pos[0] = coords[0]; - pos[1] = coords[1]; - break; - case PathIterator.SEG_CLOSE: - break; - default: - // whatever - } - it.next(); - } - return null; - } - - /** - * This method calculates intersections of two lines. - * @param a Line 1 - * @param b Line 2 - * @return Intersection point - */ - private static Point getLinesIntersection(Line2D a, - Line2D b) { - double d = (a.getX1() - a.getX2()) * (b.getY2() - b.getY1()) - (a.getY1() - a.getY2()) * (b.getX2() - b.getX1()); - double da = (a.getX1() - b.getX1()) * (b.getY2() - b.getY1()) - (a.getY1() - b.getY1()) * (b.getX2() - b.getX1()); - double ta = da / d; - Point p = new Point(); - p.setLocation(a.getX1() + ta * (a.getX2() - a.getX1()), - a.getY1() + ta * (a.getY2() - a.getY1())); - return p; - } - - public InputStream generateImage(String imageType) { - if(this.closed) { - throw new ActivitiImageException("ProcessDiagramGenerator already closed"); - } else { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - try { - ImageIO.write(this.processDiagram, imageType, out); - } catch (IOException var11) { - throw new ActivitiImageException("Error while generating process image", var11); - } finally { - try { - if(out != null) { - out.close(); - } - } catch (IOException var10) { - ; - } - - } - - return new ByteArrayInputStream(out.toByteArray()); - } - } -} - - - diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/config/DefaultProcessDiagramGenerator.java b/laws-modules/src/main/java/com/jero/modules/activiti/config/DefaultProcessDiagramGenerator.java deleted file mode 100644 index efde9ee8..00000000 --- a/laws-modules/src/main/java/com/jero/modules/activiti/config/DefaultProcessDiagramGenerator.java +++ /dev/null @@ -1,1604 +0,0 @@ -package com.jero.modules.activiti.config; - -import org.activiti.bpmn.model.Event; -import org.activiti.bpmn.model.Process; -import org.activiti.bpmn.model.*; -import org.activiti.image.ProcessDiagramGenerator; -import org.activiti.image.exception.ActivitiImageException; -import org.activiti.image.exception.ActivitiInterchangeInfoNotFoundException; - -import java.awt.*; -import java.io.InputStream; -import java.util.List; -import java.util.*; - -/** - 1. Class to generate an svg based the diagram interchange information in a - 2. BPMN 2.0 process. - */ -public class DefaultProcessDiagramGenerator implements ProcessDiagramGenerator { - - private static final String DEFAULT_ACTIVITY_FONT_NAME = "宋体"; - - private static final String DEFAULT_LABEL_FONT_NAME = "宋体"; - - private static final String DEFAULT_ANNOTATION_FONT_NAME = "宋体"; - - private static final String DEFAULT_DIAGRAM_IMAGE_FILE_NAME = "/image/na.svg"; - - protected Map, ActivityDrawInstruction> activityDrawInstructions = new HashMap, ActivityDrawInstruction>(); - - protected Map, ArtifactDrawInstruction> artifactDrawInstructions = new HashMap, ArtifactDrawInstruction>(); - - @Override - public String getDefaultActivityFontName() { - return DEFAULT_ACTIVITY_FONT_NAME; - } - - @Override - public String getDefaultLabelFontName() { - return DEFAULT_LABEL_FONT_NAME; - } - - @Override - public String getDefaultAnnotationFontName() { - return DEFAULT_ANNOTATION_FONT_NAME; - } - - @Override - public String getDefaultDiagramImageFileName() { - return DEFAULT_DIAGRAM_IMAGE_FILE_NAME; - } - - // The instructions on how to draw a certain construct is - // created statically and stored in a map for performance. - public DefaultProcessDiagramGenerator() { - // start event - activityDrawInstructions.put(StartEvent.class, - new ActivityDrawInstruction() { - - @Override - public void draw( DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - StartEvent startEvent = (StartEvent) flowNode; - if (startEvent.getEventDefinitions() != null && !startEvent.getEventDefinitions().isEmpty()) { - EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0); - if (eventDefinition instanceof TimerEventDefinition) { - processDiagramCanvas.drawTimerStartEvent(flowNode.getId(), - graphicInfo); - } else if (eventDefinition instanceof ErrorEventDefinition) { - processDiagramCanvas.drawErrorStartEvent(flowNode.getId(), - graphicInfo); - } else if (eventDefinition instanceof SignalEventDefinition) { - processDiagramCanvas.drawSignalStartEvent(flowNode.getId(), - graphicInfo); - } else if (eventDefinition instanceof MessageEventDefinition) { - processDiagramCanvas.drawMessageStartEvent(flowNode.getId(), - graphicInfo); - } else { - processDiagramCanvas.drawNoneStartEvent(flowNode.getId(), - graphicInfo); - } - } else { - processDiagramCanvas.drawNoneStartEvent(flowNode.getId(), - graphicInfo); - } - } - }); - - // signal catch - activityDrawInstructions.put(IntermediateCatchEvent.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent) flowNode; - if (intermediateCatchEvent.getEventDefinitions() != null && !intermediateCatchEvent.getEventDefinitions() - .isEmpty()) { - if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { - processDiagramCanvas.drawCatchingSignalEvent(flowNode.getId(), - flowNode.getName(), - graphicInfo, - true); - } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) { - processDiagramCanvas.drawCatchingTimerEvent(flowNode.getId(), - flowNode.getName(), - graphicInfo, - true); - } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) { - processDiagramCanvas.drawCatchingMessageEvent(flowNode.getId(), - flowNode.getName(), - graphicInfo, - true); - } - } - } - }); - - // signal throw - activityDrawInstructions.put(ThrowEvent.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - ThrowEvent throwEvent = (ThrowEvent) flowNode; - if (throwEvent.getEventDefinitions() != null && !throwEvent.getEventDefinitions().isEmpty()) { - if (throwEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { - processDiagramCanvas.drawThrowingSignalEvent(flowNode.getId(), - graphicInfo); - } else if (throwEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) { - processDiagramCanvas.drawThrowingCompensateEvent(flowNode.getId(), - graphicInfo); - } else { - processDiagramCanvas.drawThrowingNoneEvent(flowNode.getId(), - graphicInfo); - } - } else { - processDiagramCanvas.drawThrowingNoneEvent(flowNode.getId(), - graphicInfo); - } - } - }); - - // end event - activityDrawInstructions.put(EndEvent.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - EndEvent endEvent = (EndEvent) flowNode; - if (endEvent.getEventDefinitions() != null && !endEvent.getEventDefinitions().isEmpty()) { - if (endEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) { - processDiagramCanvas.drawErrorEndEvent(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } else { - processDiagramCanvas.drawNoneEndEvent(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - } else { - processDiagramCanvas.drawNoneEndEvent(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - } - }); - - // task - activityDrawInstructions.put(Task.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawTask(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - }); - - // user task - activityDrawInstructions.put(UserTask.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawUserTask(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - }); - - // script task - activityDrawInstructions.put(ScriptTask.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawScriptTask(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - }); - - // service task - activityDrawInstructions.put(ServiceTask.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - ServiceTask serviceTask = (ServiceTask) flowNode; - processDiagramCanvas.drawServiceTask(flowNode.getId(), - serviceTask.getName(), - graphicInfo); - } - }); - - // receive task - activityDrawInstructions.put(ReceiveTask.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawReceiveTask(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - }); - - // send task - activityDrawInstructions.put(SendTask.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawSendTask(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - }); - - // manual task - activityDrawInstructions.put(ManualTask.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawManualTask(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - }); - - // businessRuleTask task - activityDrawInstructions.put(BusinessRuleTask.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawBusinessRuleTask(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - }); - - // exclusive gateway - activityDrawInstructions.put(ExclusiveGateway.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawExclusiveGateway(flowNode.getId(), - graphicInfo); - } - }); - - // inclusive gateway - activityDrawInstructions.put(InclusiveGateway.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawInclusiveGateway(flowNode.getId(), - graphicInfo); - } - }); - - // parallel gateway - activityDrawInstructions.put(ParallelGateway.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawParallelGateway(flowNode.getId(), - graphicInfo); - } - }); - - // event based gateway - activityDrawInstructions.put(EventGateway.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawEventBasedGateway(flowNode.getId(), - graphicInfo); - } - }); - - // Boundary timer - activityDrawInstructions.put(BoundaryEvent.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - BoundaryEvent boundaryEvent = (BoundaryEvent) flowNode; - if (boundaryEvent.getEventDefinitions() != null && !boundaryEvent.getEventDefinitions().isEmpty()) { - if (boundaryEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) { - - processDiagramCanvas.drawCatchingTimerEvent(flowNode.getId(), - flowNode.getName(), - graphicInfo, - boundaryEvent.isCancelActivity()); - } else if (boundaryEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) { - - processDiagramCanvas.drawCatchingErrorEvent(flowNode.getId(), - graphicInfo, - boundaryEvent.isCancelActivity()); - } else if (boundaryEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { - processDiagramCanvas.drawCatchingSignalEvent(flowNode.getId(), - flowNode.getName(), - graphicInfo, - boundaryEvent.isCancelActivity()); - } else if (boundaryEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) { - processDiagramCanvas.drawCatchingMessageEvent(flowNode.getId(), - flowNode.getName(), - graphicInfo, - boundaryEvent.isCancelActivity()); - } else if (boundaryEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) { - processDiagramCanvas.drawCatchingCompensateEvent(flowNode.getId(), - graphicInfo, - boundaryEvent.isCancelActivity()); - } - } - } - }); - - // subprocess - activityDrawInstructions.put(SubProcess.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - processDiagramCanvas.drawCollapsedSubProcess(flowNode.getId(), - flowNode.getName(), - graphicInfo, - false); - } else { - processDiagramCanvas.drawExpandedSubProcess(flowNode.getId(), - flowNode.getName(), - graphicInfo, - SubProcess.class); - } - } - }); - // transaction - activityDrawInstructions.put(Transaction.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - processDiagramCanvas.drawCollapsedSubProcess(flowNode.getId(), - flowNode.getName(), - graphicInfo, - false); - } else { - processDiagramCanvas.drawExpandedSubProcess(flowNode.getId(), - flowNode.getName(), - graphicInfo, - Transaction.class); - } - } - }); - - // Event subprocess - activityDrawInstructions.put(EventSubProcess.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - processDiagramCanvas.drawCollapsedSubProcess(flowNode.getId(), - flowNode.getName(), - graphicInfo, - true); - } else { - processDiagramCanvas.drawExpandedSubProcess(flowNode.getId(), - flowNode.getName(), - graphicInfo, - EventSubProcess.class); - } - } - }); - - // call activity - activityDrawInstructions.put(CallActivity.class, - new ActivityDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawCollapsedCallActivity(flowNode.getId(), - flowNode.getName(), - graphicInfo); - } - }); - - // text annotation - artifactDrawInstructions.put(TextAnnotation.class, - new ArtifactDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - Artifact artifact) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); - TextAnnotation textAnnotation = (TextAnnotation) artifact; - processDiagramCanvas.drawTextAnnotation(textAnnotation.getId(), - textAnnotation.getText(), - graphicInfo); - } - }); - - // association - artifactDrawInstructions.put(Association.class, - new ArtifactDrawInstruction() { - - @Override - public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - Artifact artifact) { - Association association = (Association) artifact; - String sourceRef = association.getSourceRef(); - String targetRef = association.getTargetRef(); - - // source and target can be instance of FlowElement or Artifact - BaseElement sourceElement = bpmnModel.getFlowElement(sourceRef); - BaseElement targetElement = bpmnModel.getFlowElement(targetRef); - if (sourceElement == null) { - sourceElement = bpmnModel.getArtifact(sourceRef); - } - if (targetElement == null) { - targetElement = bpmnModel.getArtifact(targetRef); - } - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); - graphicInfoList = connectionPerfectionizer(processDiagramCanvas, - bpmnModel, - sourceElement, - targetElement, - graphicInfoList); - int xPoints[] = new int[graphicInfoList.size()]; - int yPoints[] = new int[graphicInfoList.size()]; - for (int i = 1; i < graphicInfoList.size(); i++) { - GraphicInfo graphicInfo = graphicInfoList.get(i); - GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); - - if (i == 1) { - xPoints[0] = (int) previousGraphicInfo.getX(); - yPoints[0] = (int) previousGraphicInfo.getY(); - } - xPoints[i] = (int) graphicInfo.getX(); - yPoints[i] = (int) graphicInfo.getY(); - } - - AssociationDirection associationDirection = association.getAssociationDirection(); - processDiagramCanvas.drawAssociation(xPoints, - yPoints, - associationDirection, - false); - } - }); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, - List highLightedActivities, - List highLightedFlows, - String activityFontName, - String labelFontName, - String annotationFontName) { - return generateDiagram(bpmnModel, - highLightedActivities, - highLightedFlows, - activityFontName, - labelFontName, - annotationFontName, - false, - null); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, - List highLightedActivities, - List highLightedFlows, - String activityFontName, - String labelFontName, - String annotationFontName, - boolean generateDefaultDiagram) { - return generateDiagram(bpmnModel, - highLightedActivities, - highLightedFlows, - activityFontName, - labelFontName, - annotationFontName, - generateDefaultDiagram, - null); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, - List highLightedActivities, - List highLightedFlows, - String activityFontName, - String labelFontName, - String annotationFontName, - boolean generateDefaultDiagram, - String defaultDiagramImageFileName) { - - if (!bpmnModel.hasDiagramInterchangeInfo()) { - if (!generateDefaultDiagram) { - throw new ActivitiInterchangeInfoNotFoundException("No interchange information found."); - } - - return getDefaultDiagram(defaultDiagramImageFileName); - } - - return generateProcessDiagram(bpmnModel, - highLightedActivities, - highLightedFlows, - activityFontName, - labelFontName, - annotationFontName).generateImage(); - } - - /** - * Get default diagram image as bytes array - * @return the default diagram image - */ - protected InputStream getDefaultDiagram(String diagramImageFileName) { - String imageFileName = diagramImageFileName != null ? - diagramImageFileName : - getDefaultDiagramImageFileName(); - InputStream imageStream = getClass().getResourceAsStream(imageFileName); - if (imageStream == null) { - throw new ActivitiImageException("Error occurred while getting default diagram image from file: " + imageFileName); - } - return imageStream; - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, - List highLightedActivities, - List highLightedFlows) { - return generateDiagram(bpmnModel, - highLightedActivities, - highLightedFlows, - null, - null, - null, - false, - null); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, - List highLightedActivities) { - return generateDiagram(bpmnModel, - highLightedActivities, - Collections.emptyList()); - } - - @Override - public InputStream generateDiagram(BpmnModel bpmnModel, - String activityFontName, - String labelFontName, - String annotationFontName) { - - return generateDiagram(bpmnModel, - Collections.emptyList(), - Collections.emptyList(), - activityFontName, - labelFontName, - annotationFontName); - } - - protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, - List highLightedActivities, - List highLightedFlows, - String activityFontName, - String labelFontName, - String annotationFontName) { - - prepareBpmnModel(bpmnModel); - - DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, - activityFontName, - labelFontName, - annotationFontName); - - // Draw pool shape, if process is participant in collaboration - for (Pool pool : bpmnModel.getPools()) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); - processDiagramCanvas.drawPoolOrLane(pool.getId(), - pool.getName(), - graphicInfo); - } - - // Draw lanes - for (Process process : bpmnModel.getProcesses()) { - for (Lane lane : process.getLanes()) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId()); - processDiagramCanvas.drawPoolOrLane(lane.getId(), - lane.getName(), - graphicInfo); - } - } - - // Draw activities and their sequence-flows - for (Process process : bpmnModel.getProcesses()) { - for (FlowNode flowNode : process.findFlowElementsOfType(FlowNode.class)) { - drawActivity(processDiagramCanvas, - bpmnModel, - flowNode, - highLightedActivities, - highLightedFlows); - } - } - - // Draw artifacts - for (Process process : bpmnModel.getProcesses()) { - - for (Artifact artifact : process.getArtifacts()) { - drawArtifact(processDiagramCanvas, - bpmnModel, - artifact); - } - - List subProcesses = process.findFlowElementsOfType(SubProcess.class, - true); - if (subProcesses != null) { - for (SubProcess subProcess : subProcesses) { - for (Artifact subProcessArtifact : subProcess.getArtifacts()) { - drawArtifact(processDiagramCanvas, - bpmnModel, - subProcessArtifact); - } - } - } - } - - return processDiagramCanvas; - } - - protected void prepareBpmnModel(BpmnModel bpmnModel) { - - // Need to make sure all elements have positive x and y. - // Check all graphicInfo and update the elements accordingly - - List allGraphicInfos = new ArrayList(); - if (bpmnModel.getLocationMap() != null) { - allGraphicInfos.addAll(bpmnModel.getLocationMap().values()); - } - if (bpmnModel.getLabelLocationMap() != null) { - allGraphicInfos.addAll(bpmnModel.getLabelLocationMap().values()); - } - if (bpmnModel.getFlowLocationMap() != null) { - for (List flowGraphicInfos : bpmnModel.getFlowLocationMap().values()) { - allGraphicInfos.addAll(flowGraphicInfos); - } - } - - if (allGraphicInfos.size() > 0) { - - boolean needsTranslationX = false; - boolean needsTranslationY = false; - - double lowestX = 0.0; - double lowestY = 0.0; - - // Collect lowest x and y - for (GraphicInfo graphicInfo : allGraphicInfos) { - - double x = graphicInfo.getX(); - double y = graphicInfo.getY(); - - if (x < lowestX) { - needsTranslationX = true; - lowestX = x; - } - if (y < lowestY) { - needsTranslationY = true; - lowestY = y; - } - } - - // Update all graphicInfo objects - if (needsTranslationX || needsTranslationY) { - - double translationX = Math.abs(lowestX); - double translationY = Math.abs(lowestY); - - for (GraphicInfo graphicInfo : allGraphicInfos) { - if (needsTranslationX) { - graphicInfo.setX(graphicInfo.getX() + translationX); - } - if (needsTranslationY) { - graphicInfo.setY(graphicInfo.getY() + translationY); - } - } - } - } - } - - protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode, - List highLightedActivities, - List highLightedFlows) { - - ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass()); - if (drawInstruction != null) { - - drawInstruction.draw(processDiagramCanvas, - bpmnModel, - flowNode); - - // Gather info on the multi instance marker - boolean multiInstanceSequential = false; - boolean multiInstanceParallel = false; - boolean collapsed = false; - if (flowNode instanceof Activity) { - Activity activity = (Activity) flowNode; - MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics(); - if (multiInstanceLoopCharacteristics != null) { - multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential(); - multiInstanceParallel = !multiInstanceSequential; - } - } - - // Gather info on the collapsed marker - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (flowNode instanceof SubProcess) { - collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded(); - } else if (flowNode instanceof CallActivity) { - collapsed = true; - } - - // Actually draw the markers - processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), - (int) graphicInfo.getY(), - (int) graphicInfo.getWidth(), - (int) graphicInfo.getHeight(), - multiInstanceSequential, - multiInstanceParallel, - collapsed); - - // Draw highlighted activities - if (highLightedActivities.contains(flowNode.getId())) { - drawHighLight(processDiagramCanvas, - bpmnModel.getGraphicInfo(flowNode.getId())); - } - } - - // Outgoing transitions of activity - for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { - boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId())); - String defaultFlow = null; - if (flowNode instanceof Activity) { - defaultFlow = ((Activity) flowNode).getDefaultFlow(); - } else if (flowNode instanceof Gateway) { - defaultFlow = ((Gateway) flowNode).getDefaultFlow(); - } - - boolean isDefault = false; - if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) { - isDefault = true; - } - boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway); - - String sourceRef = sequenceFlow.getSourceRef(); - String targetRef = sequenceFlow.getTargetRef(); - FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef); - FlowElement targetElement = bpmnModel.getFlowElement(targetRef); - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); - if (graphicInfoList != null && graphicInfoList.size() > 0) { - graphicInfoList = connectionPerfectionizer(processDiagramCanvas, - bpmnModel, - sourceElement, - targetElement, - graphicInfoList); - int xPoints[] = new int[graphicInfoList.size()]; - int yPoints[] = new int[graphicInfoList.size()]; - - for (int i = 1; i < graphicInfoList.size(); i++) { - GraphicInfo graphicInfo = graphicInfoList.get(i); - GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); - - if (i == 1) { - xPoints[0] = (int) previousGraphicInfo.getX(); - yPoints[0] = (int) previousGraphicInfo.getY(); - } - xPoints[i] = (int) graphicInfo.getX(); - yPoints[i] = (int) graphicInfo.getY(); - } - - processDiagramCanvas.drawSequenceflow(xPoints, - yPoints, - drawConditionalIndicator, - isDefault, - highLighted); - - // Draw sequenceflow label - GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId()); - if (labelGraphicInfo != null) { - processDiagramCanvas.drawLabel(sequenceFlow.getName(), - labelGraphicInfo, - false); - } - } - } - - // Nested elements - if (flowNode instanceof FlowElementsContainer) { - for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) { - if (nestedFlowElement instanceof FlowNode) { - drawActivity(processDiagramCanvas, - bpmnModel, - (FlowNode) nestedFlowElement, - highLightedActivities, - highLightedFlows); - } - } - } - } - - /** - * This method makes coordinates of connection flow better. - * @param processDiagramCanvas - * @param bpmnModel - * @param sourceElement - * @param targetElement - * @param graphicInfoList - * @return - */ - protected static List connectionPerfectionizer(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - BaseElement sourceElement, - BaseElement targetElement, - List graphicInfoList) { - GraphicInfo sourceGraphicInfo = bpmnModel.getGraphicInfo(sourceElement.getId()); - GraphicInfo targetGraphicInfo = bpmnModel.getGraphicInfo(targetElement.getId()); - - DefaultProcessDiagramCanvas.SHAPE_TYPE sourceShapeType = getShapeType(sourceElement); - DefaultProcessDiagramCanvas.SHAPE_TYPE targetShapeType = getShapeType(targetElement); - - return processDiagramCanvas.connectionPerfectionizer(sourceShapeType, - targetShapeType, - sourceGraphicInfo, - targetGraphicInfo, - graphicInfoList); - } - - /** - * This method returns shape type of base element.
- * Each element can be presented as rectangle, rhombus, or ellipse. - * @param baseElement - * @return DefaultProcessDiagramCanvas.SHAPE_TYPE - */ - protected static DefaultProcessDiagramCanvas.SHAPE_TYPE getShapeType(BaseElement baseElement) { - if (baseElement instanceof Task || baseElement instanceof Activity || baseElement instanceof TextAnnotation) { - return DefaultProcessDiagramCanvas.SHAPE_TYPE.Rectangle; - } else if (baseElement instanceof Gateway) { - return DefaultProcessDiagramCanvas.SHAPE_TYPE.Rhombus; - } else if (baseElement instanceof Event) { - return DefaultProcessDiagramCanvas.SHAPE_TYPE.Ellipse; - } - // unknown source element, just do not correct coordinates - return null; - } - - protected static GraphicInfo getLineCenter(List graphicInfoList) { - GraphicInfo gi = new GraphicInfo(); - - int xPoints[] = new int[graphicInfoList.size()]; - int yPoints[] = new int[graphicInfoList.size()]; - - double length = 0; - double[] lengths = new double[graphicInfoList.size()]; - lengths[0] = 0; - double m; - for (int i = 1; i < graphicInfoList.size(); i++) { - GraphicInfo graphicInfo = graphicInfoList.get(i); - GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); - - if (i == 1) { - xPoints[0] = (int) previousGraphicInfo.getX(); - yPoints[0] = (int) previousGraphicInfo.getY(); - } - xPoints[i] = (int) graphicInfo.getX(); - yPoints[i] = (int) graphicInfo.getY(); - - length += Math.sqrt( - Math.pow((int) graphicInfo.getX() - (int) previousGraphicInfo.getX(), - 2) + - Math.pow((int) graphicInfo.getY() - (int) previousGraphicInfo.getY(), - 2) - ); - lengths[i] = length; - } - m = length / 2; - int p1 = 0; - int p2 = 1; - for (int i = 1; i < lengths.length; i++) { - double len = lengths[i]; - p1 = i - 1; - p2 = i; - if (len > m) { - break; - } - } - - GraphicInfo graphicInfo1 = graphicInfoList.get(p1); - GraphicInfo graphicInfo2 = graphicInfoList.get(p2); - - double AB = (int) graphicInfo2.getX() - (int) graphicInfo1.getX(); - double OA = (int) graphicInfo2.getY() - (int) graphicInfo1.getY(); - double OB = lengths[p2] - lengths[p1]; - double ob = m - lengths[p1]; - double ab = AB * ob / OB; - double oa = OA * ob / OB; - - double mx = graphicInfo1.getX() + ab; - double my = graphicInfo1.getY() + oa; - - gi.setX(mx); - gi.setY(my); - return gi; - } - - protected void drawArtifact(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - Artifact artifact) { - - ArtifactDrawInstruction drawInstruction = artifactDrawInstructions.get(artifact.getClass()); - if (drawInstruction != null) { - drawInstruction.draw(processDiagramCanvas, - bpmnModel, - artifact); - } - } - - private static void drawHighLight(DefaultProcessDiagramCanvas processDiagramCanvas, - GraphicInfo graphicInfo) { - processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), - (int) graphicInfo.getY(), - (int) graphicInfo.getWidth(), - (int) graphicInfo.getHeight()); - } - - private static void drawHighLight(DefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo, Color color, FlowNode flowNode) { - if(flowNode instanceof Event){ - processDiagramCanvas.drawHighLightEvent((int)graphicInfo.getX(), (int)graphicInfo.getY(), (int)graphicInfo.getWidth(), (int)graphicInfo.getHeight(),color); - }else if(flowNode instanceof Gateway){ - processDiagramCanvas.drawHighLightGateway((int)graphicInfo.getX(), (int)graphicInfo.getY(), (int)graphicInfo.getWidth(), (int)graphicInfo.getHeight(),color); - }else if(flowNode instanceof Task){ - processDiagramCanvas.drawHighLightTask((int)graphicInfo.getX(), (int)graphicInfo.getY(), (int)graphicInfo.getWidth(), (int)graphicInfo.getHeight(),color); - }else if(flowNode instanceof SubProcess){ - processDiagramCanvas.drawHighLightSubProcess((int)graphicInfo.getX(), (int)graphicInfo.getY(), (int)graphicInfo.getWidth(), (int)graphicInfo.getHeight(),color); - }else{ - processDiagramCanvas.drawHighLight((int)graphicInfo.getX(), (int)graphicInfo.getY(), (int)graphicInfo.getWidth(), (int)graphicInfo.getHeight(),color); - } - } - - protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, - String activityFontName, - String labelFontName, - String annotationFontName) { - - // We need to calculate maximum values to know how big the image will be in its entirety - double minX = Double.MAX_VALUE; - double maxX = 0; - double minY = Double.MAX_VALUE; - double maxY = 0; - - for (Pool pool : bpmnModel.getPools()) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); - minX = graphicInfo.getX(); - maxX = graphicInfo.getX() + graphicInfo.getWidth(); - minY = graphicInfo.getY(); - maxY = graphicInfo.getY() + graphicInfo.getHeight(); - } - - List flowNodes = gatherAllFlowNodes(bpmnModel); - for (FlowNode flowNode : flowNodes) { - - GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - - if (flowNodeGraphicInfo == null) { - continue; - } - - // width - if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) { - maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth(); - } - if (flowNodeGraphicInfo.getX() < minX) { - minX = flowNodeGraphicInfo.getX(); - } - // height - if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) { - maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight(); - } - if (flowNodeGraphicInfo.getY() < minY) { - minY = flowNodeGraphicInfo.getY(); - } - - for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); - if (graphicInfoList != null) { - for (GraphicInfo graphicInfo : graphicInfoList) { - // width - if (graphicInfo.getX() > maxX) { - maxX = graphicInfo.getX(); - } - if (graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - // height - if (graphicInfo.getY() > maxY) { - maxY = graphicInfo.getY(); - } - if (graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - } - } - - List artifacts = gatherAllArtifacts(bpmnModel); - for (Artifact artifact : artifacts) { - - GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); - - if (artifactGraphicInfo != null) { - // width - if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) { - maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth(); - } - if (artifactGraphicInfo.getX() < minX) { - minX = artifactGraphicInfo.getX(); - } - // height - if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) { - maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight(); - } - if (artifactGraphicInfo.getY() < minY) { - minY = artifactGraphicInfo.getY(); - } - } - - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); - if (graphicInfoList != null) { - for (GraphicInfo graphicInfo : graphicInfoList) { - // width - if (graphicInfo.getX() > maxX) { - maxX = graphicInfo.getX(); - } - if (graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - // height - if (graphicInfo.getY() > maxY) { - maxY = graphicInfo.getY(); - } - if (graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - } - - int nrOfLanes = 0; - for (Process process : bpmnModel.getProcesses()) { - for (Lane l : process.getLanes()) { - - nrOfLanes++; - - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId()); - if (graphicInfo != null) { - // width - if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) { - maxX = graphicInfo.getX() + graphicInfo.getWidth(); - } - if (graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - // height - if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) { - maxY = graphicInfo.getY() + graphicInfo.getHeight(); - } - if (graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - } - - // Special case, see https://activiti.atlassian.net/browse/ACT-1431 - if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) { - // Nothing to show - minX = 0; - minY = 0; - } - - return new DefaultProcessDiagramCanvas((int) maxX + 10, - (int) maxY + 10, - (int) minX, - (int) minY, - activityFontName, - labelFontName, - annotationFontName); - } - - protected static List gatherAllArtifacts(BpmnModel bpmnModel) { - List artifacts = new ArrayList(); - for (Process process : bpmnModel.getProcesses()) { - artifacts.addAll(process.getArtifacts()); - } - return artifacts; - } - - protected static List gatherAllFlowNodes(BpmnModel bpmnModel) { - List flowNodes = new ArrayList(); - for (Process process : bpmnModel.getProcesses()) { - flowNodes.addAll(gatherAllFlowNodes(process)); - } - return flowNodes; - } - - protected static List gatherAllFlowNodes(FlowElementsContainer flowElementsContainer) { - List flowNodes = new ArrayList(); - for (FlowElement flowElement : flowElementsContainer.getFlowElements()) { - if (flowElement instanceof FlowNode) { - flowNodes.add((FlowNode) flowElement); - } - if (flowElement instanceof FlowElementsContainer) { - flowNodes.addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement)); - } - } - return flowNodes; - } - - public Map, ActivityDrawInstruction> getActivityDrawInstructions() { - return activityDrawInstructions; - } - - public void setActivityDrawInstructions( - Map, ActivityDrawInstruction> activityDrawInstructions) { - this.activityDrawInstructions = activityDrawInstructions; - } - - public Map, ArtifactDrawInstruction> getArtifactDrawInstructions() { - return artifactDrawInstructions; - } - - public void setArtifactDrawInstructions( - Map, ArtifactDrawInstruction> artifactDrawInstructions) { - this.artifactDrawInstructions = artifactDrawInstructions; - } - - protected interface ActivityDrawInstruction { - - void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - FlowNode flowNode); - } - - protected interface ArtifactDrawInstruction { - - void draw(DefaultProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, - Artifact artifact); - } - - public InputStream generateDiagram(BpmnModel bpmnModel, String imageType,List highLightedFinishes, List highLightedActivities, List highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, List runningActivityIdList) { - return this.generateProcessDiagram(bpmnModel, imageType,highLightedFinishes, highLightedActivities, highLightedFlows, activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor, runningActivityIdList).generateImage(); - } - - protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType,List highLightedFinishes, List highLightedActivities, List highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, List runningActivityIdList) { - this.prepareBpmnModel(bpmnModel); - DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); - Iterator var12 = bpmnModel.getPools().iterator(); - - while(var12.hasNext()) { - Pool pool = (Pool)var12.next(); - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); - processDiagramCanvas.drawPoolOrLane(pool.getId(), pool.getName(), graphicInfo); - } - - var12 = bpmnModel.getProcesses().iterator(); - - Process process; - Iterator var20; - while(var12.hasNext()) { - process = (Process)var12.next(); - var20 = process.getLanes().iterator(); - - while(var20.hasNext()) { - Lane lane = (Lane)var20.next(); - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId()); - processDiagramCanvas.drawPoolOrLane(lane.getId(), lane.getName(), graphicInfo); - } - } - - var12 = bpmnModel.getProcesses().iterator(); - while(var12.hasNext()) { - process = (Process)var12.next(); - var20 = process.findFlowElementsOfType(FlowNode.class).iterator(); - - while(var20.hasNext()) { - FlowNode flowNode = (FlowNode)var20.next(); - this.drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedFinishes,highLightedActivities, highLightedFlows, scaleFactor, runningActivityIdList); - } - } - - var12 = bpmnModel.getProcesses().iterator(); - - while(true) { - List subProcesses; - do { - if(!var12.hasNext()) { - return processDiagramCanvas; - } - - process = (Process)var12.next(); - var20 = process.getArtifacts().iterator(); - - while(var20.hasNext()) { - Artifact artifact = (Artifact)var20.next(); - this.drawArtifact(processDiagramCanvas, bpmnModel, artifact); - } - - subProcesses = process.findFlowElementsOfType(SubProcess.class, true); - } while(subProcesses == null); - - Iterator var24 = subProcesses.iterator(); - - while(var24.hasNext()) { - SubProcess subProcess = (SubProcess)var24.next(); - Iterator var17 = subProcess.getArtifacts().iterator(); - - while(var17.hasNext()) { - Artifact subProcessArtifact = (Artifact)var17.next(); - this.drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact); - } - } - } - } - - protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { - //double minX = 1.7976931348623157E308D; - //double maxX = 0.0D; - //double minY = 1.7976931348623157E308D; - //double maxY = 0.0D; - - double minX = 10; - double maxX = 2; - double minY = 6; - double maxY = 0.0D; - - GraphicInfo graphicInfo; - for(Iterator var14 = bpmnModel.getPools().iterator(); var14.hasNext(); maxY = graphicInfo.getY() + graphicInfo.getHeight()) { - Pool pool = (Pool)var14.next(); - graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); - minX = graphicInfo.getX(); - maxX = graphicInfo.getX() + graphicInfo.getWidth(); - minY = graphicInfo.getY(); - } - - List flowNodes = gatherAllFlowNodes(bpmnModel); - Iterator var24 = flowNodes.iterator(); - - label155: - while(var24.hasNext()) { - FlowNode flowNode = (FlowNode)var24.next(); - GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if(flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) { - maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth(); - } - - if(flowNodeGraphicInfo.getX() < minX) { - minX = flowNodeGraphicInfo.getX(); - } - - if(flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) { - maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight(); - } - - if(flowNodeGraphicInfo.getY() < minY) { - minY = flowNodeGraphicInfo.getY(); - } - - Iterator var18 = flowNode.getOutgoingFlows().iterator(); - - while(true) { - List graphicInfoList; - do { - if(!var18.hasNext()) { - continue label155; - } - - SequenceFlow sequenceFlow = (SequenceFlow)var18.next(); - graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); - } while(graphicInfoList == null); - - Iterator var21 = graphicInfoList.iterator(); - - while(var21.hasNext()) { - graphicInfo = (GraphicInfo)var21.next(); - if(graphicInfo.getX() > maxX) { - maxX = graphicInfo.getX(); - } - - if(graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - - if(graphicInfo.getY() > maxY) { - maxY = graphicInfo.getY(); - } - - if(graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - } - - List artifacts = gatherAllArtifacts(bpmnModel); - Iterator var27 = artifacts.iterator(); - - while(var27.hasNext()) { - Artifact artifact = (Artifact)var27.next(); - GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); - if(artifactGraphicInfo != null) { - if(artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) { - maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth(); - } - - if(artifactGraphicInfo.getX() < minX) { - minX = artifactGraphicInfo.getX(); - } - - if(artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) { - maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight(); - } - - if(artifactGraphicInfo.getY() < minY) { - minY = artifactGraphicInfo.getY(); - } - } - - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); - if(graphicInfoList != null) { - Iterator var35 = graphicInfoList.iterator(); - - while(var35.hasNext()) { - graphicInfo = (GraphicInfo)var35.next(); - if(graphicInfo.getX() > maxX) { - maxX = graphicInfo.getX(); - } - - if(graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - - if(graphicInfo.getY() > maxY) { - maxY = graphicInfo.getY(); - } - - if(graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - } - - int nrOfLanes = 0; - Iterator var30 = bpmnModel.getProcesses().iterator(); - - while(var30.hasNext()) { - Process process = (Process)var30.next(); - Iterator var34 = process.getLanes().iterator(); - - while(var34.hasNext()) { - Lane l = (Lane)var34.next(); - ++nrOfLanes; - graphicInfo = bpmnModel.getGraphicInfo(l.getId()); - if(graphicInfo.getX() + graphicInfo.getWidth() > maxX) { - maxX = graphicInfo.getX() + graphicInfo.getWidth(); - } - - if(graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - - if(graphicInfo.getY() + graphicInfo.getHeight() > maxY) { - maxY = graphicInfo.getY() + graphicInfo.getHeight(); - } - - if(graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - - if(flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) { - minX = 0.0D; - minY = 0.0D; - } - - return new DefaultProcessDiagramCanvas((int)maxX + 10, (int)maxY + 10, (int)minX, (int)minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); - } - - protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode,List highLightedFinishes, List highLightedActivities, List highLightedFlows, double scaleFactor, List runningActivityIdList) { - ActivityDrawInstruction drawInstruction = this.activityDrawInstructions.get(flowNode.getClass()); - boolean highLighted; - if(drawInstruction != null) { - drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode); - boolean multiInstanceSequential = false; - boolean multiInstanceParallel = false; - highLighted = false; - if(flowNode instanceof Activity) { - Activity activity = (Activity)flowNode; - MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics(); - if(multiInstanceLoopCharacteristics != null) { - multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential(); - multiInstanceParallel = !multiInstanceSequential; - } - } - - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if(!(flowNode instanceof SubProcess)) { - if(flowNode instanceof CallActivity) { - highLighted = true; - } - } else { - highLighted = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded().booleanValue(); - } - - if(scaleFactor == 1.0D) { - processDiagramCanvas.drawActivityMarkers((int)graphicInfo.getX(), (int)graphicInfo.getY(), (int)graphicInfo.getWidth(), (int)graphicInfo.getHeight(), multiInstanceSequential, multiInstanceParallel, highLighted); - } - // 历史节点高亮 - if(highLightedActivities.contains(flowNode.getId())) { - drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()),DefaultProcessDiagramCanvas.HIGHLIGHT_COLOR,flowNode); - } - - // if(highLightedFinishes.contains(flowNode.getId()) && !highLightedActivities.contains(flowNode.getId())) { - // 正在执行的节点高亮 - if(runningActivityIdList.contains(flowNode.getId())) { - - drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()),DefaultProcessDiagramCanvas.FINISHHIGHLIGHT_COLOR,flowNode); - } - } - - Iterator var25 = flowNode.getOutgoingFlows().iterator(); - - while(var25.hasNext()) { - SequenceFlow sequenceFlow = (SequenceFlow)var25.next(); - highLighted = highLightedFlows.contains(sequenceFlow.getId()); - String defaultFlow = null; - if(flowNode instanceof Activity) { - defaultFlow = ((Activity)flowNode).getDefaultFlow(); - } else if(flowNode instanceof Gateway) { - defaultFlow = ((Gateway)flowNode).getDefaultFlow(); - } - - boolean isDefault = false; - if(defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) { - isDefault = true; - } - - boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway); - String sourceRef = sequenceFlow.getSourceRef(); - String targetRef = sequenceFlow.getTargetRef(); - FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef); - FlowElement targetElement = bpmnModel.getFlowElement(targetRef); - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); - if(graphicInfoList != null && graphicInfoList.size() > 0) { - graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList); - int[] xPoints = new int[graphicInfoList.size()]; - int[] yPoints = new int[graphicInfoList.size()]; - - for(int i = 1; i < graphicInfoList.size(); ++i) { - GraphicInfo graphicInfo = (GraphicInfo)graphicInfoList.get(i); - GraphicInfo previousGraphicInfo = (GraphicInfo)graphicInfoList.get(i - 1); - if(i == 1) { - xPoints[0] = (int)previousGraphicInfo.getX(); - yPoints[0] = (int)previousGraphicInfo.getY(); - } - - xPoints[i] = (int)graphicInfo.getX(); - yPoints[i] = (int)graphicInfo.getY(); - } - - processDiagramCanvas.drawSequenceflow(xPoints, yPoints, drawConditionalIndicator, isDefault, highLighted, scaleFactor); - GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId()); - if(labelGraphicInfo != null) { - processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false); - } - } - } - - if(flowNode instanceof FlowElementsContainer) { - var25 = ((FlowElementsContainer)flowNode).getFlowElements().iterator(); - - while(var25.hasNext()) { - FlowElement nestedFlowElement = (FlowElement)var25.next(); - if(nestedFlowElement instanceof FlowNode) { - this.drawActivity(processDiagramCanvas, bpmnModel, (FlowNode)nestedFlowElement, highLightedFinishes,highLightedActivities, highLightedFlows, scaleFactor, runningActivityIdList); - } - } - } - - } -} - - - - diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/config/MultiInstanceTaskHandler.java b/laws-modules/src/main/java/com/jero/modules/activiti/config/MultiInstanceTaskHandler.java new file mode 100644 index 00000000..46d50063 --- /dev/null +++ b/laws-modules/src/main/java/com/jero/modules/activiti/config/MultiInstanceTaskHandler.java @@ -0,0 +1,29 @@ +package com.jero.modules.activiti.config; + +import lombok.extern.slf4j.Slf4j; +import org.activiti.bpmn.model.FlowElement; +import org.activiti.bpmn.model.UserTask; +import org.activiti.engine.delegate.DelegateExecution; +import org.activiti.engine.delegate.DelegateTask; +import org.activiti.engine.delegate.ExecutionListener; +import org.activiti.engine.delegate.TaskListener; + +import java.util.List; + +/** + * @author liJiaRao + * @date 2023-09-05 14:54 + */ +@Slf4j +public class MultiInstanceTaskHandler implements TaskListener { + + @Override + public void notify(DelegateTask delegateTask) { + DelegateExecution execution = delegateTask.getExecution(); + System.out.println("流程实例总数:" + execution.getVariable("nrOfInstances")); + System.out.println("当前活动的流程实例总数:" + execution.getVariable("nrOfActiveInstances")); + System.out.println("已经完成实例的数目:" + execution.getVariable("nrOfCompletedInstances")); + System.out.println("leader:" + execution.getVariable("leader")); + System.out.println("---------------------------------------分隔线----------------------------------------------------"); + } +} diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/config/MyGen.java b/laws-modules/src/main/java/com/jero/modules/activiti/config/MyGen.java new file mode 100644 index 00000000..00f40768 --- /dev/null +++ b/laws-modules/src/main/java/com/jero/modules/activiti/config/MyGen.java @@ -0,0 +1,17 @@ +package com.jero.modules.activiti.config; + +import org.activiti.engine.impl.cfg.IdGenerator; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author liJiaRao + * @date 2023-09-05 17:39 + */ +public class MyGen implements IdGenerator { + private AtomicLong aLong = new AtomicLong(100); + @Override + public synchronized String getNextId() { + return String.valueOf(aLong.incrementAndGet()); + } +} diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/config/WorkflowConstants.java b/laws-modules/src/main/java/com/jero/modules/activiti/config/WorkflowConstants.java new file mode 100644 index 00000000..8197ceec --- /dev/null +++ b/laws-modules/src/main/java/com/jero/modules/activiti/config/WorkflowConstants.java @@ -0,0 +1,130 @@ +package com.jero.modules.activiti.config; + +import java.awt.*; + +/** + * 常量类 + *@author jjd + **/ +public final class WorkflowConstants { + + /**businessKey**/ + public static final String WORKLOW_BUSINESS_KEY = "businessKey"; + /**按钮网关**/ + public static final String WAY_TYPE = "wayType"; + /**按钮网关**/ + public static final String WAY_TYPE_PREFIX = "way_type_"; + /**项目id**/ + public static final String PROJECT_ID = "projectId"; + /**核心企业Id变量**/ + public static final String CORE_ENTERPRISE_ID="coreEnterpriseId"; + /**链属企业Id变量**/ + public static final String CHAIN_ENTERPRISE_ID="chainEnterpriseId"; + /**银行企业Id变量**/ + public static final String BANK_ENTERPRISE_ID="bankEnterpriseId"; + /**保理公司Id变量**/ + public static final String BAOLI_ENTERPRISE_ID="baoliEnterpriseId"; + /**立账开立企业Id变量**/ + public static final String START_ENTERPRISE_ID="startEnterpriseId"; + /**立账合作企业Id变量**/ + public static final String PARTNER_ENTERPRISE_ID="partnerEnterpriseId"; + /**母公司企业id**/ + public static final String PARENT_ENTERPRISE_ID="parentEnterpriseId"; + /**指定签收企业id**/ + public static final String RECEIVE_ENTERPRISE_ID ="receiveEnterpriseId"; + /**转出方企业Id变量**/ + public static final String TRANSFER_ENTERPRISE_ID="transEnterpriseId"; + /**指定签收企业id**/ + public static final String AC_TASK_ID ="acTaskId"; + /**企业所有角色**/ + public static final String ENT_ALL_ROLE ="all"; + /**运营所有角色**/ + public static final String OPER_ALL_ROLE ="oper"; + /**流程定义缓存时间**/ + public static final int PROCESS_DEFINITION_CACHE = 60; + /**流程实例激活**/ + public static final int PROCESS_INSTANCE_ACTIVE = 1; + + /**流程实例挂起**/ + public static final int PROCESS_INSTANCE_SUSPEND = 0; + + /**读取图片**/ + public static final String READ_IMAGE = "image"; + + /**读取xml**/ + public static final String READ_XML = "xml"; + + /**流程激活**/ + public static final Integer ACTIVE_PROCESSDEFINITION = 1; + + /**流程挂起**/ + public static final Integer SUSPEND_PROCESSDEFINITION = 2; + + /**流程状态:0-全部,1-正常,2-已挂起**/ + public static final int QUERY_ALL = 0; + public static final int QUERY_NORMAL = 1; + public static final int QUERY_SUSPENDED = 2; + + /**流程实例状态:0-全部,1-正常,2-已删除**/ + public static final int INSTANCE_ALL = 0; + public static final int INSTANCE_NOT_DELETED = 1; + public static final int INSTANCE_DELETED = 2; + + /** 系统管理员ID **/ + public static final String INTERFACE_SYSTEM_ID = "-1"; + /** 系统管理员名称 **/ + public static final String INTERFACE_SYSTEM_NAME = "系统操作"; + + /** 流程部署类型:1-启动并激活,2-启动即挂起 **/ + public static final int PROCESS_START_ACTIVE = 1; + public static final int PROCESS_START_SUSPEND = 2; + + /** 用于标识流程项目配置信息校验结果:1:新流程,2:新版本, 3:流程类别有误 **/ + public static final int CHECK_NEW_PROCESS = 1; + public static final int CHECK_NEW_VERSION = 2; + public static final int CHECK_ERROR_PROCESS_TYPE = 3; + + /** 默认网关条件值 **/ + public static final Integer default_GATEWAY_CONDITION_VALUE = 1; + + /** 工作流-业务状态表数据类型:1-工作流状态,2-业务状态 **/ + public static final Integer PROCESS_STATUS = 1; + public static final Integer BIZNESS_STATUS = 2; + + /** 新增流程时标识:1-直接保存,2-提示覆盖 **/ + public static final Integer PROCESS_STATUS_SAVE = 1; + public static final Integer BIZNESS_STATUS_WARN = 2; + + /** 模板类型标识:1-新创建或直接导入的模板,2-默认模板生成 **/ + public static final Integer MODEL_TYPE_1 = 1; + public static final Integer MODEL_TYPE_2 = 2; + + /** 查询流程定义标识:1-查询最新版本流程定义,2-查询所有版本 **/ + public static final Integer QUERY_PROCESS_LATEST_VERSION = 1; + public static final Integer QUERY_PROCESS_ALL_VERSION = 2; + + /** 按钮网关 通过1 */ + public static final String WAY_TYPE_PASS = "1"; + /** 按钮网关 驳回或结束0 */ + public static final String WAY_TYPE_REJECT = "0"; + + /** 按钮网关 退回2 */ + public static final String WAY_TYPE_BACK = "2"; + + /**任务参数为空**/ + public static final int TASK_CHECK_PARAM_NULL = -1; + /**任务已办理**/ + public static final int TASK_CHECK_COMPLETED = 1; + /**无权限办理**/ + public static final int TASK_CHECK_NO_PERMISSIONS= 2; + /**任务校验通过**/ + public static final int TASK_CHECK_PASS = 0; + /** 动态流程图颜色定义 **/ + public static final Color COLOR_NORMAL = new Color(0, 205, 0); + public static final Color COLOR_CURRENT = new Color(255, 0, 0); + + /** 定义生成流程图时的边距(像素) **/ + public static final int PROCESS_PADDING = 5; + + +} diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/controller/AController.java b/laws-modules/src/main/java/com/jero/modules/activiti/controller/AController.java index 483f77b0..b59ba940 100644 --- a/laws-modules/src/main/java/com/jero/modules/activiti/controller/AController.java +++ b/laws-modules/src/main/java/com/jero/modules/activiti/controller/AController.java @@ -10,7 +10,10 @@ import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.activiti.bpmn.converter.BpmnXMLConverter; import org.activiti.bpmn.model.BpmnModel; +import org.activiti.bpmn.model.FlowElement; +import org.activiti.bpmn.model.UserTask; import org.activiti.engine.*; +import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.repository.ProcessDefinitionQuery; @@ -21,12 +24,15 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.util.*; @@ -48,18 +54,28 @@ public class AController { @GetMapping("/deploy") public Result> deploy(@RequestParam(value = "name", required = false) String name, - @RequestParam(value = "classpathResource") String classpathResource) { - if (StringUtils.isNotBlank(name)) { + @RequestParam(value = "classpathResource") String classpathResource, + @RequestParam(value = "resourceName") String resourceName, + @RequestPart(value = "files", required = false) MultipartFile file) { + if (StringUtils.isBlank(name)) { //根据流程定义Key查询 name = "出差申请流程"; } + // 3、使用RepositoryService进行部署 - Deployment deployment = repositoryService.createDeployment() - //.addClasspathResource("bpmn/diagram_1.bpmn20.xml") // 添加bpmn资源 - //.addClasspathResource("bpmn/business-trips.png") // 添加png资源 - .addClasspathResource(classpathResource) - .name(name) - .deploy(); + Deployment deployment = null; + try { + deployment = repositoryService.createDeployment() + //.addClasspathResource("bpmn/diagram_1.bpmn20.xml") // 添加bpmn资源 + //.addClasspathResource("bpmn/business-trips.png") // 添加png资源 + //.addClasspathResource(classpathResource) + .addInputStream(resourceName, file.getInputStream()) + .key(name) + .name(name) + .deploy(); + } catch (IOException e) { + e.printStackTrace(); + } // 4、输出部署信息 Map map = new HashMap<>(); @@ -114,9 +130,12 @@ public class AController { ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 2、获取RunTimeService RuntimeService runtimeService = processEngine.getRuntimeService(); + Map vars = new HashMap<>(); + vars.put("mainDrafter", "admin"); + // 3、根据流程定义Id启动流程 ProcessInstance processInstance = runtimeService - .startProcessInstanceByKey(key); + .startProcessInstanceByKey(key, vars); // 输出内容 Map map = new HashMap<>(); @@ -155,12 +174,21 @@ public class AController { @GetMapping("/complete") public Result complete(@RequestParam(value = "taskId") String taskId) { - taskService.complete(taskId); + Map vars = new HashMap<>(); + List otherDrafterList = new ArrayList<>(); + otherDrafterList.add("zhangsan"); + otherDrafterList.add("lisi"); + otherDrafterList.add("wangwu"); + vars.put("leaderList", otherDrafterList); + Map map = new HashMap<>(); + map.put("status", 2); + taskService.complete(taskId, map, vars); return Result.OK(); } /** * 加签 + * * @param taskId * @param loginName * @return @@ -181,19 +209,25 @@ public class AController { @GetMapping("/addTask") // @ApiOperation("新增节点") public Object addTask(String taskId, String assignee) { - return processService.addTask(taskId,assignee); + return processService.addTask(taskId, assignee); } @GetMapping(value = "/readResource") @ApiOperation(value = "获取实时流程图", notes = "获取实时流程图,输出跟踪流程信息") - public void getFlowImgByInstanceId(@RequestParam(value = "processInstanceId") String processInstanceId, HttpServletResponse response) { - processService.getFlowImgByInstanceId(processInstanceId, response); + public void getFlowImgByInstanceId(@RequestParam(value = "processInstanceId") String + processInstanceId, HttpServletResponse response) { + try { + processService.readResource(processInstanceId, response); + } catch (Exception e) { + e.printStackTrace(); + } } @GetMapping(value = "/export/{modelId}") - @ApiOperation(value = "将流程模型导出为 bpmn文件",notes = "将流程模型导出为 bpmn文件") - public void export(@PathVariable("modelId") @ApiParam("流程模型Id") String modelId, HttpServletResponse response) { + @ApiOperation(value = "将流程模型导出为 bpmn文件", notes = "将流程模型导出为 bpmn文件") + public void export(@PathVariable("modelId") @ApiParam("流程模型Id") String modelId, HttpServletResponse + response) { try { BpmnModel bpmnModel = repositoryService.getBpmnModel(modelId); @@ -214,11 +248,12 @@ public class AController { log.error("导出model的bpmn文件失败:modelId={}", modelId, e); } } + @GetMapping("test") - public Result getRedisTest(){ + public Result getRedisTest() { String msg1 = MessageUtils.getMessage("message"); - String msg2 = MessageUtils.getMessage("message.operate.error","123456"); + String msg2 = MessageUtils.getMessage("message.operate.error", "123456"); LanguageEnum language = MessageUtils.getLanguage(); - return Result.OK(msg1+"\n"+msg2) ; + return Result.OK(msg1 + "\n" + msg2); } } diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/service/ProcessService.java b/laws-modules/src/main/java/com/jero/modules/activiti/service/ProcessService.java index 0459ea04..37af6b42 100644 --- a/laws-modules/src/main/java/com/jero/modules/activiti/service/ProcessService.java +++ b/laws-modules/src/main/java/com/jero/modules/activiti/service/ProcessService.java @@ -7,7 +7,7 @@ import javax.servlet.http.HttpServletResponse; * @date 2023-08-03 15:37 */ public interface ProcessService { - void getFlowImgByInstanceId(String pProcessInstanceId, HttpServletResponse response); - Object addTask(String taskId, String assignee); + + void readResource(String pProcessInstanceId, HttpServletResponse response) throws Exception; } diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/ProcessServiceImpl.java b/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/ProcessServiceImpl.java index e3a92b38..aa9366b0 100644 --- a/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/ProcessServiceImpl.java +++ b/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/ProcessServiceImpl.java @@ -1,10 +1,11 @@ package com.jero.modules.activiti.service.impl; import com.jero.common.exception.JeroBootException; -import com.jero.modules.activiti.config.DefaultProcessDiagramGenerator; +import com.jero.modules.activiti.config.WorkflowConstants; import com.jero.modules.activiti.entity.ActGeBytearray; import com.jero.modules.activiti.mapper.ActGeBytearrayMapper; import com.jero.modules.activiti.service.ProcessService; +import com.jero.modules.activiti.service.impl.image.ICustomProcessDiagramGenerator; import lombok.extern.slf4j.Slf4j; import org.activiti.bpmn.BpmnAutoLayout; import org.activiti.bpmn.converter.BpmnXMLConverter; @@ -13,23 +14,30 @@ import org.activiti.bpmn.model.*; import org.activiti.engine.*; import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.history.HistoricProcessInstance; +import org.activiti.engine.impl.RepositoryServiceImpl; import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.activiti.engine.impl.persistence.deploy.DeploymentManager; +import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; +import org.activiti.engine.repository.ProcessDefinition; +import org.activiti.engine.repository.ProcessDefinitionQuery; import org.activiti.engine.runtime.Execution; +import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; +import org.activiti.image.impl.DefaultProcessDiagramGenerator; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; +import java.awt.*; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.ArrayList; +import java.util.*; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; /** @@ -54,87 +62,6 @@ public class ProcessServiceImpl implements ProcessService { @Resource private ActGeBytearrayMapper actGeBytearrayMapper; - @Override - public void getFlowImgByInstanceId(String processInstanceId, HttpServletResponse response) { - InputStream imageStream = null; - try { - // 获取历史流程实例 - HistoricProcessInstance historicProcessInstance = historyService - .createHistoricProcessInstanceQuery() - .processInstanceId(processInstanceId).singleResult(); - if (historicProcessInstance == null){ - throw new JeroBootException("历史流程不存在"); - } - // 获取流程中已经执行的节点,按照执行先后顺序排序 - List historicActivityInstances = historyService - .createHistoricActivityInstanceQuery() - .processInstanceId(processInstanceId) - .orderByHistoricActivityInstanceId() - .asc().list(); - // 高亮已经执行流程节点ID集合 - List highLightedActivitiIds = new ArrayList<>(); - for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { - // 用默认颜色 - highLightedActivitiIds.add(historicActivityInstance.getActivityId()); - } - // 正在执行的节点 - List runTaskList = runtimeService.createExecutionQuery() - .processInstanceId(processInstanceId) - .list(); - List runningActivityIdList = new ArrayList<>(); - for (Execution execution : runTaskList) { - if (!StringUtils.isEmpty(execution.getActivityId())) { - runningActivityIdList.add(execution.getActivityId()); - } - } - List currIds = historicActivityInstances.stream() - .filter(item -> item.getEndTime() != null) - .map(HistoricActivityInstance::getActivityId).collect(Collectors.toList()); - - // 获得流程引擎配置 - ProcessEngineConfiguration processEngineConfiguration = processEngine.getProcessEngineConfiguration(); - - BpmnModel bpmnModel = repositoryService - .getBpmnModel(historicProcessInstance.getProcessDefinitionId()); - // 高亮流程已发生流转的线id集合 - List highLightedFlowIds = getHighLightedFlows(bpmnModel, historicActivityInstances); - // - imageStream = new DefaultProcessDiagramGenerator().generateDiagram( - bpmnModel, - "png", - highLightedActivitiIds,//所有活动过的节点,包括当前在激活状态下的节点 - currIds,//当前为激活状态下的节点 - highLightedFlowIds,//活动过的线 - "宋体", - "宋体", - "宋体", - processEngineConfiguration.getClassLoader(), - 1.0, - runningActivityIdList); - - OutputStream out = null; - out = response.getOutputStream(); - int len = 0; - byte[] b = new byte[1024]; - while ((len = imageStream.read(b)) != -1) { - out.write(b, 0, len); - } - out.flush(); - - - } catch (Exception e) { - e.printStackTrace(); - } finally { - if (imageStream != null) { - try { - imageStream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - } - @Override public Object addTask(String taskId, String assignee) { // 1、创建ProcessEngine @@ -191,154 +118,183 @@ public class ProcessServiceImpl implements ProcessService { flow.setTargetRef(to); return flow; } - /** - * @param bpmnModel bpmnModel - * @param historicActivityInstanceList historicActivityInstanceList - * @return HighLightedFlows - */ - public List getHighLightedFlows(BpmnModel bpmnModel, - List historicActivityInstanceList) { - //historicActivityInstanceList 是 流程中已经执行的历史活动实例 - // 已经流经的顺序流,需要高亮显示 - List highFlows = new ArrayList<>(); + private List getHighLightedFlows(BpmnModel bpmnModel, ProcessDefinitionEntity processDefinitionEntity, List historicActivityInstances) { + // 高亮流程已发生流转的线id集合 + List highLightedFlowIds = new ArrayList<>(); // 全部活动节点 - List allHistoricActivityNodeList = new ArrayList<>(); + List historicActivityNodes = new ArrayList<>(); + // 已完成的历史活动节点 + List finishedActivityInstances = new ArrayList<>(); - // 拥有endTime的历史活动实例,即已经完成了的节点 - List finishedActivityInstancesList = new ArrayList<>(); - - /* - * 循环的目的: - * 获取所有的历史节点FlowNode并放入allHistoricActivityNodeList - * 获取所有确定结束了的历史节点finishedActivityInstancesList - */ - for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) { - // 获取流程节点 - // bpmnModel.getMainProcess()获取一个Process对象 + for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true); - allHistoricActivityNodeList.add(flowNode); - - // 如果结束时间不为空,表示当前节点已经完成 + historicActivityNodes.add(flowNode); if (historicActivityInstance.getEndTime() != null) { - finishedActivityInstancesList.add(historicActivityInstance); + finishedActivityInstances.add(historicActivityInstance); } } - FlowNode currentFlowNode; - FlowNode targetFlowNode; - HistoricActivityInstance currentActivityInstance; - - // 遍历已经完成的活动实例,从每个实例的outgoingFlows中找到已经执行的 - for (int k = 0; k < finishedActivityInstancesList.size(); k++) { - currentActivityInstance = finishedActivityInstancesList.get(k); - - // 获得当前活动对应的节点信息以及outgoingFlows信息 + FlowNode currentFlowNode = null; + FlowNode targetFlowNode = null; + // 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的 + for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) { + // 获得当前活动对应的节点信息及outgoingFlows信息 currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true); + List sequenceFlows = currentFlowNode.getOutgoingFlows(); - // 当前节点的所有流出线 - List outgoingFlowList = currentFlowNode.getOutgoingFlows(); - - /* - * 遍历outgoingFlows并找到已经流转的 满足如下条件认为已经流转: - * 1、当前节点是并行网关或者兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已经流转 - * 2、当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转 - * (第二点有问题,有过驳回的,会只绘制驳回的流程线,通过走向下一级的流程线没有高亮显示) + /** + * 遍历outgoingFlows并找到已已流转的 满足如下条件认为已已流转: 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转 */ - if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || - "inclusiveGateway".equals(currentActivityInstance.getActivityType())) { + if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) { // 遍历历史活动节点,找到匹配流程目标节点的 - for (SequenceFlow outgoingFlow : outgoingFlowList) { - // 获取当前节点流程线对应的下一级节点 - targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(outgoingFlow.getTargetRef(), true); - - // 如果下级节点包含在所有历史节点中,则将当前节点的流出线高亮显示 - if (allHistoricActivityNodeList.contains(targetFlowNode)) { - highFlows.add(outgoingFlow.getId()); + for (SequenceFlow sequenceFlow : sequenceFlows) { + targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true); + if (historicActivityNodes.contains(targetFlowNode)) { + highLightedFlowIds.add(targetFlowNode.getId()); } } } else { - /* - * 2、当前节点不是并行网关或者兼容网关 - * 【已解决-问题】如果当前节点有驳回功能,驳回到申请节点, - * 则因为申请节点在历史节点中,导致当前节点驳回到申请节点的流程线被高亮显示,但实际并没有进行驳回操作 - */ List> tempMapList = new ArrayList<>(); - - // 当前节点ID - String currentActivityId = currentActivityInstance.getActivityId(); - - int size = historicActivityInstanceList.size(); - boolean ifStartFind = false; - boolean ifFinded = false; - HistoricActivityInstance historicActivityInstance; - - // 循环当前节点的所有流出线 - // 循环所有的历史节点 -// log.info("【开始】-匹配当前节点-ActivityId=【{}】需要高亮显示的流出线", currentActivityId); -// log.info("循环历史节点"); - - for (int i = 0; i < size; i++) { - // // 如果当前节点流程线对应的下级节点在历史节点中,则该条流程线进行高亮显示(【问题】有驳回流程线时,即使没有进行驳回操作,因为申请节点在历史节点中,也会将驳回流程线高亮显示-_-||) - // if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) { - // Map map = new HashMap<>(); - // map.put("highLightedFlowId", sequenceFlow.getId()); - // map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime()); - // tempMapList.add(map); - // // highFlows.add(sequenceFlow.getId()); - // } - - // 历史节点 - historicActivityInstance = historicActivityInstanceList.get(i); -// log.info("第【{}/{}】个历史节点-ActivityId=【{}】", i + 1, size, historicActivityInstance.getActivityId()); - - // 如果循环历史节点中的id等于当前节点id,从当前历史节点继续先后查找是否有当前流程线等于的节点 - // 历史节点的序号需要大于等于已经完成历史节点的序号,放置驳回重审一个节点经过两次时只取第一次的流出线高亮显示,第二次的不显示 - if (i >= k && historicActivityInstance.getActivityId().equals(currentActivityId)) { -// log.info("第【{}】个历史节点和当前节点一致-ActivityId=【{}】", i + 1, historicActivityInstance.getActivityId()); - ifStartFind = true; - // 跳过当前节点继续查找下一个节点 - continue; - } - if (ifStartFind) { -// log.info("[开始]-循环当前节点-ActivityId=【{}】的所有流出线", currentActivityId); - - ifFinded = false; - for (SequenceFlow sequenceFlow : outgoingFlowList) { - // 如果当前节点流程线对应的下级节点在其后面的历史节点中,则该条流程线进行高亮显示 - // 【问题】 -// log.info("当前流出线的下级节点=[{}]", sequenceFlow.getTargetRef()); - if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) { -// log.info("当前节点[{}]需高亮显示的流出线=[{}]", currentActivityId, sequenceFlow.getId()); - highFlows.add(sequenceFlow.getId()); - // 暂时默认找到离当前节点最近的下一级节点即退出循环,否则有多条流出线时将全部被高亮显示 - ifFinded = true; - break; - } + for (SequenceFlow sequenceFlow : sequenceFlows) { + for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) { + if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) { + Map map = new HashMap<>(); + map.put("highLightedFlowId", sequenceFlow.getId()); + map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime()); + tempMapList.add(map); } -// log.info("[完成]-循环当前节点-ActivityId=【{}】的所有流出线", currentActivityId); - } - if (ifFinded) { - // 暂时默认找到离当前节点最近的下一级节点即退出历史节点循环,否则有多条流出线时将全部被高亮显示 - break; } } -// log.info("【完成】-匹配当前节点-ActivityId=【{}】需要高亮显示的流出线", currentActivityId); - // if (!CollectionUtils.isEmpty(tempMapList)) { - // // 遍历匹配的集合,取得开始时间最早的一个 - // long earliestStamp = 0L; - // String highLightedFlowId = null; - // for (Map map : tempMapList) { - // long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString()); - // if (earliestStamp == 0 || earliestStamp <= highLightedFlowStartTime) { - // highLightedFlowId = map.get("highLightedFlowId").toString(); - // earliestStamp = highLightedFlowStartTime; - // } - // } - // highFlows.add(highLightedFlowId); - // } + + if (!CollectionUtils.isEmpty(tempMapList)) { + // 遍历匹配的集合,取得开始时间最早的一个 + long earliestStamp = 0L; + String highLightedFlowId = null; + for (Map map : tempMapList) { + long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString()); + if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) { + highLightedFlowId = map.get("highLightedFlowId").toString(); + earliestStamp = highLightedFlowStartTime; + } + } + + highLightedFlowIds.add(highLightedFlowId); + } + + } + + } + return highLightedFlowIds; + } + + @Override + public void readResource(String pProcessInstanceId, HttpServletResponse response) + throws Exception { + // 设置页面不缓存 + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setDateHeader("Expires", 0); + + String processDefinitionId = ""; + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(pProcessInstanceId).singleResult(); + if(processInstance == null) { + HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(pProcessInstanceId).singleResult(); + processDefinitionId = historicProcessInstance.getProcessDefinitionId(); + } else { + processDefinitionId = processInstance.getProcessDefinitionId(); + } + ProcessDefinitionQuery pdq = repositoryService.createProcessDefinitionQuery(); + ProcessDefinition pd = pdq.processDefinitionId(processDefinitionId).singleResult(); + + String resourceName = pd.getDiagramResourceName(); + + if(resourceName.endsWith(".png") && StringUtils.isEmpty(pProcessInstanceId) == false) + { + getActivitiProccessImage(pProcessInstanceId,response); + //ProcessDiagramGenerator.generateDiagram(pde, "png", getRuntimeService().getActiveActivityIds(processInstanceId)); + } + else + { + // 通过接口读取 + InputStream resourceAsStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), resourceName); + + // 输出资源内容到相应对象 + byte[] b = new byte[1024]; + int len = -1; + while ((len = resourceAsStream.read(b, 0, 1024)) != -1) { + response.getOutputStream().write(b, 0, len); } } - return highFlows; + } + + /** + * 获取流程图像,已执行节点和流程线高亮显示 + */ + public void getActivitiProccessImage(String pProcessInstanceId, HttpServletResponse response) { + //logger.info("[开始]-获取流程图图像"); + try { + // 获取历史流程实例 + HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() + .processInstanceId(pProcessInstanceId).singleResult(); + + if (historicProcessInstance == null) { + //throw new BusinessException("获取流程实例ID[" + pProcessInstanceId + "]对应的历史流程实例失败!"); + } + else { + // 获取流程定义 + ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService) + .getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId()); + + // 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序 + List historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(pProcessInstanceId).orderByHistoricActivityInstanceId().asc().list(); + + // 已执行的节点ID集合 + List executedActivityIdList = new ArrayList(); + int index = 1; + //logger.info("获取已经执行的节点ID"); + for (HistoricActivityInstance activityInstance : historicActivityInstanceList) { + executedActivityIdList.add(activityInstance.getActivityId()); + + //logger.info("第[" + index + "]个已执行节点=" + activityInstance.getActivityId() + " : " +activityInstance.getActivityName()); + index++; + } + + BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId()); + + // 已执行的线集合 + List flowIds = new ArrayList(); + // 获取流程走过的线 (getHighLightedFlows是下面的方法) + flowIds = getHighLightedFlows(bpmnModel,processDefinition, historicActivityInstanceList); + +// // 获取流程图图像字符流 +// ProcessDiagramGenerator pec = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator(); +// //配置字体 +// InputStream imageStream = pec.generateDiagram(bpmnModel, "png", executedActivityIdList, flowIds,"宋体","微软雅黑","黑体",null,2.0); + + Set currIds = runtimeService.createExecutionQuery().processInstanceId(pProcessInstanceId).list() + .stream().map(e->e.getActivityId()).collect(Collectors.toSet()); + + ICustomProcessDiagramGenerator diagramGenerator = (ICustomProcessDiagramGenerator) processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator(); + InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", executedActivityIdList, + flowIds, "宋体", "宋体", "宋体", null, 1.0, new Color[] { WorkflowConstants.COLOR_NORMAL, WorkflowConstants.COLOR_CURRENT }, currIds); + + response.setContentType("image/png"); + OutputStream os = response.getOutputStream(); + int bytesRead = 0; + byte[] buffer = new byte[8192]; + while ((bytesRead = imageStream.read(buffer, 0, 8192)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.close(); + imageStream.close(); + } + //logger.info("[完成]-获取流程图图像"); + } catch (Exception e) { + System.out.println(e.getMessage()); + //logger.error("【异常】-获取流程图失败!" + e.getMessage()); + //throw new BusinessException("获取流程图失败!" + e.getMessage()); + } } } diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/CustomProcessDiagramCanvas.java b/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/CustomProcessDiagramCanvas.java index 8810f0db..147ec706 100644 --- a/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/CustomProcessDiagramCanvas.java +++ b/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/CustomProcessDiagramCanvas.java @@ -1,1194 +1,246 @@ package com.jero.modules.activiti.service.impl.image; +import com.jero.modules.activiti.config.WorkflowConstants; import org.activiti.bpmn.model.AssociationDirection; -import org.activiti.bpmn.model.EventSubProcess; import org.activiti.bpmn.model.GraphicInfo; -import org.activiti.bpmn.model.Transaction; -import org.activiti.engine.ActivitiException; import org.activiti.image.exception.ActivitiImageException; import org.activiti.image.impl.DefaultProcessDiagramCanvas; -import org.activiti.image.impl.ProcessDiagramSVGGraphics2D; -import org.activiti.image.impl.icon.*; -import org.apache.batik.dom.GenericDOMImplementation; -import org.apache.batik.svggen.SVGGraphics2DIOException; -import org.w3c.dom.DOMImplementation; -import org.w3c.dom.Document; -import org.w3c.dom.DocumentType; +import org.activiti.image.util.ReflectUtil; +import javax.imageio.ImageIO; import java.awt.*; import java.awt.font.FontRenderContext; import java.awt.font.LineBreakMeasurer; import java.awt.font.TextAttribute; import java.awt.font.TextLayout; -import java.awt.geom.*; -import java.io.*; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.io.IOException; import java.text.AttributedCharacterIterator; import java.text.AttributedString; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -public class CustomProcessDiagramCanvas { +public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas { - /** - * 矩形、菱形、椭圆形 - */ - public enum SHAPE_TYPE { - Rectangle, Rhombus, Ellipse; + protected static Color LABEL_COLOR = new Color(0, 0, 0); - SHAPE_TYPE() { + //font + protected String activityFontName = "宋体"; + protected String labelFontName = "宋体"; + protected String annotationFontName = "宋体"; + + private static volatile boolean flag = false; + + public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType) { + super(width, height, minX, minY, imageType); + } + + public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, + String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { + super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, + customClassLoader); + } + + public void drawHighLight(boolean isStartOrEnd, int x, int y, int width, int height, Color color) { + Paint originalPaint = g.getPaint(); + Stroke originalStroke = g.getStroke(); + + g.setPaint(color); + g.setStroke(MULTI_INSTANCE_STROKE); + if (isStartOrEnd) {// 开始、结束节点画圆 + g.drawOval(x, y, width, height); + } else {// 非开始、结束节点画圆角矩形 + RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 5, 5); + g.draw(rect); } + g.setPaint(originalPaint); + g.setStroke(originalStroke); } - protected static final int ARROW_WIDTH = 5; - protected static final int CONDITIONAL_INDICATOR_WIDTH = 16; - protected static final int DEFAULT_INDICATOR_WIDTH = 10; - protected static final int MARKER_WIDTH = 12; - protected static final int FONT_SIZE = 12; - protected static final int FONT_SPACING = 2; - protected static final int TEXT_PADDING = 3; - protected static final int ANNOTATION_TEXT_PADDING = 7; - protected static final int LINE_HEIGHT = FONT_SIZE + FONT_SPACING; - - /** - * Colors - */ - protected static Color TASK_BOX_COLOR = new Color(249, 249, 249); - protected static Color SUBPROCESS_BOX_COLOR = new Color(255, 255, 255); - protected static Color EVENT_COLOR = Color.WHITE; - protected static Color CONNECTION_COLOR = new Color(128, 128, 128); - protected static Color CONDITIONAL_INDICATOR_COLOR = new Color(255, 255, 255); - protected static Color RUNNING_HIGHLIGHT_COLOR = Color.RED; - protected static Color LAST_HIGHLIGHT_COLOR = new Color(252, 75, 52); - protected static Color HIGHLIGHT_COLOR = Color.GREEN; - protected static Color LABEL_COLOR = new Color(67, 150, 246); - // protected static Color LABEL_COLOR = Color.blue; - protected static Color TASK_BORDER_COLOR = new Color(149, 148, 148); - protected static Color EVENT_BORDER_COLOR = new Color(76, 76, 76); - protected static Color SUBPROCESS_BORDER_COLOR = Color.BLACK; - - // Fonts - protected static Font LABEL_FONT = new Font("微软雅黑", Font.ITALIC, 14); - protected static Font ANNOTATION_FONT = new Font("微软雅黑", Font.PLAIN, FONT_SIZE); - protected static Font TASK_FONT = new Font("微软雅黑", Font.PLAIN, FONT_SIZE); - - // Strokes笔画 - //TODO 边框宽度修改 - //protected static Stroke THICK_TASK_BORDER_STROKE = new BasicStroke(3.0f); - protected static Stroke THICK_TASK_BORDER_STROKE = new BasicStroke(2.0f); - protected static Stroke GATEWAY_TYPE_STROKE = new BasicStroke(3.0f); - protected static Stroke END_EVENT_STROKE = new BasicStroke(3.0f); - protected static Stroke MULTI_INSTANCE_STROKE = new BasicStroke(1.3f); - protected static Stroke EVENT_SUBPROCESS_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, new float[]{1.0f}, 0.0f); - protected static Stroke NON_INTERRUPTING_EVENT_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, new float[]{4.0f, 3.0f}, 0.0f); - protected static Stroke HIGHLIGHT_FLOW_STROKE = new BasicStroke(1.3f); - protected static Stroke ANNOTATION_STROKE = new BasicStroke(2.0f); - protected static Stroke ASSOCIATION_STROKE = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0f, new float[]{2.0f, 2.0f}, 0.0f); - - // icons - protected static int ICON_PADDING = 5; - protected static TaskIconType USERTASK_IMAGE; - protected static TaskIconType SCRIPTTASK_IMAGE; - protected static TaskIconType SERVICETASK_IMAGE; - protected static TaskIconType RECEIVETASK_IMAGE; - protected static TaskIconType SENDTASK_IMAGE; - protected static TaskIconType MANUALTASK_IMAGE; - protected static TaskIconType BUSINESS_RULE_TASK_IMAGE; - - protected static IconType TIMER_IMAGE; - protected static IconType COMPENSATE_THROW_IMAGE; - protected static IconType COMPENSATE_CATCH_IMAGE; - protected static IconType ERROR_THROW_IMAGE; - protected static IconType ERROR_CATCH_IMAGE; - protected static IconType MESSAGE_CATCH_IMAGE; - protected static IconType SIGNAL_CATCH_IMAGE; - protected static IconType SIGNAL_THROW_IMAGE; - - protected int canvasWidth = -1; - protected int canvasHeight = -1; - protected int minX = -1; - protected int minY = -1; - protected ProcessDiagramSVGGraphics2D g; - protected FontMetrics fontMetrics; - protected boolean closed; - protected String activityFontName = "微软雅黑"; - protected String labelFontName = "微软雅黑"; - protected String annotationFontName = "微软雅黑"; - - /** - * Creates an empty canvas with given width and height. Allows to specify minimal boundaries on the left and upper side of the canvas. This is useful for diagrams that have - * white space there. Everything beneath these minimum values will be cropped. It's also possible to pass a specific font name and a class loader for the icon images. - */ - public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String activityFontName, String labelFontName, String annotationFontName) { - this.canvasWidth = width; - this.canvasHeight = height; - this.minX = minX; - this.minY = minY; - if (activityFontName != null) { - this.activityFontName = activityFontName; - } - if (labelFontName != null) { - this.labelFontName = labelFontName; - } - if (annotationFontName != null) { - this.annotationFontName = annotationFontName; - } - this.initialize(); + public void drawSequenceflow(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, + boolean highLighted, double scaleFactor, Color color) { + drawConnection(xPoints, yPoints, conditional, isDefault, "sequenceFlow", AssociationDirection.ONE, highLighted, + scaleFactor, color); } - /** - * Creates an empty canvas with given width and height. Allows to specify minimal boundaries on the left and upper side of the canvas. This is useful for diagrams that have - * white space there (eg Signavio). Everything beneath these minimum values will be cropped. - * - * @param minX Hint that will be used when generating the image. Parts that fall below minX on the horizontal scale will be cropped. - * @param minY Hint that will be used when generating the image. Parts that fall below minX on the horizontal scale will be cropped. - */ - public CustomProcessDiagramCanvas(int width, int height, int minX, int minY) { - this.canvasWidth = width; - this.canvasHeight = height; - this.minX = minX; - this.minY = minY; - this.initialize(); - } + public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, + String connectionType, AssociationDirection associationDirection, boolean highLighted, double scaleFactor, + Color color) { - public void initialize() { - DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); - String svgNS = "http://www.w3.org/2000/svg"; - Document document = domImpl.createDocument(svgNS, "svg", (DocumentType) null); - this.g = new ProcessDiagramSVGGraphics2D(document); - this.g.setSVGCanvasSize(new Dimension(this.canvasWidth, this.canvasHeight)); - this.g.setBackground(new Color(255, 255, 255, 0)); - this.g.clearRect(0, 0, this.canvasWidth, this.canvasHeight); - this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - this.g.setPaint(Color.black); - Font font = new Font(this.activityFontName, 1, 11); - this.g.setFont(font); - this.fontMetrics = this.g.getFontMetrics(); - LABEL_FONT = new Font(this.labelFontName, 2, 10); - ANNOTATION_FONT = new Font(this.annotationFontName, 0, 11); + Paint originalPaint = g.getPaint(); + Stroke originalStroke = g.getStroke(); - USERTASK_IMAGE = new UserTaskIconType(); - SCRIPTTASK_IMAGE = new ScriptTaskIconType(); - SERVICETASK_IMAGE = new ServiceTaskIconType(); - RECEIVETASK_IMAGE = new ReceiveTaskIconType(); - SENDTASK_IMAGE = new SendTaskIconType(); - MANUALTASK_IMAGE = new ManualTaskIconType(); - BUSINESS_RULE_TASK_IMAGE = new BusinessRuleTaskIconType(); - TIMER_IMAGE = new TimerIconType(); - COMPENSATE_THROW_IMAGE = new CompensateThrowIconType(); - COMPENSATE_CATCH_IMAGE = new CompensateIconType(); - ERROR_THROW_IMAGE = new ErrorThrowIconType(); - ERROR_CATCH_IMAGE = new ErrorIconType(); - MESSAGE_CATCH_IMAGE = new MessageIconType(); - SIGNAL_THROW_IMAGE = new SignalThrowIconType(); - SIGNAL_CATCH_IMAGE = new SignalIconType(); - - } - - /** - * Generates an image of what currently is drawn on the canvas. Throws an {@link ActivitiException} when {@link #close()} is already called. - */ - public InputStream generateImage() { - if (closed) { - throw new ActivitiImageException("ProcessDiagramGenerator already closed"); - } else { - try { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - Writer out = new OutputStreamWriter(stream, "UTF-8"); - this.g.stream(out, true); - return new ByteArrayInputStream(stream.toByteArray()); - } catch (SVGGraphics2DIOException | UnsupportedEncodingException var3) { - throw new ActivitiImageException("Error while generating process image", var3); - } - } - } - - public void close() { - g.dispose(); - closed = true; - } - - - public void drawNoneStartEvent(String id, GraphicInfo graphicInfo) { - this.drawStartEvent(id, graphicInfo, (IconType) null); - } - - public void drawTimerStartEvent(String id, GraphicInfo graphicInfo) { - this.drawStartEvent(id, graphicInfo, TIMER_IMAGE); - } - - public void drawSignalStartEvent(String id, GraphicInfo graphicInfo) { - this.drawStartEvent(id, graphicInfo, SIGNAL_CATCH_IMAGE); - } - - public void drawMessageStartEvent(String id, GraphicInfo graphicInfo) { - this.drawStartEvent(id, graphicInfo, MESSAGE_CATCH_IMAGE); - } - - public void drawStartEvent(String id, GraphicInfo graphicInfo, IconType icon) { - Paint originalPaint = this.g.getPaint(); - this.g.setPaint(EVENT_COLOR); - Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), graphicInfo.getWidth(), graphicInfo.getHeight()); - this.g.fill(circle); - this.g.setPaint(EVENT_BORDER_COLOR); - this.g.draw(circle); - this.g.setPaint(originalPaint); - if (icon != null) { - // calculate coordinates to center image - int imageX = (int) Math.round(graphicInfo.getX() + graphicInfo.getWidth() / 2.0D - (double) (icon.getWidth() / 2)); - int imageY = (int) Math.round(graphicInfo.getY() + graphicInfo.getHeight() / 2.0D - (double) (icon.getHeight() / 2)); - icon.drawIcon(imageX, imageY, ICON_PADDING, this.g); - } - this.g.setCurrentGroupId(id); - } - - public void drawNoneEndEvent(String id, String name, GraphicInfo graphicInfo) { - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - this.g.setPaint(EVENT_COLOR); - Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), graphicInfo.getWidth(), graphicInfo.getHeight()); - this.g.fill(circle); - this.g.setPaint(EVENT_BORDER_COLOR); - this.g.setStroke(END_EVENT_STROKE); - this.g.draw(circle); - this.g.setStroke(originalStroke); - this.g.setPaint(originalPaint); - this.g.setCurrentGroupId(id); - this.drawLabel(name, graphicInfo); - } - - public void drawErrorEndEvent(String id, String name, GraphicInfo graphicInfo) { - this.drawNoneEndEvent(id, name, graphicInfo); - int imageX = (int) (graphicInfo.getX() + graphicInfo.getWidth() / 4.0D); - int imageY = (int) (graphicInfo.getY() + graphicInfo.getHeight() / 4.0D); - ERROR_THROW_IMAGE.drawIcon(imageX, imageY, ICON_PADDING, this.g); - } - - public void drawErrorStartEvent(String id, GraphicInfo graphicInfo) { - this.drawNoneStartEvent(id, graphicInfo); - int imageX = (int) (graphicInfo.getX() + graphicInfo.getWidth() / 4.0D); - int imageY = (int) (graphicInfo.getY() + graphicInfo.getHeight() / 4.0D); - ERROR_THROW_IMAGE.drawIcon(imageX, imageY, ICON_PADDING, this.g); - } - - public void drawCatchingEvent(String id, GraphicInfo graphicInfo, boolean isInterrupting, IconType icon, String eventType) { - - // event circles - Ellipse2D outerCircle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), graphicInfo.getWidth(), graphicInfo.getHeight()); - int innerCircleSize = 4; - int innerCircleX = (int) graphicInfo.getX() + innerCircleSize; - int innerCircleY = (int) graphicInfo.getY() + innerCircleSize; - int innerCircleWidth = (int) graphicInfo.getWidth() - 2 * innerCircleSize; - int innerCircleHeight = (int) graphicInfo.getHeight() - 2 * innerCircleSize; - Ellipse2D innerCircle = new Ellipse2D.Double((double) innerCircleX, (double) innerCircleY, (double) innerCircleWidth, (double) innerCircleHeight); - - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - this.g.setPaint(EVENT_COLOR); - this.g.fill(outerCircle); - - this.g.setPaint(EVENT_BORDER_COLOR); - if (!isInterrupting) { - this.g.setStroke(NON_INTERRUPTING_EVENT_STROKE); - } - this.g.draw(outerCircle); - this.g.setStroke(originalStroke); - this.g.setPaint(originalPaint); - this.g.draw(innerCircle); - - if (icon != null) { - // calculate coordinates to center image - int imageX = (int) (graphicInfo.getX() + graphicInfo.getWidth() / 2.0D - (double) (icon.getWidth() / 2)); - int imageY = (int) (graphicInfo.getY() + graphicInfo.getHeight() / 2.0D - (double) (icon.getHeight() / 2)); - if ("timer".equals(eventType)) { - imageX++; - imageY++; - } - icon.drawIcon(imageX, imageY, ICON_PADDING, this.g); - } - this.g.setCurrentGroupId(id); - } - - public void drawCatchingCompensateEvent(String id, String name, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingCompensateEvent(id, graphicInfo, isInterrupting); - this.drawLabel(name, graphicInfo); - } - - public void drawCatchingCompensateEvent(String id, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingEvent(id, graphicInfo, isInterrupting, COMPENSATE_CATCH_IMAGE, "compensate"); - } - - public void drawCatchingTimerEvent(String id, String name, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingTimerEvent(id, graphicInfo, isInterrupting); - this.drawLabel(name, graphicInfo); - } - - public void drawCatchingTimerEvent(String id, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingEvent(id, graphicInfo, isInterrupting, TIMER_IMAGE, "timer"); - } - - public void drawCatchingErrorEvent(String id, String name, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingErrorEvent(id, graphicInfo, isInterrupting); - this.drawLabel(name, graphicInfo); - } - - public void drawCatchingErrorEvent(String id, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingEvent(id, graphicInfo, isInterrupting, ERROR_CATCH_IMAGE, "error"); - } - - public void drawCatchingSignalEvent(String id, String name, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingSignalEvent(id, graphicInfo, isInterrupting); - this.drawLabel(name, graphicInfo); - } - - public void drawCatchingSignalEvent(String id, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingEvent(id, graphicInfo, isInterrupting, SIGNAL_CATCH_IMAGE, "signal"); - } - - public void drawCatchingMessageEvent(String id, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingEvent(id, graphicInfo, isInterrupting, MESSAGE_CATCH_IMAGE, "message"); - } - - public void drawCatchingMessageEvent(String id, String name, GraphicInfo graphicInfo, boolean isInterrupting) { - this.drawCatchingEvent(id, graphicInfo, isInterrupting, MESSAGE_CATCH_IMAGE, "message"); - this.drawLabel(name, graphicInfo); - } - - public void drawThrowingCompensateEvent(String id, GraphicInfo graphicInfo) { - this.drawCatchingEvent(id, graphicInfo, true, COMPENSATE_THROW_IMAGE, "compensate"); - } - - public void drawThrowingSignalEvent(String id, GraphicInfo graphicInfo) { - this.drawCatchingEvent(id, graphicInfo, true, SIGNAL_THROW_IMAGE, "signal"); - } - - public void drawThrowingNoneEvent(String id, GraphicInfo graphicInfo) { - this.drawCatchingEvent(id, graphicInfo, true, (IconType) null, "none"); - } - - public void drawSequenceflow(int srcX, int srcY, int targetX, int targetY, boolean conditional) { - this.drawSequenceflow(srcX, srcY, targetX, targetY, conditional, false); - } - - public void drawSequenceflow(int srcX, int srcY, int targetX, int targetY, boolean conditional, boolean highLighted) { - Paint originalPaint = this.g.getPaint(); - if (highLighted) { - this.g.setPaint(HIGHLIGHT_COLOR); - } - - Line2D.Double line = new Line2D.Double((double) srcX, (double) srcY, (double) targetX, (double) targetY); - this.g.draw(line); - this.drawArrowHead(line); - if (conditional) { - this.drawConditionalSequenceFlowIndicator(line); - } - - if (highLighted) { - this.g.setPaint(originalPaint); - } - - } - - public void drawAssociation(int[] xPoints, int[] yPoints, AssociationDirection associationDirection, boolean highLighted) { - boolean conditional = false; - boolean isDefault = false; - this.drawConnection(xPoints, yPoints, conditional, isDefault, "association", associationDirection, highLighted, HIGHLIGHT_COLOR); - } - - public void drawSequenceflow(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, boolean highLighted) { - this.drawConnection(xPoints, yPoints, conditional, isDefault, "sequenceFlow", AssociationDirection.ONE, highLighted, HIGHLIGHT_COLOR); - } - - public void drawLastSequenceflow(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, boolean highLighted) { - this.drawConnection(xPoints, yPoints, conditional, isDefault, "sequenceFlow", AssociationDirection.ONE, highLighted, LAST_HIGHLIGHT_COLOR); - } - - public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType, AssociationDirection associationDirection, boolean highLighted, Color HIGHLIGHT_COLOR) { - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - this.g.setPaint(CONNECTION_COLOR); - if ("association".equals(connectionType)) { - this.g.setStroke(ASSOCIATION_STROKE); + g.setPaint(CONNECTION_COLOR); + if (connectionType.equals("association")) { + g.setStroke(ASSOCIATION_STROKE); } else if (highLighted) { - this.g.setPaint(HIGHLIGHT_COLOR); - this.g.setStroke(HIGHLIGHT_FLOW_STROKE); + g.setPaint(color); + g.setStroke(HIGHLIGHT_FLOW_STROKE); } - for (int i = 1; i < xPoints.length; ++i) { + for (int i = 1; i < xPoints.length; i++) { Integer sourceX = xPoints[i - 1]; Integer sourceY = yPoints[i - 1]; Integer targetX = xPoints[i]; Integer targetY = yPoints[i]; - Line2D.Double line = new Line2D.Double((double) sourceX, (double) sourceY, (double) targetX, (double) targetY); - this.g.draw(line); + Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY); + g.draw(line); } - Line2D.Double line; if (isDefault) { - line = new Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]); - this.drawDefaultSequenceFlowIndicator(line); + Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]); + drawDefaultSequenceFlowIndicator(line, scaleFactor); } if (conditional) { - line = new Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]); - this.drawConditionalSequenceFlowIndicator(line); + Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]); + drawConditionalSequenceFlowIndicator(line, scaleFactor); } - if (associationDirection.equals(AssociationDirection.ONE) || associationDirection.equals(AssociationDirection.BOTH)) { - line = new Line2D.Double((double) xPoints[xPoints.length - 2], (double) yPoints[xPoints.length - 2], (double) xPoints[xPoints.length - 1], (double) yPoints[xPoints.length - 1]); - this.drawArrowHead(line); + if (associationDirection.equals(AssociationDirection.ONE) + || associationDirection.equals(AssociationDirection.BOTH)) { + Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], + xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]); + drawArrowHead(line, scaleFactor); } - if (associationDirection.equals(AssociationDirection.BOTH)) { - line = new Line2D.Double((double) xPoints[1], (double) yPoints[1], (double) xPoints[0], (double) yPoints[0]); - this.drawArrowHead(line); + Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]); + drawArrowHead(line, scaleFactor); } - - this.g.setPaint(originalPaint); - this.g.setStroke(originalStroke); + g.setPaint(originalPaint); + g.setStroke(originalStroke); } - public void drawSequenceflowWithoutArrow(int srcX, int srcY, int targetX, int targetY, boolean conditional) { - this.drawSequenceflowWithoutArrow(srcX, srcY, targetX, targetY, conditional, false); - } - - public void drawSequenceflowWithoutArrow(int srcX, int srcY, int targetX, int targetY, boolean conditional, boolean highLighted) { - Paint originalPaint = this.g.getPaint(); - if (highLighted) { - this.g.setPaint(HIGHLIGHT_COLOR); - } - - Line2D.Double line = new Line2D.Double((double) srcX, (double) srcY, (double) targetX, (double) targetY); - this.g.draw(line); - if (conditional) { - this.drawConditionalSequenceFlowIndicator(line); - } - - if (highLighted) { - this.g.setPaint(originalPaint); - } - - } - - public void drawArrowHead(Line2D.Double line) { - int doubleArrowWidth = 10; - if (doubleArrowWidth == 0) { - doubleArrowWidth = 2; - } - - Polygon arrowHead = new Polygon(); - arrowHead.addPoint(0, 0); - - int arrowHeadPoint = -5; - if (arrowHeadPoint == 0) { - arrowHeadPoint = -1; - } - - arrowHead.addPoint(arrowHeadPoint, -doubleArrowWidth); - arrowHeadPoint = 5; - if (arrowHeadPoint == 0) { - arrowHeadPoint = 1; - } - - arrowHead.addPoint(arrowHeadPoint, -doubleArrowWidth); - AffineTransform transformation = new AffineTransform(); - transformation.setToIdentity(); - double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1); - transformation.translate(line.x2, line.y2); - transformation.rotate(angle - 1.5707963267948966D); - AffineTransform originalTransformation = this.g.getTransform(); - this.g.setTransform(transformation); - this.g.fill(arrowHead); - this.g.setTransform(originalTransformation); - } - - public void drawDefaultSequenceFlowIndicator(Line2D.Double line) { - double length = 10.0D; - double halfOfLength = length / 2.0D; - double f = 8.0D; - Line2D.Double defaultIndicator = new Line2D.Double(-halfOfLength, 0.0D, halfOfLength, 0.0D); - double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1); - double dx = f * Math.cos(angle); - double dy = f * Math.sin(angle); - double x1 = line.x1 + dx; - double y1 = line.y1 + dy; - AffineTransform transformation = new AffineTransform(); - transformation.setToIdentity(); - transformation.translate(x1, y1); - transformation.rotate(angle - 2.356194490192345D); - AffineTransform originalTransformation = this.g.getTransform(); - this.g.setTransform(transformation); - this.g.draw(defaultIndicator); - this.g.setTransform(originalTransformation); - } - - public void drawConditionalSequenceFlowIndicator(Line2D.Double line) { - int horizontal = 11; - int halfOfHorizontal = horizontal / 2; - int halfOfVertical = 8; - Polygon conditionalIndicator = new Polygon(); - conditionalIndicator.addPoint(0, 0); - conditionalIndicator.addPoint(-halfOfHorizontal, halfOfVertical); - conditionalIndicator.addPoint(0, 16); - conditionalIndicator.addPoint(halfOfHorizontal, halfOfVertical); - AffineTransform transformation = new AffineTransform(); - transformation.setToIdentity(); - double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1); - transformation.translate(line.x1, line.y1); - transformation.rotate(angle - 1.5707963267948966D); - AffineTransform originalTransformation = this.g.getTransform(); - this.g.setTransform(transformation); - this.g.draw(conditionalIndicator); - Paint originalPaint = this.g.getPaint(); - this.g.setPaint(CONDITIONAL_INDICATOR_COLOR); - this.g.fill(conditionalIndicator); - this.g.setPaint(originalPaint); - this.g.setTransform(originalTransformation); - } - - public void drawTask(TaskIconType icon, String id, String name, GraphicInfo graphicInfo) { - this.drawTask(id, name, graphicInfo); - icon.drawIcon((int) graphicInfo.getX(), (int) graphicInfo.getY(), ICON_PADDING, this.g); - } - - public void drawTask(String id, String name, GraphicInfo graphicInfo) { - this.drawTask(id, name, graphicInfo, false); - } - - - public void drawPoolOrLane(String id, String name, GraphicInfo graphicInfo) { - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - this.g.drawRect(x, y, width, height); - if (name != null && name.length() > 0) { - int availableTextSpace = height - 6; - AffineTransform transformation = new AffineTransform(); - transformation.setToIdentity(); - transformation.rotate(4.71238898038469D); - Font currentFont = this.g.getFont(); - Font theDerivedFont = currentFont.deriveFont(transformation); - this.g.setFont(theDerivedFont); - String truncated = this.fitTextToWidth(name, availableTextSpace); - int realWidth = this.fontMetrics.stringWidth(truncated); - this.g.drawString(truncated, x + 2 + this.fontMetrics.getHeight(), 3 + y + availableTextSpace - (availableTextSpace - realWidth) / 2); - this.g.setFont(currentFont); - } - - this.g.setCurrentGroupId(id); - } - - protected void drawTask(String id, String name, GraphicInfo graphicInfo, boolean thickBorder) { - Paint originalPaint = this.g.getPaint(); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - this.g.setPaint(TASK_BOX_COLOR); - int arcR = 6; - if (thickBorder) { - arcR = 3; - } - - RoundRectangle2D rect = new RoundRectangle2D.Double((double) x, (double) y, (double) width, (double) height, (double) arcR, (double) arcR); - this.g.fill(rect); - this.g.setPaint(TASK_BORDER_COLOR); - if (thickBorder) { - Stroke originalStroke = this.g.getStroke(); - this.g.setStroke(THICK_TASK_BORDER_STROKE); - this.g.draw(rect); - this.g.setStroke(originalStroke); - } else { - this.g.draw(rect); - } - - this.g.setPaint(originalPaint); - if (name != null && name.length() > 0) { - int boxWidth = width - 6; - int boxHeight = height - 16 - ICON_PADDING - ICON_PADDING - 12 - 2 - 2; - int boxX = x + width / 2 - boxWidth / 2; - int boxY = y + height / 2 - boxHeight / 2 + ICON_PADDING + ICON_PADDING - 2 - 2; - this.drawMultilineCentredText(name, boxX, boxY, boxWidth, boxHeight); - } - - this.g.setCurrentGroupId(id); - } - - protected void drawMultilineCentredText(String text, int x, int y, int boxWidth, int boxHeight) { - this.drawMultilineText(text, x, y, boxWidth, boxHeight, true); - } - - protected void drawMultilineAnnotationText(String text, int x, int y, int boxWidth, int boxHeight) { - this.drawMultilineText(text, x, y, boxWidth, boxHeight, false); - } - - protected void drawMultilineText(String text, int x, int y, int boxWidth, int boxHeight, boolean centered) { - AttributedString attributedString = new AttributedString(text); - attributedString.addAttribute(TextAttribute.FONT, this.g.getFont()); - attributedString.addAttribute(TextAttribute.FOREGROUND, Color.black); - AttributedCharacterIterator characterIterator = attributedString.getIterator(); - int currentHeight = 0; - List layouts = new ArrayList(); - String lastLine = null; - LineBreakMeasurer measurer = new LineBreakMeasurer(characterIterator, this.g.getFontRenderContext()); - - int currentY; - int height; - for (TextLayout layout = null; measurer.getPosition() < characterIterator.getEndIndex() && currentHeight <= boxHeight; currentHeight += height) { - currentY = measurer.getPosition(); - layout = measurer.nextLayout((float) boxWidth); - height = Float.valueOf(layout.getDescent() + layout.getAscent() + layout.getLeading()).intValue(); - if (currentHeight + height > boxHeight) { - if (!layouts.isEmpty()) { - layouts.remove(layouts.size() - 1); - if (lastLine.length() >= 4) { - lastLine = lastLine.substring(0, lastLine.length() - 4) + "..."; - } - - layouts.add(new TextLayout(lastLine, this.g.getFont(), this.g.getFontRenderContext())); - } else { - layouts.add(layout); - currentHeight += height; - } - break; - } - - layouts.add(layout); - lastLine = text.substring(currentY, measurer.getPosition()); - } - - currentY = y + (centered ? (boxHeight - currentHeight) / 2 : 0); - - - TextLayout textLayout; - for (Iterator var16 = layouts.iterator(); var16.hasNext(); currentY = (int) ((float) currentY + textLayout.getDescent() + textLayout.getLeading())) { - textLayout = (TextLayout) var16.next(); - currentY = (int) ((float) currentY + textLayout.getAscent()); - height = x + (centered ? (boxWidth - Double.valueOf(textLayout.getBounds().getWidth()).intValue()) / 2 : 0); - textLayout.draw(this.g, (float) height, (float) currentY); - } - - } - - protected String fitTextToWidth(String original, int width) { - String text = original; - - for (int maxWidth = width - 10; this.fontMetrics.stringWidth(text + "...") > maxWidth && text.length() > 0; text = text.substring(0, text.length() - 1)) { - } - - if (!text.equals(original)) { - text = text + "..."; - } - - return text; - } - - public void drawUserTask(String id, String name, GraphicInfo graphicInfo) { - this.drawTask(USERTASK_IMAGE, id, name, graphicInfo); - } - - public void drawScriptTask(String id, String name, GraphicInfo graphicInfo) { - this.drawTask(SCRIPTTASK_IMAGE, id, name, graphicInfo); - } - - public void drawServiceTask(String id, String name, GraphicInfo graphicInfo) { - this.drawTask(SERVICETASK_IMAGE, id, name, graphicInfo); - } - - public void drawReceiveTask(String id, String name, GraphicInfo graphicInfo) { - this.drawTask(RECEIVETASK_IMAGE, id, name, graphicInfo); - } - - public void drawSendTask(String id, String name, GraphicInfo graphicInfo) { - this.drawTask(SENDTASK_IMAGE, id, name, graphicInfo); - } - - public void drawManualTask(String id, String name, GraphicInfo graphicInfo) { - this.drawTask(MANUALTASK_IMAGE, id, name, graphicInfo); - } - - public void drawBusinessRuleTask(String id, String name, GraphicInfo graphicInfo) { - this.drawTask(BUSINESS_RULE_TASK_IMAGE, id, name, graphicInfo); - } - - public void drawExpandedSubProcess(String id, String name, GraphicInfo graphicInfo, Class type) { - RoundRectangle2D rect = new RoundRectangle2D.Double(graphicInfo.getX(), graphicInfo.getY(), graphicInfo.getWidth(), graphicInfo.getHeight(), 8.0D, 8.0D); - if (type.equals(EventSubProcess.class)) { - Stroke originalStroke = this.g.getStroke(); - this.g.setStroke(EVENT_SUBPROCESS_STROKE); - this.g.draw(rect); - this.g.setStroke(originalStroke); - } else if (type.equals(Transaction.class)) { - RoundRectangle2D outerRect = new RoundRectangle2D.Double(graphicInfo.getX() - 3.0D, graphicInfo.getY() - 3.0D, graphicInfo.getWidth() + 6.0D, graphicInfo.getHeight() + 6.0D, 8.0D, 8.0D); - Paint originalPaint = this.g.getPaint(); - this.g.setPaint(SUBPROCESS_BOX_COLOR); - this.g.fill(outerRect); - this.g.setPaint(SUBPROCESS_BORDER_COLOR); - this.g.draw(outerRect); - this.g.setPaint(SUBPROCESS_BOX_COLOR); - this.g.fill(rect); - this.g.setPaint(SUBPROCESS_BORDER_COLOR); - this.g.draw(rect); - this.g.setPaint(originalPaint); - } else { - Paint originalPaint = this.g.getPaint(); - this.g.setPaint(SUBPROCESS_BOX_COLOR); - this.g.fill(rect); - this.g.setPaint(SUBPROCESS_BORDER_COLOR); - this.g.draw(rect); - this.g.setPaint(originalPaint); - } - - if (name != null && !name.isEmpty()) { - String text = this.fitTextToWidth(name, (int) graphicInfo.getWidth()); - this.g.drawString(text, (int) graphicInfo.getX() + 10, (int) graphicInfo.getY() + 15); - } - - this.g.setCurrentGroupId(id); - } - - public void drawCollapsedSubProcess(String id, String name, GraphicInfo graphicInfo, Boolean isTriggeredByEvent) { - this.drawCollapsedTask(id, name, graphicInfo, false); - } - - public void drawCollapsedCallActivity(String id, String name, GraphicInfo graphicInfo) { - this.drawCollapsedTask(id, name, graphicInfo, true); - } - - protected void drawCollapsedTask(String id, String name, GraphicInfo graphicInfo, boolean thickBorder) { - this.drawTask(id, name, graphicInfo, thickBorder); - } - - public void drawCollapsedMarker(int x, int y, int width, int height) { - int rectangleWidth = 12; - int rectangleHeight = 12; - Rectangle rect = new Rectangle(x + (width - rectangleWidth) / 2, y + height - rectangleHeight - 3, rectangleWidth, rectangleHeight); - this.g.draw(rect); - Line2D.Double line = new Line2D.Double(rect.getCenterX(), rect.getY() + 2.0D, rect.getCenterX(), rect.getMaxY() - 2.0D); - this.g.draw(line); - line = new Line2D.Double(rect.getMinX() + 2.0D, rect.getCenterY(), rect.getMaxX() - 2.0D, rect.getCenterY()); - this.g.draw(line); - } - - public void drawActivityMarkers(int x, int y, int width, int height, boolean multiInstanceSequential, boolean multiInstanceParallel, boolean collapsed) { - if (collapsed) { - if (!multiInstanceSequential && !multiInstanceParallel) { - this.drawCollapsedMarker(x, y, width, height); - } else { - this.drawCollapsedMarker(x - 6 - 2, y, width, height); - if (multiInstanceSequential) { - this.drawMultiInstanceMarker(true, x + 6 + 2, y, width, height); - } else { - this.drawMultiInstanceMarker(false, x + 6 + 2, y, width, height); - } - } - } else if (multiInstanceSequential) { - this.drawMultiInstanceMarker(true, x, y, width, height); - } else if (multiInstanceParallel) { - this.drawMultiInstanceMarker(false, x, y, width, height); - } - - } - - public void drawGateway(GraphicInfo graphicInfo) { - Polygon rhombus = new Polygon(); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - rhombus.addPoint(x, y + height / 2); - rhombus.addPoint(x + width / 2, y + height); - rhombus.addPoint(x + width, y + height / 2); - rhombus.addPoint(x + width / 2, y); - this.g.draw(rhombus); - } - - public void drawParallelGateway(String id, GraphicInfo graphicInfo) { - this.drawGateway(graphicInfo); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - Stroke orginalStroke = this.g.getStroke(); - this.g.setStroke(GATEWAY_TYPE_STROKE); - Line2D.Double line = new Line2D.Double((double) (x + 10), (double) (y + height / 2), (double) (x + width - 10), (double) (y + height / 2)); - this.g.draw(line); - line = new Line2D.Double((double) (x + width / 2), (double) (y + height - 10), (double) (x + width / 2), (double) (y + 10)); - this.g.draw(line); - this.g.setStroke(orginalStroke); - this.g.setCurrentGroupId(id); - } - - public void drawExclusiveGateway(String id, GraphicInfo graphicInfo) { - this.drawGateway(graphicInfo); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - int quarterWidth = width / 4; - int quarterHeight = height / 4; - Stroke orginalStroke = this.g.getStroke(); - this.g.setStroke(GATEWAY_TYPE_STROKE); - Line2D.Double line = new Line2D.Double((double) (x + quarterWidth + 3), (double) (y + quarterHeight + 3), (double) (x + 3 * quarterWidth - 3), (double) (y + 3 * quarterHeight - 3)); - this.g.draw(line); - line = new Line2D.Double((double) (x + quarterWidth + 3), (double) (y + 3 * quarterHeight - 3), (double) (x + 3 * quarterWidth - 3), (double) (y + quarterHeight + 3)); - this.g.draw(line); - this.g.setStroke(orginalStroke); - this.g.setCurrentGroupId(id); - } - - public void drawInclusiveGateway(String id, GraphicInfo graphicInfo) { - this.drawGateway(graphicInfo); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - int diameter = width / 2; - Stroke orginalStroke = this.g.getStroke(); - this.g.setStroke(GATEWAY_TYPE_STROKE); - Ellipse2D.Double circle = new Ellipse2D.Double((double) ((width - diameter) / 2 + x), (double) ((height - diameter) / 2 + y), (double) diameter, (double) diameter); - this.g.draw(circle); - this.g.setStroke(orginalStroke); - this.g.setCurrentGroupId(id); - } - - public void drawEventBasedGateway(String id, GraphicInfo graphicInfo) { - this.drawGateway(graphicInfo); - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - double scale = 0.6D; - GraphicInfo eventInfo = new GraphicInfo(); - eventInfo.setX((double) x + (double) width * (1.0D - scale) / 2.0D); - eventInfo.setY((double) y + (double) height * (1.0D - scale) / 2.0D); - eventInfo.setWidth((double) width * scale); - eventInfo.setHeight((double) height * scale); - this.drawCatchingEvent((String) null, eventInfo, true, (IconType) null, "eventGateway"); - double r = (double) width / 6.0D; - int topX = (int) (0.95D * r); - int topY = (int) (-0.31D * r); - int bottomX = (int) (0.59D * r); - int bottomY = (int) (0.81D * r); - int[] xPoints = new int[]{0, topX, bottomX, -bottomX, -topX}; - int[] yPoints = new int[]{-((int) r), topY, bottomY, bottomY, topY}; - Polygon pentagon = new Polygon(xPoints, yPoints, 5); - pentagon.translate(x + width / 2, y + width / 2); - this.g.drawPolygon(pentagon); - this.g.setCurrentGroupId(id); - } - - public void drawMultiInstanceMarker(boolean sequential, int x, int y, int width, int height) { - int rectangleWidth = 12; - int rectangleHeight = 12; - int lineX = x + (width - rectangleWidth) / 2; - int lineY = y + height - rectangleHeight - 3; - Stroke orginalStroke = this.g.getStroke(); - this.g.setStroke(MULTI_INSTANCE_STROKE); - if (sequential) { - this.g.draw(new Line2D.Double((double) lineX, (double) lineY, (double) (lineX + rectangleWidth), (double) lineY)); - this.g.draw(new Line2D.Double((double) lineX, (double) (lineY + rectangleHeight / 2), (double) (lineX + rectangleWidth), (double) (lineY + rectangleHeight / 2))); - this.g.draw(new Line2D.Double((double) lineX, (double) (lineY + rectangleHeight), (double) (lineX + rectangleWidth), (double) (lineY + rectangleHeight))); - } else { - this.g.draw(new Line2D.Double((double) lineX, (double) lineY, (double) lineX, (double) (lineY + rectangleHeight))); - this.g.draw(new Line2D.Double((double) (lineX + rectangleWidth / 2), (double) lineY, (double) (lineX + rectangleWidth / 2), (double) (lineY + rectangleHeight))); - this.g.draw(new Line2D.Double((double) (lineX + rectangleWidth), (double) lineY, (double) (lineX + rectangleWidth), (double) (lineY + rectangleHeight))); - } - - this.g.setStroke(orginalStroke); - } - - public void drawHighLight(int x, int y, int width, int height) { - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - this.g.setPaint(HIGHLIGHT_COLOR); - this.g.setStroke(THICK_TASK_BORDER_STROKE); - RoundRectangle2D rect = new RoundRectangle2D.Double((double) x, (double) y, (double) width, (double) height, 5.0D, 5.0D); - this.g.draw(rect); - this.g.setPaint(originalPaint); - this.g.setStroke(originalStroke); - } - - - /** - * Desc: 绘制正在执行中的节点红色高亮显示 - * - * @param x x - * @param y y - * @param width width - * @param height height - * @author Fuxs - */ - public void drawRunningActivityHighLight(int x, int y, int width, int height) { - Paint originalPaint = this.g.getPaint(); - Stroke originalStroke = this.g.getStroke(); - - this.g.setPaint(RUNNING_HIGHLIGHT_COLOR); - this.g.setStroke(THICK_TASK_BORDER_STROKE); - //todo 修改长方形弧度 - //RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); - RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 5, 5); - this.g.draw(rect); - - this.g.setPaint(originalPaint); - this.g.setStroke(originalStroke); - } - - public void drawTextAnnotation(String id, String text, GraphicInfo graphicInfo) { - int x = (int) graphicInfo.getX(); - int y = (int) graphicInfo.getY(); - int width = (int) graphicInfo.getWidth(); - int height = (int) graphicInfo.getHeight(); - Font originalFont = this.g.getFont(); - Stroke originalStroke = this.g.getStroke(); - this.g.setFont(ANNOTATION_FONT); - Path2D path = new Path2D.Double(); - x = (int) ((double) x + 0.5D); - int lineLength = 18; - path.moveTo((double) (x + lineLength), (double) y); - path.lineTo((double) x, (double) y); - path.lineTo((double) x, (double) (y + height)); - path.lineTo((double) (x + lineLength), (double) (y + height)); - path.lineTo((double) (x + lineLength), (double) (y + height - 1)); - path.lineTo((double) (x + 1), (double) (y + height - 1)); - path.lineTo((double) (x + 1), (double) (y + 1)); - path.lineTo((double) (x + lineLength), (double) (y + 1)); - path.closePath(); - this.g.draw(path); - int boxWidth = width - 14; - int boxHeight = height - 14; - int boxX = x + width / 2 - boxWidth / 2; - int boxY = y + height / 2 - boxHeight / 2; - if (text != null && !text.isEmpty()) { - this.drawMultilineAnnotationText(text, boxX, boxY, boxWidth, boxHeight); - } - - this.g.setFont(originalFont); - this.g.setStroke(originalStroke); - this.g.setCurrentGroupId(id); - } - - public void drawLabel(String text, GraphicInfo graphicInfo) { - this.drawLabel(text, graphicInfo, true); - } - - /** - * 绘制流程线名称 - * Desc: - * - * @param text - * @param graphicInfo - * @param centered - * @author Fuxs - */ - public void drawLabel(String text, GraphicInfo graphicInfo, boolean centered) { + public void drawLabel(boolean highLighted, String text, GraphicInfo graphicInfo, boolean centered) { float interline = 1.0f; + // text if (text != null && text.length() > 0) { - Paint originalPaint = this.g.getPaint(); - Font originalFont = this.g.getFont(); - - this.g.setPaint(LABEL_COLOR); - this.g.setFont(LABEL_FONT); + Paint originalPaint = g.getPaint(); + Font originalFont = g.getFont(); + if (highLighted) { + g.setPaint(WorkflowConstants.COLOR_NORMAL); + } else { + g.setPaint(LABEL_COLOR); + } + g.setFont(new Font(labelFontName, Font.BOLD, 10)); int wrapWidth = 100; - int textY = (int) (graphicInfo.getY() + graphicInfo.getHeight()); + int textY = (int) graphicInfo.getY(); // TODO: use drawMultilineText() AttributedString as = new AttributedString(text); - as.addAttribute(TextAttribute.FOREGROUND, this.g.getPaint()); - as.addAttribute(TextAttribute.FONT, this.g.getFont()); + as.addAttribute(TextAttribute.FOREGROUND, g.getPaint()); + as.addAttribute(TextAttribute.FONT, g.getFont()); AttributedCharacterIterator aci = as.getIterator(); FontRenderContext frc = new FontRenderContext(null, true, false); + LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc); - TextLayout tl; - for (LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc); - lbm.getPosition() < text.length(); - textY = (int) ((float) textY + tl.getDescent() + tl.getLeading() + (interline - 1.0F) * tl.getAscent()) - ) { - tl = lbm.nextLayout((float) wrapWidth); - textY = (int) ((float) textY + tl.getAscent()); + while (lbm.getPosition() < text.length()) { + TextLayout tl = lbm.nextLayout(wrapWidth); + textY += tl.getAscent(); Rectangle2D bb = tl.getBounds(); double tX = graphicInfo.getX(); if (centered) { - tX += (double) ((int) (graphicInfo.getWidth() / 2.0D - bb.getWidth() / 2.0D)); + tX += (int) (graphicInfo.getWidth() / 2 - bb.getWidth() / 2); } - - tl.draw(this.g, (float) tX, (float) textY); + tl.draw(g, (float) tX, textY); + textY += tl.getDescent() + tl.getLeading() + (interline - 1.0f) * tl.getAscent(); } // restore originals - this.g.setFont(originalFont); - this.g.setPaint(originalPaint); + g.setFont(originalFont); + g.setPaint(originalPaint); } } - /** - * This method makes coordinates of connection flow better. - * - * @param sourceShapeType - * @param targetShapeType - * @param sourceGraphicInfo - * @param targetGraphicInfo - * @param graphicInfoList - */ - public List connectionPerfectionizer(SHAPE_TYPE sourceShapeType, - SHAPE_TYPE targetShapeType, - GraphicInfo sourceGraphicInfo, - GraphicInfo targetGraphicInfo, - List graphicInfoList) { - Shape shapeFirst = createShape(sourceShapeType, sourceGraphicInfo); - Shape shapeLast = createShape(targetShapeType, targetGraphicInfo); - - if (graphicInfoList != null && graphicInfoList.size() > 0) { - GraphicInfo graphicInfoFirst = graphicInfoList.get(0); - GraphicInfo graphicInfoLast = graphicInfoList.get(graphicInfoList.size() - 1); - if (shapeFirst != null) { - graphicInfoFirst.setX(shapeFirst.getBounds2D().getCenterX()); - graphicInfoFirst.setY(shapeFirst.getBounds2D().getCenterY()); - } - if (shapeLast != null) { - graphicInfoLast.setX(shapeLast.getBounds2D().getCenterX()); - graphicInfoLast.setY(shapeLast.getBounds2D().getCenterY()); - } - - Point p = null; - - if (shapeFirst != null) { - Line2D.Double lineFirst = new Line2D.Double(graphicInfoFirst.getX(), graphicInfoFirst.getY(), graphicInfoList.get(1).getX(), graphicInfoList.get(1).getY()); - p = getIntersection(shapeFirst, lineFirst); - if (p != null) { - graphicInfoFirst.setX(p.getX()); - graphicInfoFirst.setY(p.getY()); - } - } - - if (shapeLast != null) { - Line2D.Double lineLast = new Line2D.Double(graphicInfoLast.getX(), graphicInfoLast.getY(), graphicInfoList.get(graphicInfoList.size() - 2).getX(), - graphicInfoList.get(graphicInfoList.size() - 2).getY()); - p = getIntersection(shapeLast, lineLast); - if (p != null) { - graphicInfoLast.setX(p.getX()); - graphicInfoLast.setY(p.getY()); - } - } + @Override + public BufferedImage generateBufferedImage(String imageType) { + if (closed) { + throw new ActivitiImageException("ProcessDiagramGenerator already closed"); } - return graphicInfoList; + // Try to remove white space + minX = (minX <= WorkflowConstants.PROCESS_PADDING) ? WorkflowConstants.PROCESS_PADDING : minX; + minY = (minY <= WorkflowConstants.PROCESS_PADDING) ? WorkflowConstants.PROCESS_PADDING : minY; + BufferedImage imageToSerialize = processDiagram; + if (minX >= 0 && minY >= 0) { + imageToSerialize = processDiagram.getSubimage( + minX - WorkflowConstants.PROCESS_PADDING, + minY - WorkflowConstants.PROCESS_PADDING, + canvasWidth - minX + WorkflowConstants.PROCESS_PADDING, + canvasHeight - minY + WorkflowConstants.PROCESS_PADDING); + } + return imageToSerialize; } - /** - * This method creates shape by type and coordinates. - * - * @param shapeType - * @param graphicInfo - * @return Shape - */ - private static Shape createShape(SHAPE_TYPE shapeType, GraphicInfo graphicInfo) { - if (SHAPE_TYPE.Rectangle.equals(shapeType)) { - // source is rectangle - return new Rectangle2D.Double(graphicInfo.getX(), graphicInfo.getY(), graphicInfo.getWidth(), graphicInfo.getHeight()); - } else if (SHAPE_TYPE.Rhombus.equals(shapeType)) { - // source is rhombus - Path2D.Double rhombus = new Path2D.Double(); - rhombus.moveTo(graphicInfo.getX(), graphicInfo.getY() + graphicInfo.getHeight() / 2); - rhombus.lineTo(graphicInfo.getX() + graphicInfo.getWidth() / 2, graphicInfo.getY() + graphicInfo.getHeight()); - rhombus.lineTo(graphicInfo.getX() + graphicInfo.getWidth(), graphicInfo.getY() + graphicInfo.getHeight() / 2); - rhombus.lineTo(graphicInfo.getX() + graphicInfo.getWidth() / 2, graphicInfo.getY()); - rhombus.lineTo(graphicInfo.getX(), graphicInfo.getY() + graphicInfo.getHeight() / 2); - rhombus.closePath(); - return rhombus; - } else { - return DefaultProcessDiagramCanvas.SHAPE_TYPE.Ellipse.equals(shapeType) ? new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), graphicInfo.getWidth(), graphicInfo.getHeight()) : null; + @Override + public void initialize(String imageType) { + this.processDiagram = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_ARGB); + this.g = processDiagram.createGraphics(); + + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g.setPaint(Color.black); + + Font font = new Font(activityFontName, Font.BOLD, FONT_SIZE); + g.setFont(font); + this.fontMetrics = g.getFontMetrics(); + + LABEL_FONT = new Font(labelFontName, Font.ITALIC, 10); + ANNOTATION_FONT = new Font(annotationFontName, Font.PLAIN, FONT_SIZE); + //优化加载速度 + if(flag) { + return; + } + try { + USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/userTask.png", customClassLoader)); + SCRIPTTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/scriptTask.png", customClassLoader)); + SERVICETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/serviceTask.png", customClassLoader)); + RECEIVETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/receiveTask.png", customClassLoader)); + SENDTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/sendTask.png", customClassLoader)); + MANUALTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/manualTask.png", customClassLoader)); + BUSINESS_RULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/businessRuleTask.png", customClassLoader)); + SHELL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/shellTask.png", customClassLoader)); + CAMEL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/camelTask.png", customClassLoader)); + MULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/muleTask.png", customClassLoader)); + + TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/timer.png", customClassLoader)); + COMPENSATE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/compensate-throw.png", customClassLoader)); + COMPENSATE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/compensate.png", customClassLoader)); + ERROR_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/error-throw.png", customClassLoader)); + ERROR_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/error.png", customClassLoader)); + MESSAGE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/message-throw.png", customClassLoader)); + MESSAGE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/message.png", customClassLoader)); + SIGNAL_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/signal-throw.png", customClassLoader)); + SIGNAL_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/signal.png", customClassLoader)); +/* String baseUrl = Thread.currentThread().getContextClassLoader().getResource("static/img/activiti/").getPath(); + SCRIPTTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"scriptTask.png")); + USERTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"userTask.png")); + SERVICETASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"serviceTask.png")); + RECEIVETASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"receiveTask.png")); + SENDTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"sendTask.png")); + MANUALTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"manualTask.png")); + BUSINESS_RULE_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"businessRuleTask.png")); + SHELL_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"shellTask.png")); + CAMEL_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"camelTask.png")); + MULE_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"muleTask.png")); + + TIMER_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"timer.png")); + COMPENSATE_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"compensate-throw.png")); + COMPENSATE_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"compensate.png")); + ERROR_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"error-throw.png")); + ERROR_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"error.png")); + MESSAGE_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"message-throw.png")); + MESSAGE_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"message.png")); + SIGNAL_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"signal-throw.png")); + SIGNAL_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"signal.png"));*/ + flag = true; + } catch (IOException e) { + flag = false; + LOGGER.warn("Could not load image for process diagram creation: {}", e.getMessage()); } } - /** - * This method returns intersection point of shape border and line. - * - * @param shape - * @param line - * @return Point - */ - private static Point getIntersection(Shape shape, Line2D.Double line) { - if (shape instanceof Ellipse2D) { - return getEllipseIntersection(shape, line); - } else { - return !(shape instanceof Rectangle2D) && !(shape instanceof Path2D) ? null : getShapeIntersection(shape, line); - } - } - /** - * This method calculates ellipse intersection with line - * - * @param shape Bounds of this shape used to calculate parameters of inscribed into this bounds ellipse. - * @param line - * @return Intersection point - */ - private static Point getEllipseIntersection(Shape shape, Line2D.Double line) { - double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1); - double x = shape.getBounds2D().getWidth() / 2.0D * Math.cos(angle) + shape.getBounds2D().getCenterX(); - double y = shape.getBounds2D().getHeight() / 2.0D * Math.sin(angle) + shape.getBounds2D().getCenterY(); - Point p = new Point(); - p.setLocation(x, y); - return p; - } - - /** - * This method calculates shape intersection with line. - * - * @param shape - * @param line - * @return Intersection point - */ - private static Point getShapeIntersection(Shape shape, Line2D.Double line) { - PathIterator it = shape.getPathIterator(null); - double[] coords = new double[6]; - double[] pos = new double[2]; - Line2D.Double l = new Line2D.Double(); - while (!it.isDone()) { - int type = it.currentSegment(coords); - switch (type) { - case PathIterator.SEG_MOVETO: - pos[0] = coords[0]; - pos[1] = coords[1]; - break; - case PathIterator.SEG_LINETO: - l = new Line2D.Double(pos[0], pos[1], coords[0], coords[1]); - if (line.intersectsLine(l)) { - return getLinesIntersection(line, l); - } - pos[0] = coords[0]; - pos[1] = coords[1]; - break; - case PathIterator.SEG_CLOSE: - break; - default: - // whatever - } - it.next(); - } - return null; - } - - /** - * This method calculates intersections of two lines. - * - * @param a Line 1 - * @param b Line 2 - * @return Intersection point - */ - private static Point getLinesIntersection(Line2D a, Line2D b) { - double d = (a.getX1() - a.getX2()) * (b.getY2() - b.getY1()) - (a.getY1() - a.getY2()) * (b.getX2() - b.getX1()); - double da = (a.getX1() - b.getX1()) * (b.getY2() - b.getY1()) - (a.getY1() - b.getY1()) * (b.getX2() - b.getX1()); - // double db = (a.getX1()-a.getX2())*(a.getY1()-b.getY1()) - (a.getY1()-a.getY2())*(a.getX1()-b.getX1()); - double ta = da / d; - // double tb = db/d; - Point p = new Point(); - p.setLocation(a.getX1() + ta * (a.getX2() - a.getX1()), a.getY1() + ta * (a.getY2() - a.getY1())); - return p; - } - - -} \ No newline at end of file +} diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/CustomProcessDiagramGenerator.java b/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/CustomProcessDiagramGenerator.java index bd192547..8d748bdb 100644 --- a/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/CustomProcessDiagramGenerator.java +++ b/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/CustomProcessDiagramGenerator.java @@ -1,395 +1,211 @@ package com.jero.modules.activiti.service.impl.image; -import lombok.extern.slf4j.Slf4j; import org.activiti.bpmn.model.Process; import org.activiti.bpmn.model.*; +import org.activiti.image.impl.DefaultProcessDiagramGenerator; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageOutputStream; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Set; - -/** - * Class to generate an image based the diagram interchange information in a BPMN 2.0 process. - * 在 BPMN 2.0 流程中基于图表交换信息生成图像的类。 - * - * @author Joram Barrez - * @author Tijs Rademakers - */ -@Slf4j -public class CustomProcessDiagramGenerator implements ICustomProcessDiagramGenerator { - - protected String ACTIVITY_FONT_NAME = "微软雅黑"; - protected String LABEL_FONT_NAME = "微软雅黑"; - protected String ANNOTATION_FONT_NAME = "微软雅黑"; - - protected Map, ActivityDrawInstruction> activityDrawInstructions = new HashMap<>(); - protected Map, ArtifactDrawInstruction> artifactDrawInstructions = new HashMap<>(); - - /** - * The instructions on how to draw a certain construct is - * created statically and stored in a map for performance. - */ - public CustomProcessDiagramGenerator() { - // start event - activityDrawInstructions.put(StartEvent.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - StartEvent startEvent = (StartEvent) flowNode; - if (startEvent.getEventDefinitions() != null && !startEvent.getEventDefinitions().isEmpty()) { - EventDefinition eventDefinition = startEvent.getEventDefinitions().get(0); - if (eventDefinition instanceof TimerEventDefinition) { - processDiagramCanvas.drawTimerStartEvent(flowNode.getId(), graphicInfo); - } else if (eventDefinition instanceof ErrorEventDefinition) { - processDiagramCanvas.drawErrorStartEvent(flowNode.getId(), graphicInfo); - } else if (eventDefinition instanceof SignalEventDefinition) { - processDiagramCanvas.drawSignalStartEvent(flowNode.getId(), graphicInfo); - } else if (eventDefinition instanceof MessageEventDefinition) { - processDiagramCanvas.drawMessageStartEvent(flowNode.getId(), graphicInfo); - } else { - processDiagramCanvas.drawNoneStartEvent(flowNode.getId(), graphicInfo); - } - } else { - processDiagramCanvas.drawNoneStartEvent(flowNode.getId(), graphicInfo); - } - } - }); - - // signal catch - activityDrawInstructions.put(IntermediateCatchEvent.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent) flowNode; - if (intermediateCatchEvent.getEventDefinitions() != null && !intermediateCatchEvent - .getEventDefinitions().isEmpty()) { - if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { - processDiagramCanvas.drawCatchingSignalEvent(flowNode.getId(), flowNode.getName(), graphicInfo, true); - } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) { - processDiagramCanvas.drawCatchingTimerEvent(flowNode.getId(), flowNode.getName(), graphicInfo, true); - } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) { - processDiagramCanvas.drawCatchingMessageEvent(flowNode.getId(), flowNode.getName(), graphicInfo, true); - } - } - } - }); - - // signal throw - activityDrawInstructions.put(ThrowEvent.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - ThrowEvent throwEvent = (ThrowEvent) flowNode; - if (throwEvent.getEventDefinitions() != null && !throwEvent.getEventDefinitions().isEmpty()) { - if (throwEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { - processDiagramCanvas.drawThrowingSignalEvent(flowNode.getId(), graphicInfo); - } else if (throwEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) { - processDiagramCanvas.drawThrowingCompensateEvent(flowNode.getId(), graphicInfo); - } else { - processDiagramCanvas.drawThrowingNoneEvent(flowNode.getId(), graphicInfo); - } - } else { - processDiagramCanvas.drawThrowingNoneEvent(flowNode.getId(), graphicInfo); - } - } - }); - - // end event - activityDrawInstructions.put(EndEvent.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - EndEvent endEvent = (EndEvent) flowNode; - if (endEvent.getEventDefinitions() != null && !endEvent.getEventDefinitions().isEmpty()) { - if (endEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) { - processDiagramCanvas.drawErrorEndEvent(flowNode.getId(), flowNode.getName(), graphicInfo); - } else { - processDiagramCanvas.drawNoneEndEvent(flowNode.getId(), flowNode.getName(), graphicInfo); - } - } else { - processDiagramCanvas.drawNoneEndEvent(flowNode.getId(), flowNode.getName(), graphicInfo); - } - } - }); - - // task - activityDrawInstructions.put(Task.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawTask(flowNode.getId(), flowNode.getName(), graphicInfo); - } - }); - - // user task - activityDrawInstructions.put(UserTask.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawUserTask(flowNode.getId(), flowNode.getName(), graphicInfo); - } - }); - - // script task - activityDrawInstructions.put(ScriptTask.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawScriptTask(flowNode.getId(), flowNode.getName(), graphicInfo); - } - }); - - // service task - activityDrawInstructions.put(ServiceTask.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - ServiceTask serviceTask = (ServiceTask) flowNode; - processDiagramCanvas.drawServiceTask(flowNode.getId(), flowNode.getName(), graphicInfo); - } - }); - - // receive task - activityDrawInstructions.put(ReceiveTask.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawReceiveTask(flowNode.getId(), flowNode.getName(), graphicInfo); - } - }); - - // send task - activityDrawInstructions.put(SendTask.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawSendTask(flowNode.getId(), flowNode.getName(), graphicInfo); - } - }); - - // manual task - activityDrawInstructions.put(ManualTask.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawManualTask(flowNode.getId(), flowNode.getName(), graphicInfo); - } - }); - - // businessRuleTask task - activityDrawInstructions.put(BusinessRuleTask.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawBusinessRuleTask(flowNode.getId(), flowNode.getName(), graphicInfo); - } - }); - - // exclusive gateway - activityDrawInstructions.put(ExclusiveGateway.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawExclusiveGateway(flowNode.getId(), graphicInfo); - } - }); - - // inclusive gateway - activityDrawInstructions.put(InclusiveGateway.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawInclusiveGateway(flowNode.getId(), graphicInfo); - } - }); - - // parallel gateway - activityDrawInstructions.put(ParallelGateway.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawParallelGateway(flowNode.getId(), graphicInfo); - } - }); - - // event based gateway - activityDrawInstructions.put(EventGateway.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawEventBasedGateway(flowNode.getId(), graphicInfo); - } - }); - - // Boundary timer - activityDrawInstructions.put(BoundaryEvent.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - BoundaryEvent boundaryEvent = (BoundaryEvent) flowNode; - if (boundaryEvent.getEventDefinitions() != null && !boundaryEvent.getEventDefinitions().isEmpty()) { - if (boundaryEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) { - processDiagramCanvas.drawCatchingTimerEvent(flowNode.getId(), flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity()); - } else if (boundaryEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) { - processDiagramCanvas.drawCatchingErrorEvent(flowNode.getId(), graphicInfo, boundaryEvent.isCancelActivity()); - } else if (boundaryEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) { - processDiagramCanvas.drawCatchingSignalEvent(flowNode.getId(), flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity()); - } else if (boundaryEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) { - processDiagramCanvas.drawCatchingMessageEvent(flowNode.getId(), flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity()); - } else if (boundaryEvent.getEventDefinitions().get(0) instanceof CompensateEventDefinition) { - processDiagramCanvas.drawCatchingCompensateEvent(flowNode.getId(), graphicInfo, boundaryEvent.isCancelActivity()); - } - } - - } - }); - - // subprocess - activityDrawInstructions.put(SubProcess.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - processDiagramCanvas.drawCollapsedSubProcess(flowNode.getId(), flowNode.getName(), graphicInfo, false); - } else { - processDiagramCanvas.drawExpandedSubProcess(flowNode.getId(), flowNode.getName(), graphicInfo, SubProcess.class); - } - } - }); - - // Event subprocess - activityDrawInstructions.put(EventSubProcess.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) { - processDiagramCanvas.drawCollapsedSubProcess(flowNode.getId(), flowNode.getName(), graphicInfo, false); - } else { - processDiagramCanvas.drawExpandedSubProcess(flowNode.getId(), flowNode.getName(), graphicInfo, Transaction.class); - } - } - }); - - // call activity - activityDrawInstructions.put(CallActivity.class, new ActivityDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - processDiagramCanvas.drawCollapsedCallActivity(flowNode.getId(), flowNode.getName(), graphicInfo); - } - }); - - // text annotation - artifactDrawInstructions.put(TextAnnotation.class, new ArtifactDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); - TextAnnotation textAnnotation = (TextAnnotation) artifact; - processDiagramCanvas.drawTextAnnotation(textAnnotation.getId(), textAnnotation.getText(), graphicInfo); - } - }); - - // association - artifactDrawInstructions.put(Association.class, new ArtifactDrawInstruction() { - @Override - public void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) { - Association association = (Association) artifact; - String sourceRef = association.getSourceRef(); - String targetRef = association.getTargetRef(); - - // source and target can be instance of FlowElement or Artifact - BaseElement sourceElement = bpmnModel.getFlowElement(sourceRef); - BaseElement targetElement = bpmnModel.getFlowElement(targetRef); - if (sourceElement == null) { - sourceElement = bpmnModel.getArtifact(sourceRef); - } - if (targetElement == null) { - targetElement = bpmnModel.getArtifact(targetRef); - } - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); - graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList); - int[] xPoints = new int[graphicInfoList.size()]; - int[] yPoints = new int[graphicInfoList.size()]; - for (int i = 1; i < graphicInfoList.size(); i++) { - GraphicInfo graphicInfo = graphicInfoList.get(i); - GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); - - if (i == 1) { - xPoints[0] = (int) previousGraphicInfo.getX(); - yPoints[0] = (int) previousGraphicInfo.getY(); - } - xPoints[i] = (int) graphicInfo.getX(); - yPoints[i] = (int) graphicInfo.getY(); - } - - AssociationDirection associationDirection = association.getAssociationDirection(); - processDiagramCanvas.drawAssociation(xPoints, yPoints, associationDirection, false); - } - }); +@Component +public class CustomProcessDiagramGenerator extends DefaultProcessDiagramGenerator implements ICustomProcessDiagramGenerator{ + //预初始化流程图绘制,大大提升了系统启动后首次查看流程图的速度 + static { + new CustomProcessDiagramCanvas(10,10,0,0,"png", "宋体","宋体","宋体",null); } + public CustomProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType, + List highLightedActivities, List highLightedFlows, String activityFontName, + String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, + Color[] colors, Set currIds) { - protected CustomProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, - List highLightedActivities, List runningActivityIdList, List highLightedFlows, List runningActivityFlowsIds, - String activityFontName, String labelFontName, String annotationFontName) { + if(null == highLightedActivities) { + highLightedActivities = Collections.emptyList(); + } + if(null == highLightedFlows) { + highLightedFlows = Collections.emptyList(); + } - CustomProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, activityFontName, labelFontName, annotationFontName); + prepareBpmnModel(bpmnModel); + + CustomProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); // Draw pool shape, if process is participant in collaboration for (Pool pool : bpmnModel.getPools()) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); - processDiagramCanvas.drawPoolOrLane(pool.getId(), pool.getName(), graphicInfo); + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); + processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo); } // Draw lanes for (Process process : bpmnModel.getProcesses()) { - for (Lane lane : process.getLanes()) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId()); - processDiagramCanvas.drawPoolOrLane(lane.getId(), lane.getName(), graphicInfo); - } + for (Lane lane : process.getLanes()) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId()); + processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo); + } } // Draw activities and their sequence-flows - /** - * 绘制流程图上的所有节点和流程线,对高亮显示的节点和流程线进行特殊处理 - */ - for (FlowNode flowNode : bpmnModel.getProcesses().get(0).findFlowElementsOfType(FlowNode.class)) { - drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, runningActivityIdList, - highLightedFlows, runningActivityFlowsIds); + for (Process process: bpmnModel.getProcesses()) { + List flowNodeList= process.findFlowElementsOfType(FlowNode.class); + for (FlowNode flowNode : flowNodeList) { + drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor, colors, currIds); + } } // Draw artifacts for (Process process : bpmnModel.getProcesses()) { - for (Artifact artifact : process.getArtifacts()) { - drawArtifact(processDiagramCanvas, bpmnModel, artifact); + + for (Artifact artifact : process.getArtifacts()) { + drawArtifact(processDiagramCanvas, bpmnModel, artifact); + } + + List subProcesses = process.findFlowElementsOfType(SubProcess.class, true); + if (subProcesses != null) { + for (SubProcess subProcess : subProcesses) { + for (Artifact subProcessArtifact : subProcess.getArtifacts()) { + drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact); + } } + } } return processDiagramCanvas; } - /** - * Desc: 绘制流程图上的所有节点和流程线,对高亮显示的节点和流程线进行特殊处理 - * - * @param processDiagramCanvas - * @param bpmnModel - * @param flowNode - * @param highLightedActivities - * @param highLightedFlows - * @author Fuxs - */ protected void drawActivity(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode, - List highLightedActivities, List runningActivityIdList, List highLightedFlows, List runningActivityFlowsIds) { + List highLightedActivities, List highLightedFlows, double scaleFactor, Color[] colors, Set currIds) { + ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass()); + if (drawInstruction != null) { + drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode); + + // Gather info on the multi instance marker + boolean multiInstanceSequential = false, multiInstanceParallel = false, collapsed = false; + if (flowNode instanceof Activity) { + Activity activity = (Activity) flowNode; + MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics(); + if (multiInstanceLoopCharacteristics != null) { + multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential(); + multiInstanceParallel = !multiInstanceSequential; + } + } + + // Gather info on the collapsed marker + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); + if (flowNode instanceof SubProcess) { + collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded(); + } else if (flowNode instanceof CallActivity) { + collapsed = true; + } + + if (scaleFactor == 1.0) { + // Actually draw the markers + processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(),(int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), + multiInstanceSequential, multiInstanceParallel, collapsed); + } + + // Draw highlighted activities + if (highLightedActivities.contains(flowNode.getId())) { + if(!CollectionUtils.isEmpty(currIds) + &&currIds.contains(flowNode.getId()) + && !(flowNode instanceof Gateway)) {//非结束节点,并且是当前节点 + drawHighLight((flowNode instanceof StartEvent), processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[1]); + }else {//普通节点 + drawHighLight((flowNode instanceof StartEvent)||(flowNode instanceof EndEvent),processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[0]); + } + } + + } + + // Outgoing transitions of activity + for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { + String flowId = sequenceFlow.getId(); + boolean highLighted = (highLightedFlows.contains(flowId)); + String defaultFlow = null; + if (flowNode instanceof Activity) { + defaultFlow = ((Activity) flowNode).getDefaultFlow(); + } else if (flowNode instanceof Gateway) { + defaultFlow = ((Gateway) flowNode).getDefaultFlow(); + } + + boolean isDefault = false; + if (defaultFlow != null && defaultFlow.equalsIgnoreCase(flowId)) { + isDefault = true; + } +// boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway); + + String sourceRef = sequenceFlow.getSourceRef(); + String targetRef = sequenceFlow.getTargetRef(); + FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef); + FlowElement targetElement = bpmnModel.getFlowElement(targetRef); + List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(flowId); + if (graphicInfoList != null && graphicInfoList.size() > 0) { + graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList); + int xPoints[]= new int[graphicInfoList.size()]; + int yPoints[]= new int[graphicInfoList.size()]; + + for (int i=1; i= 5); +// } + } + } + + // Nested elements + if (flowNode instanceof FlowElementsContainer) { + for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) { + if (nestedFlowElement instanceof FlowNode) { + drawActivity_highOne(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor, colors, currIds); + //drawActivity,这个是activiti自带的,子流程会出现多次高亮问题,改用 drawActivity_highOne + /*drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement, + highLightedActivities, highLightedFlows, scaleFactor);*/ + } + } + } + } + + /** + * 解决子流程多次高亮问题 + */ + protected void drawActivity_highOne(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode, + List highLightedActivities, List highLightedFlows, double scaleFactor, Color[] colors, Set currIds) { ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass()); if (drawInstruction != null) { drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode); // Gather info on the multi instance marker - boolean multiInstanceSequential = false; - boolean multiInstanceParallel = false; - boolean highLighted = false; + boolean multiInstanceSequential = false, multiInstanceParallel = false, collapsed = false; if (flowNode instanceof Activity) { Activity activity = (Activity) flowNode; MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics(); @@ -399,39 +215,37 @@ public class CustomProcessDiagramGenerator implements ICustomProcessDiagramGener } } - // Gather info on the highLighted marker + // Gather info on the collapsed marker GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - if (!(flowNode instanceof SubProcess)) { - if (flowNode instanceof CallActivity) { - highLighted = true; - } - } else { - highLighted = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded(); + if (flowNode instanceof SubProcess) { + collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded(); + } else if (flowNode instanceof CallActivity) { + collapsed = true; } - processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), multiInstanceSequential, multiInstanceParallel, highLighted); - + if (scaleFactor == 1.0) { + // Actually draw the markers + processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(),(int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), + multiInstanceSequential, multiInstanceParallel, collapsed); + } // Draw highlighted activities if (highLightedActivities.contains(flowNode.getId())) { - /* - * 如果节点为当前正在处理中的节点,则红色高亮显示 - */ - if (runningActivityIdList.contains(flowNode.getId())) { - log.debug("[绘制]-当前正在处理中的节点-红色高亮显示节点[{}-{}]", flowNode.getId(), flowNode.getName()); - drawRunningActivityHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); - } else { - log.debug("[绘制]-高亮显示节点[{}-{}]", flowNode.getId(), flowNode.getName()); - drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); + if(!CollectionUtils.isEmpty(currIds) + &&currIds.contains(flowNode.getId()) + && !(flowNode instanceof Gateway)) {//非结束节点,并且是当前节点 + drawHighLight((flowNode instanceof StartEvent), processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[1]); + }else {//普通节点 + drawHighLight((flowNode instanceof StartEvent)||(flowNode instanceof EndEvent),processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[0]); } } + } - /* - * 绘制当前节点的流程线 - */ + // Outgoing transitions of activity for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { - boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId())); + String flowId = sequenceFlow.getId(); + boolean highLighted = (highLightedFlows.contains(flowId)); String defaultFlow = null; if (flowNode instanceof Activity) { defaultFlow = ((Activity) flowNode).getDefaultFlow(); @@ -440,26 +254,24 @@ public class CustomProcessDiagramGenerator implements ICustomProcessDiagramGener } boolean isDefault = false; - if (defaultFlow != null && defaultFlow.equalsIgnoreCase(sequenceFlow.getId())) { + if (defaultFlow != null && defaultFlow.equalsIgnoreCase(flowId)) { isDefault = true; } - boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null - && !(flowNode instanceof Gateway); +// boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway); String sourceRef = sequenceFlow.getSourceRef(); String targetRef = sequenceFlow.getTargetRef(); FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef); FlowElement targetElement = bpmnModel.getFlowElement(targetRef); - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); + List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(flowId); if (graphicInfoList != null && graphicInfoList.size() > 0) { - graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, - targetElement, graphicInfoList); - int[] xPoints = new int[graphicInfoList.size()]; - int[] yPoints = new int[graphicInfoList.size()]; + graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList); + int xPoints[]= new int[graphicInfoList.size()]; + int yPoints[]= new int[graphicInfoList.size()]; - for (int i = 1; i < graphicInfoList.size(); i++) { + for (int i=1; i= 5); +// } } } - // Nested elements - if (flowNode instanceof FlowElementsContainer) { - for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) { - if (nestedFlowElement instanceof FlowNode) { - drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement, highLightedActivities, - runningActivityIdList, highLightedFlows, runningActivityFlowsIds); - } + } + + protected void drawHighLight(boolean isStartOrEnd, CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo, Color color) { + processDiagramCanvas.drawHighLight(isStartOrEnd, (int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), color); + } + + protected static CustomProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType, + String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { + + // We need to calculate maximum values to know how big the image will be in its entirety + double minX = Double.MAX_VALUE; + double maxX = 0; + double minY = Double.MAX_VALUE; + double maxY = 0; + + for (Pool pool : bpmnModel.getPools()) { + GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); + minX = graphicInfo.getX(); + maxX = graphicInfo.getX() + graphicInfo.getWidth(); + minY = graphicInfo.getY(); + maxY = graphicInfo.getY() + graphicInfo.getHeight(); } - } - } - /** - * This method makes coordinates of connection flow better. - * - * @param processDiagramCanvas - * @param bpmnModel - * @param sourceElement - * @param targetElement - * @param graphicInfoList - * @return - */ - protected static List connectionPerfectionizer(CustomProcessDiagramCanvas processDiagramCanvas, - BpmnModel bpmnModel, BaseElement sourceElement, BaseElement targetElement, - List graphicInfoList) { - GraphicInfo sourceGraphicInfo = bpmnModel.getGraphicInfo(sourceElement.getId()); - GraphicInfo targetGraphicInfo = bpmnModel.getGraphicInfo(targetElement.getId()); + List flowNodes = gatherAllFlowNodes(bpmnModel); + for (FlowNode flowNode : flowNodes) { - CustomProcessDiagramCanvas.SHAPE_TYPE sourceShapeType = getShapeType(sourceElement); - CustomProcessDiagramCanvas.SHAPE_TYPE targetShapeType = getShapeType(targetElement); + GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - return processDiagramCanvas.connectionPerfectionizer(sourceShapeType, targetShapeType, sourceGraphicInfo, - targetGraphicInfo, graphicInfoList); - } - - /** - * This method returns shape type of base element.
- * Each element can be presented as rectangle, rhombus, or ellipse. - * - * @param baseElement - * @return CustomProcessDiagramCanvas.SHAPE_TYPE - */ - protected static CustomProcessDiagramCanvas.SHAPE_TYPE getShapeType(BaseElement baseElement) { - if (baseElement instanceof Task || baseElement instanceof Activity || baseElement instanceof TextAnnotation) { - return CustomProcessDiagramCanvas.SHAPE_TYPE.Rectangle; - } else if (baseElement instanceof Gateway) { - return CustomProcessDiagramCanvas.SHAPE_TYPE.Rhombus; - } else if (baseElement instanceof Event) { - return CustomProcessDiagramCanvas.SHAPE_TYPE.Ellipse; - } else { - // unknown source element, just do not correct coordinates - } - return null; - } - - protected static GraphicInfo getLineCenter(List graphicInfoList) { - GraphicInfo gi = new GraphicInfo(); - - int[] xPoints = new int[graphicInfoList.size()]; - int[] yPoints = new int[graphicInfoList.size()]; - - double length = 0; - double[] lengths = new double[graphicInfoList.size()]; - lengths[0] = 0; - double m; - for (int i = 1; i < graphicInfoList.size(); i++) { - GraphicInfo graphicInfo = graphicInfoList.get(i); - GraphicInfo previousGraphicInfo = graphicInfoList.get(i - 1); - - if (i == 1) { - xPoints[0] = (int) previousGraphicInfo.getX(); - yPoints[0] = (int) previousGraphicInfo.getY(); - } - xPoints[i] = (int) graphicInfo.getX(); - yPoints[i] = (int) graphicInfo.getY(); - - length += Math.sqrt(Math.pow((int) graphicInfo.getX() - (int) previousGraphicInfo.getX(), 2) + Math.pow( - (int) graphicInfo.getY() - (int) previousGraphicInfo.getY(), 2)); - lengths[i] = length; - } - m = length / 2; - int p1 = 0, p2 = 1; - for (int i = 1; i < lengths.length; i++) { - double len = lengths[i]; - p1 = i - 1; - p2 = i; - if (len > m) { - break; - } - } - - GraphicInfo graphicInfo1 = graphicInfoList.get(p1); - GraphicInfo graphicInfo2 = graphicInfoList.get(p2); - - double AB = (int) graphicInfo2.getX() - (int) graphicInfo1.getX(); - double OA = (int) graphicInfo2.getY() - (int) graphicInfo1.getY(); - double OB = lengths[p2] - lengths[p1]; - double ob = m - lengths[p1]; - double ab = AB * ob / OB; - double oa = OA * ob / OB; - - double mx = graphicInfo1.getX() + ab; - double my = graphicInfo1.getY() + oa; - - gi.setX(mx); - gi.setY(my); - return gi; - } - - protected void drawArtifact(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, - Artifact artifact) { - - ArtifactDrawInstruction drawInstruction = artifactDrawInstructions.get(artifact.getClass()); - if (drawInstruction != null) { - drawInstruction.draw(processDiagramCanvas, bpmnModel, artifact); - } - } - - private static void drawHighLight(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { - processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo - .getWidth(), (int) graphicInfo.getHeight()); - - } - - /** - * Desc:绘制正在执行中的节点红色高亮显示 - * - * @param processDiagramCanvas CustomProcessDiagramCanvas - * @param graphicInfo GraphicInfo - * @author Fuxs - */ - private static void drawRunningActivityHighLight(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { - processDiagramCanvas.drawRunningActivityHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo - .getWidth(), (int) graphicInfo.getHeight()); - - } - - protected static CustomProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String activityFontName, - String labelFontName, String annotationFontName) { - - // We need to calculate maximum values to know how big the image will be in its entirety - double minX = 1.7976931348623157E308D; - double maxX = 0.0D; - double minY = 1.7976931348623157E308D; - double maxY = 0.0D; - - - for (Pool pool : bpmnModel.getPools()) { - GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId()); - minX = graphicInfo.getX(); - maxX = graphicInfo.getX() + graphicInfo.getWidth(); - minY = graphicInfo.getY(); - maxY = graphicInfo.getY() + graphicInfo.getHeight(); - } - - List flowNodes = gatherAllFlowNodes(bpmnModel); - for (FlowNode flowNode : flowNodes) { - - GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId()); - - // width - if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) { + // width + if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) { maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth(); - } - if (flowNodeGraphicInfo.getX() < minX) { + } + if (flowNodeGraphicInfo.getX() < minX) { minX = flowNodeGraphicInfo.getX(); - } - // height - if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) { + } + // height + if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) { maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight(); - } - if (flowNodeGraphicInfo.getY() < minY) { + } + if (flowNodeGraphicInfo.getY() < minY) { minY = flowNodeGraphicInfo.getY(); - } + } - for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { + for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); if (graphicInfoList != null) { - for (GraphicInfo graphicInfo : graphicInfoList) { - // width - if (graphicInfo.getX() > maxX) { - maxX = graphicInfo.getX(); - } - if (graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); - } - // height - if (graphicInfo.getY() > maxY) { - maxY = graphicInfo.getY(); - } - if (graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); - } - } - } - } - } - - List artifacts = gatherAllArtifacts(bpmnModel); - for (Artifact artifact : artifacts) { - - GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); - - if (artifactGraphicInfo != null) { - // width - if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) { - maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth(); - } - if (artifactGraphicInfo.getX() < minX) { - minX = artifactGraphicInfo.getX(); - } - // height - if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) { - maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight(); - } - if (artifactGraphicInfo.getY() < minY) { - minY = artifactGraphicInfo.getY(); - } - } - - List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); - if (graphicInfoList != null) { - for (GraphicInfo graphicInfo : graphicInfoList) { + for (GraphicInfo graphicInfo : graphicInfoList) { // width if (graphicInfo.getX() > maxX) { - maxX = graphicInfo.getX(); + maxX = graphicInfo.getX(); } if (graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); + minX = graphicInfo.getX(); } // height if (graphicInfo.getY() > maxY) { - maxY = graphicInfo.getY(); + maxY = graphicInfo.getY(); } - if (graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); + if (graphicInfo.getY()< minY) { + minY = graphicInfo.getY(); } + } } + } } - } - int nrOfLanes = 0; - for (Process process : bpmnModel.getProcesses()) { - for (Lane l : process.getLanes()) { + List artifacts = gatherAllArtifacts(bpmnModel); + for (Artifact artifact : artifacts) { + + GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId()); + + if (artifactGraphicInfo != null) { + // width + if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) { + maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth(); + } + if (artifactGraphicInfo.getX() < minX) { + minX = artifactGraphicInfo.getX(); + } + // height + if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) { + maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight(); + } + if (artifactGraphicInfo.getY() < minY) { + minY = artifactGraphicInfo.getY(); + } + } + + List graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId()); + if (graphicInfoList != null) { + for (GraphicInfo graphicInfo : graphicInfoList) { + // width + if (graphicInfo.getX() > maxX) { + maxX = graphicInfo.getX(); + } + if (graphicInfo.getX() < minX) { + minX = graphicInfo.getX(); + } + // height + if (graphicInfo.getY() > maxY) { + maxY = graphicInfo.getY(); + } + if (graphicInfo.getY()< minY) { + minY = graphicInfo.getY(); + } + } + } + } + + int nrOfLanes = 0; + for (Process process : bpmnModel.getProcesses()) { + for (Lane l : process.getLanes()) { nrOfLanes++; GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId()); // // width if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) { - maxX = graphicInfo.getX() + graphicInfo.getWidth(); + maxX = graphicInfo.getX() + graphicInfo.getWidth(); } if (graphicInfo.getX() < minX) { - minX = graphicInfo.getX(); + minX = graphicInfo.getX(); } // height if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) { - maxY = graphicInfo.getY() + graphicInfo.getHeight(); + maxY = graphicInfo.getY() + graphicInfo.getHeight(); } if (graphicInfo.getY() < minY) { - minY = graphicInfo.getY(); + minY = graphicInfo.getY(); } + } } - } - // Special case, see http://jira.codehaus.org/browse/ACT-1431 - if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) { - // Nothing to show - minX = 0.0D; - minY = 0.0D; - } - //width和height代表最大的长宽 - return new CustomProcessDiagramCanvas((int) maxX + 30, (int) maxY + 50, (int) minX, (int) minY, activityFontName, labelFontName, annotationFontName); - } - - protected static List gatherAllArtifacts(BpmnModel bpmnModel) { - List artifacts = new ArrayList(); - for (Process process : bpmnModel.getProcesses()) { - artifacts.addAll(process.getArtifacts()); - } - return artifacts; - } - - protected static List gatherAllFlowNodes(BpmnModel bpmnModel) { - List flowNodes = new ArrayList(); - for (Process process : bpmnModel.getProcesses()) { - flowNodes.addAll(gatherAllFlowNodes(process)); - } - return flowNodes; - } - - protected static List gatherAllFlowNodes(FlowElementsContainer flowElementsContainer) { - List flowNodes = new ArrayList(); - for (FlowElement flowElement : flowElementsContainer.getFlowElements()) { - if (flowElement instanceof FlowNode) { - flowNodes.add((FlowNode) flowElement); - } - if (flowElement instanceof FlowElementsContainer) { - flowNodes.addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement)); + // Special case, see https://activiti.atlassian.net/browse/ACT-1431 + if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) { + // Nothing to show + minX = 0; + minY = 0; } + + return new CustomProcessDiagramCanvas((int) maxX + 10,(int) maxY + 10, (int) minX, (int) minY, + imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); + } + + @Override + public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, + List highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, + ClassLoader customClassLoader, double scaleFactor, Color[] colors, Set currIds) { + CustomProcessDiagramCanvas customProcessDiagramCanvas = generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, + activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor,colors, currIds); + BufferedImage bufferedImage = customProcessDiagramCanvas.generateBufferedImage(imageType); + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + ImageOutputStream imOut; + try { + imOut = ImageIO.createImageOutputStream(bs); + ImageIO.write(bufferedImage, "PNG", imOut); + } catch (IOException e) { + e.printStackTrace(); } - return flowNodes; - } - public Map, ActivityDrawInstruction> getActivityDrawInstructions() { - return activityDrawInstructions; + InputStream is = new ByteArrayInputStream(bs.toByteArray()); + return is; } - - public void setActivityDrawInstructions(Map, ActivityDrawInstruction> activityDrawInstructions) { - this.activityDrawInstructions = activityDrawInstructions; - } - - public Map, ArtifactDrawInstruction> getArtifactDrawInstructions() { - return artifactDrawInstructions; - } - - public void setArtifactDrawInstructions(Map, ArtifactDrawInstruction> artifactDrawInstructions) { - this.artifactDrawInstructions = artifactDrawInstructions; - } - - protected interface ActivityDrawInstruction { - void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode); - } - - protected interface ArtifactDrawInstruction { - void draw(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact); - } - - /** - * Desc: 输入所有的参数,以获取图像 - * - * @param bpmnModel - * @param highLightedActivities - * @param runningActivityIdList - * @param highLightedFlows - * @param activityFontName - * @param labelFontName - * @param annotationFontName - * @return - */ @Override - public InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List runningActivityIdList, - List highLightedFlows, - List runningActivityFlowsIds, - String activityFontName, - String labelFontName, - String annotationFontName) { - // TODO - return generateProcessDiagram(bpmnModel, - highLightedActivities, - runningActivityIdList, - highLightedFlows, - runningActivityFlowsIds, - activityFontName, - labelFontName, - annotationFontName).generateImage(); + public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { + return generateDiagram(bpmnModel, imageType, Collections.emptyList(), Collections.emptyList(), + activityFontName, labelFontName, annotationFontName, customClassLoader, 1.0, new Color[] {Color.BLACK, Color.BLACK}, null); } - @Override - public InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List runningActivityIdList, - List highLightedFlows, - String activityFontName, - String labelFontName, - String annotationFontName) { - return generateProcessDiagram(bpmnModel, - highLightedActivities, - runningActivityIdList, - highLightedFlows, - Collections.emptyList(), - activityFontName, - labelFontName, - annotationFontName).generateImage(); - } - - @Override - public InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List highLightedFlows, - String activityFontName, - String labelFontName, - String annotationFontName) { - return generateProcessDiagram(bpmnModel, - highLightedActivities, - Collections.emptyList(), - highLightedFlows, - Collections.emptyList(), - activityFontName, - labelFontName, - annotationFontName).generateImage(); - } - - @Override - public InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List runningActivityIdList, - List highLightedFlows, - List runningActivityFlowsIds) { - return generateProcessDiagram(bpmnModel, - highLightedActivities, - runningActivityIdList, - highLightedFlows, - runningActivityFlowsIds, - ACTIVITY_FONT_NAME, - LABEL_FONT_NAME, - ANNOTATION_FONT_NAME).generateImage(); - } - - @Override - public InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List runningActivityIdList, - List highLightedFlows) { - return generateProcessDiagram(bpmnModel, - highLightedActivities, - runningActivityIdList, - highLightedFlows, - Collections.emptyList(), - ACTIVITY_FONT_NAME, - LABEL_FONT_NAME, - ANNOTATION_FONT_NAME).generateImage(); - } - - @Override - public InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List highLightedFlows) { - return generateProcessDiagram(bpmnModel, - highLightedActivities, - Collections.emptyList(), - highLightedFlows, - Collections.emptyList(), - ACTIVITY_FONT_NAME, - LABEL_FONT_NAME, - ANNOTATION_FONT_NAME).generateImage(); - } } diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/ICustomProcessDiagramGenerator.java b/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/ICustomProcessDiagramGenerator.java index 3075226d..f5687768 100644 --- a/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/ICustomProcessDiagramGenerator.java +++ b/laws-modules/src/main/java/com/jero/modules/activiti/service/impl/image/ICustomProcessDiagramGenerator.java @@ -1,61 +1,15 @@ package com.jero.modules.activiti.service.impl.image; import org.activiti.bpmn.model.BpmnModel; +import org.activiti.image.ProcessDiagramGenerator; +import java.awt.*; import java.io.InputStream; import java.util.List; +import java.util.Set; -/** - * bpmnModel bpmn模型 - * activityFontName 活动字体 - * labelFontName 标签字体 - * annotationFontName 标注字体 - * highLightedActivities 高亮活动节点(绿色) - * runningActivityIdList 正在运行的活动节点(红色) - * highLightedFlows 高亮顺序流(绿色) - * lastFlowIdList 最后一条执行的顺序流(红色) ——————未实现 - */ -public interface ICustomProcessDiagramGenerator{ - - //指定字体 - InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List runningActivityIdList, - List highLightedFlows, - List runningActivityFlowsIds, - String activityFontName, - String labelFontName, - String annotationFontName); - - InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List runningActivityIdList, - List highLightedFlows, - String activityFontName, - String labelFontName, - String annotationFontName); - - InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List highLightedFlows, - String activityFontName, - String labelFontName, - String annotationFontName); - - //无指定字体,使用默认字体 - InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List runningActivityIdList, - List highLightedFlows, - List runningActivityFlowsIds); - - InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List runningActivityIdList, - List highLightedFlows); - - InputStream generateDiagramCustom(BpmnModel bpmnModel, - List highLightedActivities, - List highLightedFlows); - +public interface ICustomProcessDiagramGenerator extends ProcessDiagramGenerator { + InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List highLightedActivities, + List highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, + ClassLoader customClassLoader, double scaleFactor, Color[] colors, Set currIds); } diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/util/CamundaTag.java b/laws-modules/src/main/java/com/jero/modules/activiti/util/CamundaTag.java new file mode 100644 index 00000000..6f11a58c --- /dev/null +++ b/laws-modules/src/main/java/com/jero/modules/activiti/util/CamundaTag.java @@ -0,0 +1,58 @@ +package com.jero.modules.activiti.util; + +/** + * @author liJiaRao + * @date 2023-09-05 17:16 + */ +public enum CamundaTag { + assignee("assignee", "camunda:assignee","activiti:assignee","指派人"), + candidateUsers("candidateUsers", "camunda:candidateUsers","activiti:candidateUsers","候选人"), + candidateGroups("candidateGroups", "camunda:candidateGroups","activiti:candidateGroups","候选组"), + exclusive("exclusive", "camunda:exclusive","activiti:exclusive","独家"), + taskListener("taskListener", "camunda:taskListener","activiti:taskListener","监听"), + ; + private String attribute; + private String camundaName; + private String activitiName; + private String note; + + + CamundaTag(String attribute, String camundaName, String activitiName, String note) { + this.attribute = attribute; + this.camundaName = camundaName; + this.activitiName = activitiName; + this.note = note; + } + + public String getAttribute() { + return attribute; + } + + public void setAttribute(String attribute) { + this.attribute = attribute; + } + + public String getCamundaName() { + return camundaName; + } + + public void setCamundaName(String camundaName) { + this.camundaName = camundaName; + } + + public String getActivitiName() { + return activitiName; + } + + public void setActivitiName(String activitiName) { + this.activitiName = activitiName; + } + + public String getNote() { + return note; + } + + public void setNote(String note) { + this.note = note; + } +} diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/util/ConversionUtil.java b/laws-modules/src/main/java/com/jero/modules/activiti/util/ConversionUtil.java new file mode 100644 index 00000000..b8112076 --- /dev/null +++ b/laws-modules/src/main/java/com/jero/modules/activiti/util/ConversionUtil.java @@ -0,0 +1,178 @@ +package com.jero.modules.activiti.util; + +import cn.hutool.core.io.FileUtil; +import org.dom4j.*; +import org.dom4j.io.OutputFormat; +import org.dom4j.io.SAXReader; +import org.dom4j.io.XMLWriter; +import org.dom4j.tree.AbstractAttribute; +import org.dom4j.tree.DefaultAttribute; +import org.dom4j.tree.DefaultElement; +import org.springframework.util.CollectionUtils; + +import java.io.*; +import java.util.List; + +/** + * 作者 CG + * 时间 2021/4/12 14:21 + * 备注 camunda 和 activiti xml 互相转换 + * 参数 + */ +public class ConversionUtil { + public static void main(String[] args) { + File file1 = new File("E:\\Data\\Downloads\\sign.bpmn"); + camundaToActiviti(file1,true); + } + + /** + * 作者 CG + * 时间 2021/4/12 14:22 + * 备注 判断文件名字是否是xml,不是xml转换为xml + * 参数 + */ + public static File isXml(File file) { +// 判断是否为null + String name = FileUtil.mainName(file); + String parent = file.getParent(); + boolean bpmn = FileUtil.pathEndsWith(file, "bpmn"); + if (bpmn) { + //转换为xml + File xmlFile = FileUtil.file(parent, name + ".xml"); + File copy = FileUtil.copy(file, xmlFile, true); + return copy; + } + return file; + } + /** + * 作者 CG + * 时间 2021/4/12 15:57 + * 备注 属性转换 + * 参数 [file, flag camunda->activiti=true activiti->camunda=false] + */ + public static void camundaToActiviti(File file, Boolean flag) { + //判断文件后缀名是否正确 + try { + File xml = isXml(file); + //转换为文档 + SAXReader reader = new SAXReader(); +// 转换为Document + Document doc = reader.read(xml); + //获取根节点 + Element rootElement = doc.getRootElement(); + //获取命名空间 + //flag camunda->activiti=true activiti->camunda=false + NamespaceHandler(rootElement, flag); + //处理userTask + Element process = rootElement.element("process"); + List userTask = process.elements("userTask"); + CamundaTag[] values = CamundaTag.values(); + if (!CollectionUtils.isEmpty(userTask)) { + for (CamundaTag value : values) { + userTask(userTask, value, flag); + } + //处理监听 + userTaskListener(userTask, flag); + } + //保存文档 + saveDocument(doc, file); + } catch (DocumentException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + /** + * 作者 CG + * 时间 2021/4/12 17:45 + * 备注 处理命名空间 + * 参数 [rootElement, flag] + */ + public static void NamespaceHandler(Element rootElement, Boolean flag) { + NamespaceName camundaNamespace = NamespaceName.camunda; + NamespaceName activitiNamespace = NamespaceName.activiti; + Namespace activiti = rootElement.getNamespaceForPrefix(flag ? camundaNamespace.getName() : activitiNamespace.getName()); + if (activiti != null) { + //删除camunda命名空间 + rootElement.remove(activiti); + //添加activiti命名空间 + Namespace namespace = new Namespace(flag ? activitiNamespace.getName() : camundaNamespace.getName(), flag ? activitiNamespace.getUrl() : camundaNamespace.getUrl()); + rootElement.add(namespace); + } + } + + /** + * 作者 CG + * 时间 2021/4/12 15:36 + * 备注 userTask 参数转换 + * 参数 [userTask 要处理的集合, camundaTag 要处理的参数类型, flag camunda->activiti=true activiti->camunda=false] + */ + public static void userTask(List userTask, CamundaTag camundaTag, Boolean flag) { + for (Element element : userTask) { + Attribute assignee = element.attribute(camundaTag.getAttribute()); + if (assignee != null) { + element.remove(assignee); + AbstractAttribute abstractAttribute = new AbstractAttribute() { + @Override + public QName getQName() { + QName qName = new QName(flag ? camundaTag.getActivitiName() : camundaTag.getCamundaName()); + return qName; + } + + @Override + public String getValue() { + return assignee.getValue(); + } + }; + element.add(abstractAttribute); + } + } + } + /** + * 作者 CG + * 时间 2021/4/12 15:36 + * 备注 userTask 参数转换 + * 参数 [userTask 要处理的集合, camundaTag 要处理的参数类型, flag camunda->activiti=true activiti->camunda=false] + */ + public static void userTaskListener(List userTask, Boolean flag) { + CamundaTag listener = CamundaTag.taskListener; + for (Element element : userTask) { + Element extensionElements = element.element("extensionElements"); + if (extensionElements!=null){ + //是否有监听 + Element taskListener = extensionElements.element(listener.getAttribute()); + if (taskListener!=null){ + //获取节点所有参数 + List attributes = taskListener.attributes(); + DefaultElement defaultElement = new DefaultElement(flag?listener.getActivitiName():listener.getCamundaName()); + //将参数拷贝到新的节点 + for (Attribute attribute : attributes) { + DefaultAttribute defaultAttribute = new DefaultAttribute(attribute.getName(), attribute.getValue()); + defaultElement.add(defaultAttribute); + } + //删除原有节点 + extensionElements.remove(taskListener); + //添加新构建的节点 + extensionElements.add(defaultElement); + } + + } + } + } + /** + * 作者 CG + * 时间 2021/4/12 15:45 + * 备注 文档保存 + * 参数 [document, xmlFile] + */ + public static void saveDocument(Document document, File xmlFile) throws IOException { + Writer osWrite = new OutputStreamWriter(new FileOutputStream(xmlFile));//创建输出流 + OutputFormat format = OutputFormat.createPrettyPrint(); //获取输出的指定格式 + format.setEncoding("UTF-8");//设置编码 ,确保解析的xml为UTF-8格式 + XMLWriter writer = new XMLWriter(osWrite, format);//XMLWriter 指定输出文件以及格式 + writer.write(document);//把document写入xmlFile指定的文件(可以为被解析的文件或者新创建的文件) + writer.flush(); + writer.close(); + } +} + diff --git a/laws-modules/src/main/java/com/jero/modules/activiti/util/NamespaceName.java b/laws-modules/src/main/java/com/jero/modules/activiti/util/NamespaceName.java new file mode 100644 index 00000000..28ef255b --- /dev/null +++ b/laws-modules/src/main/java/com/jero/modules/activiti/util/NamespaceName.java @@ -0,0 +1,34 @@ +package com.jero.modules.activiti.util; + +/** + * @author liJiaRao + * @date 2023-09-05 17:16 + */ +public enum NamespaceName { + activiti("activiti","http://activiti.org/bpmn"), + camunda("camunda","http://camunda.org/schema/1.0/bpmn"), + ; + private String name; + public String url; + + NamespaceName(String name, String url) { + this.name = name; + this.url = url; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/laws-modules/src/main/resources/bpmn/企标制修订流程.bpmn b/laws-modules/src/main/resources/bpmn/企标制修订流程.bpmn new file mode 100644 index 00000000..28bf2b93 --- /dev/null +++ b/laws-modules/src/main/resources/bpmn/企标制修订流程.bpmn @@ -0,0 +1,457 @@ + + + + + Flow_0ln2zen + + + + Flow_0ln2zen + Flow_1dmfby6 + + + + + Flow_0hkyh3o + Flow_0dlfvoz + Flow_0iw6bki + + + Flow_0iw6bki + Flow_0rw7rph + + + + Flow_1dmfby6 + Flow_0hkyh3o + + ${nrOfInstances== nrOfCompletedInstances} + + + + Flow_0rw7rph + Flow_0dlfvoz + Flow_07x6x68 + + + + ${!pass} + + + ${pass} + + + Flow_07x6x68 + Flow_1gc5b6z + + + Flow_1gc5b6z + Flow_0lxhrf3 + Flow_0s3et9m + + + + Flow_0s3et9m + Flow_1ts1npj + Flow_1yn3bo0 + + + + ${open} + + + + + + Flow_14y4j6o + Flow_1x9nrbh + + ${nrOfInstances== nrOfCompletedInstances} + + + + Flow_1ts1npj + Flow_14y4j6o + + + + Flow_1x9nrbh + Flow_0b6hwpr + Flow_1jfhrkk + + + + Flow_1jfhrkk + Flow_0n3oqju + + ${nrOfInstances== nrOfCompletedInstances} + + + + Flow_0n3oqju + Flow_0b6hwpr + Flow_0viypc1 + + + + ${!pass} + + + ${pass} + + + + Flow_0viypc1 + Flow_0lxhrf3 + + + + Flow_0114fp7 + Flow_15vlua6 + + ${nrOfInstances== nrOfCompletedInstances} + + + + Flow_1uaxx7p + Flow_02wh2wo + + + + ${pass} + + + Flow_15vlua6 + Flow_1uaxx7p + Flow_1k4inp1 + + + + ${!pass} + + + Flow_02wh2wo + Flow_0v50urt + Flow_0rkg4il + + + + ${pass} + + + ${!pass} + + + Flow_1cg7p7q + Flow_0jc597n + Flow_03b0vp0 + + + + ${pass} + + + ${!pass} + + + Flow_0jc597n + Flow_093us1v + + ${nrOfInstances== nrOfCompletedInstances} + + + + Flow_0v50urt + Flow_1cg7p7q + + + + Flow_093us1v + Flow_09gf9nd + + + + Flow_09gf9nd + Flow_0r1lb59 + + + Flow_1yn3bo0 + Flow_1k4inp1 + Flow_0rkg4il + Flow_03b0vp0 + Flow_0114fp7 + + + Flow_0r1lb59 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/laws-single-startup/src/main/java/com/jero/JeroSystemSingleApplication.java b/laws-single-startup/src/main/java/com/jero/JeroSystemSingleApplication.java index 052f3615..979e44da 100644 --- a/laws-single-startup/src/main/java/com/jero/JeroSystemSingleApplication.java +++ b/laws-single-startup/src/main/java/com/jero/JeroSystemSingleApplication.java @@ -2,7 +2,9 @@ package com.jero; import com.jero.common.util.oConvertUtils; import lombok.extern.slf4j.Slf4j; +import org.activiti.spring.boot.SecurityAutoConfiguration; import org.springframework.boot.SpringApplication; +import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; @@ -21,7 +23,8 @@ import java.net.UnknownHostException; @Slf4j @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class, - org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration.class}) + SecurityAutoConfiguration.class, + ManagementWebSecurityAutoConfiguration.class}) public class JeroSystemSingleApplication extends SpringBootServletInitializer { @Override diff --git a/pom.xml b/pom.xml index 7e8a6703..b8d3c3ca 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ 1.6.1 7.4.0 2.15.0 - 7.1.0.M1 + 6.0.0