Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

/* LinkList * Anderson, Franceschi */ /** * this class is a concrete implementat

ID: 3852773 • Letter: #

Question

/* LinkList
* Anderson, Franceschi
*/

/**
* this class is a concrete implementation of the AbstractList.
*
* properties of this implementation are such that: - the list is singly linked
* - data contained in the nodes is limited to integers - nodes are sorted in
* ascending order of data - duplicate data is allowed - note that duplicate
* data may cause inconsistent behavior in the Visualizer because the delete
* method searches for the first instance of data. if a node besides the first
* one is highlighted, the first one will still be deleted.
*/
public class LinkList extends AbstractList
{
private Node head = null;

public LinkList()
{
    super(500, 400);
    v.drawList(head);
}

public LinkList(Node head)
{
    super(500, 400); // set size for visualizer
    // set up the list
    head = head;

    animate(head);
}

public void insert(int i)
{
    // ***** Student writes the body of this method *****

    // code the insert method of a linked list of ints
    // the int to insert in the linked list is i

    // we call the animate method inside the body of this method
    // as you traverse the list looking for the place to insert,
    // call animate as follows:

    //    animate(head, current);
    // where    head is the instance variable head of the linked list
    //          current is the node that you are visiting

    // you can start coding now

    // in order to improve the animation (this is optional):
    // just before inserting, i.e. connecting the nodes,
    // make the call

    //    animate(head, previous, Visualizer.ACTION_INSERT_AFTER);

    // where    head is the instance variable head of the linked list
    //          previous is the node (not null) after which to insert

    // if you are inserting at the beginning of the list,
    // just before inserting, make the call

    //    animate(head, head, Visualizer.ACTION_INSERT_BEFORE);

    // where    head is the instance variable head of the linked list
    //
    // Part 1 student code starts here:

    // Part 1 student code ends here.

    numberNodes++;
    // call animate again to show the status of the list
    animate(head);
}

public boolean delete(int i)
{
    // ***** Student writes the body of this method *****

    // code the delete method of a linked list of ints
    // the int to delete in the linked list is i
    // if deletion is successful, return true
    // otherwise, return false

    // we call the animate method inside the body of this method
    // as you traverse the list looking for the node to delete,
    // call animate as follows:

    //    animate(head, current);

    // where    head is the instance variable head of the linked list
    //          current is the node that you are visiting

    // you can start coding now

    // in order to improve the animation (this is optional):
    // just before deleting, i.e. connecting the nodes,
    // make the call

    //    animate(head, current, Visualizer.ACTION_DELETE);

    // where    head is the instance variable head of the linked list
    //          current is the node that you are deleting
    //
    // Part 2 student code starts here:

    // Part 2 student code ends here.

    // At this point, the item has been deleted.
    // Decrement the number of nodes:
    numberNodes--;
    // Call animate again to show the status of the list:
    animate(head);
    return true;
}

public int count()
{
    int n = 0;
    Node current = head;
    while (current != null)
    {
      animate(head, current);
      n++;
      current = current.getNext();
    }
    return n;
}

public void traverse()
{
    traversal = "";
    Node current = head;
    while (current != null)
    {
      animate(head, current);
      traversal += (current.getData() + " ");
      current = current.getNext();
    }
    v.drawList(head);
}

public void clear()
{
    head = null;
    v.drawList(head);
}

public void animate(Node h, Node nd)
{
    v.drawList(h, nd);
    delay(1000);
}

public void animate(Node h)
{
    v.drawList(h);
}

public void animate(Node h, Node nd, int mode)
{
    v.drawList(h, nd, mode);
    delay(1000);
}
}

/* AbstractList
* Anderson, Franceschi
*/

public abstract class AbstractList
{
/*
       INSTANCE VARIABLES
*/

/**
   * a Visualizer instance is maintained here so that the student
   * can call it from the child class without worrying about the
   * implementation of the Visualizer. This is intended to mimic
   * the use of a Graphic object in the Swing or AWT package.
   **/
protected Visualizer v;

protected int numberNodes;
protected String traversal; // holds current traversal of the list

/*
       CONSTRUCTORS
*/

/**
   *   instantiate with the given GUI width and height for the Visualizer.
   *
   **/
public AbstractList( int width, int height )
{
    v = new Visualizer( width, height );
    numberNodes = 0;
}

/*
      METHODS STUDENTS MUST OVERRIDE
*/

/**
   *
   * insert an object in to the list.
   *
   **/
public abstract void insert( int i );

/**
   *
   * delete a node from the list based on reference.
   *
   * @ return true if the node was deleted, false otherwise
   **/


/**
   *
   * delete a node from the list based on data.
   *
   * @return true if the node was deleted, false otherwise
   *
   **/
public abstract boolean delete( int i );

/**
   *
   * returns the number of Nodes in the list.
   *
   **/
public abstract int count( );

/**
   *
   * walks the list and displays the data it contains.
   *
   **/
public abstract void traverse( );

/**
   *
   * removes all nodes from the list.
   *
   **/
public abstract void clear( );

/*
     METHODS FOR CONTROLLING VISUALIZER
*/

/**
   *
   * sets the width and height in pixels for the visualizer.
   *
   **/
public void setSize( int width, int height )
{
    v.setSize( width, height );
    v.validate( );
}

/**
   *
   * returns a reference to the Visualizer being used by this object.
   * Any object calling this method is on its honor to not modify
   * the Visualizer.
   *
   **/
public Visualizer getVisualizer( )
{
    return v;
}

/**
   *
   * simple delay routine that makes the thread sleep for the given
   * number of milliseconds. useful for when a node is being
   * highlighted by the visualizer.
   *
   **/
public void delay( int milliseconds )
{
    try
    {
      Thread.sleep( milliseconds );
    }
    catch ( Exception e )
    {
      System.out.println(" e: "+e );
    }
}

/*
   *
   * the following are wrapper methods to make calling the visualizer
   * a little more convienient. see the wrapped Visualizer methods
   * for more information.
   *
   */
/*
public void drawList( Node headNode )
{
    v.drawList( headNode );
}

public void drawList( Node headNode, int highlight )
{
    v.drawList( headNode, highlight );
}

public void drawList( Node headNode, Node highlight )
{
    v.drawList( headNode, highlight );
}

public void drawList( Node headNode, int target, int action )
{
    v.drawList( headNode, target, action );
}

public void drawList( Node headNode, Node target, int action )
{
    v.drawList( headNode, target, action );
}
*/
public String getTraversal( )
{
    return traversal;
}

} // end abstract list

