示例#1
0
  /**
   * Adds the given execution statement to the lifeline view it covers.
   *
   * @param executionStatement the {@link ExecutionStatement} to add
   */
  private void addStatementView(ExecutionStatement executionStatement) {
    Lifeline lifeline = executionStatement.getCovered().get(0);
    LifelineView lifelineView = lifelines.get(lifeline);
    int modelIndex = getModelIndex(executionStatement);

    // Currently we assume that the statements specification is always an opaque expression.
    // If this changes we need to adaptively get the actual value.
    TextView textView =
        new TextView(executionStatement, RamPackage.Literals.EXECUTION_STATEMENT__SPECIFICATION);
    textView.setNoFill(false);
    textView.setNoStroke(false);
    textView.setFillColor(Colors.MESSAGE_STATEMENT_FILL_COLOR);

    ITextViewHandler textViewHandler =
        HandlerFactoryMessageView.INSTANCE.getExecutionStatementHandler();

    textView.registerTapProcessor(textViewHandler);
    textView.registerInputProcessor(
        new TapAndHoldProcessor(RamApp.getApplication(), Constants.TAP_AND_HOLD_DURATION));
    textView.addGestureListener(TapAndHoldProcessor.class, textViewHandler);
    textView.addGestureListener(
        TapAndHoldProcessor.class,
        new TapAndHoldVisualizer(RamApp.getApplication(), RamApp.getActiveScene().getCanvas()));
    textView.setPlaceholderText(Strings.PH_SPECIFY_STATEMENT);
    addChild(textView);

    lifelineView.addStatement(textView, executionStatement, modelIndex);
    fragments.put(executionStatement, textView);

    layoutMessageView();
  }
示例#2
0
  /**
   * Removes the interaction fragment from its covered lifeline view.
   *
   * @param interactionFragment the {@link InteractionFragment} to remove
   */
  private void removeInteractionFragment(InteractionFragment interactionFragment) {
    Lifeline lifeline = interactionFragment.getCovered().get(0);
    LifelineView lifelineView = lifelines.get(lifeline);

    lifelineView.removeInteractionFragment(interactionFragment);
    layoutMessageView();
  }
示例#3
0
  /**
   * Adds a new view for the given lifeline to this view.
   *
   * @param lifeline the {@link Lifeline} a view is required for
   */
  private void addLifelineView(Lifeline lifeline) {
    LayoutElement layoutElement = layout.getValue().get(lifeline);

    LifelineView lifelineView = new LifelineView(this, lifeline, layoutElement);
    addChild(lifelineView);
    lifelineView.setHandler(HandlerFactoryMessageView.INSTANCE.getLifelineViewHandler());

    lifelines.put(lifeline, lifelineView);
  }
示例#4
0
  /**
   * Creates a view for the given assignment statement and adds it to the lifeline view it covers.
   *
   * @param assignmentStatement the {@link AssignmentStatement} to add
   */
  private void addAssignmentStatement(AssignmentStatement assignmentStatement) {
    Lifeline lifeline = assignmentStatement.getCovered().get(0);
    LifelineView lifelineView = lifelines.get(lifeline);
    int modelIndex = getModelIndex(assignmentStatement);

    AssignmentStatementView assignmentView = new AssignmentStatementView(assignmentStatement);
    addChild(assignmentView);
    assignmentView.setHandler(HandlerFactoryMessageView.INSTANCE.getAssignmentStatementHandler());

    lifelineView.addAssignment(assignmentView, assignmentStatement, modelIndex);
    fragments.put(assignmentStatement, assignmentView);

    layoutMessageView();
  }
示例#5
0
  /**
   * Removes the combined fragment from this view. Removes the combined fragment from all covered
   * lifeline views.
   *
   * @param combinedFragment the {@link CombinedFragment} to remove
   */
  private void removeCombinedFragment(CombinedFragment combinedFragment) {
    CombinedFragmentView combinedFragmentView = combinedFragments.remove(combinedFragment);

    // For debug purpose only.
    if (combinedFragmentView == null) {
      System.err.println(
          "Should not happen: Something went wrong in the order of removing objects.");
    }

    for (Lifeline lifeline : combinedFragment.getCovered()) {
      LifelineView lifelineView = lifelines.get(lifeline);
      lifelineView.removeCombinedFragment(combinedFragment);
    }

    removeChild(combinedFragmentView);
    combinedFragmentView.destroy();

    layoutMessageView();
  }
