Assignment 7 – FacePamphlet

FacePamphlet.java

package facePamphlet;

/* 
 * File: FacePamphlet.java
 * -----------------------
 * When it is finished, this program will implement a basic social network
 * management system.
 */

import acm.program.*;
import acm.graphics.*;
import acm.util.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

public class FacePamphlet extends Program 
					implements FacePamphletConstants {

	/**
	 * This method has the responsibility for initializing the 
	 * interactors in the application, and taking care of any other 
	 * initialization that needs to be performed.
	 */
	public void init() {
		addControlBars();
		addActionListeners();
		database = new FacePamphletDatabase();
		dbMgr = new SQLDatabaseMgr();
		canvas = new FacePamphletCanvas();
		add(canvas, CENTER);
		currentProfile = null;
    }
    
	private void addControlBars() {
		
		/* North control bar */
		add(new JLabel("Name"), NORTH);
		profileNameTF = new JTextField(TEXT_FIELD_SIZE);
		add(profileNameTF, NORTH);
		
		createProfileBtn = new JButton("Add");
		createProfileBtn.setActionCommand("create profile");
		add(createProfileBtn, NORTH);
		
		delProfileBtn = new JButton("Delete");
		delProfileBtn.setActionCommand("delete profile");
		add(delProfileBtn, NORTH);
		
		findProfileBtn = new JButton("Lookup");
		findProfileBtn.setActionCommand("lookup profile");
		add(findProfileBtn, NORTH);
		
		saveDB = new JButton("Save Database");
		saveDB.setActionCommand("save db");
		add(saveDB, NORTH);
		
		loadDB = new JButton("Load Database");
		loadDB.setActionCommand("load db");
		add(loadDB, NORTH);

		wipeDB = new JButton("Wipe Database");
		wipeDB.setActionCommand("wipe db");
		add(wipeDB, NORTH);
		
		/* West control bar */
		changeStatusTF = new JTextField(TEXT_FIELD_SIZE);
		changeStatusTF.setActionCommand("change status");
		changeStatusTF.addActionListener(this);
		add(changeStatusTF, WEST);
		changeStatusBtn = new JButton("Change Status");
		changeStatusBtn.setActionCommand("change status");
		add(changeStatusBtn, WEST);
		add(new JLabel(EMPTY_LABEL_TEXT), WEST);
		
		changeProfilePicTF = new JTextField(TEXT_FIELD_SIZE);
		changeProfilePicTF.setActionCommand("change picture");
		changeProfilePicTF.addActionListener(this);
		add(changeProfilePicTF, WEST);
		changeProfilePicBtn = new JButton("Change Picture");
		changeProfilePicBtn.setActionCommand("change picture");
		add(changeProfilePicBtn, WEST);
		add(new JLabel(EMPTY_LABEL_TEXT), WEST);
		
		addFreindTF = new JTextField(TEXT_FIELD_SIZE);
		addFreindTF.setActionCommand("add friend");
		addFreindTF.addActionListener(this);
		add(addFreindTF, WEST);
		addFreindBtn = new JButton("Add Friend");
		addFreindBtn.setActionCommand("add friend");
		add(addFreindBtn, WEST);
		add(new JLabel(EMPTY_LABEL_TEXT), WEST);
	}
	
    /**
     * This class is responsible for detecting when the buttons are
     * clicked or interactors are used, so you will have to add code
     * to respond to these actions.
     */
    public void actionPerformed(ActionEvent e) {
		/* North control bar */
    	String name = profileNameTF.getText();
    	if (e.getActionCommand() == "create profile" && (!name.equals(""))) {
    		createProfile(name);
    	} else if (e.getActionCommand() == "delete profile" && (!name.equals(""))) {
    		deleteProfile(name);
    	} else if (e.getActionCommand() == "lookup profile" && (!name.equals(""))) {
    		lookupProfile(name);
    	} else if (e.getActionCommand() == "save db") {
    		try {
				dbMgr.storeDatabase(database);
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
    	} else if (e.getActionCommand() == "load db") {
    		try {
				database = dbMgr.loadDatabase();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
    	} else if (e.getActionCommand() == "wipe db") {
    		try {
				dbMgr.deleteSQLDatabase();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
    	}
    	
    	/* West control bar */
    	if (e.getActionCommand() == "change status" && (!changeStatusTF.getText().equals(""))) {
    		changeProfileStatus(name);
    	} else if (e.getActionCommand() == "change picture" && (!changeProfilePicTF.getText().equals(""))) {
    		changeProfilePic(name);
    	} else if (e.getActionCommand() == "add friend" && (!addFreindTF.getText().equals(""))) {
    		addFriend(name);
    	}
	}
    
    private void addFriend(String name) {
		String friendName = addFreindTF.getText();
		if (currentProfile != null) {
			if (database.containsProfile(friendName)) {
				if (currentProfile.addFriend(friendName)) {
					database.getProfile(friendName).addFriend(name);
					canvas.displayProfile(currentProfile);
					canvas.showMessage(friendName + " added as a friend.");
				} else {
					canvas.showMessage(name + " already has " + friendName + " as a friend.");
				}
			} else {
				canvas.showMessage(friendName + " does not exist.");
			}
		} else {
			canvas.showMessage("Please select a profile first.");
		}
		println("Current profile: " + currentProfile);
	}

	private void changeProfilePic(String name) {
		if (currentProfile != null) {
			GImage image = getImageFromFile(changeProfilePicTF.getText());
			if (image != null) {
				currentProfile.setImage(image, changeProfilePicTF.getText());
				canvas.displayProfile(currentProfile);
				canvas.showMessage("Picture updated.");
			} else {
				canvas.displayProfile(currentProfile);
				canvas.showMessage("Unable to open image file: " + changeProfilePicTF.getText());
			}
		} else {
			canvas.showMessage("Please select a profile to change picture.");
		}
	}

	private void changeProfileStatus(String name) {
    	if (currentProfile != null) {
			currentProfile.setStatus(changeStatusTF.getText());
			canvas.displayProfile(currentProfile);
			canvas.showMessage("Status updated to " + currentProfile.getStatus());
		} else {
			canvas.showMessage("Please select a profile first.");
		}
		println("Current profile: " + currentProfile);
	}

	private void lookupProfile(String name) {
    	if (database.containsProfile(name)) {
			currentProfile = database.getProfile(name);
			canvas.displayProfile(currentProfile);
			canvas.showMessage("Displaying " + name);
		} else {
			currentProfile = null;
			canvas.displayProfile(currentProfile);
			canvas.showMessage(name + " does not exist.");
		}
    	println("Current profile: " + currentProfile);
	}

	private void deleteProfile(String name) {
		if (database.containsProfile(name)) {
			removeConnections(name);
			database.deleteProfile(name);
			currentProfile = null;
			canvas.displayProfile(currentProfile);
			canvas.showMessage("Profile of " + name + " deleted.");
		} else {
			currentProfile = null;
			canvas.displayProfile(currentProfile);
			canvas.showMessage("Profile with the name " + name + " does not exist.");
		}
	}

	private void createProfile(String name) {
    	if (!database.containsProfile(name)) {
			addProfileToDB(name);
			currentProfile = database.getProfile(name);
			canvas.displayProfile(currentProfile);
			canvas.showMessage("New profile created.");
		} else {
			canvas.showMessage("A profile with the name " + name + " already exist. ");
		}
	}

	/* Removes the current profile from all friend's friend list */
    private void removeConnections(String name) {
		Iterator<String> friends = database.getProfile(name).getFriends();
		while (friends.hasNext()) {
			database.getProfile(friends.next()).removeFriend(name);
		}
	}

	private GImage getImageFromFile(String fileName) {
    	/* Value of img will be null if we were unable to open the image file */
		GImage img = null;
    	try {
			img = new GImage("images\\" + fileName);
		} catch (ErrorException ex) {
			println("Cannot open file.");
		}
		return img;
	}

	/* Add a profile to the database */
    private void addProfileToDB(String profileName) {
		FacePamphletProfile profile = new FacePamphletProfile(profileName);
		database.addProfile(profile);
	}

	private JButton createProfileBtn;
    private JButton delProfileBtn;
    private JButton findProfileBtn;
    private JButton changeStatusBtn;
    private JButton changeProfilePicBtn;
    private JButton addFreindBtn;
    
    private JButton saveDB;
    private JButton loadDB;
    private JButton wipeDB;
    
    private JTextField profileNameTF;
    private JTextField changeStatusTF;
    private JTextField changeProfilePicTF;
    private JTextField addFreindTF;
    
    private FacePamphletDatabase database;
    private FacePamphletProfile currentProfile;
    private FacePamphletCanvas canvas;
    
    private SQLDatabaseMgr dbMgr;
    
}

FacePamphletCanvas.java

package facePamphlet;

/*
 * File: FacePamphletCanvas.java
 * -----------------------------
 * This class represents the canvas on which the profiles in the social
 * network are displayed.  NOTE: This class does NOT need to update the
 * display when the window is resized.
 */


import acm.graphics.*;
import java.awt.*;
import java.util.*;

public class FacePamphletCanvas extends GCanvas 
					implements FacePamphletConstants {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/** 
	 * Constructor
	 * This method takes care of any initialization needed for 
	 * the display
	 */
	public FacePamphletCanvas() {
		bottomMessage = new GLabel("");
	}

	
	/** 
	 * This method displays a message string near the bottom of the 
	 * canvas.  Every time this method is called, the previously 
	 * displayed message (if any) is replaced by the new message text 
	 * passed in.
	 */
	public void showMessage(String msg) {
		bottomMessage.setLabel(msg);
		if (!bottomMessage.equals("")) {
			double x = (getWidth() - bottomMessage.getWidth()) / 2;
			double y = (getHeight() + bottomMessage.getAscent() / 2) - BOTTOM_MESSAGE_MARGIN;
			bottomMessage.setFont(MESSAGE_FONT);
			add(bottomMessage, x, y);
		}
	}
	
	
	/** 
	 * This method displays the given profile on the canvas.  The 
	 * canvas is first cleared of all existing items (including 
	 * messages displayed near the bottom of the screen) and then the 
	 * given profile is displayed.  The profile display includes the 
	 * name of the user from the profile, the corresponding image 
	 * (or an indication that an image does not exist), the status of
	 * the user, and a list of the user's friends in the social network.
	 */
	public void displayProfile(FacePamphletProfile profile) {
		removeAll();
		if (profile != null) {
			addProfileName(profile);
			addProfileImg(profile);
			addProfileStatus(profile);
			addFriendList(profile);
		}
	}
	
	private void addProfileName(FacePamphletProfile profile) {
		profileName = new GLabel(profile.getName());
		profileName.setColor(Color.blue);
		profileName.setFont(PROFILE_NAME_FONT);
		profileName.setLocation(LEFT_MARGIN, TOP_MARGIN + profileName.getAscent());
		add(profileName);
	}
	
	private void addProfileImg(FacePamphletProfile profile) {
		profileImageY = profileName.getY() + IMAGE_MARGIN;
		if (profile.getImage() != null) {
			profileImage = profile.getImage();
			profileImage.setSize(IMAGE_WIDTH, IMAGE_HEIGHT);
			add(profileImage, LEFT_MARGIN, profileImageY);
		} else {
			LabeledBox placeholder = new LabeledBox(IMAGE_WIDTH, IMAGE_HEIGHT, "No Image");
			add(placeholder, LEFT_MARGIN, profileImageY);
		}
		
	}
	
	private void addProfileStatus(FacePamphletProfile profile) {
		profileStatus = new GLabel("No Current Status.");
		if (profile.getStatus() != null && profile.getStatus().length() > 0) {
			profileStatus.setLabel(profile.getName() + " is " + profile.getStatus());
		}
		profileStatus.setFont(PROFILE_STATUS_FONT);
		add(profileStatus, LEFT_MARGIN, profileImageY + IMAGE_HEIGHT + STATUS_MARGIN);
	}
	
	private void addFriendList(FacePamphletProfile profile) {
		GLabel friendLabel = new GLabel("Friends:", getWidth() / 2, profileImageY);
		friendLabel.setFont(PROFILE_FRIEND_LABEL_FONT);
		add(friendLabel);
		/* Display list of friends, one per line */
		Iterator<String> it = profile.getFriends();
		double nextY = friendLabel.getY() + friendLabel.getHeight(); 
		while (it.hasNext()) {
			GLabel name = new GLabel(it.next(), getWidth() / 2, nextY);
			name.setFont(PROFILE_FRIEND_FONT);
			add(name);
			nextY += name.getHeight();
		}
	}

	private GLabel bottomMessage;
	private GLabel profileName;
	private GLabel profileStatus;
	private GImage profileImage;
	private double profileImageY;

	/* LabelBox code from section 7 assignment with modification */
	/* This class defines a box with the specified label at it's center */
	class LabeledBox extends GCompound {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		public LabeledBox(double width, double height, String label) {
			super();
			w = width;
			h = height;
			boxLabel = label;
			addBox();
			addLabel();
		}
		
		// Add a rectangle to the GCompound
		private void addBox() {
			GRect box = new GRect(w, h);
			add(box);
		}
		
		// Add a label that is centered inside the rectangle box
		private void addLabel() {
			GLabel label = new GLabel(boxLabel);
			label.setFont(PROFILE_IMAGE_FONT);
			add(label, (w - label.getWidth()) / 2, (h + label.getAscent()) / 2);
		}
		
		private double w, h;
		private String boxLabel;
	}
}

FacePamphletConstants.java

package facePamphlet;

/*
 * File: FacePamphletConstants.java
 * --------------------------------
 * This file declares several constants that are shared by the
 * different modules in the FacePamphlet application.  Any class
 * that implements this interface can use these constants.
 */

public interface FacePamphletConstants {

	/** The width of the application window */
	public static final int APPLICATION_WIDTH = 800;

	/** The height of the application window */
	public static final int APPLICATION_HEIGHT = 500;

	/** Number of characters for each of the text input fields */
	public static final int TEXT_FIELD_SIZE = 15;

	/** Text to be used to create an "empty" label to put space
	 *  between interactors on EAST border of application.  Note this
	 *  label is not actually the empty string, but rather a single space */
	public static final String EMPTY_LABEL_TEXT = " ";

	/** Name of font used to display the application message at the
	 *  bottom of the display canvas */
	public static final String MESSAGE_FONT = "Dialog-18";

	/** Name of font used to display the name in a user's profile */
	public static final String PROFILE_NAME_FONT = "Dialog-24";
	
	/** Name of font used to display the text "No Image" in user
	 *  profiles that do not contain an actual image */
	public static final String PROFILE_IMAGE_FONT = "Dialog-24";
	
	/** Name of font used to display the status in a user's profile */
	public static final String PROFILE_STATUS_FONT = "Dialog-16-bold";

	/** Name of font used to display the label "Friends" above the
	 *  user's list of friends in a profile */
	public static final String PROFILE_FRIEND_LABEL_FONT = "Dialog-16-bold";

	/** Name of font used to display the names from the user's list
	 *  of friends in a profile */
	public static final String PROFILE_FRIEND_FONT = "Dialog-16";

	/** The width (in pixels) that profile images should be displayed */
	public static final double IMAGE_WIDTH = 200;

	/** The height (in pixels) that profile images should be displayed */
	public static final double IMAGE_HEIGHT = 200;	

	/** The number of pixels in the vertical margin between the bottom 
	 *  of the canvas display area and the baseline for the message 
	 *  text that appears near the bottom of the display */
	public static final double BOTTOM_MESSAGE_MARGIN = 20;

	/** The number of pixels in the hortizontal margin between the 
	 *  left side of the canvas display area and the Name, Image, and 
	 *  Status components that are display in the profile */	
	public static final double LEFT_MARGIN = 20;	

	/** The number of pixels in the vertical margin between the top 
	 *  of the canvas display area and the top (NOT the baseline) of 
	 *  the Name component that is displayed in the profile */	
	public static final double TOP_MARGIN = 20;	
	
	/** The number of pixels in the vertical margin between the 
	 *  baseline of the Name component and the top of the Image 
	 *  displayed in the profile */	
	public static final double IMAGE_MARGIN = 20;

	/** The number of vertical pixels in the vertical margin between 
	 *  the bottom of the Image and the top of the Status component 
	 *  in the profile */		
	public static final double STATUS_MARGIN = 20;

}

FacePamphletDatabase.java

package facePamphlet;

/*
 * File: FacePamphletDatabase.java
 * -------------------------------
 * This class keeps track of the profiles of all users in the
 * FacePamphlet application.  Note that profile names are case
 * sensitive, so that "ALICE" and "alice" are NOT the same name.
 */

import java.util.*;

public class FacePamphletDatabase implements FacePamphletConstants {

	/** 
	 * Constructor
	 * This method takes care of any initialization needed for 
	 * the database.
	 */
	public FacePamphletDatabase() {
		profileDB = new HashMap<String, FacePamphletProfile>();
	}
	
	
	/** 
	 * This method adds the given profile to the database.  If the 
	 * name associated with the profile is the same as an existing 
	 * name in the database, the existing profile is replaced by 
	 * the new profile passed in.
	 */
	public void addProfile(FacePamphletProfile profile) {
		profileDB.put(profile.getName(), profile);
	}

	
	/** 
	 * This method returns the profile associated with the given name 
	 * in the database.  If there is no profile in the database with 
	 * the given name, the method returns null.
	 */
	public FacePamphletProfile getProfile(String name) {
		return profileDB.get(name); //get returns null if the map contains no mapping for the key. 
	}
	
	
	/** 
	 * This method removes the profile associated with the given name
	 * from the database.  It also updates the list of friends of all
	 * other profiles in the database to make sure that this name is
	 * removed from the list of friends of any other profile.
	 * 
	 * If there is no profile in the database with the given name, then
	 * the database is unchanged after calling this method.
	 */
	public void deleteProfile(String name) {
		if (profileDB.containsKey(name)) profileDB.remove(name);
	}

	public Iterator<String> iterator() {
		return profileDB.keySet().iterator();
	}
	
	/** 
	 * This method returns true if there is a profile in the database 
	 * that has the given name.  It returns false otherwise.
	 */
	public boolean containsProfile(String name) {
		return profileDB.containsKey(name);
	}

	private Map<String, FacePamphletProfile> profileDB;
}

FacePamphletProfile.java

package facePamphlet;

/*
 * File: FacePamphletProfile.java
 * ------------------------------
 * This class keeps track of all the information for one profile
 * in the FacePamphlet social network.  Each profile contains a
 * name, an image (which may not always be set), a status (what 
 * the person is currently doing, which may not always be set),
 * and a list of friends.
 */

import acm.graphics.*;
import java.util.*;

public class FacePamphletProfile implements FacePamphletConstants {
	
	/** 
	 * Constructor
	 * This method takes care of any initialization needed for
	 * the profile.
	 */
	public FacePamphletProfile(String name) {
		profileName = name;
		profileImg = null;
		profileStatus = null;
		friendList = new ArrayList<String>();
	}

	/** This method returns the name associated with the profile. */ 
	public String getName() {
		return profileName;
	}

	/** 
	 * This method returns the image associated with the profile.  
	 * If there is no image associated with the profile, the method
	 * returns null. */ 
	public GImage getImage() {
		return profileImg;
	}
	
	public String getImageURL() {
		return imgURL;
	}

	/** This method sets the image associated with the profile. */ 
	public void setImage(GImage image, String imageURL) {
		profileImg = image;
		imgURL = imageURL;
	}
	
	/** 
	 * This method returns the status associated with the profile.
	 * If there is no status associated with the profile, the method
	 * returns the empty string ("").
	 */ 
	public String getStatus() {
		return profileStatus;
	}
	
	/** This method sets the status associated with the profile. */ 
	public void setStatus(String status) {
		profileStatus = status;
	}

	/** 
	 * This method adds the named friend to this profile's list of 
	 * friends.  It returns true if the friend's name was not already
	 * in the list of friends for this profile (and the name is added 
	 * to the list).  The method returns false if the given friend name
	 * was already in the list of friends for this profile (in which 
	 * case, the given friend name is not added to the list of friends 
	 * a second time.)
	 */
	public boolean addFriend(String friend) {
		if (!friendList.contains(friend)) {
			friendList.add(friend);
			return true;
		}
		return false;
	}

	/** 
	 * This method removes the named friend from this profile's list
	 * of friends.  It returns true if the friend's name was in the 
	 * list of friends for this profile (and the name was removed from
	 * the list).  The method returns false if the given friend name 
	 * was not in the list of friends for this profile (in which case,
	 * the given friend name could not be removed.)
	 */
	public boolean removeFriend(String friend) {
		if (friendList.contains(friend)) {
			friendList.remove(friend);
			return true;
		}
		return false;
	}

	/** 
	 * This method returns an iterator over the list of friends 
	 * associated with the profile.
	 */ 
	public Iterator<String> getFriends() {
		return friendList.iterator();
	}
	
	/** 
	 * This method returns a string representation of the profile.  
	 * This string is of the form: "name (status): list of friends", 
	 * where name and status are set accordingly and the list of 
	 * friends is a comma separated list of the names of all of the 
	 * friends in this profile.
	 * 
	 * For example, in a profile with name "Alice" whose status is 
	 * "coding" and who has friends Don, Chelsea, and Bob, this method 
	 * would return the string: "Alice (coding): Don, Chelsea, Bob"
	 */ 
	public String toString() {
		String friends = getFriendListAsString();
		return ("\"" + profileName + " " + profileStatus + " " + friends + "\"");
	}
	
	/* Returns a string representation of the profile's friend list. */
	public String getFriendListAsString() {
		String nameList = "";
		Iterator<String> it = friendList.iterator();
		while (it.hasNext()) {
			String seperator = "";
			nameList += it.next();
			if (it.hasNext()) seperator = ",";
			nameList += seperator;
		}
		return nameList;
	}

	private String profileName;
	private String profileStatus;
	private String imgURL;
	private GImage profileImg;
	private ArrayList<String> friendList;
	
}

SQLDatabaseMgr.java

package facePamphlet;

import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;

import acm.graphics.GImage;
import acm.util.ErrorException;

/*
 * This class handles all the database related operations in the social network
 */

public class SQLDatabaseMgr {
	
	public SQLDatabaseMgr() {}
	
	/* Stores the user profiles data into the SQLite database */
	public void storeDatabase(FacePamphletDatabase db) throws Exception {
		Class.forName("org.sqlite.JDBC");
		Connection conn = DriverManager.getConnection("jdbc:sqlite:a.db");
		Statement stat = conn.createStatement();
		stat.executeUpdate("DROP TABLE IF EXISTS members;");
		stat.executeUpdate("CREATE TABLE IF NOT EXISTS members(name string PRIMARY KEY, status string DEFAULT NULL, " +
							"imageURL string DEFAULT NULL, friendList string DEFAULT NULL);");
		PreparedStatement prep = conn.prepareStatement("INSERT INTO members VALUES (?, ?, ?, ?);");
		
		Iterator<String> it = db.iterator();
		while (it.hasNext()) {
			FacePamphletProfile profile = db.getProfile((String)it.next());
			parseProfile(profile);
			prep.setString(1, name);
			prep.setString(2, status);
			prep.setString(3, imageURL);
			prep.setString(4, friendList);
			prep.addBatch();
		}

		conn.setAutoCommit(false);
		prep.executeBatch();
		conn.setAutoCommit(true);

		prep.close();
		stat.close();
		conn.close();
	}

	private void parseProfile(FacePamphletProfile profile) {
		name = profile.getName();
		status = profile.getStatus();
		imageURL = profile.getImageURL();
		friendList = null;
		if (profile.getFriendListAsString().length() > 0) {
			friendList = profile.getFriendListAsString();
		}
	}
	
	public FacePamphletDatabase loadDatabase() throws Exception{
		name = null;
		status = null;
		imageURL = null;
		friendList = null;
		FacePamphletDatabase db = new FacePamphletDatabase();
		Class.forName("org.sqlite.JDBC");
		Connection conn = DriverManager.getConnection("jdbc:sqlite:a.db");
		Statement stat = conn.createStatement();
		ResultSet rs = stat.executeQuery("SELECT * FROM members;");
		while (rs.next()) {
			name = rs.getString("name");
			status = rs.getString("status");
			imageURL = rs.getString("imageURL");
			friendList = rs.getString("friendList");
			GImage profileImage = getImageFromFile(imageURL);
			FacePamphletProfile profile = new FacePamphletProfile(name);
			profile.setStatus(status);
			profile.setImage(profileImage, imageURL);
			rebuildFriendList(profile, friendList);
			System.out.println(friendList);
			db.addProfile(profile);
		}
		rs.close();
		stat.close();
		conn.close();
		return db;
	}
	
	private void rebuildFriendList(FacePamphletProfile profile,	String list) {
		if (list != null) {
			StringTokenizer tokenizer = new StringTokenizer(list, DELIMITERS);
			while (tokenizer.hasMoreTokens()) {
				profile.addFriend(tokenizer.nextToken());
			}
		}
	}

	private GImage getImageFromFile(String fileName) {
    	/* Value of img will be null if we were unable to open the image file */
		GImage img = null;
    	try {
			img = new GImage("images\\" + fileName);
		} catch (ErrorException ex) {
			System.out.println("Cannot open image file.");
		}
		return img;
	}
	
	public void deleteSQLDatabase() throws Exception {
		Class.forName("org.sqlite.JDBC");
		Connection conn = DriverManager.getConnection("jdbc:sqlite:a.db");
		Statement stat = conn.createStatement();
		stat.executeUpdate("DROP TABLE IF EXISTS members;");
		
		stat.close();
		conn.close();
	}

	private String name;
	private String status;
	private String imageURL;
	private String friendList;
	private static final String DELIMITERS = ",";
}

Assignment 6 – NameSurfer

NameSurfer.java

/*
 * File: NameSurfer.java
 * ---------------------
 * When it is finished, this program will implements the viewer for
 * the baby-name database described in the assignment handout.
 */

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

public class NameSurfer extends Program implements NameSurferConstants {

/* Method: init() */
/**
 * This method has the responsibility for reading in the data base
 * and initializing the interactors at the bottom of the window.
 */
	public void init() {
		// Create a database containing the data from the specified file
		nameDataBase = new NameSurferDataBase(NAMES_DATA_FILE);
		
		graph = new NameSurferGraph();
		add(graph);
		
	    addControlBar();
	    addActionListeners();
	}
	
	private void addControlBar() {
		nameField = new JTextField(15);
		nameField.addActionListener(this);	//Add nameField to the list of ActionListeners
		add(new JLabel("Name"), SOUTH);
		add(nameField, SOUTH);
		add(new JButton("Graph"), SOUTH);
		add(new JButton("Clear"), SOUTH);
	}

/* Method: actionPerformed(e) */
/**
 * This class is responsible for detecting when the buttons are
 * clicked, so you will have to define a method to respond to
 * button actions.
 */
	public void actionPerformed(ActionEvent e) {
		String name = nameField.getText();
		if (e.getActionCommand().equals("Graph") || nameField == e.getSource()) {
			NameSurferEntry entry = nameDataBase.findEntry(name);
			if (entry != null) {
				graph.addEntry(entry);
			}
		} else if (e.getActionCommand().equals("Clear")) {
			graph.clear();
		}
	}
	
	private NameSurferGraph graph;
	private JTextField nameField;
	private NameSurferDataBase nameDataBase;
}

NameSurferConstants.java

/*
 * File: NameSurferConstants.java
 * ------------------------------
 * This file declares several constants that are shared by the
 * different modules in the NameSurfer application.  Any class
 * that implements this interface can use these constants.
 */

public interface NameSurferConstants {

/** The width of the application window */
	public static final int APPLICATION_WIDTH = 800;

/** The height of the application window */
	public static final int APPLICATION_HEIGHT = 600;

/** The name of the file containing the data */
	public static final String NAMES_DATA_FILE = "names-data.txt";

/** The first decade in the database */
	public static final int START_DECADE = 1900;

/** The number of decades */
	public static final int NDECADES = 11;

/** The maximum rank in the database */
	public static final int MAX_RANK = 1000;

/** The number of pixels to reserve at the top and bottom */
	public static final int GRAPH_MARGIN_SIZE = 20;

}

NameSurferDataBase.java

/*
 * File: NameSurferDataBase.java
 * -----------------------------
 * This class keeps track of the complete database of names.
 * The constructor reads in the database from a file, and
 * the only public method makes it possible to look up a
 * name and get back the corresponding NameSurferEntry.
 * Names are matched independent of case, so that "Eric"
 * and "ERIC" are the same names.
 */

import java.util.*;
import java.io.*;
import acm.util.ErrorException;

public class NameSurferDataBase implements NameSurferConstants {
	
/* Constructor: NameSurferDataBase(filename) */
/**
 * Creates a new NameSurferDataBase and initializes it using the
 * data in the specified file.  The constructor throws an error
 * exception if the requested file does not exist or if an error
 * occurs as the file is being read.
 */
	public NameSurferDataBase(String filename) {
		try {
			BufferedReader rd = new BufferedReader(new FileReader(filename));
			while (true) {
				String line = rd.readLine();
				if (line == null) break;
				NameSurferEntry entry = new NameSurferEntry(line);
				databaseMap.put(entry.getName(), entry);
			}
			rd.close();
		} catch (IOException ex) {
			throw new ErrorException(ex);
		}
	}
	
/* Method: findEntry(name) */
/**
 * Returns the NameSurferEntry associated with this name, if one
 * exists.  If the name does not appear in the database, this
 * method returns null.
 */
	public NameSurferEntry findEntry(String name) {
		if (databaseMap.containsKey(name)) {
			return (databaseMap.get(name));
		}
		return null;
	}
	
	private Map<String, NameSurferEntry> databaseMap = new HashMap<String, NameSurferEntry>();
}

NameSurferEntry.java

/*
 * File: NameSurferEntry.java
 * --------------------------
 * This class represents a single entry in the database.  Each
 * NameSurferEntry contains a name and a list giving the popularity
 * of that name for each decade stretching back to 1900.
 */

import acm.util.*;
import java.util.*;

public class NameSurferEntry implements NameSurferConstants {

/* Constructor: NameSurferEntry(line) */
/**
 * Creates a new NameSurferEntry from a data line as it appears
 * in the data file.  Each line begins with the name, which is
 * followed by integers giving the rank of that name for each
 * decade.
 */
	public NameSurferEntry(String line) {
		name = parseName(line);
		rankArray = parseRank(line);
	}

	//Returns the name from the line of data
	private String parseName(String line) {
		int nameIndexEnd = line.indexOf(" ");
		return (line.substring(0, nameIndexEnd));
	}
	
	private int[] parseRank(String line) {
		int[] array = new int[NDECADES];
		int indexStart = name.length() + 1;
		for (int i = 0; i < NDECADES; i ++) {
			int indexEnd = line.indexOf(" ", indexStart);
			if (indexEnd != -1) {
				int ranking = Integer.parseInt(line.substring(indexStart, indexEnd));
				array[i] = ranking;
				indexStart = indexEnd + 1;
			} else {
				// When we are at the last rank in the line data, indexEnd will be -1 because there is no space after that entry
				array[i] = Integer.parseInt(line.substring(indexStart));
			}
		}
		return array;
	}
	
	
/* Method: getName() */
/**
 * Returns the name associated with this entry.
 */
	public String getName() {
		return name;
	}

/* Method: getRank(decade) */
/**
 * Returns the rank associated with an entry for a particular
 * decade.  The decade value is an integer indicating how many
 * decades have passed since the first year in the database,
 * which is given by the constant START_DECADE.  If a name does
 * not appear in a decade, the rank value is 0.
 */
	public int getRank(int decade) {
		if (decade < NDECADES) {
			return rankArray[decade];
		}
		return 0;
	}

/* Method: toString() */
/**
 * Returns a string that makes it easy to see the value of a
 * NameSurferEntry.
 */
	public String toString() {
		String ranks = "";
		for (int i = 0; i < rankArray.length; i++) {
			ranks += rankArray[i];
			
			// Add a space after each decade's rank except the last one to separate them 
			if (i < rankArray.length - 1) {
				ranks += " ";
			}
		}
		return ("\"" + name + " [" + ranks + "]\"");
	}
	
	private String name;
	private int[] rankArray;
}

NameSurferGraph.java

/*
 * File: NameSurferGraph.java
 * ---------------------------
 * This class represents the canvas on which the graph of
 * names is drawn. This class is responsible for updating
 * (redrawing) the graphs whenever the list of entries changes or the window is resized.
 */

import acm.graphics.*;
import java.awt.event.*;
import java.util.*;
import java.awt.*;
import java.util.List;

public class NameSurferGraph extends GCanvas
	implements NameSurferConstants, ComponentListener {

	/**
	* Creates a new NameSurferGraph object that displays the data.
	*/
	public NameSurferGraph() {
		addComponentListener(this);
	}
	
	/**
	* Clears the list of name surfer entries stored inside this class.
	*/
	public void clear() {
		entriesInDisplay.clear();
		update();
	}
	
	/* Method: addEntry(entry) */
	/**
	* Adds a new NameSurferEntry to the list of entries on the display.
	* Note that this method does not actually draw the graph, but
	* simply stores the entry; the graph is drawn by calling update.
	*/
	public void addEntry(NameSurferEntry entry) {
		entriesInDisplay.add(entry);
		update();
	}
	
	/**
	* Updates the display image by deleting all the graphical objects
	* from the canvas and then reassembling the display according to
	* the list of entries. Your application must call update after
	* calling either clear or addEntry; update is also called whenever
	* the size of the canvas changes.
	*/
	public void update() {
		removeAll();
		spacer = getWidth() / NDECADES;
		drawTopBottomMargins();
		drawDecadeLines();
		plotRankToGraph();
	}
	
	public void printList() {
		System.out.print(entriesInDisplay);
	}
	
	//Draws the plot line for all entries in the array.
	private void plotRankToGraph() {
		int colorCounter = 0;
		for (NameSurferEntry entry : entriesInDisplay) {
			double rankX = 0;
			double lastX = 0;
			double lastY = 0;
			for (int i = 0; i < NDECADES; i++) {
				
				//Add rank label to graph, if the rank of a name in the current decade is 0, the name is placed at the bottom of the graph
				double rankY = GRAPH_MARGIN_SIZE + (getHeight() - 2 * GRAPH_MARGIN_SIZE) / (double)MAX_RANK * entry.getRank(i);
				GLabel rankLabel = new GLabel(entry.getName() + " " + (entry.getRank(i) == 0 ? "*" : entry.getRank(i)));
				if (entry.getRank(i) == 0) {
					rankY = getHeight() - GRAPH_MARGIN_SIZE;
				}
				add(rankLabel, rankX, rankY);
				
				//Draws a line that connects the last rank to the current rank
				GLine graphLine = new GLine(lastX, lastY, rankX, rankY);
				add(graphLine);
				
				//Sets the color properties of the current name 
				Color color = getNextColor(colorCounter % NCOLOR);
				rankLabel.setColor(color);
				graphLine.setColor(color);
				
				lastX = rankX;
				lastY = rankY;
				rankX += spacer;
			}
			colorCounter++;
		}
	}

	private Color getNextColor(int colorNum) {

		switch (colorNum) {
			case 0: return Color.black;
			case 1: return Color.red;
			case 2: return Color.blue;
		}
		return Color.magenta;
	}

	//Add the vertical lines and labels separating the decades to the display
	private void drawDecadeLines() {
		double nextX = 0;
		int decadeLabel = START_DECADE;
		for (int i = 0; i < NDECADES; i++) {
			GLabel label = new GLabel("" + decadeLabel);
			add(new GLine(nextX, 0, nextX, getHeight()));
			add(label, nextX, getHeight() - GRAPH_MARGIN_SIZE + (GRAPH_MARGIN_SIZE + label.getAscent()) / 2);
			nextX += spacer;
			decadeLabel += YEARS_IN_DECADE;
		}
	}

	//Add the upper and lower margins to the display
	private void drawTopBottomMargins() {
		add(new GLine(0, GRAPH_MARGIN_SIZE, getWidth(), GRAPH_MARGIN_SIZE));
		add(new GLine(0, getHeight() - GRAPH_MARGIN_SIZE, getWidth(), getHeight() - GRAPH_MARGIN_SIZE));
	}

	/* Implementation of the ComponentListener interface */
	public void componentHidden(ComponentEvent e) { }
	public void componentMoved(ComponentEvent e) { }
	public void componentResized(ComponentEvent e) { update(); }
	public void componentShown(ComponentEvent e) { }
	
	private List<NameSurferEntry> entriesInDisplay = new ArrayList<NameSurferEntry>();	//List of entries to be displayed on graph
	private double spacer;																//The space between each decade on the graph
	private static final int YEARS_IN_DECADE = 10;										//Number of years in a decade
	private static final int NCOLOR = 4;												//Number of available colors
}

The Art & Science of Java Chapter 10 Programing Exercise 9 – Speed Control Bouncing Ball

package speedControlBouncingBall_10_9;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JSlider;
import java.awt.event.*;
import acm.graphics.GOval;
import acm.program.*;

public class SpeedControlBouncingBall extends GraphicsProgram {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public void init() {
		flag = false;
		initControlBar();
		addBallToCanvas();
		addActionListeners();
	}
	
	private void addBallToCanvas() {
		double cx = getWidth() / 2;
		double cy = getHeight() / 2;
		ball = new GOval(cx, cy, RADIUS * 2, RADIUS * 2 );
		ball.setFilled(true);
		add(ball, cx, cy);
	}

	public void run() {
		while (true) {
			if (flag == true) {
				moveBall();
				updateSpeed();
			}
			pause(PAUSE_TIME);
		}
	}
	
	/* Update the ball's movement speed to the value currently set in the slider.
	 * We first check the ball's movement direction, then flip the sign of the value returned by the slider accordingly
	 * so the ball will continue to move in the same direction after we unpause it.
	 */
	private void updateSpeed() {
		if (dx < 0) {
			dx = speedSlider.getValue() * -1;
		} else {
			dx = speedSlider.getValue();
		}
		
		if (dy < 0) {
			dy = speedSlider.getValue() * -1;
		} else {
			dy = speedSlider.getValue();
		}
	}

	private void moveBall() {
		if ((ball.getX() + RADIUS * 2) >= getWidth() || ball.getX() <= 0) dx *= -1; 
		if ((ball.getY() + RADIUS * 2) >= getHeight() || ball.getY() <= 0) dy *= -1; 
		ball.move(dx,  dy);
	}

	private void initControlBar() {
		addButtons();
		addSlider();
	}

	private void addButtons() {
		JButton startBtn = new JButton("Start");
		JButton stopBtn = new JButton("Stop");
		add(startBtn, SOUTH);
		add(stopBtn, SOUTH);
	}
	
	private void addSlider() {
		speedSlider = new JSlider(MIN_SIZE, MAX_SIZE, INITIAL_SIZE);
		add(new JLabel(" Slow"), SOUTH);
		add(speedSlider, SOUTH);
		add(new JLabel("Fast"), SOUTH);
	}
	
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equals("Start")) flag = true;
		if (e.getActionCommand().equals("Stop")) flag = false;
	}
	
	/* Private constants */
	private static final int MIN_SIZE = 1;
	private static final int MAX_SIZE = 20;
	private static final int INITIAL_SIZE = 5;
	private static final int PAUSE_TIME = 20;
	private static final double RADIUS = 20;
	
	/*Private instance variables*/
	private GOval ball;
	private boolean flag;
	private int dx, dy;
	private JSlider speedSlider;
}

The Art & Science of Java Chapter 10 Programing Exercise 8 – SpeedControlBar

package speedControlBar_10_8;

import javax.swing.*;

import acm.program.*;

public class SpeedControlBar extends GraphicsProgram {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public void init() {
		addButtons();
		addSlider();
	}

	private void addButtons() {
		JButton startBtn = new JButton("Start");
		JButton stopBtn = new JButton("Stop");
		add(startBtn, SOUTH);
		add(stopBtn, SOUTH);
	}
	
	private void addSlider() {
		JSlider speedSlider = new JSlider(MIN_SIZE, MAX_SIZE, INITIAL_SIZE);
		add(new JLabel(" Slow"), SOUTH);
		add(speedSlider, SOUTH);
		add(new JLabel("Fast"), SOUTH);
	}
	
	/* Private constants */
	private static final int MIN_SIZE = 1;
	private static final int MAX_SIZE = 50;
	private static final int INITIAL_SIZE = 20;
}

The Art & Science of Java Chapter 10 Programing Exercise 7 – Super Draw Star Map

package superDrawStarMap_10_7;

import acm.graphics.*;
import acm.program.GraphicsProgram;
import javax.swing.*;
import java.awt.Color;
import java.awt.event.*;

import SampleCodes.GStar;
import drawStarMap_10_6.LabeledColor;

/**
 * This program draws a 5 pointed star every time the user clicks on the canvas 
 */
public class SuperDrawStarMap extends GraphicsProgram {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/* Initialises the program */
	public void init() {
		initColorChooser();
		add(colorChooser, SOUTH);
		selectedColor = (LabeledColor)colorChooser.getSelectedItem();
		addClearButton();
		addCheckBox();
		addSlider();
		addTextField();
		setBackground(Color.gray);
		addKeyListeners();
		addMouseListeners();
		addActionListeners();
	}
	
	private void addTextField() {
		labelField = new JTextField(MAX_CHARACTERS);
		labelField.addActionListener(this);
		add(new JLabel("  Star name:"), SOUTH);
		add(labelField, SOUTH);
	}

	private void addCheckBox() {
		fillCheckBox = new JCheckBox("Filled");
		fillCheckBox.setSelected(true);
		add(fillCheckBox, SOUTH);
	}

	private void addClearButton() {
		JButton clearAll = new JButton("Clear");
		add(clearAll, SOUTH);
	}

	private void addSlider() {
		sizeSlider = new JSlider(MIN_SIZE, MAX_SIZE, INITIAL_SIZE);
		add(new JLabel(" Min"), SOUTH);
		add(sizeSlider, SOUTH);
		add(new JLabel("Max"), SOUTH);
	}

	private void initColorChooser() {
		LabeledColor white = new LabeledColor(Color.white, "White");
		colorChooser = new JComboBox();
		colorChooser.addItem(white);
		colorChooser.addItem(new LabeledColor(Color.red, "Red"));
		colorChooser.addItem(new LabeledColor(Color.yellow, "Yellow"));
		colorChooser.addItem(new LabeledColor(Color.orange, "Orange"));
		colorChooser.addItem(new LabeledColor(Color.green, "Green"));
		colorChooser.addItem(new LabeledColor(Color.blue, "Blue"));
		colorChooser.addItem(new LabeledColor(Color.black, "Black"));
		colorChooser.setEditable(false);		//Make it illegal for user to type a new value in the color field
		colorChooser.setSelectedItem(white);
	}

	/* The method to be called whenever the user clicks the mouse */
	@Override
	public void mouseClicked(MouseEvent e) {
		drawStar(e.getX(), e.getY());
		gobj = getElementAt(last);
	}
	
	/* Call on mouse pressed to record the mouse coordinates of the click */ 
	public void mousePressed(MouseEvent e) {
		last = new GPoint(e.getPoint());
		gobj = getElementAt(last);
	}
	
	/* Call on mouse drag to reposition the object */
	public void mouseDragged(MouseEvent e) {
		if (gobj != null) {
			gobj.move(e.getX() - last.getX(), e.getY() - last.getY());
			last = new GPoint(e.getPoint());
		}
	}
	
	/* Call on keyboard press to move the object in the corresponding direction */
	public void keyPressed(KeyEvent e) {
		if (gobj != null) {
			switch (e.getKeyCode()) {
				case KeyEvent.VK_UP: 	gobj.move(0, -1); break;
				case KeyEvent.VK_DOWN:	gobj.move(0, 1); break;
				case KeyEvent.VK_LEFT: 	gobj.move(-1, 0); break;
				case KeyEvent.VK_RIGHT: gobj.move(1, 0); break;
			}
		}
	}
	
	private void drawStar(double x, double y) {
		GStar star = new GStar(sizeSlider.getValue());
		star.setFilled(fillCheckBox.isSelected());
		star.setColor(selectedColor.getColor());
		add(star, x, y);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		/*Update the selectedColor variable to the value currently selected*/
		selectedColor = (LabeledColor)colorChooser.getSelectedItem();
		
		if (e.getActionCommand().equals("Clear")) removeAll();
		
		/*Add star name to the right of the current star*/
		if (gobj != null) {
			GLabel starName = new GLabel(labelField.getText());
			starName.setColor(selectedColor.getColor());
			add(starName, gobj.getX() + gobj.getWidth(), gobj.getY());
		}
	}
	
	/* Private constants */
	private static final int MIN_SIZE = 1;
	private static final int MAX_SIZE = 50;
	private static final int INITIAL_SIZE = 20;
	private static final int MAX_CHARACTERS = 20;
	
	/* Private instance variables */
	private JSlider sizeSlider;
	private JComboBox colorChooser;
	private JCheckBox fillCheckBox;
	private JTextField labelField;
	private LabeledColor selectedColor;
	private GObject gobj;
	private GPoint last;
}

The Art & Science of Java Chapter 10 Programing Exercise 6 – Draw Star Map Labeled Color

package drawStarMap_10_6;

import acm.program.GraphicsProgram;
import javax.swing.*;
import java.awt.Color;
import java.awt.event.*;
import SampleCodes.GStar;

/**
 * This program draws a 5 pointed star every time the user clicks on the canvas 
 */
public class DrawStarMapLabeledColor extends GraphicsProgram {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/* Initialises the mouse listeners */
	public void init() {
		JButton clearAll = new JButton("Clear");
		add(clearAll, SOUTH);
		fillCheckBox = new JCheckBox("Filled");
		fillCheckBox.setSelected(true);
		add(fillCheckBox, SOUTH);
		
		/* JSlider */
		sizeSlider = new JSlider(MIN_SIZE, MAX_SIZE, INITIAL_SIZE);
		add(new JLabel(" Min"), SOUTH);
		add(sizeSlider, SOUTH);
		add(new JLabel("Max"), SOUTH);
		
		/* JComboBox */
		initColorChooser();
		add(colorChooser, SOUTH);
		setBackground(Color.gray);		
		addMouseListeners();
		addActionListeners();
	}
	
	private void initColorChooser() {
		LabeledColor white = new LabeledColor(Color.white, "White");
		colorChooser = new JComboBox();
		colorChooser.addItem(white);
		colorChooser.addItem(new LabeledColor(Color.red, "Red"));
		colorChooser.addItem(new LabeledColor(Color.yellow, "Yellow"));
		colorChooser.addItem(new LabeledColor(Color.orange, "Orange"));
		colorChooser.addItem(new LabeledColor(Color.green, "Green"));
		colorChooser.addItem(new LabeledColor(Color.blue, "Blue"));
		colorChooser.addItem(new LabeledColor(Color.black, "Black"));
		colorChooser.setEditable(false);		//Make it illegal for user to type a new value in the color field
		colorChooser.setSelectedItem(white);
	}

	/* The method to be called whenever the user clicks the mouse */
	@Override
	public void mouseClicked(MouseEvent e) {
		LabeledColor selectedColor = (LabeledColor)colorChooser.getSelectedItem();
		GStar star = new GStar(sizeSlider.getValue());
		star.setFilled(fillCheckBox.isSelected());
		star.setColor(selectedColor.getColor());
		add(star, e.getX(), e.getY());
	}
	
	/* Removes all objects on canvas */
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equals("Clear")) removeAll();
	}
	
	/* Private constants */
	private static final int MIN_SIZE = 1;
	private static final int MAX_SIZE = 50;
	private static final int INITIAL_SIZE = 20;
	
	/* Private instance variables */
	private JSlider sizeSlider;
	private JComboBox colorChooser;
	private JCheckBox fillCheckBox;
}
package drawStarMap_10_6;

