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 = ",";
}