示例#6
0
  /**
   * Layouts all combined fragments of this view. The width is determined by the position of the
   * covered lifelines.
   */
  private void layoutCombinedFragments() {
    for (Entry<CombinedFragment, CombinedFragmentView> entry : combinedFragments.entrySet()) {
      CombinedFragmentView combinedFragmentView = entry.getValue();

      float minX = Float.MAX_VALUE;
      float maxX = -1;

      for (Lifeline lifeline : entry.getKey().getCovered()) {
        LifelineView lifelineView = lifelines.get(lifeline);

        Vector3D position = lifelineView.getPosition(TransformSpace.GLOBAL);
        minX = Math.min(minX, position.getX());
        maxX = Math.max(maxX, position.getX() + lifelineView.getWidth() + LIFEINE_SPACING);

        /**
         * Take into consideration the size of other fragments as well, since they could be quite
         * wide.
         */
        for (InteractionFragment fragment : lifeline.getCoveredBy()) {
          /**
           * Check whether the fragment is part of this combined fragment in its containment
           * hierarchy.
           */
          if (EcoreUtil.isAncestor(entry.getKey(), fragment)) {
            RamRectangleComponent fragmentView = fragments.get(fragment);
            if (fragmentView != null) {
              Vector3D fragmentPosition = fragmentView.getPosition(TransformSpace.GLOBAL);
              maxX =
                  Math.max(
                      maxX, fragmentPosition.getX() + fragmentView.getWidth() + LIFEINE_SPACING);
            }
          }
        }
      }

      Vector3D position = combinedFragmentView.getPosition(TransformSpace.GLOBAL);
      position.setX(minX);
      combinedFragmentView.setPositionGlobal(position);
      combinedFragmentView.setMinimumWidth(maxX - minX);
    }
  }
示例#7
0
  /**
   * Adds the given original behaviour execution fragment to the lifeline view it covers.
   *
   * @param originalBehaviorExecution the {@link OriginalBehaviorExecution} to add
   */
  private void addOriginalBehaviourView(OriginalBehaviorExecution originalBehaviorExecution) {
    Lifeline lifeline = originalBehaviorExecution.getCovered().get(0);
    LifelineView lifelineView = lifelines.get(lifeline);
    int modelIndex = getModelIndex(originalBehaviorExecution);

    // Currently we assume that the statements specification is always an opaque expression.
    // If this changes we need to adaptively get the actual value.
    RamTextComponent textView = new RamTextComponent("*");
    textView.setNoFill(false);
    textView.setNoStroke(false);
    textView.setFillColor(Colors.DEFAULT_ELEMENT_FILL_COLOR);
    textView.setBufferSize(Cardinal.NORTH, 10);
    textView.setBufferSize(Cardinal.EAST, 10);
    textView.setBufferSize(Cardinal.WEST, 10);
    textView.setBufferSize(Cardinal.SOUTH, 0);

    addChild(textView);

    lifelineView.addOriginalBehaviour(textView, originalBehaviorExecution, modelIndex);
    fragments.put(originalBehaviorExecution, textView);

    layoutMessageView();
  }
示例#8
0
  /**
   * Layouts all lifelines. The lifelines are placed at a certain height and along the x-axis with a
   * specified distance between them. Lifelines that contain a stereotype in their name are placed
   * slightly higher such that the bottom of each name is flush among all lifelines.
   */
  private void layoutLifelines() {
    float currentLifelineX = LIFELINE_START_X;
    Set<Lifeline> layoutedLifelines = new HashSet<Lifeline>();

    // Layout lifelines if they have no position. Otherwise they might have been moved on the
    // x-axis,
    // which we allow to do.
    for (InteractionFragment fragment : specification.getFragments()) {
      // In case the message add event hasn't been received yet there will be no lifeline that is
      // covered.
      // This is the case when a message and a reply are added.
      // The structure exists, but not all commands have been executed.
      for (Lifeline lifeline : fragment.getCovered()) {
        if (!layoutedLifelines.contains(lifeline)) {
          LifelineView lifelineView = lifelines.get(lifeline);
          LayoutElement layoutElement = lifelineView.getLayoutElement();

          if (layoutElement.getX() == 0) {
            lifelineView.getLayoutElement().setX(currentLifelineX);
            lifelineView.getLayoutElement().setY(LIFELINE_Y);
          }

          /**
           * Lifelines of metaclasses are double as high as regular lifelines. This causes problems
           * when dealing with combined fragments or when drawing a message from a message view of a
           * create message to one (as the first message). Therefore, these lifelines are moved up
           * so that all lifelines are flush on the bottom of their name container.
           *
           * @see issue #230
           */
          if (lifeline.getRepresents() instanceof StructuralFeature) {
            StructuralFeature structuralFeature = (StructuralFeature) lifeline.getRepresents();

            if (structuralFeature.isStatic()) {
              float y = LIFELINE_Y - (lifelineView.getNameHeight() / 2);
              if (y != lifelineView.getLayoutElement().getY()) {
                lifelineView.getLayoutElement().setY(y);
              }
            }
          }

          currentLifelineX = currentLifelineX + lifelineView.getWidth() + LIFEINE_SPACING;
          layoutedLifelines.add(lifeline);
        }
      }
    }
  }