/* LinkedListPractice
* Anderson, Franceschi
*/

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class LinkedListPractice extends JFrame
{
/*
        INSTANCE VARIABLES
           These variables are directly responsible for
           handling the student code: instantiating an
           object of the student's list, displaying it graphically,
           manipulating it by calling the various methods.
*/

/**
   * rationale: use AbstractList so that an instructor can have
   *              students create any other list type and still
   *              be able to use all the same method calls. The only
   *              change that needs to be made to this code is
   *              changing the instantiation to whatever type the
   *              instructor wants.
   **/
private AbstractList list;

/**
   *   this class is on its honor to not modify the Visualizer.
   *   the list instance returns a reference to its Visualizer
   *   so that this class can add it in to the JFrame, but this
   *   class should never directly modify that instance.
   **/
private Visualizer v;

/*
      GUI ELEMENTS
*/

// controls
private JPanel controls;     // holds the following:
private JPanel dataPanel;    // text box and label
private JButton insertNode;
private JButton deleteNode;
private JButton traverseList;
private JButton clearList;
private JButton countNodes;

private JTextField data;    // text box and label
private JLabel dataLabel; // for dataPanel

// output
private JScrollPane   outputPane; // holds the output text area
private JTextArea     outputArea; // the output text area
private String outputDisplay = ""; // message to outputArea
private JScrollPane   visualPane; // holds the Visualizer

private boolean mouseDisabled = false; // prevent clicking while drawing

private static int MAX_DATA_LENGTH = 4; // max chars allowed in the data field

/*
       CONSTRUCTOR
*/

/**
   * instantiates a new ListControl with the given width and height.
   * sets up the controls, initializes the Visualizer, makes everything
   * visible.
   *
   **/
public LinkedListPractice( int width, int height )
{
    super( ); // call to Object( ) for completeness
    setTitle( " Linked List Visualizer" );

    // set up the list and visualizer
    list = new LinkList( );
    v = list.getVisualizer( );
    visualPane = new JScrollPane( v );

    // instantiate GUI list controls

    dataPanel = new JPanel( );
    dataPanel.setLayout( new GridLayout( 2,1 ) );

    data         = new JTextField( );
    dataLabel    = new JLabel( "Node Data:" );

    dataPanel.add( dataLabel );
    dataPanel.add( data );

    controls = new JPanel( );
    controls.setLayout( new GridLayout( 6, 1 ) );

    insertNode   = new JButton( "insert" );
    deleteNode   = new JButton( "delete" );
    traverseList = new JButton( "traverse" );
    countNodes   = new JButton( "count" );
    clearList    = new JButton( "clear" );

    // set up handlers for controls
    //   private inner classes seem more readable
    //   than anonymous inner classes or one large handler
    data.addKeyListener( new DataListener( ) );
    insertNode.addActionListener( new ActionInsert( ) );
    deleteNode.addActionListener( new ActionDelete( ) );
    traverseList.addActionListener( new ActionTraverse( ) );
    countNodes.addActionListener( new ActionCount( ) );
    clearList.addActionListener( new ActionClear( ) );

    // add controls to the control pane
    controls.add( dataPanel );
    controls.add( insertNode );
    controls.add( deleteNode );
    controls.add( traverseList );
    controls.add( countNodes );
    controls.add( clearList );

    // set up GUI output
    outputArea = new JTextArea( 5, 40 );
    outputPane = new JScrollPane( outputArea );
    outputArea.setEditable( false );

    // set up ListControl GUI
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    getContentPane( ).setLayout( new BorderLayout( ) );
    getContentPane( ).add( visualPane,BorderLayout.CENTER );
    getContentPane( ).add( controls,BorderLayout.WEST );
    getContentPane( ).add( outputPane,BorderLayout.SOUTH );

    setSize( width,height );
    setVisible( true );
    doLayout( );
    validate( );
} // end default constructor

/*
       METHODS
*/

/** turn off all the buttons so they can't be clicked
       during operations **/
private void disableButtons( )
{
    insertNode.setEnabled( false );
    deleteNode.setEnabled( false );
    traverseList.setEnabled( false );
    clearList.setEnabled( false );
    countNodes.setEnabled( false );
    mouseDisabled = true;
}

/** turn on the buttons **/
private void enableButtons( )
{
    insertNode.setEnabled( true );
    deleteNode.setEnabled( true );
    traverseList.setEnabled( true );
    clearList.setEnabled( true );
    countNodes.setEnabled( true );
    mouseDisabled = false;
}

/** give focus to the text field and select any text it holds **/
private void selectData( )
{
    data.select( 0, data.getText( ).length( ) );
    data.requestFocusInWindow( );
}

private int getData( ) throws NumberFormatException
{
    return ( new Integer( data.getText( ) ) ).intValue( );
}

/*
      PRIVATE INNER CLASSES - action handlers
         each class is for a specific button,
         so the event source is not checked

         for any method that requires nodes
         to be highlighted, a new thread is created
         and started to handle calling the method.
         this allows the GUI to handle the highlighting
         and delay routines appropriately.
*/

private class ActionInsert implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      //SwingUtilities.invokeLater( new InsertThread( ) );
      ( new InsertThread( ) ).start( );
    }

    private class InsertThread extends Thread
    {
      public void run( )
      {
        disableButtons( );
        try
        {
          int i = getData( );
          outputDisplay += "insert called with " + i + " as data ";
          outputArea.setText( outputDisplay );
          list.insert(i);
        }
        catch ( Exception e )
        {
          outputDisplay += "invalid number ";
          outputArea.setText( outputDisplay );
        }
        enableButtons( );
        selectData( );
      }
    }
} // end ActionInsert

private class ActionDelete implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      ( new DeleteThread( ) ).start( );
    }

    private class DeleteThread extends Thread
    {
      public void run( )
      {
        disableButtons( );
        outputDisplay += ( "delete called with " + data.getText( ) + ": " );
        outputArea.setText( outputDisplay );
        try
        {
          boolean deleted = list.delete( new Integer( data.getText( ) ).intValue( ) );
          outputDisplay += "node " + ( (deleted)?"deleted ":"not found " );
          outputArea.setText( outputDisplay );
        }
        catch( NumberFormatException nfe )
        {
          outputDisplay += ( "data not an integer " );
          outputArea.setText( outputDisplay );
        }
        enableButtons( );
        selectData( );
      }
    }
}

private class ActionTraverse implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      outputDisplay += "traversing the list: ";
      outputArea.setText( outputDisplay );
      ( new Thread( ){
            public void run( ){
               disableButtons( );
               list.traverse( );
               outputDisplay += ( list.getTraversal( ) + " " );
               outputArea.setText( outputDisplay );
               enableButtons( );
               selectData( );
            }
         }).start( );
      }
   } // end ActionTraverse

private class ActionCount implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      ( new CountThread( ) ).start( );
    }

    private class CountThread extends Thread
    {
      public void run( )
      {
        disableButtons( );
        outputDisplay += "count called: ";
        outputArea.setText( outputDisplay );
        int n = list.count( );
        outputDisplay += ( "number of nodes = " + n + " " );
        outputArea.setText( outputDisplay );
        enableButtons( );
        selectData( );
      }
    }
} // end ActionCount

private class ActionClear implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      ( new ClearThread( ) ).start( );
    }

    private class ClearThread extends Thread
    {
      public void run( )
      {
        disableButtons( );
        outputDisplay += "clear list called ";
        outputArea.setText( outputDisplay );
        list.clear( );
        enableButtons( );
        selectData( );
      }
    }
} // end ActionClear


/** detects when key is entered in to data text field, and ensures
       that the field is limited to MAX_DATA_LENGTH. **/
private class DataListener extends KeyAdapter
{
    int key = 0; // which key was pressed
    //keyPressed will detect back space, but doesn't properly consume
    // the event, so the field still gets it. so, trap the key here
    // and assign it to variable key. thankfully by its very nature
    // keyPressed happens before keyTyped.
    public void keyPressed( KeyEvent e )
    {
      key = e.getKeyCode( );
    }

