| /********************************************************************** |
| * Copyright (c) 2005, 2014 IBM Corporation, Ericsson |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| * Bernd Hufmann - Updated for TMF |
| **********************************************************************/ |
| |
| package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor; |
| import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC; |
| import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IImage; |
| import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences; |
| import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref; |
| |
| /** |
| * Lifeline is the UML2 lifeline graphical representation.<br> |
| * Each lifeline owns a set of event occurrences. An event occurrence is the base element in UML2 to set an event in a |
| * sequence diagram.<br> |
| * Event occurrence define the drawing order of graph node along a lifeline. In this lifeline implementation, event |
| * occurrences are just integer index. The event occurrences with the same value on different lifelines will correspond |
| * the same y coordinate value. |
| * |
| * @version 1.0 |
| * @author sveyrier |
| * |
| */ |
| public class Lifeline extends GraphNode { |
| // ------------------------------------------------------------------------ |
| // Constants |
| // ------------------------------------------------------------------------ |
| /** |
| * The life line tag. |
| */ |
| public static final String LIFELINE_TAG = "Lifeline"; //$NON-NLS-1$ |
| |
| // ------------------------------------------------------------------------ |
| // Attribute |
| // ------------------------------------------------------------------------ |
| /** |
| * The lifeline position in the containing frame |
| */ |
| private int fIndexInFrame = 0; |
| /** |
| * The frame where the lifeline is drawn |
| */ |
| private Frame fFrame = null; |
| /** |
| * The current event occurrence created in the lifeline |
| */ |
| private int fEventOccurrence = 0; |
| /** |
| * The lifeline category. |
| */ |
| private int fCategory = -1; |
| /** |
| * Flag whether lifeline has time information available or not |
| */ |
| private boolean fHasTimeInfo = false; |
| |
| // ------------------------------------------------------------------------ |
| // Constructors |
| // ------------------------------------------------------------------------ |
| /** |
| * Default constructor |
| */ |
| public Lifeline() { |
| setColorPrefId(ISDPreferences.PREF_LIFELINE); |
| } |
| |
| // ------------------------------------------------------------------------ |
| // Methods |
| // ------------------------------------------------------------------------ |
| |
| @Override |
| public int getX() { |
| return Metrics.FRAME_H_MARGIN + Metrics.LIFELINE_H_MAGIN + (fIndexInFrame - 1) * Metrics.swimmingLaneWidth(); |
| } |
| |
| @Override |
| public int getY() { |
| return 2 * Metrics.FRAME_NAME_H_MARGIN + Metrics.LIFELINE_VT_MAGIN / 2 + Metrics.getFrameFontHeigth() + Metrics.getLifelineHeaderFontHeigth() + Metrics.FRAME_V_MARGIN + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN; |
| } |
| |
| @Override |
| public int getWidth() { |
| return Metrics.getLifelineWidth(); |
| } |
| |
| @Override |
| public int getHeight() { |
| // Set room for two text lines |
| return Metrics.getLifelineFontHeigth()/** 2 */ |
| + 2 * Metrics.LIFELINE_NAME_H_MARGIN; |
| } |
| |
| /** |
| * Set the lifeline category for this lifeline. |
| * |
| * @param arrayIndex the index of the category to use |
| * @see Frame#setLifelineCategories(LifelineCategories[]) |
| */ |
| public void setCategory(int arrayIndex) { |
| fCategory = arrayIndex; |
| } |
| |
| /** |
| * Gets the lifeline category for this lifeline. |
| * |
| * @return arrayIndex the index of the category to use |
| */ |
| public int getCategory() { |
| return fCategory; |
| } |
| |
| /** |
| * Returns the tooltip text for the lifeline. It is the combination between the category name(if any) and the |
| * lifeline name |
| * |
| * @return the tooltip text |
| */ |
| public String getToolTipText() { |
| if (fCategory >= 0) { |
| LifelineCategories[] categories = fFrame.getLifelineCategories(); |
| if (fCategory < categories.length) { |
| return categories[fCategory].getName() + " " + getName(); //$NON-NLS-1$ |
| } |
| } |
| return ""; //$NON-NLS-1$ |
| } |
| |
| /** |
| * Returns the index of the first visible Execution Occurrence in the execution occurrence array.<br> |
| * Execution Occurrences are Y ordered in this array |
| * |
| * @return the first visible Execution Occurrence |
| */ |
| public int getExecOccurrenceDrawIndex() { |
| if (!hasChildren()) { |
| return 0; |
| } |
| Integer ret = getIndexes().get(BasicExecutionOccurrence.EXEC_OCC_TAG); |
| return (ret == null ? 0 : ret.intValue()); |
| } |
| |
| /** |
| * Set the frame on which this lifeline must be drawn |
| * |
| * @param parentFrame |
| * Parent frame |
| */ |
| protected void setFrame(Frame parentFrame) { |
| fFrame = parentFrame; |
| if (fHasTimeInfo) { |
| fFrame.setHasTimeInfo(true); |
| } |
| if (fFrame.getMaxEventOccurrence() < getEventOccurrence() + 1) { |
| fFrame.setMaxEventOccurrence(getEventOccurrence() + 1); |
| } |
| } |
| |
| /** |
| * Returns the frame which this lifeline is drawn |
| * |
| * @return the Frame |
| */ |
| protected Frame getFrame() { |
| return fFrame; |
| } |
| |
| /** |
| * Set the lifeline position index in the containing frame |
| * |
| * @param index the lifeline X position |
| */ |
| protected void setIndex(int index) { |
| fIndexInFrame = index; |
| } |
| |
| /** |
| * Returns the lifeline position in de the containing frame |
| * |
| * @return the X position |
| */ |
| public int getIndex() { |
| return fIndexInFrame; |
| } |
| |
| /** |
| * Set the lifeline event occurrence to the value given in parameter This only change the current event occurrence, |
| * greater event created on this lifeline are still valid and usable. This also need to inform the frame of the |
| * operation mostly to store in the frame the greater event found in the diagram (used to determine the frame |
| * height) |
| * |
| * @param eventOcc the new current event occurrence |
| */ |
| public void setCurrentEventOccurrence(int eventOcc) { |
| if ((fFrame != null) && (fFrame.getMaxEventOccurrence() < eventOcc)) { |
| fFrame.setMaxEventOccurrence(eventOcc); |
| } |
| fEventOccurrence = eventOcc; |
| } |
| |
| /** |
| * Returns the last created event occurrence along the lifeline. |
| * |
| * @return the current event occurrence |
| */ |
| public int getEventOccurrence() { |
| return fEventOccurrence; |
| } |
| |
| /** |
| * Creates a new event occurrence along the lifeline. |
| * |
| * @return the new created event occurrence |
| */ |
| public int getNewEventOccurrence() { |
| setCurrentEventOccurrence(fEventOccurrence + 1); |
| return fEventOccurrence; |
| } |
| |
| /** |
| * Adds the execution occurrence given in parameter to the lifeline.<br> |
| * A Execution occurrence is never drawn in the frame instead it is added to a lifeline |
| * |
| * @param exec the execution occurrence to add |
| */ |
| public void addExecution(BasicExecutionOccurrence exec) { |
| exec.setLifeline(this); |
| addNode(exec); |
| if ((fFrame != null) && (fFrame.getMaxEventOccurrence() < exec.getEndOccurrence())) { |
| fFrame.setMaxEventOccurrence(exec.getEndOccurrence()); |
| } |
| } |
| |
| /** |
| * Set whether lifeline has time information available or not. |
| * @param value The value to set |
| */ |
| protected void setTimeInfo(boolean value) { |
| fHasTimeInfo = value; |
| if ((fFrame != null) && value) { |
| fFrame.setHasTimeInfo(value); |
| } |
| } |
| |
| /** |
| * Returns true if at least one execution occurrence has time info. |
| * |
| * @return true if at least one execution occurrence has time info |
| */ |
| public boolean hasTimeInfo() { |
| return fHasTimeInfo; |
| } |
| |
| /** |
| * Returns the list of execution occurrence on this lifeline. |
| * |
| * @return the execution occurrence list |
| */ |
| public List<GraphNode> getExecutions() { |
| if (hasChildren()) { |
| return getNodeMap().get(BasicExecutionOccurrence.EXEC_OCC_TAG); |
| } |
| return new ArrayList<>(); |
| } |
| |
| @Override |
| public boolean contains(int xValue, int yValue) { |
| int x = getX(); |
| int y = getY(); |
| int width = getWidth(); |
| int height = getHeight(); |
| |
| if (fFrame == null) { |
| return false; |
| } |
| if (GraphNode.contains(x, y, width, height, xValue, yValue)) { |
| return true; |
| } |
| if (GraphNode.contains(x + Metrics.getLifelineWidth() / 2 - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2, y + height, Metrics.EXECUTION_OCCURRENCE_WIDTH, (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fFrame.getMaxEventOccurrence() |
| + Metrics.LIFELINE_VB_MAGIN - 4, xValue, yValue)) { |
| return true; |
| } |
| |
| height = Metrics.getLifelineFontHeigth() + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN; |
| int hMargin = (Metrics.LIFELINE_VT_MAGIN - height) / 2; |
| |
| if (hMargin >= 2) { |
| if (fFrame.getVisibleAreaY() < y - height - hMargin) { |
| if (GraphNode.contains(x - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2, height + 1, xValue, yValue)) { |
| return true; |
| } |
| } else { |
| if (GraphNode.contains(x - Metrics.LIFELINE_SPACING / 2 + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height, xValue, yValue)) { |
| return true; |
| } |
| } |
| } |
| return (getNodeAt(xValue, yValue) != null); |
| } |
| |
| /** |
| * Returns the lifeline visibility for the given visible area |
| * |
| * @param vx The x coordinate of the visible area |
| * @param vy The y coordinate of the visible area |
| * @param vwidth The width of the visible area |
| * @param vheight The height of the visible area |
| * @return true if visible false otherwise |
| */ |
| @Override |
| public boolean isVisible(int vx, int vy, int vwidth, int vheight) { |
| int x = getX(); |
| int width = getWidth(); |
| return (((x >= vx) && (x <= vx + vwidth)) || ((x + width >= vx) && (x <= vx))); |
| } |
| |
| /** |
| * Draws the name within the graphical context. |
| * |
| * @param context The graphical context. |
| */ |
| protected void drawName(IGC context) { |
| ISDPreferences pref = SDViewPref.getInstance(); |
| |
| int x = getX(); |
| int y = getY(); |
| int height = Metrics.getLifelineHeaderFontHeigth() + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN; |
| int hMargin = Metrics.LIFELINE_VT_MAGIN / 4;// (Metrics.LIFELINE_NAME_H_MARGIN)/2; |
| |
| context.setLineStyle(context.getLineSolidStyle()); |
| context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE_HEADER)); |
| context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_LIFELINE_HEADER)); |
| context.setFont(pref.getFont(ISDPreferences.PREF_LIFELINE_HEADER)); |
| if (hMargin >= 0) { |
| if (fFrame.getVisibleAreaY() < y - height - hMargin) { |
| context.fillRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2, height); |
| context.drawRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2, height); |
| context.setForeground(pref.getFontColor(ISDPreferences.PREF_LIFELINE_HEADER)); |
| context.drawTextTruncatedCentred(getName(), x + Metrics.LIFELINE_NAME_V_MARGIN - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2 * Metrics.LIFELINE_NAME_V_MARGIN - 2, height, true); |
| } else { |
| context.fillRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height); |
| context.drawRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height); |
| context.setForeground(pref.getFontColor(ISDPreferences.PREF_LIFELINE_HEADER)); |
| context.drawTextTruncatedCentred(getName(), x - Metrics.LIFELINE_SPACING / 2 + Metrics.LIFELINE_NAME_V_MARGIN + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2 * Metrics.LIFELINE_NAME_V_MARGIN - 2, height, true); |
| } |
| } |
| } |
| |
| /** |
| * Force the lifeline to be drawn at the given coordinate |
| * |
| * @param context - the context to draw into |
| * @param x - the x coordinate |
| * @param y - the y coordinate |
| */ |
| public void draw(IGC context, int x, int y) { |
| |
| ISDPreferences pref = SDViewPref.getInstance(); |
| |
| // Set the draw color depending if the lifeline must be selected or not |
| context.setLineWidth(Metrics.NORMAL_LINE_WIDTH); |
| if (isSelected()) { |
| if (pref.useGradienColor()) { |
| context.setGradientColor(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE)); |
| } |
| context.setBackground(pref.getBackGroundColorSelection()); |
| context.setForeground(pref.getForeGroundColorSelection()); |
| } else { |
| if (pref.useGradienColor()) { |
| context.setGradientColor(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE)); |
| context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_FRAME)); |
| } else { |
| context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE)); |
| } |
| context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_LIFELINE)); |
| } |
| // Store the lifeline coordinates to save some calls |
| int width = getWidth(); |
| int height = getHeight(); |
| |
| // Draw the rectangle which contain the lifeline name |
| if (pref.useGradienColor()) { |
| context.fillGradientRectangle(x, y, width, height / 2 - 7, true); |
| context.fillRectangle(x, y + height / 2 - 8, width, +height / 2 - 5); |
| context.fillGradientRectangle(x, y + height, width, -height / 2 + 6, true); |
| } else { |
| context.fillRectangle(x, y, width, height); |
| } |
| context.drawRectangle(x, y, width, height); |
| |
| if (fCategory >= 0) { |
| LifelineCategories[] categories = fFrame.getLifelineCategories(); |
| if (fCategory < categories.length) { |
| IImage image = categories[fCategory].getImage(); |
| if (image != null) { |
| context.drawImage(image, x, y, width, height); |
| } |
| } |
| } |
| |
| // Draw the lifeline label into the rectangle |
| // The label is truncated if it cannot fit |
| IColor temp = context.getForeground(); |
| context.setFont(pref.getFont(ISDPreferences.PREF_LIFELINE)); |
| context.setForeground(pref.getFontColor(ISDPreferences.PREF_LIFELINE)); |
| context.drawTextTruncatedCentred(getName(), x + Metrics.LIFELINE_NAME_V_MARGIN, y, Metrics.getLifelineWidth() - 2 * Metrics.LIFELINE_NAME_V_MARGIN, height, true); |
| |
| context.setLineStyle(context.getLineDashStyle()); |
| context.setForeground(temp); |
| int oldStyle = context.getLineStyle(); |
| |
| // Now draw the lifeline vertical line |
| // this line height depends on a stop assignment |
| // if there is no stop the line is drawn to the bottom of the frame |
| |
| // by default set the height to reach the frame bottom |
| int dashedLineEnd = y + height + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fFrame.getMaxEventOccurrence() + Metrics.LIFELINE_VB_MAGIN; |
| /* |
| * if (stop != null) { dashedLineEnd = stop.getY(); } |
| */ |
| |
| if (isSelected()) { |
| context.setForeground(pref.getBackGroundColorSelection()); |
| context.setLineWidth(5); |
| context.drawLine(x + Metrics.getLifelineWidth() / 2, y + height, x + Metrics.getLifelineWidth() / 2, dashedLineEnd - 4); |
| context.setForeground(pref.getForeGroundColorSelection()); |
| } |
| |
| context.setLineWidth(Metrics.NORMAL_LINE_WIDTH); |
| context.drawLine(x + Metrics.getLifelineWidth() / 2, y + height, x + Metrics.getLifelineWidth() / 2, dashedLineEnd - 4); |
| context.drawLine(x + Metrics.getLifelineWidth() / 2, y + height, x + Metrics.getLifelineWidth() / 2, dashedLineEnd - 4); |
| context.setLineStyle(oldStyle); |
| |
| context.setLineStyle(context.getLineSolidStyle()); |
| |
| if (hasFocus()) { |
| drawFocus(context); |
| } |
| |
| super.drawChildenNodes(context); |
| } |
| |
| /** |
| * Draws the select execution occurrence region using the given color |
| * |
| * @param context the graphical context |
| * @param startEvent the region start |
| * @param nbEvent the region height |
| * @param color the color to use |
| */ |
| public void highlightExecOccurrenceRegion(IGC context, int startEvent, int nbEvent, IColor color) { |
| IColor backupColor = context.getBackground(); |
| context.setBackground(color); |
| int x = getX() + Metrics.getLifelineWidth() / 2 - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2; |
| int y = getY() + getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * startEvent; |
| int width = Metrics.EXECUTION_OCCURRENCE_WIDTH; |
| int height = ((Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing())) * nbEvent; |
| context.fillRectangle(x, y, width, height); |
| context.setBackground(backupColor); |
| } |
| |
| @Override |
| public void draw(IGC context) { |
| draw(context, getX(), getY()); |
| } |
| |
| @Override |
| public String getArrayId() { |
| return LIFELINE_TAG; |
| } |
| |
| @Override |
| public boolean positiveDistanceToPoint(int x, int y) { |
| return (getX() > x - Metrics.swimmingLaneWidth()); |
| } |
| |
| @Override |
| public GraphNode getNodeAt(int x, int y) { |
| int vy = 0; |
| int vh = 0; |
| if (getFrame() != null) { |
| vy = getFrame().getVisibleAreaY(); |
| vh = getFrame().getVisibleAreaHeight(); |
| } else { |
| return null; |
| } |
| if (getExecutions() == null) { |
| return null; |
| } |
| for (int i = getExecOccurrenceDrawIndex(); i < getExecutions().size(); i++) { |
| GraphNode node = getExecutions().get(i); |
| if (node.getHeight() < 0) { |
| if (node.getY() + node.getHeight() > vy + vh) { |
| break; |
| } |
| } else { |
| if (node.getY() > vy + vh) { |
| break; |
| } |
| } |
| if (node.contains(x, y)) { |
| GraphNode internal = node.getNodeAt(x, y); |
| if (internal != null) { |
| return internal; |
| } |
| return node; |
| } |
| } |
| return null; |
| } |
| } |