示例#9
0
  @Override
  public void notifyChanged(Notification notification) {
    EObject notifier = (EObject) notification.getNotifier();
    Object feature = notification.getFeature();

    Interaction interaction =
        EMFModelUtil.getRootContainerOfType(notifier, RamPackage.Literals.INTERACTION);

    // Notification could come from the interaction or an operand.
    if (notifier == specification || interaction == specification) {
      if (feature == RamPackage.Literals.FRAGMENT_CONTAINER__FRAGMENTS) {
        if (notification.getEventType() == Notification.ADD) {
          EObject newValue = (EObject) notification.getNewValue();

          RamSwitch<Object> switcher =
              new RamSwitch<Object>() {
                @Override
                public Object caseExecutionStatement(ExecutionStatement object) {
                  addStatementView(object);
                  return Boolean.TRUE;
                }

                @Override
                public Object caseCombinedFragment(CombinedFragment object) {
                  addCombinedFragment(object);
                  return Boolean.TRUE;
                }

                @Override
                public Object caseAssignmentStatement(AssignmentStatement object) {
                  addAssignmentStatement(object);
                  return Boolean.TRUE;
                };
              };

          switcher.doSwitch(newValue);
        } else if (notification.getEventType() == Notification.REMOVE) {
          EObject oldValue = (EObject) notification.getOldValue();

          RamSwitch<Object> switcher =
              new RamSwitch<Object>() {
                @Override
                public Object caseExecutionStatement(ExecutionStatement object) {
                  removeInteractionFragment(object);
                  return Boolean.TRUE;
                }

                @Override
                public Object caseCombinedFragment(CombinedFragment object) {
                  removeCombinedFragment(object);
                  return Boolean.TRUE;
                }

                @Override
                public Object caseAssignmentStatement(AssignmentStatement object) {
                  removeInteractionFragment(object);
                  return Boolean.TRUE;
                }
              };

          switcher.doSwitch(oldValue);
        }
      } else if (feature == RamPackage.Literals.INTERACTION__LIFELINES) {
        switch (notification.getEventType()) {
          case Notification.ADD:
            Lifeline lifeline = (Lifeline) notification.getNewValue();
            addLifelineView(lifeline);
            break;
          case Notification.REMOVE:
            lifeline = (Lifeline) notification.getOldValue();
            removeLifelineView(lifeline);
            break;
        }
      } else if (feature == RamPackage.Literals.INTERACTION__MESSAGES) {
        switch (notification.getEventType()) {
          case Notification.ADD:
            Message message = (Message) notification.getNewValue();
            addMessageView(message);
            break;
          case Notification.REMOVE:
            message = (Message) notification.getOldValue();
            removeMessageView(message);
            break;
        }
      }
    } else if (notifier == layout) {
      if (feature == RamPackage.Literals.CONTAINER_MAP__VALUE) {
        if (notification.getEventType() == Notification.ADD) {
          ElementMapImpl elementMap = (ElementMapImpl) notification.getNewValue();
          LifelineView lifelineView = lifelines.get(elementMap.getKey());
          lifelineView.setLayoutElement(elementMap.getValue());
        }
      }
    }
  }