    // keyTyped will properly consume the event, but can't detect when
    // backspace was pressed. it also lets arrow keys, home, etc. through.
    // key has been trapped by keyPressed, so it can be properly compared
    // to backspace, and consumed if it is not back space and field is
    // over 15 chars.
    public void keyTyped( KeyEvent e )
    {
      // must compare to MAX_DATA_LENGTH-1 because the key currently being examined
      // will be the last character in the field.

      if( key == KeyEvent.VK_BACK_SPACE )
      {
        // never consume backspace
        return;
      }
      if( data.getText( ).length( ) > MAX_DATA_LENGTH-1
            || key < KeyEvent.VK_0 || key > KeyEvent.VK_9 )
      {
        // if field is full, or invalid value entered, consume the key
        e.consume( );
        return;
      }
    }
}

public static void main( String args[] )
{
    LinkedListPractice app = new LinkedListPractice( 600, 400 );
}
}

/* Node
* Anderson, Franceschi
*/

public class Node
{
/** reference to the next node in the list **/
private Node nextNode;

/** the data object held by this node **/
private int data;


/**
   *
   * construct a new node with the given Object as data
   *
   **/
public Node( int i )
{
    data = i;
}

/**
   *
   * construct a new node with the given Object as data
   * and references to the next and previous nodes.
   *
   **/
public Node( int i, Node next )
{
    data = i;
    nextNode = next;
}

/**
   *
   * set the reference to the next node
   *
   **/
public void setNext( Node n )
{
    nextNode = n;
}

/**
   *
   * return the reference to the next node
   * @return reference to the next node, or null if there is no next node
   *
   **/
public Node getNext( )
{
    return nextNode;
}

/**
   *
   * set the data object held by this node
   *
   **/
public void setData( int i )
{
    data = i;
}

/**
   *
   * get the data object held by this node
   *
   **/
public int getData( )
{
    return data;
}

} // end node class

/* Visualizer
* Anderson, Franceschi
*/

import javax.swing.*;
import java.awt.*;
//import java.awt.event.*;
import java.util.ArrayList;

public class Visualizer extends JPanel
{
public static final int nodeWidth = 100;
public static final int nodeHeight = 100;
public static final int halfWidth = nodeWidth / 2;
public static final int halfHeight = nodeHeight / 2;
public static final int qrtrWidth = nodeWidth / 4;
public static final int qrtrHeight = nodeHeight / 4;

public static final int nodeSpacer = halfWidth;

/** node is drawn normally **/
public static final int ACTION_NONE          = 0;
/** node is drawn highlighted **/
public static final int ACTION_HIGHLIGHT     = 1;
/** indicator is drawn after node **/
public static final int ACTION_INSERT_AFTER = 2;
/** indicator is drawn before node **/
public static final int ACTION_INSERT_BEFORE = 3;
/** node is drawn with delete indicator **/
public static final int ACTION_DELETE        = 4;
/** node is drawn with retrieve indicator **/
public static final int ACTION_RETRIEVE      = 5;

private int initialHeight = 0;
private ArrayList<NodeWrapper> nodeData = new ArrayList<NodeWrapper>( );

/**
   *
   * creates a new Visualizer with the given width
   * and height in pixels. sets the preferred size
   * to those values, and makes the Visualizer visible.
   *
   **/
public Visualizer( int width, int height )
{
    super( );

    initialHeight = height;

    setSize( width,height );
    setPreferredSize( new Dimension( width, height ) );
    setVisible( true );
    validate( );

} // end default constructor

/**
   *
   * draws all nodes currently contained in the list of nodes.
   *
   **/
protected void paintComponent( Graphics g )
{
    super.paintComponent( g );

    for( int n = 0; n < nodeData.size( ); n++)
    {
      nodeData.get( n ).draw( g );
    }

    // the following lines let the scrollpane know to update
    revalidate( );
} // end paintComponent

/**
   *
   * convenience method that is the same as calling
   * drawList(Node, null, Visualizer.ACTION_NONE)
   * so that the list is drawn with no nodes highlighted.
   *
   **/
public synchronized void drawList( Node head )
{
    nodeData.clear( );
    Node current = head;
    //highlightData = target;
    //this.action = action;
    int x = nodeSpacer;
    int y = 50;

    while( current != null )
    {
      nodeData.add( new NodeWrapper( current, x, y, ACTION_NONE ) );

      current = current.getNext( );
      x += ( nodeWidth+nodeSpacer );
    }
    setPreferredSize( new Dimension (x + nodeWidth + nodeSpacer, initialHeight ) );
    repaint( );
} // end drawList

/**
   *
   * convenience method that is the same as calling
   * drawList(Node,Object,Visualizer.ACTION_HIGHLIGHT)
   * so that the list is drawn with a node that has a data
   * object matching the given object highlighted.
   *
   **/
public synchronized void drawList( Node head, int highlight )
{
    drawList( head, highlight, Visualizer.ACTION_HIGHLIGHT );
} // end drawList with a node highlighted

public synchronized void drawList( Node head, Node highlight )
{
    drawList( head, highlight, Visualizer.ACTION_HIGHLIGHT );
} // end drawList with a node highlighted

/**
   *
   * draws graphical representations of link list nodes. starting
   * from the head node, the list is traversed in order and each
   * node is displayed. if a node contains a data object that is
   * equal to target, that node will be drawn in such a way
   * as to stand out from the other nodes according to the
   * specified action.
   *
   * @param head the head Node of a linked list.
   *
   * @param highlight a data object to be matched against the data
   *                   objects in the list. if a match is found, that
   *                   node will be highlighted. to not highlight any
   *                   nodes, send null as the highlight parameter.
   *
   * @param action the action to display upon finding a matching node.
   *                See the ACTION_<i>actiontype</i> final static ints
   *                specified by this class.
   *
   **/
public synchronized void drawList( Node head, int target, int action )
{
    nodeData.clear( );
    Node current = head;
    //highlightData = target;
    //this.action = action;
    int x = nodeSpacer;
    int y = 50;

    while( current != null )
    {
      if( target == current.getData( ) )
      {
        nodeData.add( new NodeWrapper( current, x, y, action ) );
        action = ACTION_NONE;
      }
      else
      {
        nodeData.add( new NodeWrapper( current,x , y, ACTION_NONE ) );
      }
      current = current.getNext( );
       x += ( nodeWidth + nodeSpacer );
    }
    setPreferredSize( new Dimension( x + nodeWidth + nodeSpacer, initialHeight ) );

    repaint( );
} // end draw list (head, target, action)


/**
   * Draws the list as described in drawList(Node, int, int), except that
   * here, the target node is found by reference instead of by value.
   *
   * @param head
   * @param target
   * @param action
   */
public synchronized void drawList( Node head, Node target, int action )
{
    nodeData.clear( );
    Node current = head;
    //highlightData = target;
    //this.action = action;
    int x = nodeSpacer;
    int y = 50;

    while( current != null )
    {
      if( target == current )
      {
        nodeData.add( new NodeWrapper( current, x, y, action) );
        action = ACTION_NONE;
      }
      else
      {
        nodeData.add( new NodeWrapper( current, x, y, ACTION_NONE ) );
      }
      current = current.getNext( );
      x += ( nodeWidth + nodeSpacer );
    }
    setPreferredSize( new Dimension( x + nodeWidth + nodeSpacer, initialHeight ) );

    repaint( );
} // end draw list (head, target, action)


/** draw the reference to null **/
private void drawNullRef( Graphics g, int x, int y )
{
    int startY = y + ( ( int ) ( nodeHeight * ( 3.0f / 4.0f) ) );
    int endY = y + ( int ) ( ( nodeHeight *1.5f ) );
    g.drawLine( x, startY, x, endY );
    g.drawLine( x - 10, endY, x + 10, endY );
    g.drawLine( x - 5, endY + 5, x + 5, endY + 5 );
} // end draw null ref

/** draw reference arrows from node to node **/
private void drawRefs( Graphics g, NodeWrapper wn )
{
    int x = wn.getX( );
    int y = wn.getY( );
    Node n = wn.getNode( ).getNext( );

    if( n == null )
    {
      drawNullRef( g, x + halfWidth, y );
    }
    else
    {
      for( int i = 0; i < nodeData.size( ); i++ )
      {
        NodeWrapper nw = nodeData.get( i );
        if( n == nw.getNode( ) )
        {
          int targetX = nw.getX( );
          int targetY = nw.getY( );
          g.fillOval( x + halfWidth, y + ( (int ) ( nodeHeight * ( 3.0f / 4.0f ) ) ) - 3, 6, 6 );
          g.drawLine( x + halfWidth, y + ( ( int ) ( nodeHeight * ( 3.0f / 4.0f ) ) ), x + nodeWidth + 13, y + ( ( int ) ( nodeHeight * ( 3.0f / 4.0f ) ) ) );
          g.drawLine( x + nodeWidth + 13, y + ( ( int ) ( nodeHeight * ( 3.0f / 4.0f ) ) ), targetX - 13, targetY + 15 );
          g.drawLine( targetX - 13, targetY + 15, targetX, targetY + 15 );

          g.drawLine( targetX, targetY + 15, targetX - 7, targetY + 10 );
          g.drawLine( targetX, targetY + 15, targetX - 7, targetY + 20 );

          break;
        }
      }
    }
} // end draw refs

/**
   *
   * detect if there is a node at the given the x,y coordinate. if
   * there is, it will be highlighted and that node will be returned.
   *
   * @return the node at the given coordinate, or null if there is no
   *          node at the coordinate
   *
   **/
public Node selectNode( int mouseX, int mouseY )
{
    int x = 0;
    int y = 0;

    int size = nodeData.size( );
    Node n = null;
    for( int i = 0; i < size; i++ )
    {
      x = nodeData.get( i ).getX( );
      y = nodeData.get( i ).getY( );

      if(   x < mouseX && mouseX < x + nodeWidth
            && y < mouseY && mouseY < y + nodeHeight )
      {
            // if it was selected, hightlight it
            ( nodeData.get( i ) ).setAction( ACTION_HIGHLIGHT );

            // output.put( "panel clicked: "" + ( nodeData.get( i ) ).getNode( ).getData( )+"" selected" );
            n = ( nodeData.get( i ) ).getNode( );

      }
      else
      {
        // otherwise, no special treatment
        ( nodeData.get( i ) ).setAction( ACTION_NONE );
      }
    }
    repaint( );
    return n;
} // end selectNode at coordinate


/** wraps a Node with extra information so it can
      be displayed in the Visualizer.
**/
private class NodeWrapper
{
    int nodeAction = ACTION_NONE;
    Node node = null;
    int x = 0;
    int y = 0;

