package org.eclipse.uml2.diagram.sequence.internal.layout.horizontal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.gmf.runtime.notation.LayoutConstraint;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.Size;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.uml2.diagram.sequence.internal.layout.GeometryConstants;
import org.eclipse.uml2.diagram.sequence.internal.layout.model.LMFrame;
import org.eclipse.uml2.diagram.sequence.internal.layout.model.LMVisibleFrameWithPentagon;
import org.eclipse.uml2.diagram.sequence.internal.missed.MissedMethods;
/**
*
*/
class LifeLineDressImpl implements LifeLineDress, MissedMethods.DifferentSemanticInArcasAndGMF {
LifeLineDressImpl(boolean pos) {
myIgnoreCurrentPos = pos;
}
public int getLeftMinSpace() {
return myLeftSide.getMinOffsetWidth();
}
public int getRightMinSpace() {
return myRightSide.getMinOffsetWidth();
}
public int getRightSpace() {
return myRightSide.getOuterOffsetWidth();
}
public void setMinLeftAndCenter(int minLeft, int center) {
// System.out.println("[LifeLineDressImpl] setMinLeftAndCenter before " + myLeftSide);
// System.out.println("[LifeLineDressImpl] setMinLeftAndCenter before " + myRightSide);
myLeftSide.setLifelinePos(center, !myIgnoreCurrentPos);
myRightSide.setLifelinePos(center, !myIgnoreCurrentPos);
// System.out.println("[LifeLineDressImpl] setMinLeftAndCenter after " + myLeftSide);
// System.out.println("[LifeLineDressImpl] setMinLeftAndCenter after " + myRightSide);
if (!myIgnoreCurrentPos) {
if (myLeftJustReshaped != null) {
int currentOffset = myLeftJustReshaped.getCurrentOffset(center);
myLeftJustReshaped.setOffsetLimit(currentOffset);
myLeftSide.revalidateOffsets(center);//minimal offset constraints could be broken
}
if (myRightJustReshaped != null) {
int currentOffset = myRightJustReshaped.getCurrentOffset(center);
myRightJustReshaped.setOffsetLimit(currentOffset);
myRightSide.revalidateOffsets(center);//minimal offset constraints could be broken
}
}
// System.out.println("[LifeLineDressImpl] setMinLeftAndCenter reshape " + myLeftSide);
// System.out.println("[LifeLineDressImpl] setMinLeftAndCenter reshape " + myRightSide);
myLeftSide.setOuterOffsetLimit(center - minLeft);
}
public void setMaxRight(int center, int maxRight) {
myRightSide.setOuterOffsetLimit(maxRight - center);
}
public void layout(final int center) {
//System.out.println("[SDHorizontalLayout.layout] myLeftSpace="+myLeftSpace);
//System.out.println("[SDHorizontalLayout.layout] myRightSpace="+myRightSpace);
//System.out.println("[SDHorizontalLayout.layout] myLeftFrames="+myLeftFrames);
//System.out.println("[SDHorizontalLayout.layout] myRightFrames="+myRightFrames);
{
//System.out.println("[LifeLineDressImpl.layout] leftPos = "+leftPos);
PositionSetter leftPositionSetter = new PositionSetter() {
void setFrameBorderPosition(LMFrame lmFrame, int offset) {
lmFrame.setLeftBorderPosByLayout(center - offset);
}
void setUntiedFramePosition(UntiedFrameHorizontalLayouter untiedFrameLayouter, int outerSizePos) {
untiedFrameLayouter.layout(center - outerSizePos);
}
};
myLeftSide.layout(leftPositionSetter);
}
{
//System.out.println("[LifeLineDressImpl.layout] rightPos = "+rightPos);
PositionSetter rightPositionSetter = new PositionSetter() {
void setFrameBorderPosition(LMFrame lmFrame, int offset) {
lmFrame.setRightBorderPosByLayout(center + offset);
}
void setUntiedFramePosition(UntiedFrameHorizontalLayouter untiedFrameLayouter, int outerSizePos) {
throw new UnsupportedOperationException();
}
};
myRightSide.layout(rightPositionSetter);
}
}
LeftSideFrameWrapper addLeftFrame(LMFrame lmFrame, int maxLeftBracketOffset, UntiedFrameHorizontalLayouter untiedFrameLayouter, boolean addAsJustReshaped) {
LeftSideFrameWrapper frameWrapper = (LeftSideFrameWrapper)myLeftSide.addFrame(lmFrame, untiedFrameLayouter, maxLeftBracketOffset);
if (addAsJustReshaped) {
myLeftJustReshaped = frameWrapper;
}
return frameWrapper;
}
void addRightFrame(LMFrame lmFrame, int maxRightBracketOffset, boolean addAsJustReshaped, LeftSideFrameWrapper leftSideOnTheSameLifeline) {
RightSideFrameWrapper frameWrapper = (RightSideFrameWrapper)myRightSide.addFrame(lmFrame, null, maxRightBracketOffset);
frameWrapper.setLeftSideWrapperOnTheSameLifeline(leftSideOnTheSameLifeline);
if (addAsJustReshaped) {
myRightJustReshaped = frameWrapper;
}
}
private final boolean myIgnoreCurrentPos;
private FrameWrapper myLeftJustReshaped;
private FrameWrapper myRightJustReshaped;
private final OneSide myLeftSide = new LeftSide();
private final OneSide myRightSide = new RightSide();
private abstract static class PositionSetter {
abstract void setFrameBorderPosition(LMFrame lmFrame, int offset);
abstract void setUntiedFramePosition(UntiedFrameHorizontalLayouter untiedFrameLayouter, int outerSizePos);
}
private static abstract class OneSide {
FrameWrapper addFrame(LMFrame lmFrame, UntiedFrameHorizontalLayouter untiedFrameLayouter, int offset) {
//System.out.println("[LifeLineDressImpl.addFrame] |"+myDebugId+"| lmFrame="+lmFrame);
ArrayList innerFrames = new ArrayList(myOuterFrameWrappers.size());
for (Iterator it = myOuterFrameWrappers.iterator(); it.hasNext(); ) {
FrameWrapper frameWrapper = (FrameWrapper) it.next();
if (frameWrapper.getLMFrame().getContainer() == lmFrame) {
innerFrames.add(frameWrapper);
//System.out.println("[LifeLineDressImpl.addFrame] |"+myDebugId+"| enclosed frame "+frameWrapper.getLMFrame());
int offset2 = frameWrapper.getMinOuterOffset();
//System.out.println("[LifeLineDressImpl.addFrame] |"+myDebugId+"| offset2 = "+offset2);
if (offset2 > offset) {
offset = offset2;
}
it.remove();
}
}
//System.out.println("[LifeLineDressImpl.addFrame] |"+myDebugId+"| result offset="+offset);
FrameWrapper frameWrapper = createFrameWrapper(lmFrame, offset, untiedFrameLayouter, innerFrames);
if (innerFrames.isEmpty()) {
myInnerFrameWrappers.add(frameWrapper);
}
myOuterFrameWrappers.add(frameWrapper);
myFrameWrappers.add(frameWrapper);
return frameWrapper;
}
abstract FrameWrapper createFrameWrapper(LMFrame frame, int innerElementsMinOffset, UntiedFrameHorizontalLayouter untiedFrameLayouter, ArrayList children);
void setLifelinePos(int lifelinePos, boolean considerCurrentPos) {
for (int i = 0; i < myInnerFrameWrappers.size(); i++) {
FrameWrapper frameWrapper = (FrameWrapper)myInnerFrameWrappers.get(i);
frameWrapper.setLifelinePos(lifelinePos, considerCurrentPos);
}
}
void revalidateOffsets(int lifelinePos) {
for (int i = 0; i < myInnerFrameWrappers.size(); i++) {
FrameWrapper frameWrapper = (FrameWrapper)myInnerFrameWrappers.get(i);
frameWrapper.revalidateOffsetsAfterReshape(lifelinePos);
}
}
void setOuterOffsetLimit(int externalPos) {
for (Iterator it = myOuterFrameWrappers.iterator(); it.hasNext(); ) {
FrameWrapper frameWrapper = (FrameWrapper) it.next();
frameWrapper.setOuterOffsetLimit(externalPos);
}
}
void layout(PositionSetter positionSetter) {
//System.out.println("[LifeLineDressImpl.layout] |"+myDebugId+"| ");
// reverse order: move outer frames first
for (int i=myFrameWrappers.size()-1; i>=0; i--) {
FrameWrapper frameWrapper = (FrameWrapper) myFrameWrappers.get(i);
//System.out.println("[LifeLineDressImpl.layout] |"+myDebugId+"| frame="+frameWrapper.getLMFrame()+", offset="+frameWrapper.getOffset());
positionSetter.setFrameBorderPosition(frameWrapper.getLMFrame(), frameWrapper.getPreferredOffset());
UntiedFrameHorizontalLayouter untiedFrameLayouter = frameWrapper.getUntiedFrameLayouter();
if (untiedFrameLayouter != null) {
positionSetter.setUntiedFramePosition(untiedFrameLayouter, frameWrapper.getPreferredOffset() - GeometryConstants.Frames.UNTIED_FRAME_OUTER_SPACE_HORIZONTAL);
}
}
}
int getMinOffsetWidth() {
int offset = 0;
for (Iterator it = myOuterFrameWrappers.iterator(); it.hasNext(); ) {
FrameWrapper frameWrapper = (FrameWrapper) it.next();
int offset2 = frameWrapper.getMinOuterOffset();
if (offset2 > offset) {
offset = offset2;
}
}
return offset;
}
int getOuterOffsetWidth() {
int offset = 0;
for (Iterator it = myOuterFrameWrappers.iterator(); it.hasNext(); ) {
FrameWrapper frameWrapper = (FrameWrapper) it.next();
int offset2 = frameWrapper.getPreferredOuterOffset();
if (offset2 > offset) {
offset = offset2;
}
}
return offset;
}
public String toString() {
StringBuffer result = new StringBuffer();
for(Iterator it = myOuterFrameWrappers.iterator(); it.hasNext(); ) {
FrameWrapper next = (FrameWrapper)it.next();
result.append(next.treeToString("")); //$NON-NLS-1$
}
return result.toString();
}
private final List myOuterFrameWrappers = new LinkedList();
private final List myFrameWrappers = new ArrayList();
private final List myInnerFrameWrappers = new ArrayList();
}
private static class RightSide extends OneSide {
FrameWrapper createFrameWrapper(LMFrame frame, int offset, UntiedFrameHorizontalLayouter untiedFrameLayouter, ArrayList children) {
return new RightSideFrameWrapper(frame, offset, untiedFrameLayouter, children);
}
public String toString() {
return "<RightSide: \n"+super.toString()+"\n>"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
private static class LeftSide extends OneSide {
FrameWrapper createFrameWrapper(LMFrame frame, int offset, UntiedFrameHorizontalLayouter untiedFrameLayouter, ArrayList children) {
return new LeftSideFrameWrapper(frame, offset, untiedFrameLayouter, children);
}
public String toString() {
return "<LeftSide: \n"+super.toString()+"\n>"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
private abstract static class FrameWrapper {
FrameWrapper(LMFrame frame, int offset, UntiedFrameHorizontalLayouter untiedFrameLayouter, ArrayList children) {
myLMFrame = frame;
myInnerElementsMinimalOffset = offset;
myUntiedFrameLayouter = untiedFrameLayouter;
{
int innerSpace = myLMFrame.getInnerHorizontalPadding();
if (myUntiedFrameLayouter != null) {
innerSpace += myUntiedFrameLayouter.getWidth() + 2*GeometryConstants.Frames.UNTIED_FRAME_OUTER_SPACE_HORIZONTAL;
}
myFrameInnerAdditionalSpace = innerSpace;
}
myPreferredOffset = myInnerElementsMinimalOffset + myFrameInnerAdditionalSpace;
{
myChildren = children;
for (int i = 0; i<children.size(); i++) {
((FrameWrapper) children.get(i)).setParent(this);
}
}
}
LMFrame getLMFrame() {
return myLMFrame;
}
int getMinOuterOffset() {
return myInnerElementsMinimalOffset + myFrameInnerAdditionalSpace + getOuterAdditionalSpace();
}
int getPreferredOffset() {
return myPreferredOffset;
}
int getPreferredOuterOffset() {
return myPreferredOffset + getOuterAdditionalSpace();
}
private int getOuterAdditionalSpace() {
return myLMFrame.getOuterHorizontalPadding();
}
UntiedFrameHorizontalLayouter getUntiedFrameLayouter() {
return myUntiedFrameLayouter;
}
void setLifelinePos(int lifelinePos, boolean considerCurrentPos) {
recalculatePreferredOffset(lifelinePos, considerCurrentPos);
}
void revalidateOffsetsAfterReshape(int lifelinePos) {
recalculatePreferredOffset(lifelinePos, false);
}
private void recalculatePreferredOffset(int lifelinePos, final boolean considerCurrentOffset) {
myInnerElementsMinimalOffset = recalculateMinInnerOffset(lifelinePos);
int minPreferredOffset = recalculateMinPreferredOffset(lifelinePos);
myPreferredOffset = Math.max(myPreferredOffset, minPreferredOffset);
if (considerCurrentOffset) {
int currentOffset = getCurrentOffset(lifelinePos);
myPreferredOffset = Math.max(myPreferredOffset, currentOffset);
}
if (myParent != null) {
myParent.recalculatePreferredOffset(lifelinePos, considerCurrentOffset);
}
}
int getCurrentOffset(int lifelinePos) {
if (isJustCreated(myLMFrame)) {
return 0;
} else {
return getPreviousOffset(lifelinePos);
}
}
abstract int getPreviousOffset(int lifelinePos);
int recalculateMinInnerOffset(int lifelinePos) {
int result = myInnerElementsMinimalOffset;
for (int i = 0; i < myChildren.size(); i++) {
FrameWrapper frameWrapper = (FrameWrapper)myChildren.get(i);
result = Math.max(result, frameWrapper.getMinOuterOffset());
}
return result;
}
int recalculateMinPreferredOffset(int lifelinePos) {
int offset = myInnerElementsMinimalOffset;
for (int i = 0; i < myChildren.size(); i++) {
FrameWrapper frameWrapper = (FrameWrapper)myChildren.get(i);
offset = Math.max(offset, frameWrapper.getPreferredOuterOffset());
}
return offset + myFrameInnerAdditionalSpace;
}
void setOuterOffsetLimit(int maxOffset) {
setOffsetLimit(maxOffset-getOuterAdditionalSpace());
}
void setOffsetLimit(int maxOffset) {
if (myPreferredOffset > maxOffset) {
myPreferredOffset = maxOffset;
final int innerMaxOffset = maxOffset - myFrameInnerAdditionalSpace;
for (int i = 0; i < myChildren.size(); i++) {
FrameWrapper frameWrapper = (FrameWrapper)myChildren.get(i);
frameWrapper.setOuterOffsetLimit(innerMaxOffset);
}
}
}
private void setParent(FrameWrapper parent) {
myParent = parent;
}
String treeToString(String margin) {
StringBuffer result = new StringBuffer();
result.append(margin).append(this.toString()).append("\n"); //$NON-NLS-1$
margin += " "; //$NON-NLS-1$
for (int i = 0; i<myChildren.size(); i++) {
result.append(((FrameWrapper)myChildren.get(i)).treeToString(margin));
}
return result.toString();
}
public String toString() {
return "LMFame: "+myLMFrame.getGdeNode().getModelEntity().eClass().getName()+"; minInnerOffset = "+myInnerElementsMinimalOffset+"; preferredOffset = "+myPreferredOffset+ //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
"; current bounds = "+myLMFrame.getGdeNode().getX()+", "+myLMFrame.getGdeNode().getY()+", "+myLMFrame.getGdeNode().getWidth()+", "+myLMFrame.getGdeNode().getHeight(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
private FrameWrapper myParent;
private final ArrayList myChildren;
protected final LMFrame myLMFrame;
private final UntiedFrameHorizontalLayouter myUntiedFrameLayouter;
private final int myFrameInnerAdditionalSpace;
protected int myInnerElementsMinimalOffset;
private int myPreferredOffset;
}
static class RightSideFrameWrapper extends FrameWrapper {
RightSideFrameWrapper(LMFrame frame, int offset, UntiedFrameHorizontalLayouter untiedFrameLayouter, ArrayList children) {
super(frame, offset, untiedFrameLayouter, children);
}
int getPreviousOffset(int lifelinePos) {
int frameRightPos = myLMFrame.getGdeNode().getX() + myLMFrame.getGdeNode().getWidth();
return frameRightPos - lifelinePos;
}
protected int recalculateMinInnerOffset(int lifelinePos) {
int result = super.recalculateMinInnerOffset(lifelinePos);
return stretchToPentagon(result, lifelinePos);
}
protected int recalculateMinPreferredOffset(int lifelinePos) {
int result = super.recalculateMinPreferredOffset(lifelinePos);
return stretchToPentagon(result, lifelinePos);
}
private int stretchToPentagon(int currentOffset, int lifelinePos) {
if (myLMFrame instanceof LMVisibleFrameWithPentagon) {
int pentagonWidth = ((LMVisibleFrameWithPentagon) myLMFrame).getMinimumWidth();
int minOffset;
if (myLeftSideWrapperOnTheSameLifeline == null) {
int minPos = myLMFrame.getGdeNode().getX() + pentagonWidth;
minOffset = minPos - lifelinePos;
} else {
minOffset = pentagonWidth - myLeftSideWrapperOnTheSameLifeline.getPreferredOffset();
}
minOffset += GeometryConstants.Frames.PENTAGON_MIN_RIGHT_OUTER_SPACE;
return Math.max(currentOffset, minOffset);
} else {
return currentOffset;
}
}
public String toString() {
return "<RightSideFrameWrapper: "+super.toString()+">"; //$NON-NLS-1$ //$NON-NLS-2$
}
void setLeftSideWrapperOnTheSameLifeline(LeftSideFrameWrapper leftSideWrapperOnTheSameLifeline) {
myLeftSideWrapperOnTheSameLifeline = leftSideWrapperOnTheSameLifeline;
}
/**
* To determine left pos of frame with pentagon after left side layout.
*/
private LeftSideFrameWrapper myLeftSideWrapperOnTheSameLifeline;
}
static class LeftSideFrameWrapper extends FrameWrapper {
LeftSideFrameWrapper(LMFrame frame, int offset, UntiedFrameHorizontalLayouter untiedFrameLayouter, ArrayList children) {
super(frame, offset, untiedFrameLayouter, children);
}
int recalculateMinInnerOffset(int lifelinePos) {
return myInnerElementsMinimalOffset;
}
int getPreviousOffset(int lifelinePos) {
return lifelinePos - myLMFrame.getGdeNode().getX();
}
public String toString() {
return "<LeftSideFrameWrapper: "+super.toString()+">"; //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* @return true if element has just been added to diagram and its position must be updated
*/
static boolean isJustCreated(LMFrame frame) {
MissedMethods.DifferentSemanticInArcasAndGMF marker = null;
// [U2T] in Arcas was:
// Rectangle bounds = ViewOptionsAccessor.getBounds(frame.getGdeNode().getReference());
// return bounds == null || bounds.width == 0;
View reference = frame.getGdeNode().getReference();
if (false == reference instanceof Node){
//strange
return false;
}
LayoutConstraint notationConstraint = ((Node)reference).getLayoutConstraint();
if (notationConstraint == null) {
return true;
}
if (notationConstraint instanceof Size){
return !((Size)notationConstraint).eIsSet(NotationPackage.eINSTANCE.getSize_Width());
}
return false;
}
}