cs106a – Assignment #7 – Task #5

The complete specification of assignment #7 can be found as part of the stream at iTunes.

Implement the FacePamphletCanvas class and complete the implementation of the FacePamphlet class

The class (which extends GCanvas) contains three public entries:

  • A constructor that has no parameters. You can use this to perform any initialization you may need for the canvas. Note: depending on how you implement the canvas, it is entirely possible that your constructor may not need to do anything. It’s perfectly fine if that’s the case.
  • A showMessage method that is passed a String, and is responsible for displaying that string as the Application Message at the bottom of the canvas. The method should display this Application Message text centered horizontally with respect to the width of the canvas, and the vertical baseline for the text should be located BOTTOM_MESSAGE_MARGIN pixels up from the bottom of the canvas. The font for the text should be set to MESSAGE_FONT. Note that BOTTOM_MESSAGE_MARGIN and MESSAGE_FONT are simply constants defined in FacePamphletConstants. Whenever this method is called, any previously displayed message is replaced with the new message text that is passed in.
  • A displayProfile method that is passed a FacePamphletProfile, and is responsible for displaying the contents of that profile in the canvas, including the profile’s name, image (if any), the status of the profile (if any), and the list of friends (if any). Whenever this method is called, all existing contents of the canvas should be cleared (including any previously displayed profile as well as any displayed Application Messages), and the profile passed in should be displayed. How the various components of the profile should be displayed is discussed in more detail below.

To start adding the graphical display code for profiles, you should go back to the FacePamphlet class and change its definition so that it extends Program rather than the temporary expedient of extending ConsoleProgram (as you may have been using during the milestones above). At the same time, you should remove the various println calls that allowed you to trace the operation of the interactors in the earlier milestones.
Now, you’ll need to declare a FacePamphletCanvas private instance variable in your main FacePamphlet class:

private FacePamphletCanvas canvas;

You should then change the constructor of the FacePamphlet class so that it creates a
new FacePamphletCanvas object and adds that object to the display, as follows:

canvas = new FacePamphletCanvas();
add(canvas);

Start by changing the parent of the main class and adding the snippets as described above.

Much of the layout for graphical display of profiles is dictated by constant values defined in FacePamphletConstants. Here we explain how each component of the profile display should be set up, and refer to the sample screen below as necessary:

cs106a – assignment #7 – task #5

  • Name: Near the top of the display, the name associated with the profile (“Julie Zelenski” in the example above) should be displayed in the color Blue. Horizontally, the text should located LEFT_MARGIN pixels in from the left-hand side of the canvas. Vertically, the top of the text (not its baseline) should be TOP_MARGIN pixels from the top of the canvas. The font for the text should be set to PROFILE_NAME_FONT.
  • Image: Although there is currently no image associated with the profile above, we can see that there is space set aside to display an image immediately under the name of the profile. The space for the image will always be IMAGE_WIDTH by IMAGE_HEIGHT pixels.
  • If no image is associated with the profile then a rectangle of the dimensions of the image size should be drawn. Horizontally, this rectangle should be located LEFT_MARGIN pixels in from the left-hand side of the canvas. Vertically, the top of the rectangle should be should be IMAGE_MARGIN pixels below the baseline of the profile name text. Centered (both horizontally and vertically) within this rectangle should be the text “No Image” in the font PROFILE_IMAGE_FONT.
    If an image is associated with the profile then the image should be displayed (in the same location as the rectangle described above). The image should be scaled so that it displays with IMAGE_WIDTH by IMAGE_HEIGHT pixels. The scale method of GImage should be useful to make image display with the appropriate size.

  • Status: Under the area for the image, the current status of the person with this profile should be displayed (Julie’s status is “running” in the example above). If the profile currently has no status (i.e., it has an empty status string), the text “No current status” should be displayed. If the profile does have a status, the status text should have the name of the profile followed by the word “is” and then the status text for the profile. In any case, the line describing the profile’s status should be located horizontally LEFT_MARGIN pixels in from the left-hand side of the canvas. Vertically, the top of the text (not its baseline) should be located STATUS_MARGIN pixels below the bottom of the image. The font for the text should be set to PROFILE_STATUS_FONT.
  • Friends: To the right of the profile’s name, there is the header text “Friends:”, and the names of the friends of this profile (e.g., Mehran Sahami, Bob Plummer, and Eric Roberts) are listed below. The start of the header text “Friends:” should be horizontally located at the midpoint of width of the canvas. Vertically, the baseline for this text should be the same as the top of the image area. The “Friends:” header text should be displayed in the font PROFILE_FRIEND_LABEL_FONT. Immediately below the header, the friends of this profile should be listed sequentially, one per line, with the same horizontal location as the “Friends:” header text. You can use the getHeight() method of GLabel to determine how to vertically space out the list of friends to get one friend per line. The friend names should be displayed in the font PROFILE_FRIEND_FONT.
  • Application Message: As described previously (but repeated here for completeness) the Application Message text (“Displaying Julie Zelenski” in the example above) should be centered with respect to the width of the canvas, and the baseline for the text should be located BOTTOM_MESSAGE_MARGIN pixels up from the bottom of the canvas. The font for the text should be set to MESSAGE_FONT.

