package com.horstmann.violet.product.diagram.sequence.node; import com.horstmann.violet.framework.graphics.content.*; import com.horstmann.violet.framework.graphics.shape.ContentInsideCustomShape; import com.horstmann.violet.framework.graphics.shape.ContentInsideRectangle; import com.horstmann.violet.product.diagram.abstracts.edge.IEdge; import com.horstmann.violet.product.diagram.abstracts.node.AbstractNode; import com.horstmann.violet.product.diagram.property.choiceList.ChoiceList; import com.horstmann.violet.product.diagram.property.choiceList.TextChoiceList; import com.horstmann.violet.product.diagram.abstracts.node.INode; import com.horstmann.violet.product.diagram.abstracts.node.IResizableNode; import com.horstmann.violet.product.diagram.property.text.LineText; import com.horstmann.violet.product.diagram.property.text.MultiLineText; import com.horstmann.violet.product.diagram.property.text.SingleLineText; import com.horstmann.violet.product.diagram.property.text.decorator.LargeSizeDecorator; import com.horstmann.violet.product.diagram.property.text.decorator.OneLineText; import com.horstmann.violet.product.diagram.sequence.SequenceDiagramConstant; import java.awt.*; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** * A Combined fragment node in a UML diagram. * * @author Adrian Bobrowski <adrian071993@gmail.com> * @date 21.02.2016 */ public class CombinedFragmentNode extends AbstractNode implements IResizableNode { public CombinedFragmentNode() { operator = new TextChoiceList<String>(TYPE_KEYS, TYPE_VALUE); selectedType = operator.getSelectedPos(); operatorText = new SingleLineText(nameConverter); operatorText.setText(operator.getSelectedValue()); operatorText.setPadding(0,8,0,18); frameContent = new MultiLineText(); createContentStructure(); } protected CombinedFragmentNode(CombinedFragmentNode node) throws CloneNotSupportedException { super(node); operator = node.operator; selectedType = operator.getSelectedPos(); operatorText = node.operatorText.clone(); frameContent = node.frameContent.clone(); createContentStructure(); } @Override protected void beforeReconstruction() { super.beforeReconstruction(); if(null==frameContent) { frameContent = new MultiLineText(); } if(null==operatorText) { operatorText = new SingleLineText(); } frameContent.reconstruction(); operatorText.reconstruction(nameConverter); operatorText.setPadding(0,8,0,18); operator = new TextChoiceList<String>(TYPE_KEYS, TYPE_VALUE); operator.setSelectedIndex(selectedType); } @Override protected void afterReconstruction() { setOperator(getOperator()); wantedSizeContent.setMinWidth(wantedWeight); wantedSizeContent.setMinHeight(wantedHeight); super.afterReconstruction(); } @Override protected INode copy() throws CloneNotSupportedException { return new CombinedFragmentNode(this); } @Override protected void createContentStructure() { wantedSizeContent = new EmptyContent(); RelativeLayout relativeGroupContent = new RelativeLayout(); relativeGroupContent.setMinHeight(DEFAULT_HEIGHT); relativeGroupContent.setMinWidth(DEFAULT_WIDTH); TextContent nameContent = new TextContent(operatorText); nameContent.setMinHeight(DEFAULT_TYPE_HEIGHT); nameContent.setMinWidth(DEFAULT_TYPE_WIDTH); ContentInsideShape nameInsideShape = new ContentInsideCustomShape(nameContent, new ContentInsideCustomShape.ShapeCreator() { @Override public Shape createShape(double contentWidth, double contentHeight) { GeneralPath path = new GeneralPath(); path.moveTo(0, 0); path.lineTo(contentWidth, 0); path.lineTo(contentWidth, contentHeight / 2); path.lineTo(contentWidth - contentHeight / 2, contentHeight); path.lineTo(0, contentHeight); path.closePath(); return path; } }); ContentBackground nameBackground = new ContentBackground(new ContentBorder(nameInsideShape, BORDER_COLOR), BACKGROUND_COLOR); EmptyContent nameMarginRight = new EmptyContent(); nameMarginRight.setMinWidth(NAME_MARGIN_RIGHT); HorizontalLayout horizontalLayout = new HorizontalLayout(); horizontalLayout.add(nameBackground); horizontalLayout.add(nameMarginRight); relativeGroupContent.add(wantedSizeContent); relativeGroupContent.add(horizontalLayout); relativeGroupContent.add(new ContentInsideRectangle(new TextContent(frameContent)), new Point2D.Double(0,DEFAULT_TYPE_HEIGHT+5)); ContentInsideShape contentInsideShape = new ContentInsideRectangle(relativeGroupContent); setContent(new ContentBorder(contentInsideShape, BORDER_COLOR)); } @Override public String getToolTip() { return SequenceDiagramConstant.SEQUENCE_DIAGRAM_RESOURCE.getString("tooltip.combined_fragment_node"); } @Override public boolean addConnection(IEdge edge) { return false; } @Override public void setWantedSize(Rectangle2D size) { wantedWeight = size.getWidth(); wantedHeight = size.getHeight(); wantedSizeContent.setMinWidth(wantedWeight); wantedSizeContent.setMinHeight(wantedHeight); } @Override public Rectangle2D getResizablePoint() { Rectangle2D nodeBounds = getBounds(); double x = nodeBounds.getMaxX() - RESIZABLE_POINT_SIZE; double y = nodeBounds.getMaxY() - RESIZABLE_POINT_SIZE; return new Rectangle2D.Double(x, y, RESIZABLE_POINT_SIZE, RESIZABLE_POINT_SIZE); } /** * Sets the contents property value. * * @param newValue the contents of this class */ public void setFrameContent(LineText newValue) { frameContent.setText(newValue.toEdit()); } /** * Gets the contents property value. * * @return the contents of this class */ public LineText getFrameContent() { return frameContent; } /** * Gets the type property value. * * @return the type of this frame */ public ChoiceList getOperator() { return operator; } /** * Sets the type property value. * * @param type the type of this frame */ public void setOperator(ChoiceList type) { this.operator = (TextChoiceList<String>)type; selectedType = this.operator.getSelectedPos(); operatorText.setText(this.operator.getSelectedValue()); } private SingleLineText operatorText; private MultiLineText frameContent; private int selectedType; private transient TextChoiceList<String> operator; private double wantedWeight; private double wantedHeight; private transient EmptyContent wantedSizeContent; private static final int DEFAULT_TYPE_WIDTH = 60; private static final int DEFAULT_TYPE_HEIGHT = 20; private static final int DEFAULT_WIDTH = 80; private static final int DEFAULT_HEIGHT = 50; private static final int NAME_MARGIN_RIGHT = 10; private static final int RESIZABLE_POINT_SIZE = 5; private static final Color BORDER_COLOR = new Color(191, 191, 191, 255); private static final Color BACKGROUND_COLOR = new Color(255, 255, 153, 255); private static final LineText.Converter nameConverter = new LineText.Converter() { @Override public OneLineText toLineString(String text) { return new LargeSizeDecorator(new OneLineText(text)); } }; private static final String[] TYPE_VALUE = new String[]{ "alt", "opt", "loop", "break", "par", "strict", "seq", "critical", "ignore", "consider", "assert", "neg" }; public static String[] TYPE_KEYS = new String[TYPE_VALUE.length]; static { for(int i=0; i< TYPE_KEYS.length; ++i) { try { TYPE_KEYS[i] = SequenceDiagramConstant.SEQUENCE_DIAGRAM_RESOURCE.getString( ("operator." + TYPE_VALUE[i]).toLowerCase() ); }catch (Exception ignored){} } } }