    NodeWrapper( Node n, int x, int y, int action )
    {
      this.nodeAction = action;
      this.node = n;
      this.x = x;
      this.y = y;

    }

    public Node getNode( )
    {
      return node;
    }

    public int getX( )
    {
      return x;
    }

    public int getY( )
    {
      return y;
    }

    public void setAction( int action )
    {
      this.nodeAction = action;
    }

    /** draw the node at current x,y coord with current action type **/
    void draw( Graphics g )
    {
      // draw the node representation
      g.setColor( Color.BLACK );
      g.drawRect( x, y, nodeWidth, nodeHeight ); // main rectangle
      g.drawLine( x, y + halfHeight, x + nodeWidth, y + halfHeight ); //horizontal line
      //g.drawLine( x + halfWidth, y + halfHeight, x + halfWidth,y+nodeHeight ); // vertical line

      // in case the data.toString is really long, this will shrink the
      // font size so that it fits in the node drawing.
      int fontSize = 16;
      Font font = new Font( "SansSerif", Font.PLAIN, fontSize );
      FontMetrics metrics = getFontMetrics( font );
      String str = ""+node.getData( );
      while( fontSize > 0 && metrics.stringWidth( str ) > nodeWidth - 10 )
      {
        //System.out.println( "str: " + str + " width: " + metrics.stringWidth( str ) + " size: " + fontSize );
        font = new Font( "SansSerif", Font.PLAIN, fontSize-- );
        metrics = getFontMetrics( font );
      }

      g.setFont( font );

      g.drawString( str, x + 5, y + 20 ); // data as a string

      // draw the reference arrows
      drawRefs( g, this );

      // determine which action should be used, draw anything special for it.
      if( nodeAction == ACTION_HIGHLIGHT )
      {
        g.setColor( Color.BLUE );
        g.drawRect( x, y, nodeWidth, nodeHeight ); // main rectangle
        g.drawLine( x, y + halfHeight, x + nodeWidth, y + halfHeight ); //horizontal line
        // g.drawLine(x+halfWidth,y+halfHeight,x+halfWidth,y+nodeHeight); // vertical line
        g.drawString(str,x+5,y+20);
        g.setColor(Color.magenta);
        drawRefs(g,this);
      }
      else if( nodeAction == ACTION_INSERT_BEFORE )
      {
        g.setColor( Color.GREEN );
        int offset = nodeSpacer>>1;
        g.drawLine( x - offset, y, x - offset, y - 30 ); // arrow shaft
        g.drawLine( x - offset, y, x - offset + 5, y - 10 ); // arrow left
        g.drawLine( x - offset, y, x - offset - 5, y - 10 ); // arrow right
      }
      else if( nodeAction == ACTION_INSERT_AFTER )
      {
        g.setColor( Color.GREEN );
        int offset = nodeSpacer >> 1;
        g.drawLine( x + nodeWidth + offset, y, x + nodeWidth + offset, y - 30 ); // arrow shaft
        g.drawLine( x + nodeWidth + offset, y, x + nodeWidth + offset + 5, y - 10 ); // arrow left
        g.drawLine( x + nodeWidth + offset, y, x + nodeWidth + offset - 5, y - 10 ); // arrow right
      }
      else if( nodeAction == ACTION_DELETE )
      {
        g.setColor( Color.red );
        g.drawLine( x - 10, y - 10, x + nodeWidth + 10, y + nodeHeight + 10 );
        g.drawLine( x - 10, y + nodeHeight + 10, x + nodeWidth + 10, y - 10 );
      }
      else if( nodeAction == ACTION_RETRIEVE )
      {
        g.setColor( Color.YELLOW );
        g.drawRect( x - 10, y - 10, nodeWidth + 20, nodeHeight + 20 );
      } // end drawing decision block

    } // end draw

} // end node wrapper

} // end visualizer

