package ui.bigstep;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import javax.swing.JScrollPane;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeModelEvent;
import bigstep.BigStepProofNode;
import common.ProofNode;
import ui.AbstractNode;
import ui.AbstractView;
public class BigStepView extends AbstractView implements Scrollable {
private int availableWidth;
/**
* Only used temporarily
*/
private int maxWidth;
/**
* Only used temporarily
*/
private int maxHeight;
/**
* Only used temporarily
*/
private int nodeId;
/**
*
*/
private ProofNode jumpNode;
/**
*/
private boolean isLayouting;
public BigStepView () {
super ();
this.isLayouting = false;
setLayout (null);
}
public int getAvailableWidth() {
return availableWidth;
}
public void setAvailableWidth(int availableWidth) {
this.availableWidth = availableWidth;
}
private Dimension layout (ProofNode node, int inset) {
int margin = 25;
int spacing = 10;
int realSize = this.availableWidth - inset - margin;
BigStepNode bigStepNode = (BigStepNode)node.getUserObject();
if (bigStepNode == null) {
bigStepNode = new BigStepNode ((BigStepProofNode)node);
bigStepNode.addBigStepNodeListener(new BigStepNodeListener() {
public void aboutToProve(ProofNode node) {
BigStepView.this.aboutToProve(node);
}
});
bigStepNode.setModel(this.model);
bigStepNode.updateNode();
bigStepNode.buildMenu();
node.setUserObject(bigStepNode);
}
bigStepNode.setLocationId(nodeId++);
add (bigStepNode);
Dimension d = bigStepNode.layout(this.availableWidth - inset);
if (d.width + inset + margin> maxWidth) {
maxWidth = d.width + inset + margin;
}
bigStepNode.setBounds(inset + margin, maxHeight + spacing, d.width, d.height);
maxHeight += d.height + spacing;
for (int i=0; i<node.getChildCount(); i++) {
layout (node.getChildAt(i), inset + 25);
}
return new Dimension (maxWidth, maxHeight);
}
public void layout(int availableWidth) {
removeAll ();
this.availableWidth = availableWidth;
maxWidth = 0;
maxHeight = 25;
nodeId = 1;
Dimension size = layout (this.model.getRoot(), 0);
setSize (size);
setPreferredSize (size);
setMinimumSize (size);
setMaximumSize (size);
this.repaint();
}
private void paintNodeArrow(ProofNode node, Graphics g) {
FontMetrics fm = getFontMetrics (getFont ());
g.setColor(Color.BLACK);
if (node.getChildCount() == 0) return;
BigStepNode rootNode = (BigStepNode)node.getUserObject();
if (rootNode == null) return;
Point rootPoint = rootNode.getArrowPoint();
rootPoint.x += rootNode.getX();
rootPoint.y += rootNode.getY();
int a, b;
a = fm.getHeight();
b = a / 2;
Polygon arrow = new Polygon();
arrow.addPoint(rootPoint.x, rootPoint.y);
arrow.addPoint(rootPoint.x + b, rootPoint.y + a);
arrow.addPoint(rootPoint.x, rootPoint.y + b);
arrow.addPoint(rootPoint.x - b, rootPoint.y + a);
g.fillPolygon(arrow);
for (int i=0; i<node.getChildCount(); i++) {
ProofNode childNode = node.getChildAt(i);
BigStepNode bigStepNode = (BigStepNode)childNode.getUserObject();
if (bigStepNode == null) continue;
Point jointPoint = bigStepNode.getJointPoint();
jointPoint.x += bigStepNode.getX();
jointPoint.y += bigStepNode.getY();
g.drawLine(rootPoint.x, rootPoint.y, rootPoint.x, jointPoint.y);
g.drawLine(rootPoint.x, jointPoint.y, jointPoint.x - 2, jointPoint.y);
paintNodeArrow (childNode, g);
}
}
@Override
protected AbstractNode createNode(ProofNode node) {
return null;
}
@Override
protected void relayout() {
// do nothing here its not needed within the big step view
}
@Override
protected void doLayouting() {
if (this.isLayouting) return;
this.isLayouting = true;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
BigStepView.this.layout(BigStepView.this.availableWidth);
BigStepView.this.isLayouting = false;
BigStepView.this.scrollToVisible(BigStepView.this.jumpNode);
BigStepView.this.jumpNode = null;
}
});
}
@Override
protected void nodeAdded(AbstractNode node) {
}
@Override
public void treeNodesChanged(TreeModelEvent e) {
Object[] children = e.getChildren();
if (children == null) {
BigStepNode node = (BigStepNode)this.model.getRoot().getUserObject();
if (node != null) {
node.updateNode();
}
}
else {
for (Object o : children) {
ProofNode pNode = (ProofNode)o;
BigStepNode node = (BigStepNode)pNode.getUserObject();
if (node != null) {
node.updateNode();
}
}
}
doLayouting();
}
@Override
public void treeNodesInserted (TreeModelEvent e) {
// find the node that has been inserted.
// save this node to scroll to it later
Object[] children = e.getChildren();
if (children.length != 0) {
this.jumpNode = (ProofNode)children[0];
}
this.doLayouting();
}
@Override
public void treeNodesRemoved (TreeModelEvent e) {
}
/**
* Paints the content of the BigStepView
*/
@Override
public void paintComponent (Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.drawLine(0, 0, getWidth() - 1, getHeight() - 1);
g.drawLine(0, getHeight() - 1, getWidth() - 1, 0);
paintNodeArrow (this.model.getRoot(), g);
}
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 75;
}
public boolean getScrollableTracksViewportHeight() {
return false;
}
public boolean getScrollableTracksViewportWidth() {
return false;
}
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 75;
}
private ProofNode getVisibleNode (ProofNode parentNode) {
if (parentNode == null) {
return null;
}
if (parentNode.getSteps().length == 0) {
BigStepNode bigStepNode = (BigStepNode)parentNode.getUserObject();
if (bigStepNode != null)
{
// check if node is currently visible
Rectangle visibleRect = getVisibleRect ();
int top = bigStepNode.getY();
int bottom = bigStepNode.getY () + bigStepNode.getHeight();
if ( top >= visibleRect.y && top <= visibleRect.y + visibleRect.height
|| bottom >= visibleRect.y && bottom <= visibleRect.y + visibleRect.height) {
return parentNode;
}
}
}
for (int i=0; i<parentNode.getChildCount(); i++) {
ProofNode node = getVisibleNode (parentNode.getChildAt(i));
if (node != null) {
return node;
}
}
return null;
}
private ProofNode getFirstUnproovenNode (ProofNode parentNode) {
if (parentNode == null) {
return null;
}
if (parentNode.getSteps().length == 0) {
return parentNode;
}
for (int i=0; i<parentNode.getChildCount(); i++) {
ProofNode node = getFirstUnproovenNode (parentNode.getChildAt(i));
if (node != null) {
return node;
}
}
return null;
}
public void guessNode () throws Exception {
ProofNode node = getVisibleNode (this.model.getRoot());
if (node == null) {
node = getFirstUnproovenNode (this.model.getRoot());
}
if (node == null) {
return;
}
BigStepNode bigStepNode = (BigStepNode)node.getUserObject();
if (bigStepNode != null) {
bigStepNode.guessNode();
}
}
public void aboutToProve (ProofNode node) {
this.jumpNode = node;
}
public void scrollToVisible (ProofNode node) {
if (node == null) return;
BigStepNode bigStepNode = (BigStepNode)node.getUserObject();
if (bigStepNode == null) return;
Rectangle rect = bigStepNode.getBounds ();
Rectangle visibleRect = this.getVisibleRect();
rect.x = visibleRect.x;
rect.width = 1;
this.scrollRectToVisible(rect);
}
}