To display a profile, start by removing everything and then draw the elements if there is profile data available:

	public void displayProfile(FacePamphletProfile profile) {
		removeAll();
		if (profile == null) return;
		double x = LEFT_MARGIN;
		double y = TOP_MARGIN;
		y = drawName(profile.getName(), x, y);
		y += IMAGE_MARGIN;
		drawFriends(profile.getFriends(), getWidth() / 2, y);
		y = drawImage(profile.getImage(), x, y);
		drawStatus(profile, x, y + STATUS_MARGIN);
	}
	
	private double drawName(String name, double x, double y) {
		GLabel label = new GLabel(name);
		label.setFont(PROFILE_NAME_FONT);
		label.setColor(PROFILE_NAME_COLOR);
		label.setLocation(x, y += label.getAscent());
		add(label);
		return y;
	}
	
	private double drawImage(GImage image, double x, double y) {
		double width = IMAGE_WIDTH;
		double height = IMAGE_HEIGHT;
		if (image == null) {
			add(new GRect(x, y, width, height));
			GLabel label = new GLabel(NO_IMAGE_TEXT);
			label.setFont(PROFILE_IMAGE_FONT);
			label.setLocation(
					x + (width - label.getWidth()) / 2, 
					y + (height + label.getAscent()) / 2);
			add(label);
		} else {
			image.scale(width / image.getWidth(), height / image.getHeight());
			image.setLocation(x, y);
			add(image);
		}
		return y + height;
	}
	
	private void drawStatus(FacePamphletProfile profile, double x, double y) {
		String status = profile.getStatus(); 
		if (status.equals("")) {
			status = NO_STATUS_TEXT;
		} else {
			status = profile.getName() + STATUS_TEXT_DELIMITER + status;
		}
		GLabel label = new GLabel(status);
		label.setFont(PROFILE_STATUS_FONT);
		label.setLocation(x, y += label.getAscent());
		add(label);
	}
	
	private void drawFriends(Iterator<String> friends, double x, double y) {
		GLabel label = new GLabel(FRIENDS_LABEL_TEXT, x, y);
		label.setFont(PROFILE_FRIEND_LABEL_FONT);
		add(label);
		y += label.getHeight();
		while (friends.hasNext()) {
			GLabel friend = new GLabel(friends.next(), x, y);
			friend.setFont(PROFILE_FRIEND_FONT);
			y += friend.getHeight();
			add(friend);
		}
	}

Displaying the message works similar – just make sure to use it after displaying the profile, as this removes the message, too:

	public void showMessage(String msg) {
		GLabel label = new GLabel(msg);
		label.setFont(MESSAGE_FONT);
		label.setLocation(
				(getWidth() - label.getWidth()) / 2,
				getHeight() - BOTTOM_MESSAGE_MARGIN);
		add(label);
	}

In finishing up the program, you need to make calls at appropriate times to displayProfile and showMessage in your FacePamphlet class:

  • Adding a Profile
    When a new profile is being added you should see if a profile with that name already exists. If it does, you should display the existing profile and give the user the message “A profile with the name already exists”. If the profile does not already exist, you should display the newly created profile and give the user the message “New profile created”.
  • Deleting a Profile
    When a profile is being deleted you should see if a profile with that name exists. If it does, you should delete the profile, clear any existing profile from the display, and give the user the message “Profile of deleted”. If the profile does not exist, you should clear any existing profile from the display, and give the user the message “A profile with the name does not exist”.
  • Looking up a Profile
    When a profile is being looked up you should see if a profile with that name exists. If it does, you should display the profile, and give the user the message “Displaying “. If the profile does not exist, you should clear any existing profile from the display, and give the user the message “A profile with the name does not exist”.
  • Changing Status
    When the status for a profile is being changed, you should determine if there is a current profile. If no current profile exists, you should just give the user the message “Please select a profile to change status”. If there is a current profile, you should update its status, redisplay the profile (to show the changed status), and give the user the message “Status updated to “.
  • Changing Picture
    When the picture for a profile is being changed, you should determine if there is a current profile. If no current profile exists, you should just give the user the message “Please select a profile to change picture”. If there is a current profile, you should see if the filename given for the picture contains a valid image, and if it does, you should add the image to the profile, redisplay the current profile (to show the new image), and give the user the message “Picture updated”. If the given filename could not be opened, you should just give the user the message “Unable to open image file: “. In that case, the image associated with the profile is unchanged.
  • Adding Friend
    When a friend is being added to a profile, you should determine if there is a current profile. If no current profile exists, you should just give the user the message “Please select a profile to add friend”. If there is a current profile, you should see if the given friend name is the name for a valid profile in the social network. If the name is valid and the current profile does not already have that person as a friend, then you should update the friend list for both the current profile and the named friend, redisplay the current profile (to show the addition of the friend), and give the user the message “ added as a friend”. If the named friend is already a friend of the current profile, you should just display the message “ already has as a friend.” If the named friend does not have a profile in the social network, then you should simply display the message “ does not exist.”