Please only answer if you know the output so I do not lose any of my remaining question. Thank you.

Explanation / Answer

Find the program below

public class LinkList extends AbstractList
{
private Node head = null;

public LinkList()
{
    super(500, 400);
    v.drawList(head);
}

public LinkList(Node head)
{
    super(500, 400); // set size for visualizer
    // set up the list
    head = head;

    animate(head);
}

public void insert(int i)
{
    // ***** Student writes the body of this method *****

    // code the insert method of a linked list of ints
    // the int to insert in the linked list is i

    // we call the animate method inside the body of this method
    // as you traverse the list looking for the place to insert,
    // call animate as follows:

    //    animate(head, current);
    // where    head is the instance variable head of the linked list
    //          current is the node that you are visiting

    // you can start coding now

    // in order to improve the animation (this is optional):
    // just before inserting, i.e. connecting the nodes,
    // make the call

    //    animate(head, previous, Visualizer.ACTION_INSERT_AFTER);

    // where    head is the instance variable head of the linked list
    //          previous is the node (not null) after which to insert

    // if you are inserting at the beginning of the list,
    // just before inserting, make the call

    //    animate(head, head, Visualizer.ACTION_INSERT_BEFORE);

    // where    head is the instance variable head of the linked list
    //
    // Part 1 student code starts here:

    // Part 1 student code ends here.

    numberNodes++;
    // call animate again to show the status of the list
    animate(head);
}

public boolean delete(int i)
{
    // ***** Student writes the body of this method *****

    // code the delete method of a linked list of ints
    // the int to delete in the linked list is i
    // if deletion is successful, return true
    // otherwise, return false

    // we call the animate method inside the body of this method
    // as you traverse the list looking for the node to delete,
    // call animate as follows:

    //    animate(head, current);

    // where    head is the instance variable head of the linked list
    //          current is the node that you are visiting

    // you can start coding now

    // in order to improve the animation (this is optional):
    // just before deleting, i.e. connecting the nodes,
    // make the call

    //    animate(head, current, Visualizer.ACTION_DELETE);

    // where    head is the instance variable head of the linked list
    //          current is the node that you are deleting
    //
    // Part 2 student code starts here:

    // Part 2 student code ends here.

    // At this point, the item has been deleted.
    // Decrement the number of nodes:
    numberNodes--;
    // Call animate again to show the status of the list:
    animate(head);
    return true;
}

public int count()
{
    int n = 0;
    Node current = head;
    while (current != null)
    {
      animate(head, current);
      n++;
      current = current.getNext();
    }
    return n;
}

public void traverse()
{
    traversal = "";
    Node current = head;
    while (current != null)
    {
      animate(head, current);
      traversal += (current.getData() + " ");
      current = current.getNext();
    }
    v.drawList(head);
}

public void clear()
{
    head = null;
    v.drawList(head);
}

public void animate(Node h, Node nd)
{
    v.drawList(h, nd);
    delay(1000);
}

public void animate(Node h)
{
    v.drawList(h);
}

public void animate(Node h, Node nd, int mode)
{
    v.drawList(h, nd, mode);
    delay(1000);
}
}

/* AbstractList
* Anderson, Franceschi
*/

public abstract class AbstractList
{
/*
       INSTANCE VARIABLES
*/

/**
   * a Visualizer instance is maintained here so that the student
   * can call it from the child class without worrying about the
   * implementation of the Visualizer. This is intended to mimic
   * the use of a Graphic object in the Swing or AWT package.
   **/
protected Visualizer v;

protected int numberNodes;
protected String traversal; // holds current traversal of the list

/*
       CONSTRUCTORS
*/

/**
   *   instantiate with the given GUI width and height for the Visualizer.
   *
   **/
public AbstractList( int width, int height )
{
    v = new Visualizer( width, height );
    numberNodes = 0;
}

/*
      METHODS STUDENTS MUST OVERRIDE
*/

/**
   *
   * insert an object in to the list.
   *
   **/
public abstract void insert( int i );

/**
   *
   * delete a node from the list based on reference.
   *
   * @ return true if the node was deleted, false otherwise
   **/


/**
   *
   * delete a node from the list based on data.
   *
   * @return true if the node was deleted, false otherwise
   *
   **/
public abstract boolean delete( int i );

/**
   *
   * returns the number of Nodes in the list.
   *
   **/
public abstract int count( );

/**
   *
   * walks the list and displays the data it contains.
   *
   **/
public abstract void traverse( );

/**
   *
   * removes all nodes from the list.
   *
   **/
public abstract void clear( );

/*
     METHODS FOR CONTROLLING VISUALIZER
*/

/**
   *
   * sets the width and height in pixels for the visualizer.
   *
   **/
public void setSize( int width, int height )
{
    v.setSize( width, height );
    v.validate( );
}

/**
   *
   * returns a reference to the Visualizer being used by this object.
   * Any object calling this method is on its honor to not modify
   * the Visualizer.
   *
   **/
public Visualizer getVisualizer( )
{
    return v;
}

/**
   *
   * simple delay routine that makes the thread sleep for the given
   * number of milliseconds. useful for when a node is being
   * highlighted by the visualizer.
   *
   **/
public void delay( int milliseconds )
{
    try
    {
      Thread.sleep( milliseconds );
    }
    catch ( Exception e )
    {
      System.out.println(" e: "+e );
    }
}

/*
   *
   * the following are wrapper methods to make calling the visualizer
   * a little more convienient. see the wrapped Visualizer methods
   * for more information.
   *
   */
/*
public void drawList( Node headNode )
{
    v.drawList( headNode );
}

public void drawList( Node headNode, int highlight )
{
    v.drawList( headNode, highlight );
}

public void drawList( Node headNode, Node highlight )
{
    v.drawList( headNode, highlight );
}

public void drawList( Node headNode, int target, int action )
{
    v.drawList( headNode, target, action );
}

public void drawList( Node headNode, Node target, int action )
{
    v.drawList( headNode, target, action );
}
*/
public String getTraversal( )
{
    return traversal;
}

} // end abstract list

