OW2 Consortium orchestra

Rev

Rev 6221 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Bull SAS / OW2 Orchestra
 * Copyright (C) 2011 Bull S.A.S, and individual contributors as indicated
 * by the @authors tag.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 */

package org.ow2.orchestra.designer.bpmn.views {
import flash.display.DisplayObject;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;

import mx.binding.utils.BindingUtils;
import mx.binding.utils.ChangeWatcher;
import mx.containers.Canvas;
import mx.containers.HBox;
import mx.containers.VBox;
import mx.controls.Image;
import mx.controls.Label;
import mx.controls.Spacer;
import mx.events.FlexEvent;

import org.ow2.orchestra.designer.bpmn.model.AbstractElement;
import org.ow2.orchestra.designer.bpmn.model.TaskModel;
import org.ow2.orchestra.designer.bpmn.model.TaskType;
import org.ow2.orchestra.designer.bpmn.views.utils.ArrowStyle;
import org.ow2.orchestra.designer.bpmn.views.utils.ArrowUtil;
import org.ow2.orchestra.designer.bpmn.views.utils.GraphicUtils;

public class TaskView extends AbstractElementView implements IFlowNodeView {
  [Bindable]
  private var _taskModel:TaskModel;

  private var _processView:ProcessView;
  /**
   * The source for "event" image data binding.
   */
  [Bindable]
  [Embed(source="/../assets/task.svg")]
  public var taskBackgroundImage:Class;
  /**
   * The source for "event" image data binding.
   */
  [Bindable]
  [Embed(source="/../assets/serviceTask.svg")]
  public var serviceTaskImage:Class;

  private var imageTaskBackground:Image = new Image();
  private var imageTask:Image = new Image();
  private var messageFlowCanvas:Canvas = new Canvas();
  private var messageFlowLabel:Label = new Label();


  function TaskView(taskModel:TaskModel, processView:ProcessView) {
    _processView = processView;
    _taskModel = taskModel;
    this.setStyle("horizontalAlign", "center");
    imageTaskBackground.percentWidth = 100;
    imageTaskBackground.minWidth = 60;
    imageTaskBackground.percentHeight = 100;

    imageTaskBackground.maintainAspectRatio = false;
    imageTaskBackground.automationName = "TaskImage" + _taskModel.id;
    imageTaskBackground.source = taskBackgroundImage;

    watchers.addItem(BindingUtils.bindProperty(this, "x", _taskModel, "x"));
    watchers.addItem(BindingUtils.bindProperty(this, "y", _taskModel, "y"));

    var label:Label = new Label();
    watchers.addItem(BindingUtils.bindProperty(label, "text", _taskModel, "name"));
    watchers.addItem(ChangeWatcher.watch(_taskModel, "taskType", updateImage));
    watchers.addItem(ChangeWatcher.watch(_taskModel, "operation", redraw));
    watchers.addItem(ChangeWatcher.watch(this, "x", redraw));
    watchers.addItem(ChangeWatcher.watch(this, "y", redraw));

    var canvas:Canvas = new Canvas();


    canvas.addChild(imageTaskBackground);

    imageTask.x = 3;
    imageTask.y = 3;
    imageTask.height = 16;
    imageTask.width = 16;
    canvas.addChild(imageTask);

    var hbox:HBox = new HBox();
    hbox.percentWidth = 100;
    hbox.percentHeight = 100;
    var s1:Spacer = new Spacer();
    s1.percentWidth = 100;
    var s2:Spacer = new Spacer();
    s2.percentWidth = 100;
    var vbox:VBox = new VBox();
    vbox.percentHeight = 100;
    vbox.percentWidth = 100;
    var s3:Spacer = new Spacer();
    s3.height = 10;
    var s4:Spacer = new Spacer();
    s4.height = 5;

    vbox.addChild(s3);
    vbox.addChild(label);
    vbox.addChild(s4);
    hbox.addChild(s1);
    hbox.addChild(vbox);
    hbox.addChild(s2);

    canvas.addChild(hbox);
    this.addChild(canvas);
    messageFlowCanvas.clipContent = false;
    messageFlowCanvas.autoLayout = false;
    messageFlowCanvas.width = 0;
    messageFlowCanvas.height = 0;
    this.addChild(messageFlowCanvas);
    messageFlowCanvas.addChild(messageFlowLabel);

    this.addEventListener(FlexEvent.CREATION_COMPLETE, updateImage);
  }


  override public function get model():AbstractElement {
    return _taskModel;
  }

  override public function copy():AbstractElementView {
    return new TaskView(_taskModel, _processView);
  }

  override public function get borderImage():DisplayObject {
    return imageTaskBackground;
  }

  override public function get subtypeImage():DisplayObject {
    return imageTask;
  }

  protected function updateImage(event:Event = null):void {
    if (_taskModel.taskType == TaskType.SERVICE) {
      imageTask.source = serviceTaskImage;
    }
    this.redraw();
  }

  protected function redraw(event:Event = null):void {
    var clearMsgFlow:Boolean = false;
    if (_taskModel.taskType == TaskType.SERVICE
            && _taskModel.operation != null
            && _taskModel.operation.interfaceModel != null
            && _taskModel.operation.interfaceModel.poolModel != null) {
      var targetView:AbstractElementView = this._processView.getElementViewByModel(_taskModel.operation.interfaceModel.poolModel);
      if (targetView != null) {
        // get source and target border image
        var sourceImage:DisplayObject = this.borderImage;

        // get image centers in y, and this view center in x
        var sourceCenterPoint:Point = this.localToGlobal(new Point(sourceImage.x + (sourceImage.width / 2), sourceImage.y + (sourceImage.height / 2)));
        var targetCenterPoint:Point = this._processView.localToGlobal(new Point(0, targetView.y + (targetView.height / 2)));
        targetCenterPoint.x = sourceCenterPoint.x;

        // update source and target points
        var sourcePoint:Point = GraphicUtils.findIntersection(sourceImage, sourceCenterPoint, targetCenterPoint, _processView);
        var targetPoint:Point = GraphicUtils.findIntersection(targetView.borderImage, targetCenterPoint, sourceCenterPoint, _processView);

        // draw arrow
        var style:ArrowStyle = new ArrowStyle();
        style.headWidth = 11;
        style.headLength = 17;
        style.color = 0x000000;
        style.headFill = false;
        style.thickness = 0;
        style.isDashed = true;
        style.isMessage = true;
        var localTarget:Point = messageFlowCanvas.globalToLocal(targetPoint);
        messageFlowLabel.text = _taskModel.operation.name;
        messageFlowLabel.width = messageFlowLabel.measureText(messageFlowLabel.text).width + 10;
        messageFlowLabel.y = localTarget.y + 10;
        if (_taskModel.operation.outMessageType == null) {
          messageFlowLabel.x = localTarget.x + 10;
          ArrowUtil.drawArrow(messageFlowCanvas.graphics, messageFlowCanvas.globalToLocal(sourcePoint), messageFlowCanvas.globalToLocal(targetPoint), style);
        } else {
          messageFlowLabel.x = localTarget.x + 20;
          sourcePoint.x -= 10;
          targetPoint.x -= 10;
          ArrowUtil.drawArrow(messageFlowCanvas.graphics, messageFlowCanvas.globalToLocal(sourcePoint), messageFlowCanvas.globalToLocal(targetPoint), style);
          sourcePoint.x += 20;
          targetPoint.x += 20;
          ArrowUtil.drawArrow(messageFlowCanvas.graphics, messageFlowCanvas.globalToLocal(targetPoint), messageFlowCanvas.globalToLocal(sourcePoint), style, false);
        }
      } else {
        clearMsgFlow = true;
      }
    } else {
      clearMsgFlow = true;
    }
    if (clearMsgFlow) {
      messageFlowCanvas.graphics.clear();
      messageFlowLabel.text = "";
    }
  }


  ////////////////////////////////////////////////////////////////////////////////////////
  // Override selection function: clicking on a message flow should not select the task //
  ////////////////////////////////////////////////////////////////////////////////////////
  override public function includeInto(selection:Rectangle, targetCoordinateSpace:DisplayObject):Boolean {
    var bounds:Rectangle = this.borderImage.getRect(targetCoordinateSpace);
    return selection.containsRect(bounds);
  }

  override public function containsRectangle(selection:Rectangle, targetCoordinateSpace:DisplayObject):Boolean {
    var objectRect:Rectangle = this.borderImage.getRect(targetCoordinateSpace);
    return objectRect.containsRect(selection);
  }

  public function getCollisionRectangle(targetCoordinateSpace:DisplayObject):Rectangle {
    return this.borderImage.getRect(targetCoordinateSpace);
  }
}
}