Package org.activiti.image.impl

Source Code of org.activiti.image.impl.DefaultProcessDiagramGenerator

/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.activiti.image.impl;

import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.bpmn.model.Activity;
import org.activiti.bpmn.model.Artifact;
import org.activiti.bpmn.model.Association;
import org.activiti.bpmn.model.AssociationDirection;
import org.activiti.bpmn.model.BaseElement;
import org.activiti.bpmn.model.BoundaryEvent;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.BusinessRuleTask;
import org.activiti.bpmn.model.CallActivity;
import org.activiti.bpmn.model.EndEvent;
import org.activiti.bpmn.model.ErrorEventDefinition;
import org.activiti.bpmn.model.Event;
import org.activiti.bpmn.model.EventDefinition;
import org.activiti.bpmn.model.EventGateway;
import org.activiti.bpmn.model.EventSubProcess;
import org.activiti.bpmn.model.ExclusiveGateway;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.FlowElementsContainer;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.Gateway;
import org.activiti.bpmn.model.GraphicInfo;
import org.activiti.bpmn.model.InclusiveGateway;
import org.activiti.bpmn.model.IntermediateCatchEvent;
import org.activiti.bpmn.model.Lane;
import org.activiti.bpmn.model.ManualTask;
import org.activiti.bpmn.model.MultiInstanceLoopCharacteristics;
import org.activiti.bpmn.model.ParallelGateway;
import org.activiti.bpmn.model.Pool;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.ReceiveTask;
import org.activiti.bpmn.model.ScriptTask;
import org.activiti.bpmn.model.SendTask;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.ServiceTask;
import org.activiti.bpmn.model.SignalEventDefinition;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.bpmn.model.SubProcess;
import org.activiti.bpmn.model.Task;
import org.activiti.bpmn.model.TextAnnotation;
import org.activiti.bpmn.model.ThrowEvent;
import org.activiti.bpmn.model.TimerEventDefinition;
import org.activiti.bpmn.model.UserTask;
import org.activiti.image.ProcessDiagramGenerator;

/**
* Class to generate an image based the diagram interchange information in a
* BPMN 2.0 process.
*
* @author Joram Barrez
* @author Tijs Rademakers
*/
public class DefaultProcessDiagramGenerator implements ProcessDiagramGenerator {

  protected final Map<Class<? extends BaseElement>, ActivityDrawInstruction> activityDrawInstructions = new HashMap<Class<? extends BaseElement>, ActivityDrawInstruction>();
  protected final Map<Class<? extends BaseElement>, ArtifactDrawInstruction> artifactDrawInstructions = new HashMap<Class<? extends BaseElement>, ArtifactDrawInstruction>();
 
  public DefaultProcessDiagramGenerator() {
    this(1.0);
  }
 