/* LinkedListPractice
* Anderson, Franceschi
*/

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class LinkedListPractice extends JFrame
{
/*
        INSTANCE VARIABLES
           These variables are directly responsible for
           handling the student code: instantiating an
           object of the student's list, displaying it graphically,
           manipulating it by calling the various methods.
*/

/**
   * rationale: use AbstractList so that an instructor can have
   *              students create any other list type and still
   *              be able to use all the same method calls. The only
   *              change that needs to be made to this code is
   *              changing the instantiation to whatever type the
   *              instructor wants.
   **/
private AbstractList list;

/**
   *   this class is on its honor to not modify the Visualizer.
   *   the list instance returns a reference to its Visualizer
   *   so that this class can add it in to the JFrame, but this
   *   class should never directly modify that instance.
   **/
private Visualizer v;

/*
      GUI ELEMENTS
*/

// controls
private JPanel controls;     // holds the following:
private JPanel dataPanel;    // text box and label
private JButton insertNode;
private JButton deleteNode;
private JButton traverseList;
private JButton clearList;
private JButton countNodes;

private JTextField data;    // text box and label
private JLabel dataLabel; // for dataPanel

// output
private JScrollPane   outputPane; // holds the output text area
private JTextArea     outputArea; // the output text area
private String outputDisplay = ""; // message to outputArea
private JScrollPane   visualPane; // holds the Visualizer

private boolean mouseDisabled = false; // prevent clicking while drawing

private static int MAX_DATA_LENGTH = 4; // max chars allowed in the data field

/*
       CONSTRUCTOR
*/

/**
   * instantiates a new ListControl with the given width and height.
   * sets up the controls, initializes the Visualizer, makes everything
   * visible.
   *
   **/
public LinkedListPractice( int width, int height )
{
    super( ); // call to Object( ) for completeness
    setTitle( " Linked List Visualizer" );

    // set up the list and visualizer
    list = new LinkList( );
    v = list.getVisualizer( );
    visualPane = new JScrollPane( v );

    // instantiate GUI list controls

    dataPanel = new JPanel( );
    dataPanel.setLayout( new GridLayout( 2,1 ) );

    data         = new JTextField( );
    dataLabel    = new JLabel( "Node Data:" );

    dataPanel.add( dataLabel );
    dataPanel.add( data );

    controls = new JPanel( );
    controls.setLayout( new GridLayout( 6, 1 ) );

    insertNode   = new JButton( "insert" );
    deleteNode   = new JButton( "delete" );
    traverseList = new JButton( "traverse" );
    countNodes   = new JButton( "count" );
    clearList    = new JButton( "clear" );

    // set up handlers for controls
    //   private inner classes seem more readable
    //   than anonymous inner classes or one large handler
    data.addKeyListener( new DataListener( ) );
    insertNode.addActionListener( new ActionInsert( ) );
    deleteNode.addActionListener( new ActionDelete( ) );
    traverseList.addActionListener( new ActionTraverse( ) );
    countNodes.addActionListener( new ActionCount( ) );
    clearList.addActionListener( new ActionClear( ) );

    // add controls to the control pane
    controls.add( dataPanel );
    controls.add( insertNode );
    controls.add( deleteNode );
    controls.add( traverseList );
    controls.add( countNodes );
    controls.add( clearList );

    // set up GUI output
    outputArea = new JTextArea( 5, 40 );
    outputPane = new JScrollPane( outputArea );
    outputArea.setEditable( false );

    // set up ListControl GUI
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    getContentPane( ).setLayout( new BorderLayout( ) );
    getContentPane( ).add( visualPane,BorderLayout.CENTER );
    getContentPane( ).add( controls,BorderLayout.WEST );
    getContentPane( ).add( outputPane,BorderLayout.SOUTH );

    setSize( width,height );
    setVisible( true );
    doLayout( );
    validate( );
} // end default constructor

/*
       METHODS
*/

/** turn off all the buttons so they can't be clicked
       during operations **/
private void disableButtons( )
{
    insertNode.setEnabled( false );
    deleteNode.setEnabled( false );
    traverseList.setEnabled( false );
    clearList.setEnabled( false );
    countNodes.setEnabled( false );
    mouseDisabled = true;
}

/** turn on the buttons **/
private void enableButtons( )
{
    insertNode.setEnabled( true );
    deleteNode.setEnabled( true );
    traverseList.setEnabled( true );
    clearList.setEnabled( true );
    countNodes.setEnabled( true );
    mouseDisabled = false;
}

/** give focus to the text field and select any text it holds **/
private void selectData( )
{
    data.select( 0, data.getText( ).length( ) );
    data.requestFocusInWindow( );
}

private int getData( ) throws NumberFormatException
{
    return ( new Integer( data.getText( ) ) ).intValue( );
}

/*
      PRIVATE INNER CLASSES - action handlers
         each class is for a specific button,
         so the event source is not checked

         for any method that requires nodes
         to be highlighted, a new thread is created
         and started to handle calling the method.
         this allows the GUI to handle the highlighting
         and delay routines appropriately.
*/

private class ActionInsert implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      //SwingUtilities.invokeLater( new InsertThread( ) );
      ( new InsertThread( ) ).start( );
    }

    private class InsertThread extends Thread
    {
      public void run( )
      {
        disableButtons( );
        try
        {
          int i = getData( );
          outputDisplay += "insert called with " + i + " as data ";
          outputArea.setText( outputDisplay );
          list.insert(i);
        }
        catch ( Exception e )
        {
          outputDisplay += "invalid number ";
          outputArea.setText( outputDisplay );
        }
        enableButtons( );
        selectData( );
      }
    }
} // end ActionInsert

private class ActionDelete implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      ( new DeleteThread( ) ).start( );
    }

    private class DeleteThread extends Thread
    {
      public void run( )
      {
        disableButtons( );
        outputDisplay += ( "delete called with " + data.getText( ) + ": " );
        outputArea.setText( outputDisplay );
        try
        {
          boolean deleted = list.delete( new Integer( data.getText( ) ).intValue( ) );
          outputDisplay += "node " + ( (deleted)?"deleted ":"not found " );
          outputArea.setText( outputDisplay );
        }
        catch( NumberFormatException nfe )
        {
          outputDisplay += ( "data not an integer " );
          outputArea.setText( outputDisplay );
        }
        enableButtons( );
        selectData( );
      }
    }
}

private class ActionTraverse implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      outputDisplay += "traversing the list: ";
      outputArea.setText( outputDisplay );
      ( new Thread( ){
            public void run( ){
               disableButtons( );
               list.traverse( );
               outputDisplay += ( list.getTraversal( ) + " " );
               outputArea.setText( outputDisplay );
               enableButtons( );
               selectData( );
            }
         }).start( );
      }
   } // end ActionTraverse

private class ActionCount implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      ( new CountThread( ) ).start( );
    }

    private class CountThread extends Thread
    {
      public void run( )
      {
        disableButtons( );
        outputDisplay += "count called: ";
        outputArea.setText( outputDisplay );
        int n = list.count( );
        outputDisplay += ( "number of nodes = " + n + " " );
        outputArea.setText( outputDisplay );
        enableButtons( );
        selectData( );
      }
    }
} // end ActionCount

private class ActionClear implements ActionListener
{
    public void actionPerformed( ActionEvent e )
    {
      ( new ClearThread( ) ).start( );
    }

    private class ClearThread extends Thread
    {
      public void run( )
      {
        disableButtons( );
        outputDisplay += "clear list called ";
        outputArea.setText( outputDisplay );
        list.clear( );
        enableButtons( );
        selectData( );
      }
    }
} // end ActionClear


/** detects when key is entered in to data text field, and ensures
       that the field is limited to MAX_DATA_LENGTH. **/
private class DataListener extends KeyAdapter
{
    int key = 0; // which key was pressed
    //keyPressed will detect back space, but doesn't properly consume
    // the event, so the field still gets it. so, trap the key here
    // and assign it to variable key. thankfully by its very nature
    // keyPressed happens before keyTyped.
    public void keyPressed( KeyEvent e )
    {
      key = e.getKeyCode( );
    }

