HOMEWORK 3: More Component Interactions

This is an INDIVIDUAL assignment.

Objective

In the last assignment you learned how to create your own swing component from scratch. In this assignment, you will focus on developing rich integration with all of the components in the app. The additional features you will be adding will require you to do more mouse event handling, working with drag and drop, and working with copy and paste.

The learning goals for this assignment are:

Description

This homework extends the functionality you began in the previous homework. Now that you have the ability to add text and strokes to your content area, we now want to add integration with the components built into the left-pane. The requirements for this assignment are:

#1: Implementing copy/paste from the web browser

You will need to implement copy and paste for the web browser. This means you should be able to select and copy text and images from a web-page; pasting this content into the right pane should create a new, custom component that contains the content from the web browser.

To invoke copy/paste you will need to use the standard keyboard shortcuts; you can add a popup or contextual menu if you wish, but the keyboard shortcuts must also work. You should work with the standard Swing copy-and-paste framework (java.awt.datatransfer and other packages) for this assignment.

When content copied from the browser is pasted into the content area, a new component should be created to hold this content. In other words, copied content is not simply stored directly in your canvas's display list; instead, it should appear as a kind of "sticky note" or "clipping" component that appears to be on top of the underlying canvas. This sticky note should be implemented as a new custom type of component that you create; each paste will result in a new instance of the sticky note being created and added as a child component of your content area.

This sticky note should have an appropriate appearance (it might look like a yellow sticky note, for instance), and should be draggable around your content area with the mouse. The sticky note should appear over the top of any strokes or text rendered on the underlying content area, which means that it may obscure content depending on where the user places it; you don't have to worry about pushing content out of the way as the sticky note is dragged around. You also don't have to worry about things like resizing the sticky note or adding scroll bars to it--it should be just large enough to contain the pasted content.

The content that's pasted into the sticky note can be just the text and any images copied from the web page. You don't have to worry about formatting the text so that it looks just like the original web content--in other words, just plain text along with any images is fine (although we'll give extra credit if you maintain the rich formatting).

Hint: The simplest way to handle placing an image is to simply line break before and after the image so it appears in-line with the text. For extra credit you can implement more complicated image placement strategies, like flowing the text around the image.

#2: Implementing drag and drop from the address book

For the address book you will need to implement drag and drop of address book items into the content area on the right. You should use the Java drag-and-drop framework (java.awt.dnd) for this.

Selection and dragging should be straightforward and behave as you would expect: the user should be able to drag either a row from the table, or the "prettified" view below the table, over into the content area. (You should set up your table so that dragging muiltiple rows is not allowed, if you don't wish to support it.)

When dropping the selected address into the right pane, you should again create a custom component to contain the content, which should be installed as a child of your content area. This component should format and display the address in a sensible way, for example:

Jane Dough
1555 Fancypants Drive
Sub Urbia, 03045
555 555 5483

This "address clipping" component should also be draggable, and be just large enough to contain the content; you don't need to worry about resizing the component, adding internal scroll bars to it, etc.

Some Hints

Managing children

One of the key things you'll have to do in this assignment is tweak your content area component so that it can handle children. There's actually not a ton of work you need to do to allow this: the standard add() method can already be used to add children to your component, and paintChildren() (which is already called automatically by your component) will draw them for you. In the end, you should be able to add your new components as children of your content area, and access them using getComponents() and other standard Swing methods, just like any other normal Swing components.

You will need to make sure you're handling layout correctly. In particular, make sure your component does not have a layout manager set, since you'll be managing the locations and sizes of your child components directly.

Design rationale: If you've done much Swing programming in the past, you know that Swing typically uses Layout Managers to handle the sizing and positioning of child components inside a container. Why are we not implementing this as a custom layout manager? The main reason is that I want to be able to drag and move child components without having to compete with whatever positions that a layout manager would be trying to set for these. If you do want to implement a custom layout manager to do this, see me about getting some extra credit. :-)

Moving Child Components

You'll need to respond to MouseEvents and MouseMotionEvents in order to implement the ability to drag stickies and address book clippings around in the content area. Your content area should listen for these event types; when mousePressed() is invoked, you can iterate through your list of children (using the already defined getComponents() method) to cycle through your child components, and see if the event falls within the bounding box of one of them.

If it does, then you can remember that component as being "in motion"; in other words, when successive mouse drags happen, you update the position of that component until mouse release occurs, at which point the drag ends.

Hint: Having repaint problems? Are your changes not getting reflected on screen? Be sure to call revalidate() anytime the set of children changes, or your size changes.

Design rationale: In the description above, I have the content area doing the input processing, while individual stickies and clippings are "output only." You could also do this a different way, with the subcomponents themselves soliciting the events that make them clickable, draggable, etc.

While each strategy has it's own merits, I think the one I've outlined above is the most sensible. It's the content area, after all, that owns the real estate for what it displays overall. You might, for example, want to reuse the sticky notes class in a window other than the Courier content area, and so selecting and dragging might have different semantics there. If the sticky class itself implemented this functionality, it would make thumbnails harder to reuse.

Possible gotcha: If you make the stickies or clippings classes respond to mouse events, then they'll consume any events that happen on them (remember that Swing dispatches events to the lowest leaf-node component that can accept those events). Be sure to not make these components a MouseListener or MouseMotionListener if you don't want this to happen.

Extra Credit

There are a lot of ways to augment this assignment, should you choose to. Some obvious ways are:

Deliverable

This is an INDIVIDUAL assignment; while you may ask others for help on Java or Swing details, please build your application on your own.

Here are the details for how to turn in the assignment. We'll be using this structure for all of the turn-ins:

1. Create an executable JAR file named courier.jar that contains your runnable application. (See here for details on how to create executable JAR files.) We should be able to run your program by typing "java -jar courier.jar" on the command line; please be sure that your application runs correctly using ONLY this command, and that it doesn't require any additional CLASSPATH or other environment variables, no additional parameters, no classfiles or images located outside the JAR file, etc.

2. Create a new directory using your last name as the name of the directory.

3. Put the courier.jar file into the top level of this directory, and all of your source files into a "source" subdirectory inside this directory.

4. Put a README.txt file into the top level of this directory. This file should contain your name and email address, the version of Java you used (Java 1.6.x only, please) as well as any special info we might need to know about your program (let us know if you did extra credit, for example).

5. ZIP this directory and submit via T-Square (instructions are here).

Please take care to remove any platform dependencies, such as hardcoded Windows path names or dependence on a particular look-and-feel that may not exist on all platforms. Also, if you use any images in your application, please make sure that you include these in your JAR file and that your code will refer to them and load them properly when they're in this JAR file (see this page for some details on how to include and load images from within a JAR file).

Grading for this assignment, and future assignments, will roughly follow this breakdown:

Please let the TA or me know if you have any questions.