committing everything FIRST POST
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.SimpleDrawingApp"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0" >
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="7" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:icon="@drawable/ic_launcher"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
<activity
|
||||||
|
android:name=".SimpleDrawingAppActivity"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
|
@ -0,0 +1 @@
|
||||||
|
This is a very simple drawing app that just displays a square everywhere you drag your finger. That's it.
|
|
@ -0,0 +1,3 @@
|
||||||
|
# cache for current jar dependecy. DO NOT EDIT.
|
||||||
|
# format is <lastModified> <length> <SHA-1> <path>
|
||||||
|
# Encoding is UTF-8
|
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,6 @@
|
||||||
|
/** Automatically generated file. DO NOT MODIFY */
|
||||||
|
package com.SimpleDrawingApp;
|
||||||
|
|
||||||
|
public final class BuildConfig {
|
||||||
|
public final static boolean DEBUG = true;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* AUTO-GENERATED FILE. DO NOT MODIFY.
|
||||||
|
*
|
||||||
|
* This class was automatically generated by the
|
||||||
|
* aapt tool from the resource data it found. It
|
||||||
|
* should not be modified by hand.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.SimpleDrawingApp;
|
||||||
|
|
||||||
|
public final class R {
|
||||||
|
public static final class attr {
|
||||||
|
}
|
||||||
|
public static final class drawable {
|
||||||
|
public static final int ic_launcher=0x7f020000;
|
||||||
|
}
|
||||||
|
public static final class layout {
|
||||||
|
public static final int main=0x7f030000;
|
||||||
|
}
|
||||||
|
public static final class string {
|
||||||
|
public static final int app_name=0x7f040001;
|
||||||
|
public static final int hello=0x7f040000;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
# To enable ProGuard in your project, edit project.properties
|
||||||
|
# to define the proguard.config property as described in that file.
|
||||||
|
#
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# By default, the flags in this file are appended to flags specified
|
||||||
|
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||||
|
# You can edit the include path and order by changing the ProGuard
|
||||||
|
# include property in project.properties.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# Add any project specific keep options here:
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
|
@ -0,0 +1,14 @@
|
||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system edit
|
||||||
|
# "ant.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
#
|
||||||
|
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||||
|
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||||
|
|
||||||
|
# Project target.
|
||||||
|
target=android-7
|
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/hello" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<string name="hello">Hello World, SimpleDrawingAppActivity!</string>
|
||||||
|
<string name="app_name">SimpleDrawingApp</string>
|
||||||
|
|
||||||
|
</resources>
|
|
@ -0,0 +1,94 @@
|
||||||
|
package com.SimpleDrawingApp;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
//import android.content.Intent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
//import android.view.View;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.opengl.GLSurfaceView;
|
||||||
|
//import android.widget.EditText;
|
||||||
|
|
||||||
|
public class SimpleDrawingAppActivity extends Activity {
|
||||||
|
/** Called when the activity is first created. */
|
||||||
|
public final static String EXTRA_MESSAGE = "firstApp.main.MESSAGE";
|
||||||
|
private GLSurfaceView mGLView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
// setContentView(R.layout.main);
|
||||||
|
mGLView = new FirstAppSurfaceView(this);
|
||||||
|
setContentView(mGLView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
mGLView.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
mGLView.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*public void sendMessage(View view) {
|
||||||
|
Intent intent = new Intent(this, DisplayMessageActivity.class);
|
||||||
|
EditText editText = (EditText) findViewById(R.id.edit_message);
|
||||||
|
String message = editText.getText().toString();
|
||||||
|
intent.putExtra(EXTRA_MESSAGE, message);
|
||||||
|
startActivity(intent);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
class FirstAppSurfaceView extends GLSurfaceView {
|
||||||
|
private final float X_SCALE_FACTOR = 1f / (240); // determined through trial
|
||||||
|
// and error
|
||||||
|
private final float Y_SCALE_FACTOR = 1f / (240);
|
||||||
|
private SimpleDrawingAppRenderer mRenderer;
|
||||||
|
private float mPreviousX;
|
||||||
|
private float mPreviousY;
|
||||||
|
|
||||||
|
public FirstAppSurfaceView(Context context) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
mRenderer = new SimpleDrawingAppRenderer();
|
||||||
|
setRenderer(mRenderer);
|
||||||
|
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent e) {
|
||||||
|
float x = e.getX();
|
||||||
|
float y = e.getY();
|
||||||
|
|
||||||
|
float dx = 0;
|
||||||
|
float dy = 0;
|
||||||
|
|
||||||
|
switch (e.getAction()) {
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
dx = x - mPreviousX;
|
||||||
|
dx *= -1;
|
||||||
|
mRenderer.xPosition = x*X_SCALE_FACTOR*-1 + 1;
|
||||||
|
mRenderer.dx = dx*X_SCALE_FACTOR;
|
||||||
|
|
||||||
|
dy = y - mPreviousY;
|
||||||
|
dy *= -1;
|
||||||
|
mRenderer.yPosition = y*Y_SCALE_FACTOR*-1 + 1.6f;
|
||||||
|
mRenderer.dy = dy * Y_SCALE_FACTOR;
|
||||||
|
|
||||||
|
Square s = new Square(x*X_SCALE_FACTOR*-1 + .975f, y*Y_SCALE_FACTOR*-1 + 1.5f);
|
||||||
|
mRenderer.squareList.insertBack(s);
|
||||||
|
|
||||||
|
requestRender();
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mPreviousX = x;
|
||||||
|
mPreviousY = y;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package com.SimpleDrawingApp;
|
||||||
|
|
||||||
|
import javax.microedition.khronos.egl.EGLConfig;
|
||||||
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
|
import android.opengl.GLSurfaceView;
|
||||||
|
import android.opengl.GLU;
|
||||||
|
|
||||||
|
import com.SimpleDrawingApp.list.*;
|
||||||
|
|
||||||
|
public class SimpleDrawingAppRenderer implements GLSurfaceView.Renderer {
|
||||||
|
public DList squareList = new DList();
|
||||||
|
public float xPosition, dx;
|
||||||
|
public float yPosition, dy;
|
||||||
|
|
||||||
|
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
|
||||||
|
gl.glClearColor(0f, 0f, 0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDrawFrame(GL10 gl) {
|
||||||
|
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
|
||||||
|
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||||
|
gl.glLoadIdentity();
|
||||||
|
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ListNode currentNode = squareList.front();
|
||||||
|
while(currentNode.isValidNode()) {
|
||||||
|
Square s = (Square)currentNode.item();
|
||||||
|
s.Draw(gl);
|
||||||
|
|
||||||
|
currentNode = currentNode.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidNodeException e) {
|
||||||
|
System.err.println(e + "in onDrawFrame");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSurfaceChanged(GL10 gl, int width, int height) {
|
||||||
|
gl.glViewport(0, 0, width, height);
|
||||||
|
|
||||||
|
float ratio = (float) width / height;
|
||||||
|
gl.glMatrixMode(GL10.GL_PROJECTION); // set matrix to projection mode
|
||||||
|
gl.glLoadIdentity(); // reset the matrix to its default state
|
||||||
|
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // apply the projection
|
||||||
|
// matrix
|
||||||
|
|
||||||
|
initShapes();
|
||||||
|
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initShapes() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package com.SimpleDrawingApp;
|
||||||
|
|
||||||
|
import java.nio.*;
|
||||||
|
|
||||||
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
|
||||||
|
class Square {
|
||||||
|
|
||||||
|
private FloatBuffer squareVB, squareVB2;
|
||||||
|
|
||||||
|
static float squareCoords[] = { -0.1f, 0.1f, 0.0f, // top left
|
||||||
|
-0.1f, -0.1f, 0.0f, // bottom left
|
||||||
|
0.1f, -0.1f, 0.0f}; // bottom right
|
||||||
|
|
||||||
|
static float square2Coords[] = { -0.1f, 0.1f, 0.0f, // top left
|
||||||
|
0.1f, -0.1f, 0.0f, // bottom right
|
||||||
|
0.1f, 0.1f, 0.0f }; // top right
|
||||||
|
private float x,y;
|
||||||
|
|
||||||
|
public Square() {
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
|
||||||
|
ByteBuffer vbb = ByteBuffer.allocateDirect(squareCoords.length * 4);
|
||||||
|
vbb.order(ByteOrder.nativeOrder());
|
||||||
|
squareVB = vbb.asFloatBuffer();
|
||||||
|
squareVB.put(squareCoords);
|
||||||
|
squareVB.position(0);
|
||||||
|
|
||||||
|
ByteBuffer vbb2 = ByteBuffer.allocateDirect(square2Coords.length * 4);
|
||||||
|
vbb2.order(ByteOrder.nativeOrder());
|
||||||
|
squareVB2 = vbb2.asFloatBuffer();
|
||||||
|
squareVB2.put(square2Coords);
|
||||||
|
squareVB2.position(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Square(float x, float y) {
|
||||||
|
this();
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(GL10 gl) {
|
||||||
|
gl.glPushMatrix();
|
||||||
|
gl.glTranslatef(this.x,this.y,0);
|
||||||
|
gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, squareVB);
|
||||||
|
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
|
||||||
|
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, squareVB2);
|
||||||
|
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
|
||||||
|
gl.glPopMatrix();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,280 @@
|
||||||
|
/* DList.java */
|
||||||
|
|
||||||
|
package com.SimpleDrawingApp.list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DList is a mutable doubly-linked list ADT. Its implementation is
|
||||||
|
* circularly-linked and employs a sentinel node at the head of the list.
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE ANY METHOD PROTOTYPES IN THIS FILE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
public class DList extends List {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (inherited) size is the number of items in the list.
|
||||||
|
* head references the sentinel node.
|
||||||
|
* Note that the sentinel node does not store an item, and is not included
|
||||||
|
* in the count stored by the "size" field.
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THE FOLLOWING FIELD DECLARATION.
|
||||||
|
**/
|
||||||
|
|
||||||
|
protected DListNode head;
|
||||||
|
|
||||||
|
/* DList invariants:
|
||||||
|
* 1) head != null.
|
||||||
|
* 2) For every DListNode x in a DList, x.next != null.
|
||||||
|
* 3) For every DListNode x in a DList, x.prev != null.
|
||||||
|
* 4) For every DListNode x in a DList, if x.next == y, then y.prev == x.
|
||||||
|
* 5) For every DListNode x in a DList, if x.prev == y, then y.next == x.
|
||||||
|
* 6) For every DList l, l.head.myList = null. (Note that l.head is the
|
||||||
|
* sentinel.)
|
||||||
|
* 7) For every DListNode x in a DList l EXCEPT l.head (the sentinel),
|
||||||
|
* x.myList = l.
|
||||||
|
* 8) size is the number of DListNodes, NOT COUNTING the sentinel,
|
||||||
|
* that can be accessed from the sentinel (head) by a sequence of
|
||||||
|
* "next" references.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* newNode() calls the DListNode constructor. Use this method to allocate
|
||||||
|
* new DListNodes rather than calling the DListNode constructor directly.
|
||||||
|
* That way, only this method need be overridden if a subclass of DList
|
||||||
|
* wants to use a different kind of node.
|
||||||
|
*
|
||||||
|
* @param item the item to store in the node.
|
||||||
|
* @param list the list that owns this node. (null for sentinels.)
|
||||||
|
* @param prev the node previous to this node.
|
||||||
|
* @param next the node following this node.
|
||||||
|
**/
|
||||||
|
protected DListNode newNode(Object item, DList list,
|
||||||
|
DListNode prev, DListNode next) {
|
||||||
|
return new DListNode(item, list, prev, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DList() constructs for an empty DList.
|
||||||
|
**/
|
||||||
|
public DList() {
|
||||||
|
// Your solution here. Similar to Homework 4, but now you need to specify
|
||||||
|
// the `list' field (second parameter) as well.
|
||||||
|
head = newNode(null,this,null,null);
|
||||||
|
head.next = head;
|
||||||
|
head.prev = head;
|
||||||
|
head.myList = null; //not a valid node
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertFront() inserts an item at the front of this DList.
|
||||||
|
*
|
||||||
|
* @param item is the item to be inserted.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
**/
|
||||||
|
public void insertFront(Object item) {
|
||||||
|
// Your solution here. Similar to Homework 4, but now you need to specify
|
||||||
|
// the `list' field (second parameter) as well.
|
||||||
|
DListNode newNode = newNode(item,this,head,head.next);
|
||||||
|
head.next = newNode;
|
||||||
|
newNode.next.prev = newNode;
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertBack() inserts an item at the back of this DList.
|
||||||
|
*
|
||||||
|
* @param item is the item to be inserted.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
**/
|
||||||
|
public void insertBack(Object item) {
|
||||||
|
// Your solution here. Similar to Homework 4, but now you need to specify
|
||||||
|
// the `list' field (second parameter) as well.
|
||||||
|
DListNode newNode = newNode(item,this,head.prev,head);
|
||||||
|
head.prev = newNode;
|
||||||
|
newNode.prev.next = newNode;
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* front() returns the node at the front of this DList. If the DList is
|
||||||
|
* empty, return an "invalid" node--a node with the property that any
|
||||||
|
* attempt to use it will cause an exception. (The sentinel is "invalid".)
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THIS METHOD.
|
||||||
|
*
|
||||||
|
* @return a ListNode at the front of this DList.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public ListNode front() {
|
||||||
|
return head.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* back() returns the node at the back of this DList. If the DList is
|
||||||
|
* empty, return an "invalid" node--a node with the property that any
|
||||||
|
* attempt to use it will cause an exception. (The sentinel is "invalid".)
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THIS METHOD.
|
||||||
|
*
|
||||||
|
* @return a ListNode at the back of this DList.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public ListNode back() {
|
||||||
|
return head.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
//added by me, not from class
|
||||||
|
public void concat(List s) {
|
||||||
|
ListNode currentNode = s.front();
|
||||||
|
try {
|
||||||
|
while(currentNode.isValidNode()) {
|
||||||
|
this.insertBack(currentNode.item());
|
||||||
|
currentNode = currentNode.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(InvalidNodeException e) {
|
||||||
|
System.err.println(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toString() returns a String representation of this DList.
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THIS METHOD.
|
||||||
|
*
|
||||||
|
* @return a String representation of this DList.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(n) time, where n is the length of the list.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
String result = "[ ";
|
||||||
|
DListNode current = head.next;
|
||||||
|
while (current != head) {
|
||||||
|
result = result + current.item + " ";
|
||||||
|
current = current.next;
|
||||||
|
}
|
||||||
|
return result + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testInvalidNode(ListNode p) {
|
||||||
|
System.out.println("p.isValidNode() should be false: " + p.isValidNode());
|
||||||
|
try {
|
||||||
|
p.item();
|
||||||
|
System.out.println("p.item() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.item() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.setItem(new Integer(0));
|
||||||
|
System.out.println("p.setItem() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.setItem() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.next();
|
||||||
|
System.out.println("p.next() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.next() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.prev();
|
||||||
|
System.out.println("p.prev() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.prev() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.insertBefore(new Integer(1));
|
||||||
|
System.out.println("p.insertBefore() should throw an exception, but " +
|
||||||
|
"didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.insertBefore() should throw an exception, and did."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.insertAfter(new Integer(1));
|
||||||
|
System.out.println("p.insertAfter() should throw an exception, but " +
|
||||||
|
"didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.insertAfter() should throw an exception, and did."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.remove();
|
||||||
|
System.out.println("p.remove() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.remove() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testEmpty() {
|
||||||
|
List l = new DList();
|
||||||
|
System.out.println("An empty list should be [ ]: " + l);
|
||||||
|
System.out.println("l.isEmpty() should be true: " + l.isEmpty());
|
||||||
|
System.out.println("l.length() should be 0: " + l.length());
|
||||||
|
System.out.println("Finding front node p of l.");
|
||||||
|
ListNode p = l.front();
|
||||||
|
testInvalidNode(p);
|
||||||
|
System.out.println("Finding back node p of l.");
|
||||||
|
p = l.back();
|
||||||
|
testInvalidNode(p);
|
||||||
|
l.insertFront(new Integer(10));
|
||||||
|
System.out.println("l after insertFront(10) should be [ 10 ]: " + l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] argv) {
|
||||||
|
testEmpty();
|
||||||
|
List l = new DList();
|
||||||
|
l.insertFront(new Integer(3));
|
||||||
|
l.insertFront(new Integer(2));
|
||||||
|
l.insertFront(new Integer(1));
|
||||||
|
System.out.println("l is a list of 3 elements: " + l);
|
||||||
|
try {
|
||||||
|
ListNode n;
|
||||||
|
int i = 1;
|
||||||
|
for (n = l.front(); n.isValidNode(); n = n.next()) {
|
||||||
|
System.out.println("n.item() should be " + i + ": " + n.item());
|
||||||
|
n.setItem(new Integer(((Integer) n.item()).intValue() * 2));
|
||||||
|
System.out.println("n.item() should be " + 2 * i + ": " + n.item());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
System.out.println("After doubling all elements of l: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
|
||||||
|
i = 6;
|
||||||
|
for (n = l.back(); n.isValidNode(); n = n.prev()) {
|
||||||
|
System.out.println("n.item() should be " + i + ": " + n.item());
|
||||||
|
n.setItem(new Integer(((Integer) n.item()).intValue() * 2));
|
||||||
|
System.out.println("n.item() should be " + 2 * i + ": " + n.item());
|
||||||
|
i = i - 2;
|
||||||
|
}
|
||||||
|
System.out.println("After doubling all elements of l again: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
|
||||||
|
n = l.front().next();
|
||||||
|
System.out.println("Removing middle element (8) of l: " + n.item());
|
||||||
|
n.remove();
|
||||||
|
System.out.println("l is now: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
n = l.back();
|
||||||
|
System.out.println("Removing end element (12) of l: " + n.item());
|
||||||
|
n.remove();
|
||||||
|
System.out.println("l is now: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
|
||||||
|
n = l.front();
|
||||||
|
System.out.println("Removing first element (4) of l: " + n.item());
|
||||||
|
n.remove();
|
||||||
|
System.out.println("l is now: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.err.println ("Caught InvalidNodeException that should not happen."
|
||||||
|
);
|
||||||
|
System.err.println ("Aborting the testing code.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
/* DListNode.java */
|
||||||
|
|
||||||
|
package com.SimpleDrawingApp.list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A DListNode is a mutable node in a DList (doubly-linked list).
|
||||||
|
**/
|
||||||
|
|
||||||
|
public class DListNode extends ListNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (inherited) item references the item stored in the current node.
|
||||||
|
* (inherited) myList references the List that contains this node.
|
||||||
|
* prev references the previous node in the DList.
|
||||||
|
* next references the next node in the DList.
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS.
|
||||||
|
**/
|
||||||
|
|
||||||
|
protected DListNode prev;
|
||||||
|
protected DListNode next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DListNode() constructor.
|
||||||
|
* @param i the item to store in the node.
|
||||||
|
* @param l the list this node is in.
|
||||||
|
* @param p the node previous to this node.
|
||||||
|
* @param n the node following this node.
|
||||||
|
*/
|
||||||
|
DListNode(Object i, DList l, DListNode p, DListNode n) {
|
||||||
|
item = i;
|
||||||
|
myList = l;
|
||||||
|
prev = p;
|
||||||
|
next = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* isValidNode returns true if this node is valid; false otherwise.
|
||||||
|
* An invalid node is represented by a `myList' field with the value null.
|
||||||
|
* Sentinel nodes are invalid, and nodes that don't belong to a list are
|
||||||
|
* also invalid.
|
||||||
|
*
|
||||||
|
* @return true if this node is valid; false otherwise.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public boolean isValidNode() {
|
||||||
|
return myList != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* next() returns the node following this node. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @return the node following this node.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public ListNode next() throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("next() called on invalid node");
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prev() returns the node preceding this node. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @param node the node whose predecessor is sought.
|
||||||
|
* @return the node preceding this node.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public ListNode prev() throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("prev() called on invalid node");
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertAfter() inserts an item immediately following this node. If this
|
||||||
|
* node is invalid, throws an exception.
|
||||||
|
*
|
||||||
|
* @param item the item to be inserted.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public void insertAfter(Object item) throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("insertAfter() called on invalid node");
|
||||||
|
}
|
||||||
|
// Your solution here. Will look something like your Homework 4 solution,
|
||||||
|
// but changes are necessary. For instance, there is no need to check if
|
||||||
|
// "this" is null. Remember that this node's "myList" field tells you
|
||||||
|
// what DList it's in. You should use myList.newNode() to create the
|
||||||
|
// new node.
|
||||||
|
DListNode newNode = ((DList)myList).newNode(item,(DList)myList,this,this.next);
|
||||||
|
this.next.prev = newNode;
|
||||||
|
this.next = newNode;
|
||||||
|
myList.size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertBefore() inserts an item immediately preceding this node. If this
|
||||||
|
* node is invalid, throws an exception.
|
||||||
|
*
|
||||||
|
* @param item the item to be inserted.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public void insertBefore(Object item) throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("insertBefore() called on invalid node");
|
||||||
|
}
|
||||||
|
// Your solution here. Will look something like your Homework 4 solution,
|
||||||
|
// but changes are necessary. For instance, there is no need to check if
|
||||||
|
// "this" is null. Remember that this node's "myList" field tells you
|
||||||
|
// what DList it's in. You should use myList.newNode() to create the
|
||||||
|
// new node.
|
||||||
|
DListNode newNode = ((DList)myList).newNode(item,(DList)myList,this.prev,this);
|
||||||
|
this.prev.next = newNode;
|
||||||
|
this.prev = newNode;
|
||||||
|
myList.size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove() removes this node from its DList. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public void remove() throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("remove() called on invalid node");
|
||||||
|
}
|
||||||
|
// Your solution here. Will look something like your Homework 4 solution,
|
||||||
|
// but changes are necessary. For instance, there is no need to check if
|
||||||
|
// "this" is null. Remember that this node's "myList" field tells you
|
||||||
|
// what DList it's in.
|
||||||
|
this.prev.next = this.next;
|
||||||
|
this.next.prev = this.prev;
|
||||||
|
myList.size--;
|
||||||
|
|
||||||
|
|
||||||
|
// Make this node an invalid node, so it cannot be used to corrupt myList.
|
||||||
|
myList = null;
|
||||||
|
// Set other references to null to improve garbage collection.
|
||||||
|
next = null;
|
||||||
|
prev = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* InvalidNodeException.java */
|
||||||
|
|
||||||
|
package com.SimpleDrawingApp.list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements an Exception that signals an attempt to use an invalid ListNode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class InvalidNodeException extends Exception {
|
||||||
|
private static final long serialVersionUID = 1L; //eclipse complained...
|
||||||
|
|
||||||
|
protected InvalidNodeException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InvalidNodeException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/* List.java */
|
||||||
|
|
||||||
|
package com.SimpleDrawingApp.list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A List is a mutable list ADT. No implementation is provided.
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THIS FILE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
public abstract class List {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* size is the number of items in the list.
|
||||||
|
**/
|
||||||
|
|
||||||
|
protected int size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* isEmpty() returns true if this List is empty, false otherwise.
|
||||||
|
*
|
||||||
|
* @return true if this List is empty, false otherwise.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
**/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* length() returns the length of this List.
|
||||||
|
*
|
||||||
|
* @return the length of this List.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
**/
|
||||||
|
public int length() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertFront() inserts an item at the front of this List.
|
||||||
|
*
|
||||||
|
* @param item is the item to be inserted.
|
||||||
|
**/
|
||||||
|
public abstract void insertFront(Object item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertBack() inserts an item at the back of this List.
|
||||||
|
*
|
||||||
|
* @param item is the item to be inserted.
|
||||||
|
**/
|
||||||
|
public abstract void insertBack(Object item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* front() returns the node at the front of this List. If the List is
|
||||||
|
* empty, return an "invalid" node--a node with the property that any
|
||||||
|
* attempt to use it will cause an exception.
|
||||||
|
*
|
||||||
|
* @return a ListNode at the front of this List.
|
||||||
|
*/
|
||||||
|
public abstract ListNode front();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* back() returns the node at the back of this List. If the List is
|
||||||
|
* empty, return an "invalid" node--a node with the property that any
|
||||||
|
* attempt to use it will cause an exception.
|
||||||
|
*
|
||||||
|
* @return a ListNode at the back of this List.
|
||||||
|
*/
|
||||||
|
public abstract ListNode back();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toString() returns a String representation of this List.
|
||||||
|
*
|
||||||
|
* @return a String representation of this List.
|
||||||
|
*/
|
||||||
|
public abstract String toString();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/* ListNode.java */
|
||||||
|
|
||||||
|
package com.SimpleDrawingApp.list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ListNode is a mutable node in a list. No implementation is provided.
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THIS FILE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
public abstract class ListNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* item references the item stored in the current node.
|
||||||
|
* myList references the List that contains this node.
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected Object item;
|
||||||
|
protected List myList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* isValidNode returns true if this node is valid; false otherwise.
|
||||||
|
* By default, an invalid node is one that doesn't belong to a list (myList
|
||||||
|
* is null), but subclasses can override this definition.
|
||||||
|
*
|
||||||
|
* @return true if this node is valid; false otherwise.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public boolean isValidNode() {
|
||||||
|
return myList != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* item() returns this node's item. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @return the item stored in this node.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public Object item() throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException();
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setItem() sets this node's item to "item". If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public void setItem(Object item) throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException();
|
||||||
|
}
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* next() returns the node following this node. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @return the node following this node.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*/
|
||||||
|
public abstract ListNode next() throws InvalidNodeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prev() returns the node preceding this node. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @param node the node whose predecessor is sought.
|
||||||
|
* @return the node preceding this node.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*/
|
||||||
|
public abstract ListNode prev() throws InvalidNodeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertAfter() inserts an item immediately following this node. If this
|
||||||
|
* node is invalid, throws an exception.
|
||||||
|
*
|
||||||
|
* @param item the item to be inserted.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*/
|
||||||
|
public abstract void insertAfter(Object item) throws InvalidNodeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertBefore() inserts an item immediately preceding this node. If this
|
||||||
|
* node is invalid, throws an exception.
|
||||||
|
*
|
||||||
|
* @param item the item to be inserted.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*/
|
||||||
|
public abstract void insertBefore(Object item) throws InvalidNodeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove() removes this node from its List. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*/
|
||||||
|
public abstract void remove() throws InvalidNodeException;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,261 @@
|
||||||
|
/* SList.java */
|
||||||
|
|
||||||
|
package com.SimpleDrawingApp.list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A SList is a mutable singly-linked list ADT. Its implementation employs
|
||||||
|
* a tail reference.
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THIS FILE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
public class SList extends List {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (inherited) size is the number of items in the list.
|
||||||
|
* head references the first node.
|
||||||
|
* tail references the last node.
|
||||||
|
**/
|
||||||
|
|
||||||
|
protected SListNode head;
|
||||||
|
protected SListNode tail;
|
||||||
|
|
||||||
|
/* SList invariants:
|
||||||
|
* 1) Either head == null and tail == null, or tail.next == null and the
|
||||||
|
* SListNode referenced by tail can be reached from the head by a
|
||||||
|
* sequence of zero or more "next" references. This implies that the
|
||||||
|
* list is not circularly linked.
|
||||||
|
* 2) The "size" field is the number of SListNodes that can be accessed
|
||||||
|
* from head (including head itself) by a sequence of "next" references.
|
||||||
|
* 3) For every SListNode x in an SList l, x.myList = l.
|
||||||
|
**/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* newNode() calls the SListNode constructor. Use this method to allocate
|
||||||
|
* new SListNodes rather than calling the SListNode constructor directly.
|
||||||
|
* That way, only this method need be overridden if a subclass of SList
|
||||||
|
* wants to use a different kind of node.
|
||||||
|
*
|
||||||
|
* @param item the item to store in the node.
|
||||||
|
* @param next the node following this node.
|
||||||
|
**/
|
||||||
|
protected SListNode newNode(Object item, SListNode next) {
|
||||||
|
return new SListNode(item, this, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SList() constructs for an empty SList.
|
||||||
|
**/
|
||||||
|
public SList() {
|
||||||
|
head = null;
|
||||||
|
tail = null;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertFront() inserts an item at the front of this SList.
|
||||||
|
*
|
||||||
|
* @param item is the item to be inserted.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
**/
|
||||||
|
public void insertFront(Object item) {
|
||||||
|
head = newNode(item, head);
|
||||||
|
if (size == 0) {
|
||||||
|
tail = head;
|
||||||
|
}
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertBack() inserts an item at the back of this SList.
|
||||||
|
*
|
||||||
|
* @param item is the item to be inserted.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
**/
|
||||||
|
public void insertBack(Object item) {
|
||||||
|
if (head == null) {
|
||||||
|
head = newNode(item, null);
|
||||||
|
tail = head;
|
||||||
|
} else {
|
||||||
|
tail.next = newNode(item, null);
|
||||||
|
tail = tail.next;
|
||||||
|
}
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* front() returns the node at the front of this SList. If the SList is
|
||||||
|
* empty, return an "invalid" node--a node with the property that any
|
||||||
|
* attempt to use it will cause an exception.
|
||||||
|
*
|
||||||
|
* @return a ListNode at the front of this SList.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public ListNode front() {
|
||||||
|
if (head == null) {
|
||||||
|
// Create an invalid node.
|
||||||
|
SListNode node = newNode(null, null);
|
||||||
|
node.myList = null;
|
||||||
|
return node;
|
||||||
|
} else {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* back() returns the node at the back of this SList. If the SList is
|
||||||
|
* empty, return an "invalid" node--a node with the property that any
|
||||||
|
* attempt to use it will cause an exception.
|
||||||
|
*
|
||||||
|
* @return a ListNode at the back of this SList.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public ListNode back() {
|
||||||
|
if (tail == null) {
|
||||||
|
// Create an invalid node.
|
||||||
|
SListNode node = newNode(null, null);
|
||||||
|
node.myList = null;
|
||||||
|
return node;
|
||||||
|
} else {
|
||||||
|
return tail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toString() returns a String representation of this SList.
|
||||||
|
*
|
||||||
|
* @return a String representation of this SList.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(n) time, where n is the length of the list.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
String result = "[ ";
|
||||||
|
SListNode current = head;
|
||||||
|
while (current != null) {
|
||||||
|
result = result + current.item + " ";
|
||||||
|
current = current.next;
|
||||||
|
}
|
||||||
|
return result + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testInvalidNode(ListNode p) {
|
||||||
|
System.out.println("p.isValidNode() should be false: " + p.isValidNode());
|
||||||
|
try {
|
||||||
|
p.item();
|
||||||
|
System.out.println("p.item() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.item() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.setItem(new Integer(0));
|
||||||
|
System.out.println("p.setItem() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.setItem() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.next();
|
||||||
|
System.out.println("p.next() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.next() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.prev();
|
||||||
|
System.out.println("p.prev() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.prev() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.insertBefore(new Integer(1));
|
||||||
|
System.out.println("p.insertBefore() should throw an exception, but " +
|
||||||
|
"didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.insertBefore() should throw an exception, and did."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.insertAfter(new Integer(1));
|
||||||
|
System.out.println("p.insertAfter() should throw an exception, but " +
|
||||||
|
"didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.insertAfter() should throw an exception, and did."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
p.remove();
|
||||||
|
System.out.println("p.remove() should throw an exception, but didn't.");
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.out.println("p.remove() should throw an exception, and did.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testEmpty() {
|
||||||
|
List l = new SList();
|
||||||
|
System.out.println("An empty list should be [ ]: " + l);
|
||||||
|
System.out.println("l.isEmpty() should be true: " + l.isEmpty());
|
||||||
|
System.out.println("l.length() should be 0: " + l.length());
|
||||||
|
System.out.println("Finding front node p of l.");
|
||||||
|
ListNode p = l.front();
|
||||||
|
testInvalidNode(p);
|
||||||
|
System.out.println("Finding back node p of l.");
|
||||||
|
p = l.back();
|
||||||
|
testInvalidNode(p);
|
||||||
|
l.insertFront(new Integer(10));
|
||||||
|
System.out.println("l after insertFront(10) should be [ 10 ]: " + l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] argv) {
|
||||||
|
testEmpty();
|
||||||
|
List l = new SList();
|
||||||
|
l.insertFront(new Integer(3));
|
||||||
|
l.insertFront(new Integer(2));
|
||||||
|
l.insertFront(new Integer(1));
|
||||||
|
System.out.println("l is a list of 3 elements: " + l);
|
||||||
|
try {
|
||||||
|
ListNode n;
|
||||||
|
int i = 1;
|
||||||
|
for (n = l.front(); n.isValidNode(); n = n.next()) {
|
||||||
|
System.out.println("n.item() should be " + i + ": " + n.item());
|
||||||
|
n.setItem(new Integer(((Integer) n.item()).intValue() * 2));
|
||||||
|
System.out.println("n.item() should be " + 2 * i + ": " + n.item());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
System.out.println("After doubling all elements of l: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
|
||||||
|
i = 6;
|
||||||
|
for (n = l.back(); n.isValidNode(); n = n.prev()) {
|
||||||
|
System.out.println("n.item() should be " + i + ": " + n.item());
|
||||||
|
n.setItem(new Integer(((Integer) n.item()).intValue() * 2));
|
||||||
|
System.out.println("n.item() should be " + 2 * i + ": " + n.item());
|
||||||
|
i = i - 2;
|
||||||
|
}
|
||||||
|
System.out.println("After doubling all elements of l again: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
|
||||||
|
n = l.front().next();
|
||||||
|
System.out.println("Removing middle element (8) of l: " + n.item());
|
||||||
|
n.remove();
|
||||||
|
System.out.println("l is now: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
n = l.back();
|
||||||
|
System.out.println("Removing end element (12) of l: " + n.item());
|
||||||
|
n.remove();
|
||||||
|
System.out.println("l is now: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
|
||||||
|
n = l.front();
|
||||||
|
System.out.println("Removing first element (4) of l: " + n.item());
|
||||||
|
n.remove();
|
||||||
|
System.out.println("l is now: " + l);
|
||||||
|
testInvalidNode(n);
|
||||||
|
} catch (InvalidNodeException lbe) {
|
||||||
|
System.err.println ("Caught InvalidNodeException that should not happen."
|
||||||
|
);
|
||||||
|
System.err.println ("Aborting the testing code.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
/* SListNode.java */
|
||||||
|
|
||||||
|
package com.SimpleDrawingApp.list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An SListNode is a mutable node in an SList (singly-linked list).
|
||||||
|
**/
|
||||||
|
|
||||||
|
public class SListNode extends ListNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (inherited) item references the item stored in the current node.
|
||||||
|
* (inherited) myList references the List that contains this node.
|
||||||
|
* next references the next node in the SList.
|
||||||
|
*
|
||||||
|
* DO NOT CHANGE THE FOLLOWING FIELD DECLARATIONS.
|
||||||
|
**/
|
||||||
|
|
||||||
|
protected SListNode next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SListNode() constructor.
|
||||||
|
* @param i the item to store in the node.
|
||||||
|
* @param l the list this node is in.
|
||||||
|
* @param n the node following this node.
|
||||||
|
*/
|
||||||
|
SListNode(Object i, SList l, SListNode n) {
|
||||||
|
item = i;
|
||||||
|
myList = l;
|
||||||
|
next = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* next() returns the node following this node. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @return the node following this node.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public ListNode next() throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("next() called on invalid node");
|
||||||
|
}
|
||||||
|
if (next == null) {
|
||||||
|
// Create an invalid node.
|
||||||
|
SListNode node = ((SList) myList).newNode(null, null);
|
||||||
|
node.myList = null;
|
||||||
|
return node;
|
||||||
|
} else {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prev() returns the node preceding this node. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @param node the node whose predecessor is sought.
|
||||||
|
* @return the node preceding this node.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(this.size) time.
|
||||||
|
*/
|
||||||
|
public ListNode prev() throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("prev() called on invalid node");
|
||||||
|
}
|
||||||
|
SListNode prev = ((SList) myList).head;
|
||||||
|
if (prev == this) {
|
||||||
|
// Create an invalid node.
|
||||||
|
prev = ((SList) myList).newNode(null, null);
|
||||||
|
prev.myList = null;
|
||||||
|
} else {
|
||||||
|
while (prev.next != this) {
|
||||||
|
prev = prev.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertAfter() inserts an item immediately following this node. If this
|
||||||
|
* node is invalid, throws an exception.
|
||||||
|
*
|
||||||
|
* @param item the item to be inserted.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(1) time.
|
||||||
|
*/
|
||||||
|
public void insertAfter(Object item) throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("insertAfter() called on invalid node");
|
||||||
|
}
|
||||||
|
SListNode newNode = ((SList) myList).newNode(item, next);
|
||||||
|
if (next == null) {
|
||||||
|
((SList) myList).tail = newNode;
|
||||||
|
}
|
||||||
|
next = newNode;
|
||||||
|
myList.size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* insertBefore() inserts an item immediately preceding this node. If this
|
||||||
|
* node is invalid, throws an exception.
|
||||||
|
*
|
||||||
|
* @param item the item to be inserted.
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(this.size) time.
|
||||||
|
*/
|
||||||
|
public void insertBefore(Object item) throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("insertBefore() called on invalid node");
|
||||||
|
}
|
||||||
|
SListNode newNode = ((SList) myList).newNode(item, this);
|
||||||
|
if (this == ((SList) myList).head) {
|
||||||
|
((SList) myList).head = newNode;
|
||||||
|
} else {
|
||||||
|
SListNode prev = (SListNode) prev();
|
||||||
|
prev.next = newNode;
|
||||||
|
}
|
||||||
|
myList.size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove() removes this node from its SList. If this node is invalid,
|
||||||
|
* throws an exception.
|
||||||
|
*
|
||||||
|
* @exception InvalidNodeException if this node is not valid.
|
||||||
|
*
|
||||||
|
* Performance: runs in O(this.size) time.
|
||||||
|
*/
|
||||||
|
public void remove() throws InvalidNodeException {
|
||||||
|
if (!isValidNode()) {
|
||||||
|
throw new InvalidNodeException("remove() called on invalid node");
|
||||||
|
}
|
||||||
|
if (this == ((SList) myList).head) {
|
||||||
|
((SList) myList).head = next;
|
||||||
|
if (next == null) {
|
||||||
|
((SList) myList).tail = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SListNode prev = (SListNode) prev();
|
||||||
|
prev.next = next;
|
||||||
|
if (next == null) {
|
||||||
|
((SList) myList).tail = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myList.size--;
|
||||||
|
|
||||||
|
// Make this node an invalid node, so it cannot be used to corrupt myList.
|
||||||
|
myList = null;
|
||||||
|
// Set other reference to null to improve garbage collection.
|
||||||
|
next = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|