    // keyTyped will properly consume the event, but can't detect when
    // backspace was pressed. it also lets arrow keys, home, etc. through.
    // key has been trapped by keyPressed, so it can be properly compared
    // to backspace, and consumed if it is not back space and field is
    // over 15 chars.
    public void keyTyped( KeyEvent e )
    {
      // must compare to MAX_DATA_LENGTH-1 because the key currently being examined
      // will be the last character in the field.

      if( key == KeyEvent.VK_BACK_SPACE )
      {
        // never consume backspace
        return;
      }
      if( data.getText( ).length( ) > MAX_DATA_LENGTH-1
            || key < KeyEvent.VK_0 || key > KeyEvent.VK_9 )
      {
        // if field is full, or invalid value entered, consume the key
        e.consume( );
        return;
      }
    }
}

public static void main( String args[] )
{
    LinkedListPractice app = new LinkedListPractice( 600, 400 );
}
}

/* Node
* Anderson, Franceschi
*/

public class Node
{
/** reference to the next node in the list **/
private Node nextNode;

/** the data object held by this node **/
private int data;


/**
   *
   * construct a new node with the given Object as data
   *
   **/
public Node( int i )
{
    data = i;
}

/**
   *
   * construct a new node with the given Object as data
   * and references to the next and previous nodes.
   *
   **/
public Node( int i, Node next )
{
    data = i;
    nextNode = next;
}

/**
   *
   * set the reference to the next node
   *
   **/
public void setNext( Node n )
{
    nextNode = n;
}

/**
   *
   * return the reference to the next node
   * @return reference to the next node, or null if there is no next node
   *
   **/
public Node getNext( )
{
    return nextNode;
}

/**
   *
   * set the data object held by this node
   *
   **/
public void setData( int i )
{
    data = i;
}

/**
   *
   * get the data object held by this node
   *
   **/
public int getData( )
{
    return data;
}

} // end node class

/* Visualizer
* Anderson, Franceschi
*/

import javax.swing.*;
import java.awt.*;
//import java.awt.event.*;
import java.util.ArrayList;

public class Visualizer extends JPanel
{
public static final int nodeWidth = 100;
public static final int nodeHeight = 100;
public static final int halfWidth = nodeWidth / 2;
public static final int halfHeight = nodeHeight / 2;
public static final int qrtrWidth = nodeWidth / 4;
public static final int qrtrHeight = nodeHeight / 4;

public static final int nodeSpacer = halfWidth;

/** node is drawn normally **/
public static final int ACTION_NONE          = 0;
/** node is drawn highlighted **/
public static final int ACTION_HIGHLIGHT     = 1;
/** indicator is drawn after node **/
public static final int ACTION_INSERT_AFTER = 2;
/** indicator is drawn before node **/
public static final int ACTION_INSERT_BEFORE = 3;
/** node is drawn with delete indicator **/
public static final int ACTION_DELETE        = 4;
/** node is drawn with retrieve indicator **/
public static final int ACTION_RETRIEVE      = 5;

private int initialHeight = 0;
private ArrayList<NodeWrapper> nodeData = new ArrayList<NodeWrapper>( );

/**
   *
   * creates a new Visualizer with the given width
   * and height in pixels. sets the preferred size
   * to those values, and makes the Visualizer visible.
   *
   **/
public Visualizer( int width, int height )
{
    super( );

    initialHeight = height;

    setSize( width,height );
    setPreferredSize( new Dimension( width, height ) );
    setVisible( true );
    validate( );

} // end default constructor

/**
   *
   * draws all nodes currently contained in the list of nodes.
   *
   **/
protected void paintComponent( Graphics g )
{
    super.paintComponent( g );

    for( int n = 0; n < nodeData.size( ); n++)
    {
      nodeData.get( n ).draw( g );
    }

    // the following lines let the scrollpane know to update
    revalidate( );
} // end paintComponent

/**
   *
   * convenience method that is the same as calling
   * drawList(Node, null, Visualizer.ACTION_NONE)
   * so that the list is drawn with no nodes highlighted.
   *
   **/
public synchronized void drawList( Node head )
{
    nodeData.clear( );
    Node current = head;
    //highlightData = target;
    //this.action = action;
    int x = nodeSpacer;
    int y = 50;

    while( current != null )
    {
      nodeData.add( new NodeWrapper( current, x, y, ACTION_NONE ) );

      current = current.getNext( );
      x += ( nodeWidth+nodeSpacer );
    }
    setPreferredSize( new Dimension (x + nodeWidth + nodeSpacer, initialHeight ) );
    repaint( );
} // end drawList

/**
   *
   * convenience method that is the same as calling
   * drawList(Node,Object,Visualizer.ACTION_HIGHLIGHT)
   * so that the list is drawn with a node that has a data
   * object matching the given object highlighted.
   *
   **/
public synchronized void drawList( Node head, int highlight )
{
    drawList( head, highlight, Visualizer.ACTION_HIGHLIGHT );
} // end drawList with a node highlighted

public synchronized void drawList( Node head, Node highlight )
{
    drawList( head, highlight, Visualizer.ACTION_HIGHLIGHT );
} // end drawList with a node highlighted

/**
   *
   * draws graphical representations of link list nodes. starting
   * from the head node, the list is traversed in order and each
   * node is displayed. if a node contains a data object that is
   * equal to target, that node will be drawn in such a way
   * as to stand out from the other nodes according to the
   * specified action.
   *
   * @param head the head Node of a linked list.
   *
   * @param highlight a data object to be matched against the data
   *                   objects in the list. if a match is found, that
   *                   node will be highlighted. to not highlight any
   *                   nodes, send null as the highlight parameter.
   *
   * @param action the action to display upon finding a matching node.
   *                See the ACTION_<i>actiontype</i> final static ints
   *                specified by this class.
   *
   **/
public synchronized void drawList( Node head, int target, int action )
{
    nodeData.clear( );
    Node current = head;
    //highlightData = target;
    //this.action = action;
    int x = nodeSpacer;
    int y = 50;

    while( current != null )
    {
      if( target == current.getData( ) )
      {
        nodeData.add( new NodeWrapper( current, x, y, action ) );
        action = ACTION_NONE;
      }
      else
      {
        nodeData.add( new NodeWrapper( current,x , y, ACTION_NONE ) );
      }
      current = current.getNext( );
       x += ( nodeWidth + nodeSpacer );
    }
    setPreferredSize( new Dimension( x + nodeWidth + nodeSpacer, initialHeight ) );

    repaint( );
} // end draw list (head, target, action)


/**
   * Draws the list as described in drawList(Node, int, int), except that
   * here, the target node is found by reference instead of by value.
   *
   * @param head
   * @param target
   * @param action
   */
public synchronized void drawList( Node head, Node target, int action )
{
    nodeData.clear( );
    Node current = head;
    //highlightData = target;
    //this.action = action;
    int x = nodeSpacer;
    int y = 50;

    while( current != null )
    {
      if( target == current )
      {
        nodeData.add( new NodeWrapper( current, x, y, action) );
        action = ACTION_NONE;
      }
      else
      {
        nodeData.add( new NodeWrapper( current, x, y, ACTION_NONE ) );
      }
      current = current.getNext( );
      x += ( nodeWidth + nodeSpacer );
    }
    setPreferredSize( new Dimension( x + nodeWidth + nodeSpacer, initialHeight ) );

    repaint( );
} // end draw list (head, target, action)


/** draw the reference to null **/
private void drawNullRef( Graphics g, int x, int y )
{
    int startY = y + ( ( int ) ( nodeHeight * ( 3.0f / 4.0f) ) );
    int endY = y + ( int ) ( ( nodeHeight *1.5f ) );
    g.drawLine( x, startY, x, endY );
    g.drawLine( x - 10, endY, x + 10, endY );
    g.drawLine( x - 5, endY + 5, x + 5, endY + 5 );
} // end draw null ref

/** draw reference arrows from node to node **/
private void drawRefs( Graphics g, NodeWrapper wn )
{
    int x = wn.getX( );
    int y = wn.getY( );
    Node n = wn.getNode( ).getNext( );

    if( n == null )
    {
      drawNullRef( g, x + halfWidth, y );
    }
    else
    {
      for( int i = 0; i < nodeData.size( ); i++ )
      {
        NodeWrapper nw = nodeData.get( i );
        if( n == nw.getNode( ) )
        {
          int targetX = nw.getX( );
          int targetY = nw.getY( );
          g.fillOval( x + halfWidth, y + ( (int ) ( nodeHeight * ( 3.0f / 4.0f ) ) ) - 3, 6, 6 );
          g.drawLine( x + halfWidth, y + ( ( int ) ( nodeHeight * ( 3.0f / 4.0f ) ) ), x + nodeWidth + 13, y + ( ( int ) ( nodeHeight * ( 3.0f / 4.0f ) ) ) );
          g.drawLine( x + nodeWidth + 13, y + ( ( int ) ( nodeHeight * ( 3.0f / 4.0f ) ) ), targetX - 13, targetY + 15 );
          g.drawLine( targetX - 13, targetY + 15, targetX, targetY + 15 );

          g.drawLine( targetX, targetY + 15, targetX - 7, targetY + 10 );
          g.drawLine( targetX, targetY + 15, targetX - 7, targetY + 20 );

          break;
        }
      }
    }
} // end draw refs

/**
   *
   * detect if there is a node at the given the x,y coordinate. if
   * there is, it will be highlighted and that node will be returned.
   *
   * @return the node at the given coordinate, or null if there is no
   *          node at the coordinate
   *
   **/
public Node selectNode( int mouseX, int mouseY )
{
    int x = 0;
    int y = 0;

    int size = nodeData.size( );
    Node n = null;
    for( int i = 0; i < size; i++ )
    {
      x = nodeData.get( i ).getX( );
      y = nodeData.get( i ).getY( );

      if(   x < mouseX && mouseX < x + nodeWidth
            && y < mouseY && mouseY < y + nodeHeight )
      {
            // if it was selected, hightlight it
            ( nodeData.get( i ) ).setAction( ACTION_HIGHLIGHT );

            // output.put( "panel clicked: "" + ( nodeData.get( i ) ).getNode( ).getData( )+"" selected" );
            n = ( nodeData.get( i ) ).getNode( );

      }
      else
      {
        // otherwise, no special treatment
        ( nodeData.get( i ) ).setAction( ACTION_NONE );
      }
    }
    repaint( );
    return n;
} // end selectNode at coordinate


/** wraps a Node with extra information so it can
      be displayed in the Visualizer.
**/
private class NodeWrapper
{
    int nodeAction = ACTION_NONE;
    Node node = null;
    int x = 0;
    int y = 0;