import java.awt.*;

/** This class implements a LabeledColor class that extends the standard Color class. This class takes a name to use as the result of the
 *  toStrong method. 
 */
public class LabeledColor extends Color{
	
	/** Creates a LabeledColor that contains a color object and a name to use as the result of the toString method */
	public LabeledColor(Color color, String str) {
		super(color.getRGB());
		colorName = str;
		this.color = color;
	}
	
	/** Returns the color of this object */
	public Color getColor() {
		return this.color;
	}
	
	/** Override the default toString method so that string specified by the user in the constructor is returned instead */ 
	@Override
	public String toString() {
		return colorName;
	}
	
	private String colorName;
	private Color color;
}

The Art & Science of Java Chapter 10 Programing Exercise 5 – Drawing Program

package drawingProgram_10_5;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;

import acm.program.*;
import acm.graphics.*;

import javax.swing.*;

public class DrawingProgram extends GraphicsProgram {

	private static final long serialVersionUID = 1L;

	/* This class is the super class for various palette buttons */
	class PaletteButton extends JButton{

		private static final long serialVersionUID = 1L;

		public PaletteButton(String imgURL, String actionCommand)  {
			super();
			ImageIcon icon = new ImageIcon(imgURL);
			setIcon(icon);
			setActionCommand(actionCommand);
			setFocusPainted(true);
			setBorderPainted(false);
			setContentAreaFilled(false);
		}
	}
	
