Lab 2: iSwat Media Library
Due on Wednesday, February 13th at 11:59 PM. This is an individual lab. You are to complete this lab on your own, although you may discuss the lab concepts with your classmates. Remember the Academic Integrity Policy: do not show your code to anyone outside of the course staff and do not look at anyone else’s code for this lab. If you need help, please post on the Piazza forum or contact the instructor or ninjas. If you have any doubts about what is okay and what is not, it’s much safer to ask than to risk violating the Academic Integrity Policy.
When you are done with the lab, be sure to fill out this survey on your experience.
Overview
The goal of this lab is to continue your introduction to basic concepts in the C++ programming language. Concepts you will be familiar with after this lab include:
- file input/output
- Object-Oriented Programming (OOP) in C++
- inheritance and polymorphism
- defensive programming (e.g., detecting improper input)
- designing and compiling multi-file programs
In this lab, you will create several classes representing different
types of media, including text, pictures, and videos. All of these
classes will be subclasses of an abstract Media
class. This Media
class will encapsulate all functionality common to all types of media.
Your subclasses will add additional unique data as well as implement
inherited methods in a way specific to that media. For example,
“opening” a text file should be different from “opening” a picture
or video.
In addition, you will create a MediaLibrary
class which acts as a
container for up to 50 Media
objects (think of how iTunes stores all
of your eBooks, music, movies, etc.). You will also build capability in
the MediaLibrary
class for obtaining information about your different
media objects and for playing the media itself.
Starting Point
You will access your code through a git repository, which is
named lab02-<userID>.git
. Please access your lab by cloning the
appropriate git repository, e.g.:
$ cd ~/cs35
$ git clone git@github.swarthmore.edu:CS35-s19/lab02-userID.git
$ cd lab02-userID/
You can also get the ssh git url from CS35 github org.
You have been given the following files in your repository. Those highlighted (in bold) will require modification. Otherwise, the file is complete and should not be modified (but you should understand what has been given to you to properly implement this lab).
Makefile
- contains scripts for compiling.test_data/example1.library
- small test file of 3 media items.test_data/example2.library
- larger media library. You do not need to modify, but may do so to add more examples (optional).media.h
- declares theMedia
class, an abstract parent class of all media types.text{.h,.cpp}
- declares and defines theText
class, a subclass ofMedia
. Some of this implementation has been provided for you.image{.h,.cpp}
- declares and defines theImage
class, a subclass ofMedia
.video{.h,.cpp}
- declares and defines theVideo
class, a subclass ofMedia
.mediaLibrary{.h,.cpp}
- declares and defines theMediaLibrary
class. This class acts as the overall container for allMedia
items.iSwatMedia.cpp
- This is the main function for your program.testMediaLib.cpp
- This has another main function that you can use to experiment with your program. Graders will look at this file to see how you tested your program.
Running Your Program
Your code in this assignment is broken in to several different files. To
aid in the compilation process, we’ve created a Makefile
which should
make compilation easy. To compile and run your test program, just type:
$ make testMediaLib
$ ./testMediaLib
To compile and run your main program:
$ make iSwatMedia
$ ./iSwatMedia test_data/example1.library # or whichever library file you choose
To compile both, you can run make all
or just make
.
Implementation Details
There are three main components to this lab that you will need to understand and implement (in part or whole):
- The
Media
class and its three subclasses,Text
,Image
,Video
- The
MediaLibrary
class, which manages a collection ofMedia
objects - Two main programs, one for testing (
testMediaLib.cpp
) and one application (iSwatMedia.cpp
)
The Media Class
The Media
class contains virtual methods which are common to all media objects. You will not directly create objects of type Media
(in fact, you can’t because it is an abstract class). We have provided this parent class to you; you will need to implement the subclasses to be able to create each of three types of media objects.
See the method comments on the declarations of those classes
for more information about the behavior you need to implement. Each
subclass will have methods getName()
, getDescription()
, and open()
; the specifics of their implementation depend on the
subclass you are implementing. Similarly, the data members needed
for each subclass may vary. We have provided the data members for
Text
, so that would be a good starting point (you will need to determine what data members are needed for the other two subclasses).
The getDescription()
method is used to summarize a file for printing in the
main application menu (see the application section for an example). Each Media
subclass implements it in a different way:
Text::getDescription()
should give the string"[text] "
followed by the name of the document (e.g."[text] Gettysburg-Address"
).Image::getDescription()
should do likewise but with the prefix"[image]"
(e.g."[image] Brown-Flames"
).Video::getDescription()
uses the prefix"[video]"
and suffixes the video length in parentheses (e.g."[video] Running-Gerbil (0:29)"
).
The open
method of each Media
object should behave
as follows:
- For
Text
, it should open the file, read it line by line, and print each line it reads. - For
Image
, it should open the image viewergpicview
to display the image to the user. You can accomplish this by using thesystem
function (discussed below). - For
Video
, should open the URL of the video usingmediaLibPlayer.sh
. You should usesystem
for this as well.
The MediaLibrary Class
This class keeps track of all Media
objects in a library. It allows a
user to ask for a description of all Media
objects that are in the library and gives them
access those objects on request.
Its constructor takes in a single string
which represents the name of the file containing the media library. In
the MediaLibrary
constructor, you should open this file and create
Media
objects accordingly (and store the number of elements you add using the size
data member). You will store each of these in the library
data member e.g., library[index] = new Image(...)
to add an Image
into the library
. While the specific subclasses will vary from item to item,
C++ will treat them all as of type Media
. This is a use of polymorphism; read the section below to ensure you understand how this works.
The Media Library File
When the program starts, the user will provide the name of a media library file which will contains the individual media objects you will load into your library.
The first line of the media library file should indicate the number of
media objects it contains so you know exactly how many items to load.
Each item is represented by several lines: the first line will describe the media type (i.e., text
, image
, or video
); the remaining lines depend
on the specific media type. Here is example1.library
followed by a detailed
explanation of each line:
3
image
/usr/swat/pics/brownflames.gif
Brown-Flames
image
/usr/swat/pics/aliens.jpg
Aliens
text
/usr/local/doc/GettysburgAddress
Gettysburg-Address
- For a text file, the first line will be
text
. The following line will contain the location of the text file e.g. (e.g./usr/local/doc/GettsburgAddress
); the next line will contain the document’s name (e.g.Gettysburg-Address
). - For an image, the first line will be
image
. The following line will contain the location of the image file (e.g./usr/swat/pics/brownflames.gif
); the next line will contain the image’s name (e.g.Brown-Flames
). - For a video, the first line will be
video
. The following line will be the URL for the video (e.g.https://vimeo.com/28241047
). The line after that will be the name of the video (e.g.Running-Gerbil
) followed by a line containing the video length as a string (e.g.(0:29)
)
To simplify your job of parsing the file, you can assume that each line of the media library file contains a single element with no whitespace (this creates odd document names, but allows for a single file read per line).
Main Program: iSwatMedia
Example run of the small test library with three media items (example1.library
):
$ ./iSwatMedia test_data/example1.library
Welcome to the iSwat Media Library!
0. Quit
1. [image] Brown-Flames
2. [image] Aliens
3. [text] Gettysburg-Address
What would you like to open (or 0 to quit)? 3
Four Score and seven years ago our fathers brought forth on
this continent a new nation, conceived in Liberty, and dedicated
to the proposition that all men are created equal.
...
[truncated for space]
...
government of the people, by the people, and for the people, shall
not perish from the earth.
0. Quit
1. [image] Brown-Flames
2. [image] Aliens
3. [text] Gettysburg-Address
What would you like to open (or 0 to quit)? -1
Illegal choice. Would would you like to open (or 0 to quit)? 4
Illegal choice. Would would you like to open (or 0 to quit)? 2
[should open window with picture of alien drawings from a CS21 lab]
0. Quit
1. [image] Brown-Flames
2. [image] Aliens
3. [text] Gettysburg-Address
What would you like to open (or 0 to quit)? 0
Goodbye!
As mentioned above, your main
function should expect the user to provide
name of a media library file via the command line. Using that file, it should display a menu
listing the media files in order and allow the user to pick a media file
to open. If the user gives an invalid file name (or none at all), your program should
print an error message on screen and end.
Media files should be listed by positive integers. The first media file you show should be selected by the input 1. After opening that media file, the menu should be repeated again. The program should continue until the user types 0, after which the program should terminate. If the user enters an invalid option, your program should print an error message, then print the menu again.
Tips and Requirements
Polymorphism
Understanding polymorphism in C++ is essential to completing this lab.
The main takeaway for this lab is that polymorphic behavior allows you
to treat different types of objects (i.e., Video
, Image
, Text
)
as if they are of one common type (Media
). In fact, aside from the construction of an object, you will never need to specify if a particular object is of a particular subclass. As an example, consider the code provided in testMediaLib.cpp
:
Media* testText = new Text("Sample","/home/soni/public/cs35/mediaLibrary/sampleText.txt");
cout << testText->getName() << endl;
cout << testText->getDescription() << endl;
testText->open(); //This should output exactly three lines
Notice that the only time we specify that testText
is pointing to an
object of type Text
is in the construction. For the remaining three
lines, the type of testText
is just Media*
. But the beauty of
polymorphism is that we don’t need to know the try underlying type;
the code would not change since all subclasses of Media
are guaranteed to
implement the methods getName()
, getDescription()
, and open()
.
Consider this function:
void doStuff(Media* media){
cout << media->getName() << endl;
cout << media->getDescription() << endl;
media->open();
}
This will work! You may wonder how the correct version of open()
gets called. While you
do not need to specify this, the compiler does keep track and will call the
correct version automatically. As you implement the main program, you should
identify locations where the true underlying class is abstracted from you
as the programmer (i.e., you only know that it is a type of Media
object).
Implementation Strategy
We recommend implementing your program in 5 parts:
- Initial file I/O – be able to read in an example media library from a file. For now, don’t worry about actually using this information; just print the contents of the file to the screen so you know your file I/O is working.
Text
class – be able to view a text file. Test that this works intestMediaLib.cpp
.Image
andVideo
classes – be able to open an image or play a video. Test that this works intestMediaLib.cpp
.- Media Library – build and test a
MediaLibrary
class which holds up to 50 media objects and lets the user access the objects. - Finish the main program – once you have your media objects and
MediaLibrary
set up, complete the program. When completed, your program should ask the user for a media library, present a menu of media objects, and allow the user to select and open the media.
Your program must use good design principles, and you should use defensive
programming as you develop your code. Your program will be tested on
your understanding on how to define C++ classes and use inheritance. In
addition, you should implement small test functions in testMediaLib.cpp
in between each phase. Do not use your MediaLibrary to test and debug your Media
objects - doing so is a recipe for extra headaches, and a loss of points for failing to write test code.
Defensive programming
As we learned last week, programs should not assume that provided inputs are valid. For this program, at a minimum you should prevent the following errors:
- If the user does not provide the correct number of command-line arguments, the program should print an error message and end
- If the user provides a library file that does not exist, you should print
an error message and exit gracefully. This must be implemented in
fileExists()
iniSwatLibrary.cpp
. IffileExist()
returnstrue
, proceed with the rest of the program. Otherwise, print an error message an exit the program. To determine if a file exists, follow these general steps: - Your main menu should ask the user for another choice if they select an illegal item (e.g., negative or a number larger than the number of media items)
In addition, you are not responsible for these errors (although you are welcome to think about ways to resolve the issue):
- You can assume that the library file is formatted correctly. That is, if you can open the file, all of the content will be as specified in the library file section above.
- You can assume that the media file location are correct (e.g., the location of an image is correct).
The system
Function
The library cstdlib
contains a function system
which can run
commands for you. You pass a C-style string to the system
function
and it will run it in much the same way as the shell we use to e.g.
compile our programs. For instance, the following program will open
the Google home page in Firefox (use our program mediaLibPlayer.sh
which prevents some annoying behaviour by Firefox). After it does that, it will open a picture.
#include <cstdlib>
#include <string>
using namespace std;
int main() {
string cmd1 = "mediaLibPlayer.sh http://www.google.com";
string cmd2 = "gpicview /home/soni/public_html/cs35/f13/Labs/images/01/oberon.png";
system(cmd1.c_str());
system(cmd2.c_str());
return 0;
}
In larger applications, we avoid using the system
function in favor of
more precise ways to launch other programs from within our own code. For
this lab, however, the system
function suits us quite well.
Extra Challenges
There are many ways of extending this lab. If you’re looking for an extra challenge, consider implementing one of the following:
- Songs. Design an implement a new media subclass to represent songs. Represent the songs as mp3 files. When a user "opens" a song, fire off a system call that plays the mp3.
- Design Changes. Are there any design changes you’d make to the lab? i.e., are there any aspects of the lab design that you weren’t a fan of? If so, add a paragraph in your README file describing which aspects/features you would have done differently, and implement your changes.
- Additional Functionality. The current program provides very basic functionality — given a library, your program will only play selected files until the user decides to quit. Add some additional functionality to your media library program, such as giving the user the ability to add or delete objects from the library.
These additional features are optional – we’ll look at them, but they won’t be for credit. Make sure you complete and push the main lab before starting any extra challenge, and note in your README file that you’ve done extra challenges so the graders know which version of your lab to grade. (There’s a chance your added features will break our grading scripts; we’ll grade the base version of your lab to ensure you don’t get penalized in the off-chance your extra features break our grading scripts)
Summary
To summarize the requirements of this lab:
- Your program must be able to read in and open text, image, and video files.
- Your program must store media items in a
MediaLibrary
object. - You must incrementally test your program and save your tests in
testMediaLib.cpp
- All functions and methods should have a top-level comment. Your program should use top-down design principles were applicable and proper coding style including meaningful variable names, proper indentation, and concise comments within the code.
Survey
When you have completed your lab, be sure to answer the survey questions to report on your experience with this assignment.
Submit
Once you are satisfied with your code, hand it in using git. Remember the add, commit, push development cycle. You can push as many times as you like, but only the most recent submission will be graded. You may want to run git status to confirm all modifications have been pushed.