Lab 4

Windows Manager
Due before 8pm, Sunday 7 Oct 2012

In this lab you will implement a doubly linked list, and use it to construct a windows manager.

The purpose of this lab is to:

If you'd like, you may work with one partner on this lab. If you choose to do so, you must both contribute equally to the work of this lab, and are both responsible for understanding its workings. You must hand in one submission between the two of you, with both your names clearly marked somewhere obvious to the graders.

I can offer groups a way to share their files using a "version control system" so that they can collaborate without just emailing files back and forth. Talk to me if you're interested.


Motivation

On your monitor right now, you most likely have at least two open windows. Often, the windows on the screen get "stacked" one on top of the other, and depending on how they are arranged you may be able to see all the windows, or just parts of some. To bring a hidden window to the front, you just click on it, and all the other windows remain in the same order as before. For example,

 

 

A stack of windows After clicking on the fourth window from the top

We are going to model this behaviour, using a linked list to store the stack of windows on your monitor. There is some starter code (for the GUI), which you should get from lab04.jar.


Part 1 - Doubly Linked Lists

Before you get to the windows manager application, you may as well get your doubly-linked list up and running. Thus, your first task is to implement a doubly linked list called MyLinkedList and a corresponding ListIterator for your class.

MyLinkedList

Your MyLinkedList class is just a subset of LinkedList, and therefore should match its behaviour on this subset.

You should extend AbstractList and create a ListIterator (either as a separate class or as an anonymous class).

When you are finished your implementation, be sure to test your implementation thoroughly before continuing. In doubly linked lists, the removal of items can be especially tricky as you need to be sure to properly update the neighbour's next and previous pointers, as well as handle the special cases for removal from the front or tail.

You should not allow "null" pointers to be inserted into the list; if the user of your class attempts to do so, you should throw a NullPointerException.

Constructors

You need two constructors. One is a 0-argument constructor that creates an empty list, and the other is a protected 3-argument constructor that initializes your head, tail, and size class members (and this second constructor may want to ensure that head.prev and tail.next are null, if the list is not empty.)

Iterator

You will need to create a ListIterator which is returned by the factory listIterator() method. You can do this one of two ways:

  1. Through the use of an anyonymous class:
  2. Or through the use of a helper class (contained in the same file as MyLinkedList).

In either case, you will need to implement all of the methods of a ListIterator: hasNext(), next(), hasPrevious(), previous(), nextIndex(), previousIndex(), remove(), set(x), and add(x). See the JavaDoc for details.

If you want to, you can use the protected variable modCount to check for and prevent the iterator being used after changes have been made. Note that you'll also need to update that variable for many of the methods listed below.

Private Methods

ListNode getNth(int index)
a method that returns the ListNode at a specified index, not the content.

Public Methods

boolean add(T data)
void add(int index, T data)
add an element into this list (either at end or by index)
throw a NullPointerException if the user tries to add a null pointer
throw IndexOutOfBoundsException as needed (same rules as MyArrayList)
the boolean add method will presumably always return true; it is a
boolean function due to the method definition in AbstractList

T get(int i)
get contents at position i
throw IndexOutOfBoundsException as needed

T set(int i,T data)
set the value at index i to data
and return the OLD data value that was overwritten
throw NullPointerException if data is null
throw IndexOutOfBoundsException as needed

T remove(int i)
remove the element from position i in this list
throw IndexOutOfBoundsException as needed

void clear()
remove all elements from the list

boolean isEmpty()
determine if the list is empty

int size()
return the number of elements being stored

ListIterator<T> listIterator()
Iterator<T> iterator()
have these factory methods return your ListIterator class for the current list.

Programming hints

Testing your List

You should be able to re-use the tests you wrote in Lab 1 for MyArrayList. Just make changes similar to

    MyLinkedList<String> x = new MyLinkedList<String>();

Testing your Iterator

You'll want to test your ListIterator and be sure that it works properly. As a partial test, you should create a JUnit test that will perform the Sieve of Eratosthenes. In case you've not encountered this before, the "sieve" is used to determine prime numbers. The basic idea is that you initially list all of the integers in the range as potential prime numbers, then go through the possible factors one-by-one (starting from 2) and cross out any value on your list that is a multiple of it (but not the number itself).

So assuming you have the numbers from 2-10, you'd first go through and cross out the multiples of 2 other than itself (4,6,8,10) and then multiples of 3 other than itself (9, since the 6 is already gone), etc. You should stop when you reach the square root of the larger range end. What you're left with should be all the primes in the given range.

For example, the Sieve of [11,20] would return 11, 13, 17, and 19, and the Sieve of [1,20] would return 2, 3, 5, 7, 11, 13, 17, and 19.