示例#10
0
  /**
   * Layouts all fragments along this view. Can be called recursively for different fragment
   * containers.
   *
   * @param container the {@link FragmentContainer} for which fragments should be layouted
   * @param nextfragmentY the y-position for the next fragment
   * @return the y-position for the next fragment
   */
  private float layoutFragments(FragmentContainer container, float nextfragmentY) {
    float previousFragmentY = nextfragmentY;
    float currentFragmentY = nextfragmentY;
    boolean receiveEventNext = false;

    // Make sure that all messages are updated, since this might be necessary due to moving the
    // lifelines around.
    for (InteractionFragment fragment : container.getFragments()) {
      int index = fragment.getContainer().getFragments().indexOf(fragment);

      for (Lifeline lifeline : fragment.getCovered()) {
        LifelineView lifelineView = lifelines.get(lifeline);

        // In case of a create message the lifeline has to be moved down depending on the name
        // height.
        if (fragment instanceof MessageOccurrenceSpecification) {
          MessageOccurrenceSpecification messageEnd = (MessageOccurrenceSpecification) fragment;

          // If the message was removed, but the message ends are still there,
          // ignore them.
          if (!messages.containsKey(messageEnd.getMessage())) {
            continue;
          }

          if (messageEnd.getMessage().getMessageSort() == MessageSort.CREATE_MESSAGE
              && messageEnd.getMessage().getReceiveEvent() == messageEnd) {
            float lifelineNameHeight = lifelineView.getNameHeight();
            float difference = lifelineNameHeight - BOX_HEIGHT;
            float lifelineY = currentFragmentY - (difference / 2f);
            /** Convert global position to relative one. */
            lifelineY =
                getGlobalVecToParentRelativeSpace(lifelineView, new Vector3D(0, lifelineY)).y;
            lifelineView.getLayoutElement().setY(lifelineY);
            currentFragmentY += lifelineNameHeight;
            receiveEventNext = false;
            continue;
          }
        }

        RamRectangleComponent fragmentView = lifelineView.getFragmentView(fragment, index);
        // view is null when message was just removed
        if (fragmentView != null) {
          RamRectangleComponent spacer = lifelineView.getSpacerForFragmentAt(fragment, index);

          // Start with the position of the first spacer.
          if (currentFragmentY == LIFELINE_Y) {
            currentFragmentY = spacer.getPosition(TransformSpace.GLOBAL).getY();
          }

          if (!receiveEventNext) {
            currentFragmentY += BOX_HEIGHT;
          }

          Vector3D currentPosition = fragmentView.getPosition(TransformSpace.GLOBAL);

          if (currentPosition.getY() != currentFragmentY) {
            float difference = currentFragmentY - currentPosition.getY();
            float height = spacer.getHeight() + difference;
            // Fix the height to not go below the minimum size.
            if (height < BOX_HEIGHT) {
              height = BOX_HEIGHT;
            }

            spacer.setMinimumHeight(height);
            // Need to inform parent manually.
            spacer.updateParent();
          }

          if (fragment instanceof MessageOccurrenceSpecification) {
            MessageOccurrenceSpecification messageEnd = (MessageOccurrenceSpecification) fragment;
            Message message = messageEnd.getMessage();

            /**
             * Prevent moving downwards if the next event will be a receive event. However, if it is
             * a self message we need to move downwards. If it is the send event of a reply that
             * ends in a gate, there will be no next event.
             */
            if (!message.isSelfMessage()
                && message.getSendEvent() == messageEnd
                && message.getReceiveEvent().eClass() != RamPackage.Literals.GATE) {
              receiveEventNext = true;
            } else {
              receiveEventNext = false;
            }
          }

          if (fragment instanceof CombinedFragment) {
            CombinedFragment combinedFragment = (CombinedFragment) fragment;
            CombinedFragmentView combinedFragmentView = combinedFragments.get(combinedFragment);

            if (combinedFragment.getCovered().indexOf(lifeline) == 0) {
              Vector3D position = combinedFragmentView.getPosition(TransformSpace.GLOBAL);
              position.setY(currentFragmentY);
              combinedFragmentView.setPositionGlobal(position);

              receiveEventNext = true;
            }

            // Only increase y if it is the last lifeline.
            int lastIndex = combinedFragment.getCovered().size() - 1;
            if (combinedFragment.getCovered().indexOf(lifeline) == lastIndex) {
              for (InteractionOperand operand : combinedFragment.getOperands()) {
                float operandHeight = combinedFragmentView.getOperandMinimumHeight(operand);

                if (operand.getFragments().size() > 0) {
                  operandHeight += layoutFragments(operand, currentFragmentY + operandHeight);
                }

                // Add an additional space due to the additional spacer in the operand.
                // This also supports empty operands.
                operandHeight += BOX_HEIGHT;
                combinedFragmentView.setOperandHeight(operand, operandHeight);

                currentFragmentY += operandHeight;
              }

              combinedFragmentView.updateLayout();
              receiveEventNext = false;
            }
          } else if (!receiveEventNext) {
            currentFragmentY += fragmentView.getHeight();
          }
        }
      }
    }

    return currentFragmentY - previousFragmentY;
  }
