示例#1
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);
        }
      }
    }
  }
示例#2
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;
  }