	/* Initialize the canvas */
	public void init() {
		initPalette();
		drawingTool = "Oval";		//Set default drawing tool to oval
		addActionListeners();
		addMouseListeners();
	}
	
	/* Initialize the tool palette */
	private void initPalette() {
		PaletteButton ovalBtn = new PaletteButton("images/chapter10/OvalButton.png", "Oval");
		PaletteButton ovalFilledBtn = new PaletteButton("images/chapter10/OvalFilledButton.png", "OvalFilled");
		PaletteButton rectBtn = new PaletteButton("images/chapter10/RectangleButton.png", "Rectangle");
		PaletteButton rectFilledBtn = new PaletteButton("images/chapter10/RectangleFilledButton.png", "RectangleFilled");
		PaletteButton lineBtn = new PaletteButton("images/chapter10/LineButton.png", "Line");
		add(ovalBtn, WEST);
		add(ovalFilledBtn, WEST);
		add(rectBtn, WEST);
		add(rectFilledBtn, WEST);
		add(lineBtn, WEST);
	}
	
	/** Sets the drawing tool to the client's selection */
	public void actionPerformed(ActionEvent e) {
		drawingTool = e.getActionCommand();
	}
	
	/** Call on mouse pressed */
	public void mousePressed(MouseEvent e) {
		startX = e.getX();
		startY = e.getY();
		obj = getElementAt(e.getX(), e.getY());
		/* If there is no element at the coordinate of the mouse press, we assume that the client wants to draw a shape */
		if (obj == null) {
			if (drawingTool.equals("Rectangle")) {
				drawRect(startX, startY, false);
			} else if (drawingTool.equals("RectangleFilled")) {
				drawRect(startX, startY, true);
			} else if (drawingTool.equals("Oval")) {
				drawOval(startX, startY, false);
			} else if (drawingTool.equals("OvalFilled")) {
				drawOval(startX, startY, true);
			} else if (drawingTool.equals("Line")) {
				drawLine(startX, startY);
			}
		} else {
			last = new GPoint(e.getPoint());
			obj = getElementAt(last);
		}
	}
	
