package org.eclipse.uml2.diagram.sequence.internal.layout.vertical.state; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.HorizontalConstraint; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.LifeLine; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.LifeLineElement; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.LifeLineIterator; import org.eclipse.uml2.diagram.sequence.internal.layout.vertical.input.OrderingConstraint; /** * Most of methods are package-local. All actual work should be done via St* classes to enforce using class * in correct state only. * */ public class LifelineState { private static final boolean DEBUG_SAVE_POS = false; private static final boolean DEBUG_LOAD_POS = false; public LifelineState(LifeLine lifeLine, int topPos, boolean resetPositions, Set brokenOrderingConstraints) { myLifeLine = lifeLine; myBase = topPos; myWrapperList = new ArrayList(); myBrokenOrderingConstraints = brokenOrderingConstraints; int priorityCounter = 0; for (LifeLineIterator it = lifeLine.iterator(); it.hasNext(); ) { it.nextClueValue(); LifeLineElement element = it.nextElement(); if (resetPositions) { element.optimizeSize(); } if (element.getPosition().isFirstPrioritedPosition()) { priorityCounter++; } myWrapperList.add(new ElementWrapper(element, priorityCounter > 0)); if (element.getPosition().isLastPrioritedPosition()) { priorityCounter--; } } myIndex = -1; if (resetPositions) { resetPositions(topPos); } else { loadPositions(topPos); } nextStep(); if (isFinished()) { myState = St9LifelineFinished.class; } else { myState = St1MinPosIsCalculated.class; } } public String getStateStringDebug() { return "element="+myCurrentWrapper.getElement(); //$NON-NLS-1$ } public String toString() { return "LifelineState<"+myLifeLine+">"; //$NON-NLS-1$ //$NON-NLS-2$ } private void loadPositions(int topPos) { if (DEBUG_LOAD_POS) { System.out.println("[LifelineState] loadPositions>>>>>: "+this); //$NON-NLS-1$ } ElementWrapper firstElementWrapper = (ElementWrapper) myWrapperList.get(0); firstElementWrapper.setPos(topPos); for (int i=1; i<myWrapperList.size(); i++) { ElementWrapper elementWrapper = (ElementWrapper) myWrapperList.get(i); elementWrapper.loadPos(); if (DEBUG_LOAD_POS) { System.out.println("[LifelineState] loadPositions: "+elementWrapper.getElement()+ " pos = "+elementWrapper.getPos()); //$NON-NLS-1$ //$NON-NLS-2$ } } if (DEBUG_LOAD_POS) { System.out.println("[LifelineState] loadPositions<<<<<<<<< "); //$NON-NLS-1$ } } private void resetPositions(int topPos) { for (int i=0; i<myWrapperList.size(); i++) { ElementWrapper elementWrapper = (ElementWrapper) myWrapperList.get(i); elementWrapper.setPos(topPos); } } public void savePositions() { assert checkPositionsMonotonous(); if (DEBUG_SAVE_POS) { System.out.println("[LifelineState] savePositions----------->>>>: "+this); //$NON-NLS-1$ } for (int i=0; i<myWrapperList.size(); i++) { ElementWrapper elementWrapper = (ElementWrapper) myWrapperList.get(i); elementWrapper.savePos(); if (DEBUG_SAVE_POS) { System.out.println("[LifelineState] savePositions: "+elementWrapper.getElement()+ " pos = "+elementWrapper.getPos()); //$NON-NLS-1$//$NON-NLS-2$ } } assert checkPositionsSaved(); if (DEBUG_SAVE_POS) { System.out.println("[LifelineState] savePositions-----------<<<<<: "+this); //$NON-NLS-1$ } } private boolean checkPositionsMonotonous() { ElementWrapper firstElementWrapper = (ElementWrapper) myWrapperList.get(0); LifeLineElement firstElement = firstElementWrapper.getElement(); int base = firstElementWrapper.getPos() - firstElement.getPointOffset() + firstElement.getSize(); for (int i=1; i<myWrapperList.size(); i++) { ElementWrapper elementWrapper = (ElementWrapper) myWrapperList.get(i); LifeLineElement element = elementWrapper.getElement(); int pos = elementWrapper.getPos(); if (pos < base) { throw new RuntimeException(pos + " < " + base); //$NON-NLS-1$ } base = pos - element.getPointOffset() + element.getSize(); } return true; } private boolean checkPositionsSaved() { for (int i=0; i<myWrapperList.size(); i++) { ElementWrapper elementWrapper = (ElementWrapper) myWrapperList.get(i); elementWrapper.assertSaved(); } return true; } void nextStep() { if (hasRequired()) { throw new IllegalStateException("Lifeline is blocked"); //$NON-NLS-1$ } if (myCurrentWrapper != null) { goodbyeElement(); } if (myIndex+1 >= myWrapperList.size()) { myCurrentWrapper = null; return; } myIndex++; myCurrentWrapper = (ElementWrapper) myWrapperList.get(myIndex); hoorayElement(); } /** * @return true, if some 'after' constraints were found */ private void goodbyeElement() { myBeforeConstraintPos = 0; } private void hoorayElement() { for (Enumeration constrEnum = myCurrentWrapper.getElement().beforeConstraints(); constrEnum.hasMoreElements(); ) { OrderingConstraint constraint = (OrderingConstraint) constrEnum.nextElement(); myRequiredOrderingConstraints.add(constraint); } } public Class getState() { return myState; } void setState(Class state) { myState = state; } boolean isFinished() { return myCurrentWrapper == null; } HorizontalConstraint getHorizontalConstraint() { assert myHorizontalConstraintCalculated; return myRequiredHorizontalConstraint; } Set getRequiredOrderingConstraints() { return myRequiredOrderingConstraints; } public Map getEncounteredOrderingConstraints2Pos() { return myEncounteredOrderingConstraints2Pos; } private boolean hasRequired() { return myHorizontalConstraintCalculated || !myRequiredOrderingConstraints.isEmpty(); } void setCurrentPos(int pos) { if (pos < getMinPos()) { throw new IllegalArgumentException("pos is too small"); //$NON-NLS-1$ } // if (pos < 0) { // throw new IllegalArgumentException("pos < 0"); //$NON-NLS-1$ // } myCurrentWrapper.setPos(pos); myBase = pos + myCurrentWrapper.getPostSize(); } int getMinPos() { return myBase + myCurrentWrapper.getPreSize(); } int getCurrentPos() { if (myCurrentWrapper.isVirtual()) { return getMinPos(); } else { int result = myCurrentWrapper.getPos(); return result; } } int getBase() { return myBase; } boolean isPrioritedPosition() { return myCurrentWrapper.isPriorited(); } void addEncounteredAfterConstraints() { for (Enumeration constrEnum = myCurrentWrapper.getElement().afterConstraints(); constrEnum.hasMoreElements(); ) { OrderingConstraint constraint = (OrderingConstraint) constrEnum.nextElement(); if (myBrokenOrderingConstraints.remove(constraint)) { // OK, now we can forget about this constraint } else { myEncounteredOrderingConstraints2Pos.put(constraint, new Integer(myCurrentWrapper.getPos())); } } } public void dismissRequiredHorizontalConstraint() { myHorizontalConstraintCalculated = false; myRequiredHorizontalConstraint = null; } public void addBrokenHorizontalConstraints(HorizontalConstraint constraint) { Counter counter = (Counter) myBrokenHorizontalConstraints2Counter.get(constraint); if (counter == null) { counter = new Counter(); myBrokenHorizontalConstraints2Counter.put(constraint, counter); } counter.increase(); } int getBeforeConstraintPos() { return myBeforeConstraintPos; } void setBeforeConstraintPos(int beforeConstraintPos) { myBeforeConstraintPos = beforeConstraintPos; } public LifeLineElement getCurrentElement() { return myCurrentWrapper.getElement(); } void prepareHorizontalConstraint() { assert !myHorizontalConstraintCalculated; myRequiredHorizontalConstraint = myCurrentWrapper.getElement().getHorizontalConstraint(); if (myRequiredHorizontalConstraint != null) { Counter counter = (Counter) myBrokenHorizontalConstraints2Counter.get(myRequiredHorizontalConstraint); if (counter != null && counter.getCount() > 0) { myRequiredHorizontalConstraint = null; counter.decrease(); } } myHorizontalConstraintCalculated = true; } private final LifeLine myLifeLine; private int myBase; private HorizontalConstraint myRequiredHorizontalConstraint; private boolean myHorizontalConstraintCalculated = false; private final Set myRequiredOrderingConstraints = new HashSet(3); private final Map myEncounteredOrderingConstraints2Pos = new HashMap(3); private ElementWrapper myCurrentWrapper; private final List myWrapperList; private int myIndex; private final Map myBrokenHorizontalConstraints2Counter = new HashMap(2); private final Set myBrokenOrderingConstraints; private Class myState; private int myBeforeConstraintPos; static class ElementWrapper { ElementWrapper(LifeLineElement element, boolean isPriorited) { myElement = element; myIsPriorited = isPriorited; } void loadPos() { myPos = myElement.getPosition().getPositionValue(); } void savePos() { myElement.getPosition().setPositionValue(myPos); } void assertSaved() { assert isVirtual() || myElement.getPosition().getPositionValue() == myPos; } boolean isVirtual() { return myElement.getPosition().isVirtual(); } int getPreSize() { return myElement.getPointOffset(); } int getPostSize() { return myElement.getSize() - myElement.getPointOffset(); } int getPos() { return myPos; } void setPos(int pos) { myPos = pos; } boolean isPriorited() { return myIsPriorited; } LifeLineElement getElement() { return myElement; } private final LifeLineElement myElement; private final boolean myIsPriorited; private int myPos; } private static class Counter { void increase() { myInt++; } void decrease() { myInt--; } int getCount() { return myInt; } int myInt = 0; } }