    NodeWrapper( Node n, int x, int y, int action )
    {
      this.nodeAction = action;
      this.node = n;
      this.x = x;
      this.y = y;

    }

    public Node getNode( )
    {
      return node;
    }

    public int getX( )
    {
      return x;
    }

    public int getY( )
    {
      return y;
    }

    public void setAction( int action )
    {
      this.nodeAction = action;
    }

    /** draw the node at current x,y coord with current action type **/
    void draw( Graphics g )
    {
      // draw the node representation
      g.setColor( Color.BLACK );
      g.drawRect( x, y, nodeWidth, nodeHeight ); // main rectangle
      g.drawLine( x, y + halfHeight, x + nodeWidth, y + halfHeight ); //horizontal line
      //g.drawLine( x + halfWidth, y + halfHeight, x + halfWidth,y+nodeHeight ); // vertical line

      // in case the data.toString is really long, this will shrink the
      // font size so that it fits in the node drawing.
      int fontSize = 16;
      Font font = new Font( "SansSerif", Font.PLAIN, fontSize );
      FontMetrics metrics = getFontMetrics( font );
      String str = ""+node.getData( );
      while( fontSize > 0 && metrics.stringWidth( str ) > nodeWidth - 10 )
      {
        //System.out.println( "str: " + str + " width: " + metrics.stringWidth( str ) + " size: " + fontSize );
        font = new Font( "SansSerif", Font.PLAIN, fontSize-- );
        metrics = getFontMetrics( font );
      }

      g.setFont( font );

      g.drawString( str, x + 5, y + 20 ); // data as a string

      // draw the reference arrows
      drawRefs( g, this );

      // determine which action should be used, draw anything special for it.
      if( nodeAction == ACTION_HIGHLIGHT )
      {
        g.setColor( Color.BLUE );
        g.drawRect( x, y, nodeWidth, nodeHeight ); // main rectangle
        g.drawLine( x, y + halfHeight, x + nodeWidth, y + halfHeight ); //horizontal line
        // g.drawLine(x+halfWidth,y+halfHeight,x+halfWidth,y+nodeHeight); // vertical line
        g.drawString(str,x+5,y+20);
        g.setColor(Color.magenta);
        drawRefs(g,this);
      }
      else if( nodeAction == ACTION_INSERT_BEFORE )
      {
        g.setColor( Color.GREEN );
        int offset = nodeSpacer>>1;
        g.drawLine( x - offset, y, x - offset, y - 30 ); // arrow shaft
        g.drawLine( x - offset, y, x - offset + 5, y - 10 ); // arrow left
        g.drawLine( x - offset, y, x - offset - 5, y - 10 ); // arrow right
      }
      else if( nodeAction == ACTION_INSERT_AFTER )
      {
        g.setColor( Color.GREEN );
        int offset = nodeSpacer >> 1;
        g.drawLine( x + nodeWidth + offset, y, x + nodeWidth + offset, y - 30 ); // arrow shaft
        g.drawLine( x + nodeWidth + offset, y, x + nodeWidth + offset + 5, y - 10 ); // arrow left
        g.drawLine( x + nodeWidth + offset, y, x + nodeWidth + offset - 5, y - 10 ); // arrow right
      }
      else if( nodeAction == ACTION_DELETE )
      {
        g.setColor( Color.red );
        g.drawLine( x - 10, y - 10, x + nodeWidth + 10, y + nodeHeight + 10 );
        g.drawLine( x - 10, y + nodeHeight + 10, x + nodeWidth + 10, y - 10 );
      }
      else if( nodeAction == ACTION_RETRIEVE )
      {
        g.setColor( Color.YELLOW );
        g.drawRect( x - 10, y - 10, nodeWidth + 20, nodeHeight + 20 );
      }

    }

}

}