SE-1021 Software Development 2
Lab 9: Drawing Program - Part 2

Outcomes

bulletDesign and implement a Graphical User Interface (GUI) using Java Swing classes
bulletimplement inheritance and polymorphism on classes that extend an abstract class
bulletimplement handling of events generated by a graphical user interface
bulletimplement exception handling in an application to react to error conditions
bulletimplement file I/O read and write files in various formats

Assignment

Here in the second part of this assignment, you will implement the following additional functionality, where:
  1. Selecting the Background Color item from the Options menu allows a user to select a color for the application window background.
  2. Selecting the Pen Color item from the Options menu allows a user to select a color for subsequent shapes to be drawn. (When a different Pen Color is selected, the shapes already drawn do not change color; they retain the pen color with which they were previously drawn.)
  3. Selecting the Save item from the File menu allows a user to select a file for saving the created shapes in one of three different file formats - text, binary, and serialized object.
  4. Selecting the Load item from the File menu allows a user to select a file for loading the previously saved shapes (in different formats).

Assignment details for Part 2

In this assignment, you will implement the handleColorCommand(), handleFileSaveCommand(), and handleFileLoadCommand() methods of the DrawingProgramApp class (see the UML class diagram from the previous lab). The handleColorCommand(), handleFileSaveCommand() and handleFileLoadCommand() methods are already in the DrawingProgramApp class, although they are empty.

The handleColorCommand() method is called by the menu action listener when the user selects the Options/Pen Color... or Options/Background Color... commands. In response to these events, the handleColorCommand() method is called with a String argument indicating which menu item was selected. In either case, in handleColorCommand(), you are to post a JColorChooser dialog, and (only if the user chooses a color and presses OK) set the penColor or backgroundColor attribute appropriately. Be careful in implementing this; in the case where the user presses the cancel button, no color will be selected!

The purpose of the handleFileSaveCommand() and handleFileLoadCommand() methods is described in the comments above the empty method bodies; that is, they post the JFileChooser dialogs that prompt the user for the files to save or load. After obtaining the file names from the user, these two methods call the saveTextImage(), saveBinaryImage(), saveObjectImage(), loadTextImage(), loadBinaryImage(), and loadObjectImage() methods where the actual File I/O is done. You'll have to create these methods  - be sure to follow the method signatures found in the UML class diagram.

The saveTextImage(), saveBinaryImage(), and saveObjectImage() methods save each created shape contained in the List of shapes in one of three different formats, depending on the specified file extension of the filename you specify. For example, if the specified filename is "image.txt" (ending with the "txt" extension), you are to save the individual shapes in a human-readable text file format using saveTextImage(). If the filename is "image.bin" (extension is "bin"), then the individual shapes are to be stored in binary format by saveBinaryImage(). Finally, if the filename is "image.obj", the serialization functions provided by Java are to be used to store the shapes in object format with saveObjectImage(). The exact formats are described in the section below.

Similarly, the loadTextImage(), loadBinaryImage(), and loadObjectImage() methods read in files of previously-saved shapes (in the various formats), replacing any existing shape collection with the shapes found in the specified file. Before replacing any existing shape collection, be sure the image loading operations completed successfully (without generating any exceptions). That is, don't replace an existing image unless you are successful!

Any exceptions encountered either loading or saving files must be presented to the user (using JOptionPane dialogs) without crashing the application or causing loss of data (shapes). Your program must not crash or allow exceptions to propagate out to the JVM!

Catch
the exceptions in the handleFileSave() and handleFileLoad() methods - not in the saveXXX() or loadXXX() methods.

Here is a UML Sequence diagram showing the flow of method calls for the File Load and File Save sequences (for the case where a text file is specified):

File Formats

You must support saving and loading shape information with three file formats: text, binary, and object. We'll adopt the convention that files ending with the "txt" extension contain a representation of the shape data in text (human-readable) format, the "bin" extension indicates a file containing shape data in binary format, and the "obj" extension represents shapes stored as serialized objects.