  // The instructions on how to draw a certain construct is
  // created statically and stored in a map for performance.
  public DefaultProcessDiagramGenerator(final double scaleFactor) {
    // start event
    activityDrawInstructions.put(StartEvent.class, new ActivityDrawInstruction() {

      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(graphicInfo, scaleFactor);
          } else if (eventDefinition instanceof ErrorEventDefinition) {
            processDiagramCanvas.drawErrorStartEvent(graphicInfo, scaleFactor);
          } else if (eventDefinition instanceof SignalEventDefinition) {
            processDiagramCanvas.drawSignalStartEvent(graphicInfo, scaleFactor);
          }
        } else {
          processDiagramCanvas.drawNoneStartEvent(graphicInfo);
        }
      }
    });

    // signal catch
    activityDrawInstructions.put(IntermediateCatchEvent.class, new ActivityDrawInstruction() {
     
      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.getName(), graphicInfo, true, scaleFactor);
          } else if (intermediateCatchEvent.getEventDefinitions().get(0) instanceof TimerEventDefinition) {
            processDiagramCanvas.drawCatchingTimerEvent(flowNode.getName(), graphicInfo, true, scaleFactor);
          }
        }
      }
    });
   
    // signal throw
    activityDrawInstructions.put(ThrowEvent.class, new ActivityDrawInstruction() {
     
      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(graphicInfo, scaleFactor);
          }
        } else {
          processDiagramCanvas.drawThrowingNoneEvent(graphicInfo, scaleFactor);
        }
      }
    });
   
    // end event
    activityDrawInstructions.put(EndEvent.class, new ActivityDrawInstruction() {

      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.getName(), graphicInfo, scaleFactor);
          }
        } else {
          processDiagramCanvas.drawNoneEndEvent(graphicInfo, scaleFactor);
        }
      }
    });

    // task
    activityDrawInstructions.put(Task.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawTask(flowNode.getName(), graphicInfo);
      }
    });

    // user task
    activityDrawInstructions.put(UserTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawUserTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // script task
    activityDrawInstructions.put(ScriptTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawScriptTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // service task
    activityDrawInstructions.put(ServiceTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        ServiceTask serviceTask = (ServiceTask) flowNode;
        if ("camel".equalsIgnoreCase(serviceTask.getType())) {
          processDiagramCanvas.drawCamelTask(serviceTask.getName(), graphicInfo, scaleFactor);
        } else if ("mule".equalsIgnoreCase(serviceTask.getType())) {
          processDiagramCanvas.drawMuleTask(serviceTask.getName(), graphicInfo, scaleFactor);
        } else {
          processDiagramCanvas.drawServiceTask(serviceTask.getName(), graphicInfo, scaleFactor);
        }
      }
    });

    // receive task
    activityDrawInstructions.put(ReceiveTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawReceiveTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // send task
    activityDrawInstructions.put(SendTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawSendTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // manual task
    activityDrawInstructions.put(ManualTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawManualTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });
   
    // businessRuleTask task
    activityDrawInstructions.put(BusinessRuleTask.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawBusinessRuleTask(flowNode.getName(), graphicInfo, scaleFactor);
      }
    });

    // exclusive gateway
    activityDrawInstructions.put(ExclusiveGateway.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawExclusiveGateway(graphicInfo, scaleFactor);
      }
    });

    // inclusive gateway
    activityDrawInstructions.put(InclusiveGateway.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawInclusiveGateway(graphicInfo, scaleFactor);
      }
    });

    // parallel gateway
    activityDrawInstructions.put(ParallelGateway.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawParallelGateway(graphicInfo, scaleFactor);
      }
    });
   
    // event based gateway
    activityDrawInstructions.put(EventGateway.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawEventBasedGateway(graphicInfo, scaleFactor);
      }
    });
   

    // Boundary timer
    activityDrawInstructions.put(BoundaryEvent.class, new ActivityDrawInstruction() {

      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.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
           
          } else if (boundaryEvent.getEventDefinitions().get(0) instanceof ErrorEventDefinition) {
           
            processDiagramCanvas.drawCatchingErrorEvent(graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
           
          } else if (boundaryEvent.getEventDefinitions().get(0) instanceof SignalEventDefinition) {
            processDiagramCanvas.drawCatchingSignalEvent(flowNode.getName(), graphicInfo, boundaryEvent.isCancelActivity(), scaleFactor);
          }
        }
       
      }
    });

    // subprocess
    activityDrawInstructions.put(SubProcess.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
          processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, false);
        } else {
          processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, false, scaleFactor);
        }
      }
    });
   
    // Event subprocess
    activityDrawInstructions.put(EventSubProcess.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        if (graphicInfo.getExpanded() != null && !graphicInfo.getExpanded()) {
          processDiagramCanvas.drawCollapsedSubProcess(flowNode.getName(), graphicInfo, true);
        } else {
          processDiagramCanvas.drawExpandedSubProcess(flowNode.getName(), graphicInfo, true, scaleFactor);
        }
      }
    });

    // call activity
    activityDrawInstructions.put(CallActivity.class, new ActivityDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
        processDiagramCanvas.drawCollapsedCallActivity(flowNode.getName(), graphicInfo);
      }
    });

    // text annotation
    artifactDrawInstructions.put(TextAnnotation.class, new ArtifactDrawInstruction() {

      public void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact) {
        GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
        TextAnnotation textAnnotation = (TextAnnotation) artifact;
        processDiagramCanvas.drawTextAnnotation(textAnnotation.getText(), graphicInfo);
      }
    });
   
    // association
    artifactDrawInstructions.put(Association.class, new ArtifactDrawInstruction() {

      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<GraphicInfo> 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, scaleFactor);
      }
    });
  }

  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
      String activityFontName, String labelFontName, ClassLoader customClassLoader, double scaleFactor) {
   
    return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
        activityFontName, labelFontName, customClassLoader, scaleFactor).generateImage(imageType);
  }
 
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows) {
    return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, 1.0);
  }
 
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType,
      List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
    return generateDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, scaleFactor);
  }
 
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities) {
    return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.<String>emptyList());
  }
 
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, double scaleFactor) {
    return generateDiagram(bpmnModel, imageType, highLightedActivities, Collections.<String>emptyList(), scaleFactor);
  }
 
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, String labelFontName, ClassLoader customClassLoader) {
    return generateDiagram(bpmnModel, imageType, Collections.<String>emptyList(), Collections.<String>emptyList(),
        activityFontName, labelFontName, customClassLoader, 1.0);
  }
 
  public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName,
      String labelFontName, ClassLoader customClassLoader, double scaleFactor) {
   
    return generateDiagram(bpmnModel, imageType, Collections.<String>emptyList(), Collections.<String>emptyList(),
        activityFontName, labelFontName, customClassLoader, scaleFactor);
  }

  public InputStream generatePngDiagram(BpmnModel bpmnModel) {
    return generatePngDiagram(bpmnModel, 1.0);
  }
 
  public InputStream generatePngDiagram(BpmnModel bpmnModel, double scaleFactor) {
    return generateDiagram(bpmnModel, "png", Collections.<String>emptyList(), Collections.<String>emptyList(), scaleFactor);
  }

  public InputStream generateJpgDiagram(BpmnModel bpmnModel) {
    return generateJpgDiagram(bpmnModel, 1.0);
  }
 
  public InputStream generateJpgDiagram(BpmnModel bpmnModel, double scaleFactor) {
    return generateDiagram(bpmnModel, "jpg", Collections.<String>emptyList(), Collections.<String>emptyList());
  }
 
  public BufferedImage generateImage(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
      String activityFontName, String labelFontName, ClassLoader customClassLoader, double scaleFactor) {
   
    return generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
        activityFontName, labelFontName, customClassLoader, scaleFactor).generateBufferedImage(imageType);
  }
 
  public BufferedImage generateImage(BpmnModel bpmnModel, String imageType,
      List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
   
    return generateImage(bpmnModel, imageType, highLightedActivities, highLightedFlows, null, null, null, scaleFactor);
  }
 
  public BufferedImage generatePngImage(BpmnModel bpmnModel, double scaleFactor) {
    return generateImage(bpmnModel, "png", Collections.<String>emptyList(), Collections.<String>emptyList(), scaleFactor);
  }

  protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType,
      List<String> highLightedActivities, List<String> highLightedFlows,
      String activityFontName, String labelFontName, ClassLoader customClassLoader, double scaleFactor) {
   
    DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, customClassLoader);
   
    // Draw pool shape, if process is participant in collaboration
    for (Pool pool : bpmnModel.getPools()) {
      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.getName(), graphicInfo);
      }
    }
   
    // Draw activities and their sequence-flows
    for (FlowNode flowNode : bpmnModel.getProcesses().get(0).findFlowElementsOfType(FlowNode.class)) {
      drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor);
    }
   
    // Draw artifacts
    for (Process process : bpmnModel.getProcesses()) {
      for (Artifact artifact : process.getArtifacts()) {
        drawArtifact(processDiagramCanvas, bpmnModel, artifact);
      }
    }
   
    return processDiagramCanvas;
  }

  protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel,
      FlowNode flowNode, List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor) {
   
    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())) {
        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<GraphicInfo> 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, scaleFactor);
 
        // Draw sequenceflow label
        GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId());
        if (labelGraphicInfo != null) {
          GraphicInfo lineCenter = getLineCenter(graphicInfoList);
          processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false);
        }
      }
    }

    // Nested elements
    if (flowNode instanceof FlowElementsContainer) {
      for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
        if (nestedFlowElement instanceof FlowNode) {
          drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement,
              highLightedActivities, highLightedFlows, scaleFactor);
        }
      }
    }
  }
 
  /**
   * This method makes coordinates of connection flow better.
   * @param processDiagramCanvas
   * @param bpmnModel
   * @param sourceElement
   * @param targetElement
   * @param graphicInfoList
   * @return
   */
  protected static List<GraphicInfo> connectionPerfectionizer(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, BaseElement sourceElement, BaseElement targetElement, List<GraphicInfo> 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.<br>
   * 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;
    } else {
        // unknown source element, just do not correct coordinates
    }
    return null;
  }
 
  protected static GraphicInfo getLineCenter(List<GraphicInfo> 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(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());

  }

  protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType,
      String activityFontName, String labelFontName, 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();
    }
   
    List<FlowNode> flowNodes = gatherAllFlowNodes(bpmnModel);
    for (FlowNode flowNode : flowNodes) {

      GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
     
      // 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<GraphicInfo> 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<Artifact> 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<GraphicInfo> 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();
        }
        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 http://jira.codehaus.org/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,
        imageType, activityFontName, labelFontName, customClassLoader);
  }
 
  protected static List<Artifact> gatherAllArtifacts(BpmnModel bpmnModel) {
    List<Artifact> artifacts = new ArrayList<Artifact>();
    for (Process process : bpmnModel.getProcesses()) {
      artifacts.addAll(process.getArtifacts());
    }
    return artifacts;
  }
 
  protected static List<FlowNode> gatherAllFlowNodes(BpmnModel bpmnModel) {
    List<FlowNode> flowNodes = new ArrayList<FlowNode>();
    for (Process process : bpmnModel.getProcesses()) {
      flowNodes.addAll(gatherAllFlowNodes(process));
    }
    return flowNodes;
  }
 
  protected static List<FlowNode> gatherAllFlowNodes(FlowElementsContainer flowElementsContainer) {
    List<FlowNode> flowNodes = new ArrayList<FlowNode>();
    for (FlowElement flowElement : flowElementsContainer.getFlowElements()) {
      if (flowElement instanceof FlowNode) {
        flowNodes.add((FlowNode) flowElement);
      }
      if (flowElement instanceof FlowElementsContainer) {
        flowNodes.addAll(gatherAllFlowNodes((FlowElementsContainer) flowElement));
      }
    }
    return flowNodes;
  }

  protected interface ActivityDrawInstruction {
    void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode);
  }

  protected interface ArtifactDrawInstruction {
    void draw(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, Artifact artifact);
  }
}
TOP

Related Classes of org.activiti.image.impl.DefaultProcessDiagramGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.