Finish up by calling the appropriate functions (essentially by replacing the printlns):

	public void actionPerformed(ActionEvent e) {
		Object source = e.getSource();
		if (source == addButton) {
			if (!emptyTextField(nameField)) {
				String name = nameField.getText();
				if (data.containsProfile(name)) {
					profile = data.getProfile(name);
					canvas.displayProfile(profile);
					canvas.showMessage("A profile with the name " + name + " already exists");
				} else {
					profile = new FacePamphletProfile(name);
					data.addProfile(profile);
					canvas.displayProfile(profile);
					canvas.showMessage("New profile created");
				}				
			}    		
		} else if (source == deleteButton) {
			if (!emptyTextField(nameField)) {
				String name = nameField.getText();
				if (data.containsProfile(name)) {
					data.deleteProfile(name);
					profile = null;
					canvas.displayProfile(profile);
					canvas.showMessage("Profile of " + name + " deleted");
				} else {
					profile = null;
					canvas.displayProfile(profile);
					canvas.showMessage("A profile with the name " + name + " does not exist");
				}				
			}    		    		
		} else if (source == lookupButton) {
			if (!emptyTextField(nameField)) {
				String name = nameField.getText();
				if (data.containsProfile(name)) {
					profile = data.getProfile(name);
					canvas.displayProfile(profile);
					canvas.showMessage("Displaying " + name);
				} else {
					profile = null;
					canvas.displayProfile(profile);
					canvas.showMessage("A profile with the name " + name + " does not exist");
				}
			}    		    		
		} else if ((source == statusField) || (source == statusButton)) {
			if (!emptyTextField(statusField)) {    			
				if (profile != null) {
					String status = statusField.getText();
					profile.setStatus(status);
					canvas.displayProfile(profile);
					canvas.showMessage("Status updated to " + status);
				} else {
					canvas.displayProfile(profile);
					canvas.showMessage("Please select a profile to change status");
				}    			
			}    		
		} else if ((source == pictureField) || (source == pictureButton)) {
			if (!emptyTextField(pictureField)) {
				if (profile != null) {
					String filename = pictureField.getText();    			
					GImage image = null;
					try {
						image = new GImage(filename);
					} catch (ErrorException ex) {
						// Code that is executed if the filename cannot be opened. 
					}
					if (image != null) {
						profile.setImage(image);
						canvas.displayProfile(profile);
						canvas.showMessage("Picture updated");
					} else {
						canvas.displayProfile(profile);
						canvas.showMessage("Unable to open image file: " + filename);
					}
				} else {
					canvas.displayProfile(profile);
					canvas.showMessage("Please select a profile to change picture");
				}    			
			}    		
		} else if ((source == friendField) || (source == friendButton)) {
			if (!emptyTextField(friendField)) {
				if (profile != null) {
					String friend = friendField.getText();
					if (data.containsProfile(friend)) {
						if (profile.addFriend(friend)) {
							data.getProfile(friend).addFriend(profile.getName());
							canvas.displayProfile(profile);
							canvas.showMessage(friend + " added as friend");
						} else {
							canvas.displayProfile(profile);
							canvas.showMessage(profile.getName() + " already has " + friend + " as a friend.");
						}
					} else {
						canvas.displayProfile(profile);
						canvas.showMessage(friend + " does not exist");
					}
				} else {
					canvas.displayProfile(profile);
					canvas.showMessage("Please select a profile to add friend");
				}
			}    		    		
		}
	}

The code for this assignment is available on github.

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Flattr this!

Leave a Reply

Your email address will not be published. Required fields are marked *