	/** Call on mouse click to move this object to the front */
	public void mouseClicked(MouseEvent e) {
		obj = getElementAt(e.getX(), e.getY());
		if (obj != null) {
			obj.sendToFront();
		}
	}
	
	/** Call on mouse release */
	public void mouseReleased(MouseEvent e) {
		obj = null;
	}
	
	/** Call on mouse drag. */
	public void mouseDragged(MouseEvent e) {
		double mouseX = e.getX();
		double mouseY = e.getY();
		calculateShapeProperties(mouseX, mouseY);
		if (obj != null) {
			obj.move(mouseX - last.getX(), mouseY - last.getY());
			last = new GPoint(e.getPoint());
		} else {
			if (drawingTool.equals("Rectangle") || drawingTool.equals("RectangleFilled")) {
				rect.setLocation(shapeX, shapeY);
				rect.setSize(shapeW, shapeH);
			} else if (drawingTool.equals("Oval") || drawingTool.equals("OvalFilled")) {
				oval.setLocation(shapeX, shapeY);
				oval.setSize(shapeW, shapeH);
			} else if (drawingTool.equals("Line")) {
				line.setEndPoint(mouseX, mouseY);
			}
		}
	}
	
	/* Draws a line on canvas */
	private void drawLine(double x, double y) {
		line = new GLine(x, y, x, y);
		add(line);
	}

