/** By Kristi Thompson and Sean McLaughlin
*
* April 10 & 11, 1997
*
* CISC 235 - Information Structures (Winter 1997) taught by David Alex Lamb
*
* Dept of Computer Science
* Queen's University, Kingston
*
* kristi@merlan.ca , seanster@merlan.ca
*
* http://qlink.queensu.ca/~3sm79/BplusTree
*
* Feel free to copy and modify this applet, but please give credit
* to the original author where appropriate
*
* This applet was inspired by and partly based upon the BST Search Tree Applet
* by James Stewart.
*
* http://www.dgp.toronto.edu/people/JamesStewart/applets/bst/bst-property.html
*
*/
import java.util.*;
import java.awt.*;
/** A BplusTree
Uses the following classes:
INode (Inner nodes, which hold keys and pointers to other nodes
Bucket (leaf nodes that keys and their associated data)
Node (abstract superclass for INode and Bucket)
*/
public class BplusTree extends java.applet.Applet
{
// DEFINES
static final int N = 2;
static final int Ndiv2 = 1;
boolean PROMOTION = true;
boolean NO_PROMOTION = false;
final String TREENAME = "BplusTree";
final Color LineColor = Color.black;
final Color HighlightColor = Color.orange;
final Color BackgroundColor = Color.lightGray;
static final int BRANCH_SPACING = (int) (Math.max( Bucket.BUCKET_HEIGHT, INode.INODE_HEIGHT) * 1.5); // When a new level is added to the tree, move everyone down this much
boolean GetParms = true;
int root_X_pos = 100;
int root_Y_pos = 50;
// DEFINES
Node root = null; // root of tree
Bucket first_Bucket = null; // For sequential Access (Fully Implemented)
Insert_T insert; // thread to handle insertions
int newKey;
String newData;
// Things having to do with appearance:
Font f = new Font( "TimesRoman", Font.PLAIN, 14 );
FontMetrics fm = getFontMetrics( f );
TextField keyField;
TextField dataField;
Button insertB;
Button repaintB;
Button clearB;
Label keyLabel;
Label dataLabel;
Image buffer_image;
Graphics buffer_graphics;
Dimension buffer_size;
///////////////////////////////////////////////////////
/**
* Init the applet. Just insert elements into the tree and
* compute the tree's initial position.
*/
public void init() {
setLayout(null);
root_X_pos = bounds().x + ((bounds().width - Bucket.BUCKET_WIDTH - 25) / 2);
root_Y_pos = 60;
// Set the Applett Background
setBackground(BackgroundColor);
keyField = new TextField("", 5);
dataField = new TextField("", 15);
// Get the applet parameters/build tree
if ( GetParms != false)
{
parse_parameters();
}
// First, set up text fields and buttons
//setLayout(new FlowLayout(FlowLayout.LEFT));
insertB = new Button("Insert");
add(insertB);
insertB.setForeground(Color.yellow);
repaintB = new Button("Repaint");
add(repaintB);
repaintB.setForeground(Color.green);
clearB = new Button("Clear");
add(clearB);
clearB.setForeground(Color.orange);
add( keyLabel = new Label("Key:", Label.RIGHT));
add(keyField);
keyLabel.setForeground(Color.red);
add( dataLabel = new Label("Data:", Label.RIGHT));
add(dataField);
dataLabel.setForeground(Color.black);
insertB.reshape( 20, 20, 50, 25 );
keyLabel.reshape( 70, 20, 40, 25 );
keyField.reshape( 110, 20, 40, 25 );
dataLabel.reshape( 150, 20, 40, 25 );
dataField.reshape( 190, 20, 50, 25 );
repaintB.reshape( 20, 50, 50, 25 );
clearB.reshape( bounds().x + bounds().width - 70, 20, 50, 25 );
Layout_Tree();
}
/**
* Upon starting, start any threads that were previously stopped
*/
public void start()
{
if (insert != null && insert.isAlive()) insert.resume();
}
/**
* Upon stopping, stop all active threads
*/
public void stop()
{
if (insert != null && insert.isAlive()) insert.suspend();
}
/**
* Upon a `paint', just redraw the tree.
*/
public void paint( Graphics g )
{
// Draw A nice border
g.setColor(Color.black);
g.drawRect( 0, 0, bounds().width - 1, bounds().height - 1);
g.setColor(Color.blue);
g.drawRect( 1, 1, bounds().width - 3, bounds().height - 3);
g.drawRect( 2, 2, bounds().width - 5, bounds().height - 5);
g.setColor(Color.black);
g.drawRect( 3, 3, bounds().width - 7, bounds().height - 7);
}
/**
* Use update() to do double buffering.
*/
public synchronized void update( Graphics g )
{
if (buffer_image == null)
{
buffer_size = size();
buffer_image = createImage( buffer_size.width, buffer_size.height );
buffer_graphics = buffer_image.getGraphics();
buffer_graphics.setFont( getFont() );
}
buffer_graphics.setColor( getBackground() );
buffer_graphics.fillRect( 0, 0, buffer_size.width, buffer_size.height );
paint( buffer_graphics );
g.drawImage( buffer_image, 0, 0, null );
}
/**
* Upon a mouseDown, colour the two nodes involved, but
* don't rotate.
*/
public boolean mouseDown( Event evt, int x, int y )
{
/*
// Ignore mouse if rotations are not allowed
if (! allow_rotation)
return false;
// Ignore mouse if still rotating
if (rotate_thread != null && rotate_thread.isAlive())
return false;
// Find node closest to mouse
rotation_node = find_closest_node( root, x, y );
// Highlight rotation node and its parent
if (rotation_node != null) {
rotation_node.highlight_node = true;
rotation_node.parent.highlight_node = true;
repaint();
}
*/
return true;
}
/**
* Upon a mouseUp, rotate the two nodes. This involves spawning
* a thread that will slowly move the nodes.
*/
public boolean mouseUp( Event evt, int x, int y )
{
/*
// Ignore mouse if still rotating
if (rotate_thread != null && rotate_thread.isAlive())
return false;
// Ignore mouse no node selected for rotation
if (rotation_node == null)
return true;
// Start rotating
rotation_node.highlight_node = false;
rotation_node.parent.highlight_node = false;
rotate_thread = new rotate(this);
rotate_thread.start();
*/
return true;
}
/**
* Handle an action from one of the UI components.
*/
public boolean action( Event evt, Object arg )
{
if (arg.equals("Insert"))
{
try
{
newKey = Integer.parseInt( keyField.getText().trim() );
newData = dataField.getText().trim();
}
catch (NumberFormatException e)
{
play(getCodeBase(), "audio/error.au");
System.out.println( "ERROR in " + TREENAME + " applet: `Key' value must be an integer" );
return true;
}
// Ignore if still inserting
if (insert != null && insert.isAlive())
return true;
// Start rotating
insert = new Insert_T (this);
insert.start();
play(getCodeBase(), "audio/insert.au");
return true;
}
else if (arg.equals("Clear"))
{
// Ignore if still inserting
if (insert != null && insert.isAlive())
return true;
// Wipe Tree
play(getCodeBase(), "audio/clear.au");
removeAll(); // Heh heh must implelemt children deleting themselves :)
root = null;
GetParms = false;
init();
GetParms = true;
return true;
}
else if (arg.equals("Repaint"))
{
play(getCodeBase(), "audio/repaint.au");
Layout_Tree();
return true;
}
else
{
System.out.println( "ERROR in BST applet: Unrecognized UI event" );
}
return true;
}
/**
* Parse the parameters supplied with the applet. These are listed at the
* top of this file.
*/
void parse_parameters