Text Format

In a text file (ending with "txt"), each record in the file specifies a single shape. The example below illustrates a text file containing two shapes. Your text file must be able to store any number of shapes (including none at all), using this exact format:

bullet
The 1st token in a record specifies the shape type; the value is equivalent to one of the static final ints defined within the AbstractShape class (e.g. a Line is represented by a 0, a Rectangle is represented by a 1, etc).
bullet
The 2nd and 3rd tokens specify the starting x and y locations of the shape.
bullet
The 4th and 5th tokens specify the ending x and y locations of the shape.
bulletThe last three tokens specify, respectively, the Red, Green, and Blue color values of the shape; each value may be between 0-255.

Following this specification, the first record below specifies a Line (shape type 0), starting at coordinates (18,40), ending at coordinates (95,196), and white in color (Red, Green and Blue are all 255). The second record specifies a blue Ellipse.

 0 18 40 95 196 255 255 255 
 2 104 38 167 158 0 0 255

The easiest way to output a shape's text representation is by writing the result returned by the shape's toString() method.

When reading shapes from a file, you have to read the first token in each record to determine the shape type, then use the remaining information in that record to create that shape.

Binary Format

In a binary file (ending with "bin"), raw integer values are stored rather than the characters representing the digits of those values. Binary files don't contain explicit records either, so the files will just be continuous sequences of bytes that represent the integer values of the shapes' parameters. For each shape stored, the file will contain 32 bytes representing eight 4-byte integers, in the following order:

<shape type><starting x><starting y><ending x><ending y><red component><green component><blue component>

The binary file must be able to store any number of shapes (including none at all).

Object Format

In an object file (ending with "obj"), shapes will be stored using Java's built-in serialization capability. Rather than serializing each individual shape, however, you'll serialize the entire ArrayList of shapes. Thus, you only need to write or read the ArrayList and everything contained within that collection will be automatically serialized (this is one of the benefits of Java's serialization feature). You of course need to ensure that the shapes all implement the serialization interface in order for this to work correctly - you do this by making the AbstractShape class itself serializable.

Testing your program

Test your program to verify that it works correctly: Create various shapes of different colors, save the shapes to files in different formats, and exit the program. Restart the program, and add some new shapes. Then open the files containing the previously-saved shapes; those shapes should replace the new shapes you just created. Be sure that the shapes restored from the file have the same positions and colors as they had when you had saved them.

Use the following three files to validate that your program can correctly load images of each format:
bullettest.txt
bullettest.bin
bulletAn object file cannot be supplied due to the fact that the information serialized into the file contains the complete package name of the classes being serialized. In your individual implementations, your classes each have packages names that are specific to your MSOE email name. Thus, when you load a previously-saved object file, the Java deserialization algorithm will require that the shapes that it's deserializing will contain your package names.

These files when loaded both should result in the following image:

Lab Submission (due date in Blackboard)

  1. Demonstrate your Drawing Program to your instructor. If you can't do this by the end of class, you must demonstrate it sometime during Office Hours before the following lab. You will not receive a grade until you provide this demonstration. Demonstrations after the due date will be considered a late submission.
     
  2. Upload all files  (Ellipse.java, Rectangle.java, Line.java, DrawingProgramApp.java, and AbstractShape.java) through Blackboard (assignment "Lab 9: Drawing Program - Part 2"). Be sure to keep copies of all your files, in case something gets lost.

Your grade will be based on the following criteria:

bulletMeeting requirements; your program must compile and run, and produce well-formed, explicit error messages. If you have trouble, you must come to see me. If you don't and you submit a program that does not compile or produce detailed meaningful results will receive a grade of no higher than 50, even after reworking your program.
 
bulletTechnical quality of your program. Technical quality consists of formatting, commenting, and following coding style guidelines.
 
bulletSpelling and grammar.
 
bulletTimeliness of submission as stated in the course policies.