blob: af7db3b1b9f7c8f27fddc9a231843df7d6d30836 [file] [log] [blame]
/*******************************************************************************
* <copyright>
*
* Copyright (c) 2011, 2012 SAP AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API, implementation and documentation
* mwenz - Bug 358255 - Add Border/Background decorators
*
* </copyright>
*
*******************************************************************************/
package org.eclipse.graphiti.examples.chess.features;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.graphiti.examples.chess.Messages;
import org.eclipse.graphiti.examples.chess.MoveUtil;
import org.eclipse.graphiti.examples.chess.diagram.ChessToolBehaviorProvider;
import org.eclipse.graphiti.examples.mm.chess.Piece;
import org.eclipse.graphiti.examples.mm.chess.Square;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.ICreateConnectionContext;
import org.eclipse.graphiti.features.context.impl.AddConnectionContext;
import org.eclipse.graphiti.features.impl.AbstractCreateConnectionFeature;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.AnchorContainer;
import org.eclipse.graphiti.mm.pictograms.BoxRelativeAnchor;
import org.eclipse.graphiti.mm.pictograms.Connection;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
public class CreateChessMoveFeature extends AbstractCreateConnectionFeature {
public CreateChessMoveFeature(IFeatureProvider fp) {
super(fp, Messages.CreateChessMoveFeature_name, Messages.CreateChessMoveFeature_description);
}
public boolean canStartConnection(ICreateConnectionContext context) {
// We can start a move connection at every anchor that belong to a
// square holding a piece or that belongs to a move connection
Piece piece = getPiece(context.getSourceAnchor());
return piece != null;
}
public boolean canCreate(ICreateConnectionContext context) {
// Get the piece to move (potentially follow connection)
Piece piece = getPiece(context.getSourceAnchor());
if (piece == null) {
return false;
}
// The start square for the current move
Square sourceSquare = getSquare(context.getSourceAnchor());
if (sourceSquare == null) {
return false;
}
// The end square for the current move
Square targetSquare = getSquare(context.getTargetAnchor());
if (targetSquare == null) {
return false;
}
// Check if the piece can move from start to end square
return MoveUtil.isMoveAllowed(piece, sourceSquare, targetSquare);
}
public Connection create(ICreateConnectionContext context) {
// Take back the highlighting
takeBackHighlighting();
Connection newConnection = null;
Anchor sourceAnchor = context.getSourceAnchor();
// Get Squares to be connected
Square sourceSquare = getPiece(sourceAnchor).getSquare();
Square targetSquare = getSquare(context.getTargetAnchor());
if (sourceSquare != null && targetSquare != null) {
AddConnectionContext addContext;
AnchorContainer parent = sourceAnchor.getParent();
if (parent instanceof ContainerShape) {
// Add connection for normal container shape (either piece or
// square)
addContext = new AddConnectionContext(getSquareConnectionAnchor(sourceAnchor),
getSquareConnectionAnchor(context.getTargetAnchor()));
} else if (parent instanceof Connection) {
// Add connection for move connection, use end anchor
addContext = new AddConnectionContext(((Connection) parent).getEnd(),
getSquareConnectionAnchor(context.getTargetAnchor()));
} else {
throw new IllegalStateException("Parent in neither a ContainerShape nor a Connection: " + parent); //$NON-NLS-1$
}
// Set the property identifying a move connection
addContext.putProperty(MoveUtil.PROPERTY_MOVE, Boolean.TRUE);
// Add the connection to the diagram
newConnection = (Connection) getFeatureProvider().addIfPossible(addContext);
}
return newConnection;
}
@Override
public void attachedToSource(ICreateConnectionContext context) {
// Called as soon as a connection is started
Piece piece = getPiece(context.getSourceAnchor());
if (piece == null) {
return;
}
Square sourceSquare = getSquare(context.getSourceAnchor());
if (sourceSquare == null) {
return;
}
// Highlight all allowed squares.
showFeedback(context);
}
@Override
public void canceledAttaching(ICreateConnectionContext context) {
// Take back the highlighting
takeBackHighlighting();
}
private void takeBackHighlighting() {
ChessToolBehaviorProvider toolBehaviorProvider = (ChessToolBehaviorProvider) getFeatureProvider()
.getDiagramTypeProvider().getCurrentToolBehaviorProvider();
toolBehaviorProvider.clearAllowedSquaresForMove();
getDiagramBehavior().refresh();
}
private void showFeedback(ICreateConnectionContext context) {
// Find the piece that shall be moved (potentially follow move
// connections)
Piece piece = getPiece(context.getSourceAnchor());
if (piece == null) {
return;
}
// Find the square to start th move step from
Square sourceSquare = getSquare(context.getSourceAnchor());
if (sourceSquare == null) {
return;
}
// Find all allowed squares to move to
EList<Square> allSquares = sourceSquare.getBoard().getSquares();
final List<Square> allowedSquares = new ArrayList<Square>();
for (Square square : allSquares) {
if (MoveUtil.isMoveAllowed(piece, sourceSquare, square)) {
allowedSquares.add(square);
}
}
// Mark the allowed squares using decorators
ChessToolBehaviorProvider toolBehaviorProvider = (ChessToolBehaviorProvider) getFeatureProvider()
.getDiagramTypeProvider().getCurrentToolBehaviorProvider();
toolBehaviorProvider.addToAllowedSquaresForMove(allowedSquares);
for (Square square : allowedSquares) {
PictogramElement pe = getFeatureProvider().getPictogramElementForBusinessObject(square);
getDiagramBehavior().refreshRenderingDecorators(pe);
}
}
private Piece getPiece(Anchor anchor) {
// Try to find a piece for the given anchor
if (anchor != null) {
AnchorContainer parent = anchor.getParent();
Object obj = getBusinessObjectForPictogramElement(parent);
if (obj instanceof Piece) {
// The shape of the anchor represents the piece
return (Piece) obj;
} else if (obj instanceof Square) {
// The shape of the anchor represents a square
Piece pieceOnSquare = ((Square) obj).getPiece();
if (pieceOnSquare != null) {
// Return the piece on the square
return pieceOnSquare;
}
// No piece on the square, check for move connection
EList<Connection> incomingConnections = anchor.getIncomingConnections();
for (Connection connection : incomingConnections) {
// Follow the first connection back to a piece
Piece piece = getPiece(connection.getStart());
if (piece != null) {
return piece;
}
}
} else if (parent instanceof Connection) {
// Anchor of a connection, follow it backwards to its piece
Anchor startAnchor = ((Connection) parent).getStart();
return getPiece(startAnchor);
}
}
return null;
}
private Square getSquare(Anchor anchor) {
// Try to find a square for the given anchor
if (anchor != null) {
AnchorContainer parent = anchor.getParent();
Object obj = getBusinessObjectForPictogramElement(parent);
if (obj instanceof Square) {
// The shape of the anchor represents a square
return (Square) obj;
} else if (obj instanceof Piece) {
// The shape of the anchor represents a piece
return ((Piece) obj).getSquare();
} else if (parent instanceof Connection) {
// The anchor belongs to a connection; get the square at its end
Anchor startAnchor = ((Connection) parent).getEnd();
return getSquare(startAnchor);
}
}
return null;
}
private Anchor getSquareConnectionAnchor(Anchor anchor) {
// Find the anchor to attach a move connection to a square
if (anchor != null) {
AnchorContainer parent = anchor.getParent();
if (parent instanceof ContainerShape) {
Object obj = getBusinessObjectForPictogramElement(parent);
if (obj instanceof Square) {
// Anchor belongs to a shape that represents a square
EList<Anchor> anchors = parent.getAnchors();
return findConnectionAnchor(anchors);
} else if (obj instanceof Piece) {
// Anchor belongs to a shape that represents a piece, use
// the anchors of the parent shape
EList<Anchor> anchors = ((ContainerShape) parent).getContainer().getAnchors();
return findConnectionAnchor(anchors);
}
} else {
throw new IllegalStateException("Parent shape is not a container shape"); //$NON-NLS-1$
}
}
return null;
}
private Anchor findConnectionAnchor(EList<Anchor> anchors) {
// Return the right anchor from the list of found anchors (the
// BoxRelativeAnchor is used for connections while the ChopboxAnchor
// only catches the connection attachment)
for (Anchor connectionAnchor : anchors) {
if (connectionAnchor instanceof BoxRelativeAnchor) {
return connectionAnchor;
}
}
throw new IllegalStateException("No BoxRelativeAnchor found"); //$NON-NLS-1$
}
}