Lab 3: OO Review and Intro

The goal of this lab is to practice object-oriented design on a problem that will help you review the object-oriented features of Java and prepare for an exploration of object-oriented design techniques. A second purpose of this lab is to practice using subversion.

1. Introduction

Object-oriented design is concerned with the relationship among classes and other types--- which classes implement which interfaces, which classes serve as components to other classes (by means of instance variables), and (as we will learn about soon) which classes share code by inheritance or composition.

You will practice doing object-oriented design (and think about how revision control works) by designing your own simple revision control system. You will write a program that presents the user with a simple text area to edit. The user can "commit" changes made to the text area; these changes are saved in memory and assigned a version number; and the user can then go back to them later.

The user interface is a window that looks like this:

The "current" and "max" indicator at the top should display the version number of the currently displayed version (besides any changes that have been made since the last commit or recall) and the highest version number that has been assigned, respectively. When the program starts up, these should read "Current: 0" and "Max: 0", not "Current" and "Max" as the image shows.

When the user enters some text and then presses the "commit" button, the current and max counters should increment. Suppose the user then enters more text and presses "commit" again. If the user then presses the "<" button, the text should then revert to its state when the "commit" button was pressed the first time. Pressing the ">" button will change the text to what it was when "commit" was pressed the second time. In this way the user can shuffle though versions. Pressing "<" when the current indicator is 0 does nothing, and pressing ">" when the current indicator is equal to the max does nothing.

That specification would be adequate (and the problem very easy) if all the revisions were made in a linear fashion, and the user commited changes made only on the latest version-- in which case we would have an organization like

But what should happen if the user flips back to an earlier version, makes changes, and commits? Should the new version simply be put at the end of the chain, even though it does not descend from the latest version? Should the new version replace the version that used to come after the version that was edited, and the rest of the chain be lost?

Instead of the two options mentioned, your program should consider the series of versions to branch at this point. The new version will receive the next verions number (ie, the max version plus one), but instead of conceptually coming after the most recent version, it will be considered to branch off from the version it was derived from.

Suppose the user takes the collection of versions illustrated above, and then navigates back to version 3, makes a change, and commits (creating version 6). Then he or she makes another change (to the new version 6) and commits it as version 7. Then he or she navigates to 4, changes and commits, navigates back to 6 and makes to changes in a row, and navigates to version 5 to make and commit a final change. That would result in the following tree of versions.

At this point, your version navigation feature should work as follows: When at version 6, pressing the "<" button will bring up version 3, the parent. Pressing ">" (at version 6) would bring up verion 9, the most recent decendant. To move among "sibling" versions, the user would use the "-" button; so, pressing the "-" button at version 6 would bring up version 4, and pressing "-" again would bring back version 6. If there are more than two siblings, the "-" should move from the most recent to the oldest, in a circular manner.

2. Set up

After making a new directory for this lab, use subversion to checkout code for this project.

svn checkout file:///cslab.all/ubuntu/cs245/general/#####/lab3

where ###### is cs245a, cs245b, cs245c, or cs245d.

3. Inspecting the code

You will find four sets of classes:

Look at the file VCWindow.java. This interface describes how to interact with the window that the user sees. ConcreteVCWindow is a class that implements this interface, and it has a no-parameter constructor. ConcreteVCWindow$SuperButton is a helper class. I have not given you the source code for these, because you won't need them.

Look at the file VersionControl. You'll see it has a main method which makes a new window and a new controller. It also creates action listeners for the buttons.

Look at one of the action listener classes (they're all about the same). You'll see they simply call an appropriate method on the controller object.

Finally, look at Controller.java. This is a class you will modify. This defines the object that needs to keep track of the various versions and update the window appropriately.

Compile and run Controller.java. You'll see a window appears on the screen, and you can type in it, but nothing happens when you click on the buttons. You'll be implementing the features of the buttons as you go along.

4. Step 1: The commit feature

The first feature you will implement in the system is the ability to commit a version. When the user clicks the commit button, the text currently on the textfield should be stored (in computer memory; we won't be doing file I/O in this lab), that version should be given a new version number, and the "max" and "current" version indicators should be incremented.

Write a class to represent versions of the text. Think about what information would need to be stored in a version object, and write a constructor. Don't worry about methods yet, you'll write those as we go along.

Controller will need an instance variable to refer to the current version and it will need a counter to keep track of the latest version number. Finally, fill in the commit() method in Controller so that it makes a new version and updates the indicators on the window.

Test to make sure this is working before moving on.

5. Step 2: The "previous" feature

Now that the program has the ability to label the versions, we want to be able to retrieve an earlier version. Pressing the "previous" button should bring back the version that the current version was based on.

What information should your version class have in order for that to be retrieved? What method would the class need so that the controller can retrieve the previous version?

Implement this change in your version class and in the previous() method in Controller.java. Make sure all the instance variables of your version class are private.

If the user tries to move to the "previous" version of version 1, nothing should happen (but the program shouldn't crash). Also, make sure that if the user navigates to an older version, edits, and commits, that the new version is given the next version number and is hooked properly into the chain of versions. At this point in development, it's ok if the later versions get lost; you'll fix that in the next step 4.

Test this feature before moving on.

6. Step 3: The "next" feature

Now update your version class and fill in the next() method of Controller so that we can move to the next version.

7. Step 4: The "parallel" feature

Now update the program so that if someone edits and commits based on an earlier version, the later versions are no longer lost, and the "-" button can be used to navigate among siblings, as described above.

8. Time permitting: Step 5: The "go to" feature

Update the program so that the user can jump directly to a version by giving its number.

4. To turn in

You will submit your lab this week using subversion. First, add the file you wrote so that svn is aware of it.

svn add Version.java

(Or replace Version.java with whatever your version class is called.)

svn commit

You do not need to turn in a hard copy.


Thomas VanDrunen
Last modified: Tue Jan 27 10:35:00 CST 2009