/*******************************************************************************
* Copyright (c) 2009 the CHISEL group and contributors.
* 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:
* Del Myers - initial API and implementation
*******************************************************************************/
package ca.uvic.chisel.javasketch.ui.internal.presentation;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CatchClause;
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.EnhancedForStatement;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.WhileStatement;
import org.eclipse.swt.graphics.Color;
import org.eclipse.zest.custom.uml.viewers.IMessageGrouper;
import org.eclipse.zest.custom.uml.viewers.IMessageGrouping;
import org.eclipse.zest.custom.uml.viewers.MessageGrouping;
import org.eclipse.zest.custom.uml.viewers.UMLSequenceViewer;
import ca.uvic.chisel.javasketch.data.model.IActivation;
import ca.uvic.chisel.javasketch.data.model.IMessage;
import ca.uvic.chisel.javasketch.internal.ast.groups.ASTLoopGroupCalculator;
import ca.uvic.chisel.javasketch.internal.ast.groups.ASTMessageGroupingTree;
import ca.uvic.chisel.javasketch.ui.ISketchColorConstants;
/**
* @author Del Myers
*
*/
public class CopyOfASTMessageGrouper implements IMessageGrouper {
private static class ASTMessageGrouping extends MessageGrouping implements Comparable<ASTMessageGrouping>{
private ASTMessageGroupingTree node;
/**
* @param activationElement
*/
public ASTMessageGrouping(Object activationElement, ASTMessageGroupingTree node) {
super(activationElement);
this.node = node;
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(ASTMessageGrouping that) {
//first, compare by indexes
if (this.getOffset() < that.getOffset()) {
return -1;
} else if (this.getOffset() > that.getOffset()) {
return 1;
} else {
//the offsets are equal, the smaller one is the
//one with the smaller length
if (this.getLength() < that.getLength()) {
return -1;
} else if (this.getLength() > that.getLength()){
return 1;
} else {
//the only other option is that they cover the same
//messages, use the AST to decide which one is
//internal
if (this.node.getNode().getStartPosition() <
that.node.getNode().getStartPosition()) {
return -1;
} else if (this.node.getNode().getStartPosition() >
that.node.getNode().getStartPosition()) {
return 1;
} else {
if (this.node.getNode().getLength() <
that.node.getNode().getLength()) {
return -1;
} else if (this.node.getNode().getLength() >
that.node.getNode().getLength()) {
return 1;
}
}
}
}
//can't decide which is greater.
return 0;
}
}
/* (non-Javadoc)
* @see org.eclipse.zest.custom.uml.viewers.IMessageGrouper#dispose()
*/
@Override
public void dispose() {
}
/* (non-Javadoc)
* @see org.eclipse.zest.custom.uml.viewers.IMessageGrouper#calculateGroups(org.eclipse.zest.custom.uml.viewers.UMLSequenceViewer, java.lang.Object, java.lang.Object[])
*/
@Override
public IMessageGrouping[] calculateGroups(UMLSequenceViewer viewer,
Object activationElement, Object[] children) {
HashMap<ASTMessageGroupingTree, ASTMessageGrouping> groups =
new HashMap<ASTMessageGroupingTree, ASTMessageGrouping>();
if (activationElement instanceof IActivation) {
ASTMessageGroupingTree tree = ASTLoopGroupCalculator.calculateGroups((IActivation) activationElement);
if (tree == null) {
return new IMessageGrouping[0];
}
for (int i = 0; i < children.length; i++) {
Object child = children[i];
if (child instanceof IMessage) {
ASTMessageGroupingTree node = tree.getMessageContainer((IMessage) child);
//put in the node and all of its parents.
while (node != null && node.getParent() != null) {
ASTMessageGrouping grouping = groups.get(node);
if (grouping == null) {
grouping = new ASTMessageGrouping(activationElement, node);
grouping.setOffset(i);
groups.put(node, grouping);
}
grouping.setLength(i - grouping.getOffset() + 1);
node = node.getParent();
}
}
}
}
for (ASTMessageGroupingTree node : groups.keySet()) {
updateGrouping(groups.get(node), node.getNode());
}
ASTMessageGrouping[] result = groups.values().toArray(new ASTMessageGrouping[groups.values().size()]);
Arrays.sort(result);
return result;
}
/**
* Updates labels and colours for the grouping.
* @param currentGrouping
*/
private void updateGrouping(ASTMessageGrouping grouping, ASTNode node ) {
String text = "";
int i;
Color bg = null;
Color fg = null;
switch (node.getNodeType()) {
case ASTNode.IF_STATEMENT:
IfStatement ifStatement = (IfStatement) node;
text = "if (" + ifStatement.getExpression().toString() + ")";
fg = ISketchColorConstants.CONDITION_FG;
bg = ISketchColorConstants.CONDITION_BG;
break;
case ASTNode.WHILE_STATEMENT:
WhileStatement whileStatement = (WhileStatement) node;
text = "while (" + whileStatement.getExpression().toString() + ")";
fg = ISketchColorConstants.LOOP_FG;
bg = ISketchColorConstants.LOOP_BG;
break;
case ASTNode.DO_STATEMENT:
DoStatement doStatement = (DoStatement) node;
text = "do..while (" + doStatement.getExpression().toString() + ")";
fg = ISketchColorConstants.LOOP_FG;
bg = ISketchColorConstants.LOOP_BG;
break;
case ASTNode.FOR_STATEMENT:
ForStatement forStatement = (ForStatement) node;
List<?> initializers = forStatement.initializers();
List<?> updaters = forStatement.updaters();
text = "for (";
for (i=0; i < initializers.size(); i++) {
text += initializers.get(i).toString();
if (i < initializers.size()-1) {
text += ",";
}
}
text += ";";
if (forStatement.getExpression() != null) {
text += forStatement.getExpression();
}
text += ";";
for (i = 0; i < updaters.size(); i++) {
text += updaters.get(i).toString();
if (i < updaters.size()-1) {
text += ",";
}
}
text += ")";
fg = ISketchColorConstants.LOOP_FG;
bg = ISketchColorConstants.LOOP_BG;
break;
case ASTNode.ENHANCED_FOR_STATEMENT:
EnhancedForStatement enhancedForStatement = (EnhancedForStatement) node;
text = "for (" + enhancedForStatement.getExpression().toString() + ")";
fg = ISketchColorConstants.LOOP_FG;
bg = ISketchColorConstants.LOOP_BG;
break;
case ASTNode.TRY_STATEMENT:
text = "try";
fg = ISketchColorConstants.ERROR_FG;
bg = ISketchColorConstants.ERROR_BG;
break;
case ASTNode.CATCH_CLAUSE:
CatchClause catchClause = (CatchClause) node;
text = "catch (" + catchClause.getException().toString() + ")";
fg = ISketchColorConstants.ERROR_FG;
bg = ISketchColorConstants.ERROR_BG;
break;
default:
//get the else blocks
if (node instanceof Statement) {
Statement statement = (Statement) node;
if (statement.getParent() instanceof IfStatement) {
if (((IfStatement)statement.getParent()).getElseStatement() == statement) {
text = "else";
fg = ISketchColorConstants.CONDITION_FG;
bg = ISketchColorConstants.CONDITION_BG;
}
}
}
break;
}
if (grouping.node.isLoop()) {
ASTMessageGroupingTree[] siblings = grouping.node.getSiblings();
text = text + "[" + grouping.node.getIteration() + " of " + (siblings.length + 1) + "]";
}
grouping.setName(text);
grouping.setForeground(fg);
grouping.setBackground(bg);
}
}