	/* Draws a oval on canvas */
	private void drawOval(double x, double y, boolean fill) {
		oval = new GOval(0,0);
		oval.setFillColor(Color.blue);
		oval.setFilled(fill);
		add(oval, x, y);
	}

	/* Draws a rect on canvas */
	private void drawRect(double x, double y, boolean fill) {
		rect = new GRect(0,0);
		rect.setFillColor(Color.green);
		rect.setFilled(fill);
		add(rect, x, y);
	}
		
	/* Calculate the X, Y, width and length of a GRect or GOval relative to the specified mouse position */
	private void calculateShapeProperties(double mouseX, double mouseY) {
		
		/* Mouse cursor is in NE region of  */
		if (mouseX > startX && mouseY < startY) {
			shapeX = startX;
			shapeY = mouseY;
			shapeW = mouseX - startX;
			shapeH = startY - mouseY;
		/* Mouse cursor is in NW region */
		} else if (mouseX < startX && mouseY < startY) {
			shapeX = mouseX;
			shapeY = mouseY;
			shapeW = startX - mouseX;
			shapeH = startY - mouseY;
		/* Mouse cursor is in SW region */	
		} else if (mouseX < startX && mouseY > startY) {
			shapeX = mouseX;
			shapeY = startY;
			shapeW = startX - mouseX;
			shapeH = mouseY - startY;
		/* Mouse cursor is in SE region */ 
		} else {
			shapeX = startX;
			shapeY = startY;
			shapeW = mouseX - startX;
			shapeH = mouseY - startY;
		}
	}

	private GObject obj;
	private GPoint last;
	private String drawingTool;
	private GLine line;
	private GOval oval;
	private GRect rect;
	private double startX, startY, shapeX, shapeY, shapeW, shapeH;
}
Follow

Get every new post delivered to your Inbox.