示例#11
0
  /**
   * Adds a new view for the given message to this view. A message is represented by a view on each
   * end and a view representing the actual call. The end views are added to the corresponding
   * lifelines. In case an end is a gate and not placed on a lifeline, a {@link GateView} is used
   * instead and added to this view at the left side.
   *
   * @param message the {@link Message} to add
   */
  private void addMessageView(Message message) {
    LifelineView toView = null;
    LifelineView fromView = null;
    RamRectangleComponent sendEventView = null;
    RamRectangleComponent receiveEventView = null;
    MessageEnd sendEvent = message.getSendEvent();
    MessageEnd receiveEvent = message.getReceiveEvent();

    Operation signature = message.getSignature();
    boolean messageViewDefined = false;

    if (signature != null && specifies != signature) {
      Aspect aspect = EMFModelUtil.getRootContainerOfType(signature, RamPackage.Literals.ASPECT);
      /**
       * Make sure that the signature still exists in the aspect. It could have been deleted and
       * would then cause problems here.
       */
      if (aspect != null) {
        messageViewDefined = RAMModelUtil.isMessageViewDefined(aspect, signature);
      }
    }

    if (sendEvent instanceof MessageOccurrenceSpecification) {
      MessageOccurrenceSpecification event = (MessageOccurrenceSpecification) sendEvent;

      fromView = lifelines.get(event.getCovered().get(0));
      int modelIndex = event.getContainer().getFragments().indexOf(sendEvent);

      if (fromView != null) {
        boolean allowMessageCreation = false;
        // Allow creation after sending a message where no return is expected.
        if (signature != null && signature.getReturnType() != null) {
          Type returnType = signature.getReturnType();
          allowMessageCreation =
              message.getMessageSort() != MessageSort.REPLY
                  && !message.isSelfMessage()
                  && (returnType.eClass() == RamPackage.Literals.RVOID
                      || message.getMessageSort() == MessageSort.CREATE_MESSAGE
                      || signature.eContainer() instanceof ImplementationClass
                      // When a message view is defined, there will be no reply, so we need to allow
                      // it.
                      || messageViewDefined);
        }

        sendEventView = fromView.addMessageEnd(event, modelIndex, allowMessageCreation);
      }
    }

    if (receiveEvent instanceof MessageOccurrenceSpecification) {
      MessageOccurrenceSpecification event = (MessageOccurrenceSpecification) receiveEvent;

      toView = lifelines.get(event.getCovered().get(0));
      int modelIndex = event.getContainer().getFragments().indexOf(receiveEvent);

      if (toView != null) {
        if (message.getMessageSort() == MessageSort.CREATE_MESSAGE) {
          receiveEventView = toView;
        } else {
          boolean allowMessageCreation = message.getMessageSort() != MessageSort.DELETE_MESSAGE;
          if (signature != null) {
            // Don't allow message creation if the receiving end is on an implementation class.
            // If it is a self message it cannot be on an implementation class and is allowed.
            allowMessageCreation =
                allowMessageCreation
                    && !(signature.eContainer() instanceof ImplementationClass)
                    && (!messageViewDefined || message.isSelfMessage());
          }

          receiveEventView = toView.addMessageEnd(event, modelIndex, allowMessageCreation);
        }
      }
    }

    if (sendEventView == null) {
      Vector3D oppositePosition = receiveEventView.getPosition(TransformSpace.GLOBAL);
      sendEventView = new GateView(0, oppositePosition.getY(), BOX_WIDTH, BOX_HEIGHT);
      addChild(sendEventView);
    } else if (receiveEventView == null) {
      Vector3D oppositePosition = sendEventView.getPosition(TransformSpace.GLOBAL);
      receiveEventView = new GateView(0, oppositePosition.getY(), BOX_WIDTH, BOX_HEIGHT);
      addChild(receiveEventView);
    }

    MessageCallView messageCallView = new MessageCallView(message, sendEventView, receiveEventView);
    addChild(messageCallView);
    messageCallView.setHandler(HandlerFactoryMessageView.INSTANCE.getMessageHandler());
    messages.put(message, messageCallView);

    layoutMessageView();

    messageCallView.updateLines();
  }
示例#12
0
  /**
   * Removes the given lifeline from this view.
   *
   * @param lifeline the {@link Lifeline} to remove
   */
  private void removeLifelineView(Lifeline lifeline) {
    LifelineView lifelineView = lifelines.remove(lifeline);

    removeChild(lifelineView);
    lifelineView.destroy();
  }