For your JUnit test, create a few methods that perform the Sieve using the incorporated ListIterator, on a variety of ranges.

Part 2 - Windows Manager

Now that you have your working doubly linked list (and associated iterator), we can start talking about the Windows manager and the starter files.

Program Structure

A WindowsManager object is a "monitor" that maintains a list of rectangular windows displayed within it. It may contain any number of windows, and they may overlap; overlapping windows form a sort of stack, stored in a WindowList object that you will write.

Windows respond to mouse clicks; the clicked-on window moves to the top of the "stack".

Each Window may contain coloured squares, stored in a SquareList object that you will write. One may draw a square in a window by clicking in the window somewhere that's not already occupied by a square. One may remove a square from a window by clicking on the square. Thus each window is associated with a list of squares to be drawn in the window. The squares in the window are drawn (in any order) when the window is drawn. All squares in a window are drawn in the same colour, a colour associated with the window (thus different windows may be associated with different colours.)

Each Square is a square of a given colour. It draws itself using a paint method, which is called when a window changes or is moved in the list.

Starter files

Window.java -- This class represents a single window. You do not need to modify the Window class.

Square.java -- This class represents a single square that is drawn in a window. You do not need to modify the Square class.

Squares are normally 20 pixels wide and 20 pixels high. However, they may be smaller if near the border of a window, since they do not extend beyond the window that contains them. Thus when a square is created, its dimensions are reduced if necessary to make it fit within the window.

WindowsManager.java -- This class keeps track of all the windows, and takes care of displaying them. Its paint method is called when a window changes or when a window is exposed by moving another window from in front of it. It asks its WindowsList for windows, starting with the bottom window and ending with the top, and calls each window's paint method. Windows in turn call the paint method for its squares.

Clicking any of the mouse buttons in a window should do the following:

In either case, the window is redrawn.

You do not need to modify the WindowsManager class.

WindowsManagerTester.java -- This is a test file to run the program with a specific set of windows and colours. You will want to modify this file when you add more tests to your program.


Your job is to implement the following two classes:

WindowList.java

This represents a list of windows on the monitor. Your class should store your list of windows as a (surprise, surprise) linked list -- your MyLinkedList, in fact. Implement the following public methods.

public WindowList()
construct an empty list of windows
void add(Window w)
add a window to the "top" of the stack of windows. You can choose whether the "top" is at the front or back of your list, just use it consistently.
Iterator<Window> windows()
return an iterator that returns windows in bottom-to-top sequence.
void handleClick( int x, int y )
This method is called when the mouse has been clicked at position (x,y). It should find the top window on the stack (if any) that contains the given coordinate, and move that window to the top of the stack without disturbing the order of the other windows. Then tell the moved window to handle the click. If none of the windows on the stack were clicked on, just return.

SquareList.java

This represents a list of squares on a given window. Your class should store your list of squares as a linked list. Implement the following public methods.

public SquareList()
construct an empty list of squares
void add(Square sq)
add a square to the list
boolean handleClick( int x, int y )
delete all squares from the list that contain the position (x,y). Return true if any squares get deleted and return false otherwise.
Iterator<Square> elements()
return an iterator of the squares in the list.

You may add private data or methods to WindowList and SquareList, but you are not to change the public interface. Also make no changes to WindowsManager, Square, or Window.

Testing

Now you should be able to run the WindowsManagerTester class as a Java application, and click away. You should add more comprehensive tests to WindowsManagerTester; calls to the WindowsManager simulateClick method provide a way to automate the testing.

Part 3 - Written Work

Include in your submission a file named README. The contents of the README file should include the following:

  1. Your name (and your partner's name, if you have one.)
  2. Any known problems or assumptions made in your classes or programs.
  3. Estimates of the running time of the operations performed on your WindowList and SquareList objects. Assume for these estimates that the WindowsManager contains n windows. Then give, and briefly justify, a big-Oh estimate for the time your program requires for each of the following
    • finding the clicked-on window, assuming it's the kth window down from the top of the stack;
    • moving that window to the top of the stack;
    • determining which squares were clicked on, assuming that there are m squares in the window;
    • creating an (m+1)st square for the window;
    • removing j clicked-on squares from among the m in the window.
  4. An annotated listing of your WindowsManagerTester file, indicating for each test what evidence it provides for the correctness of your program. An example annotation would be something like "deleting from start of list" or "adding a square to an empty list".

handin

Look through your programs and make sure you've included your name at the top of all of them.

Honor code

If you adhered to the honor code in this assignment, add the following statement to your README file:

I have adhered to the Honor Code in this assignment.

handin

You now just need to electronically handin all your files. Assignment is 4.

Don't forget to run lshand and verify that things were submitted.


Thanks to Nifty Assignments for the base of this lab.