The MoviesListScreen
class provides the user interface
for the list of movies and displays the list to the user. The class organizes
the information into two adjacent panels using the landscape style layout.
Create the MoviesListScreen
class
file.
Import the
required classes and assign this class to the package moviebooking.ui
.
package moviebooking.ui; import java.io.InputStream; import java.io.IOException; import moviebooking.moviedb.Movie; import org.eclipse.ercp.swt.mobile.Command; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.List; import org.eclipse.swt.widgets.Shell; /** * This class takes the list of movies and displays it to the user * The list of movies is shown at the right and a description of each * at the left. */ class MoviesListScreen implements SelectionListener { private Command reserveMovieCommand, exitCommand; private MovieBooking main; private List moviesList; private java.util.Vector movies; private Composite mainComposite; private Image image; private Label imageLabel; private Label descriptionText;
Create a Shell
.
For more information the Shell
class, see the class Shell
.
MoviesListScreen(MovieBooking main, Shell mainShell, java.util.Vector movies) { this.main = main; this.movies = movies; mainShell.setText("Movies"); mainComposite = new Composite(mainShell, SWT.NO_BACKGROUND); // Size and location of this Composite are controlled by // the GridLayout of the mainShell. mainComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); mainShell.layout(); // this contains the list of movies moviesList = new List(mainComposite, SWT.BORDER);
Create widgets
for the screen. For a full list of widgets offered and additional information,
see the package org.eclipse.swt.widgets
.
// This contains the list of movies moviesList = new List(mainComposite, SWT.BORDER); // Widgets to describe the movie imageLabel = new Label(mainComposite, SWT.TOP | SWT.CENTER); descriptionText = new Label(mainComposite, SWT.WRAP | SWT.CENTER); // Populate moviesList for(int i = 0; i < movies.size(); ++i) { Movie m = (Movie)movies.elementAt(i); moviesList.add(m.getName()); } if (movies.size() > 0) { moviesList.select(0); movieSelected(0); } moviesList.addSelectionListener(this);
Organize the
widgets by using a layout. For a full list of layouts offered and additional
information, see the package org.eclipse.swt.layout
.
// Distribute the widgets using a FormLayout FormLayout layout = new FormLayout(); mainComposite.setLayout(layout); // Set movies list location FormData moviesListData = new FormData(); moviesListData.top = new FormAttachment(0); moviesListData.left = new FormAttachment(0); moviesListData.right = new FormAttachment(50); moviesListData.bottom = new FormAttachment(100); moviesList.setLayoutData(moviesListData); // Set image location FormData imageLabelData = new FormData(); imageLabelData.top = new FormAttachment(moviesList, 0, SWT.TOP); imageLabelData.left = new FormAttachment(moviesList); imageLabelData.right = new FormAttachment(100); imageLabel.setLayoutData(imageLabelData); // Set image location FormData descriptionTextData = new FormData(); descriptionTextData.top = new FormAttachment(imageLabel); descriptionTextData.left = new FormAttachment(imageLabel, 0, SWT.LEFT); descriptionTextData.right = new FormAttachment(100); descriptionTextData.bottom = new FormAttachment(moviesList, 0, SWT.BOTTOM); descriptionText.setLayoutData(descriptionTextData);
Add commands
to the screen. For more information on the Command
class,
see the class Command
.
// Add commands exitCommand = new Command(mainComposite, Command.EXIT, 0); exitCommand.setText("Exit"); exitCommand.addSelectionListener(this);
In the code above, a new Command
instance
is created for exiting. setText()
defines the text to
be displayed for the command. Finally, the command is associated with a typed
listener called SelectionListener
, which invokes the
appropriate method after an event has been generated by the control. For more
information on eSWT API typed listeners, see the package org.eclipse.swt.events
.
reserveMovieCommand = new Command(mainComposite, Command.GENERAL, 1); reserveMovieCommand.setText("Reserve"); reserveMovieCommand.addSelectionListener(this); reserveMovieCommand.setDefaultCommand(); }
In the code above, a new Command
instance
is created for reserving a movie. setText()
defines the
text to be displayed for the command. Then, the command is associated with
a typed listener (see the package org.eclipse.swt.events
)
called SelectionListener
, which invokes the appropriate
method after an event has been generated by the control. Finally, setDefaultCommand()
is
used to set the command as a default command, meaning that a device selection
key can be used to activate the command. For more information on default commands,
see the class Command
.
Add rules for events.
// Called when a command is invoked or a movie is selected public void widgetSelected(SelectionEvent e) { if (e.widget == exitCommand) { destroy(); main.exit(); } else if (e.widget == reserveMovieCommand) { if (moviesList.getSelectionIndex() >= 0) { // Order of operations is important. // We need to destroy before reserve that will create a new UI. // But need to call moviesList.getSelectionIndex() before destroy. Movie selectedMovie = (Movie)movies.elementAt(moviesList.getSelectionIndex()); destroy(); main.startReserve(selectedMovie); } } else if (e.widget == moviesList) { // This is called when the user selects a movie movieSelected(moviesList.getSelectionIndex()); } } public void widgetDefaultSelected(SelectionEvent e) { // Do nothing } // Called when a movie is selected. // Take the picture and name and put in the // right side window. private void movieSelected(int index) { if (index >= 0) { Movie m = (Movie) movies.elementAt(index); if (m != null) { if (m.getImageLocation()!= null) { try { InputStream stream = getClass().getResourceAsStream( m.getImageLocation()); if (stream != null) { Image newImage = new Image(mainComposite.getDisplay(), stream); imageLabel.setImage(newImage); if(image != null) { image.dispose(); } image = newImage; stream.close(); } } catch (IOException e) { // Do nothing, a picture is missing } descriptionText.setText(m.getDescription()); } } } } private void destroy() { // Dispose the widgets by disposing the parent mainComposite.dispose(); // Dispose the current image if (image != null && !image.isDisposed()) { image.dispose(); } } }
The ReservationForm
class contains a typical form
for entering data required for making a reservation. The basic fields contained
include name, family name, and date. Note that the seating arrangement is
obtained in a separate form. The form is created using a GridLayout
with
two columns that contain standard eSWT widgets. The chosen layout is as follows:
In the first column of the GridLayout
are five
Labels. In the second column are five other widgets: Two Text
widgets,
a DateEditor
, Combo
, and at the
bottom a ConstrainedText
widget. Organizing the layout
for these widgets is described in step 5.
Create the ReservationForm
class
file.
Import the
required classes and assign this class to the package moviebooking.ui
.
package moviebooking.ui; import java.util.Vector; import java.util.Calendar; import java.util.Date; import java.util.Hashtable; import moviebooking.moviedb.Movie; import moviebooking.moviedb.Showing; import org.eclipse.ercp.swt.mobile.Command; import org.eclipse.ercp.swt.mobile.ConstrainedText; import org.eclipse.ercp.swt.mobile.DateEditor; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Combo; /** * This class contains a common Form to enter the data needed to make * a reservation. It contains fields such as first name, * family name date, etc. * * The seating location is obtained in a separate form */ public class ReservationForm implements SelectionListener, ModifyListener { private MovieBooking main; private Command exitCommand, seatCommand, confirmCommand; private DateEditor movieDate; private Combo movieTime; private Composite mainComposite; private Hashtable validDates = new Hashtable(); private Text firstNameText, familyNameText; private ConstrainedText ticketsText; private int[][] selectedSeats;
Build the Shell
.
For more information the Shell
class, see the class Shell
.
ReservationForm(MovieBooking main, Shell mainShell, Movie movie) { this.main = main; mainShell.setText("Reservation"); mainComposite = new Composite(mainShell, SWT.NONE); // Size and location of this Composite are controlled by // the GridLayout of the mainShell mainComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
Create widgets.
For a full list of widgets offered and additional information, see the package org.eclipse.swt.widgets
.
// Create all the widgets in the Composite Label firstNameLabel = new Label(mainComposite, SWT.NONE); firstNameLabel.setText("First name"); // Contains the first name firstNameText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER); firstNameText.setTextLimit(20); Label familyNameLabel = new Label(mainComposite, SWT.NONE); familyNameLabel.setText("Family name"); // Contains the family name familyNameText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER); familyNameText.setTextLimit(20); Label dateLabel = new Label(mainComposite, SWT.NONE); dateLabel.setText("Date"); // Date for the movie, by default today movieDate = new DateEditor( mainComposite, SWT.NONE, DateEditor.DATE | SWT.BORDER); movieDate.setDate(new Date()); movieDate.addModifyListener(this); // A drop-down list of times Label timeLabel = new Label(mainComposite, SWT.NONE); timeLabel.setText("Time"); movieTime = new Combo(mainComposite, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); Vector showings = movie.getShowings(); Vector times = new Vector(); // Store in the time combo the time valid // for all showings, validDates contains // a map between showingDate and showing for(int i = 0; i < showings.size(); ++i) { Showing show = (Showing)showings.elementAt(i); Calendar cal = Calendar.getInstance(); cal.setTime(show.getDate()); String showingTime = cal.get(Calendar.HOUR_OF_DAY) + ":00"; if (!times.contains(showingTime)) { times.addElement(showingTime); } validDates.put(show.getDate(), show); } for(int i = 0; i < times.size(); ++i) { movieTime.add((String) times.elementAt(i)); } movieTime.select(0); movieTime.addSelectionListener(this); Label ticketsLabel = new Label(mainComposite, SWT.NONE); ticketsLabel.setText("Tickets"); // Amount of tickets, note that ConstrainedText only takes numbers ticketsText = new ConstrainedText(mainComposite, SWT.SINGLE | SWT.BORDER, ConstrainedText.NUMERIC); ticketsText.addModifyListener(this); ticketsText.setText("2");
Organize the
widgets by using a layout. For a full list of layouts offered and additional
information, see the package org.eclipse.swt.layout
.
// Use a grid layout with two columns GridLayout layout = new GridLayout(); layout.makeColumnsEqualWidth = false; layout.numColumns = 2; mainComposite.setLayout(layout); // Distribute the forms using the layout firstNameText.setLayoutData( new GridData(SWT.FILL, SWT.CENTER, true, false)); familyNameText.setLayoutData( new GridData(SWT.FILL, SWT.CENTER, true, false)); ticketsText.setLayoutData( new GridData(SWT.FILL, SWT.CENTER, true, false)); movieDate.setLayoutData( new GridData(SWT.FILL, SWT.CENTER, true, false)); movieTime.setLayoutData( new GridData(SWT.FILL, SWT.CENTER, true, false)); setCommands(); mainShell.layout(); }
Add commands.
For more information on the Command
class, see the class Command
.
private void setCommands() { // add commands exitCommand = new Command(mainComposite, Command.EXIT, 0); exitCommand.setText("Exit"); exitCommand.addSelectionListener(this); seatCommand = new Command(mainComposite, Command.GENERAL, 1); seatCommand.setText("Seating"); seatCommand.addSelectionListener(this); seatCommand.setDefaultCommand(); }
Add rules for events.
// Called when some command is selected public void widgetSelected(SelectionEvent e) { if (e.widget == exitCommand) { // Exit the main application destroy(); main.exit(); } else if (e.widget == movieTime) { selectedSeats = null; if (confirmCommand != null) { confirmCommand.dispose(); confirmCommand = null; } } else if (e.widget == seatCommand) { // Iterate over the valid dates Date showingDate = calculateTime(); if (validDates.containsKey(showingDate) || (ticketsText.getText().length() == 0)) { int ticketsCount = 0; try { ticketsCount = Integer.parseInt(ticketsText.getText()); } catch (NumberFormatException ex) { // Ignore, just use 0 } if (ticketsCount == 0) { return; } Showing show = (Showing) validDates.get(showingDate); exitCommand.dispose(); exitCommand = null; seatCommand.dispose(); seatCommand = null; if (confirmCommand != null) { confirmCommand.dispose(); confirmCommand = null; } main.showSeatingDialog(show, selectedSeats, ticketsCount); } else { main.displayMessageBox(SWT.ICON_ERROR | SWT.OK, "Error", "Wrong date selected"); } } else if (e.widget == confirmCommand) { Date showingDate = calculateTime(); // Validate the fields if (selectedSeats == null || firstNameText.getText().equals("") || familyNameText.getText().equals("")) { main.displayMessageBox(SWT.ICON_ERROR | SWT.OK, "Error", "Missing required fields"); return; } else { // Request to main to make the reservation String firstName = firstNameText.getText(); String familyName = familyNameText.getText(); destroy(); main.confirmReservation(firstName, familyName, (Showing) validDates .get(showingDate), selectedSeats); } } } public void widgetDefaultSelected(SelectionEvent e) {} // Called when the user has selected the seats void setSelectedSeats(int[][] selected) { this.selectedSeats = selected; setCommands(); if (confirmCommand == null && selectedSeats != null) { // Add a new command confirmCommand = new Command( mainComposite, Command.GENERAL, 1); confirmCommand.setText("Confirm"); confirmCommand.addSelectionListener(this); confirmCommand.setDefaultCommand(); } } void cancelSeatSelection() { selectedSeats = null; if (confirmCommand != null) { confirmCommand.dispose(); confirmCommand = null; } setCommands(); } // Close the main composite and dispose it private void destroy() { mainComposite.dispose(); }
Fetch the time and date of the movie showing.
// Create a time based on movieDate and timeCombo private Date calculateTime() { if (movieTime.getSelectionIndex() == -1) { return null; } else { Calendar cal = Calendar.getInstance(); // Take the date from movieDate Date showingDate = movieDate.getDate(); cal.setTime(showingDate); // Get the time from movieTime, so we remove the last ":00" // Notice that we expect only exact minutes String time = movieTime.getItem(movieTime.getSelectionIndex()); int hourOfDay = Integer.parseInt(time.substring(0, time.indexOf(':'))); int minutes = Integer.parseInt(time.substring(time.indexOf(':') + 1, time.length() - 1)); cal.set(Calendar.HOUR_OF_DAY, hourOfDay); cal.set(Calendar.MINUTE, minutes); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); return cal.getTime(); } } public void modifyText(ModifyEvent e) { selectedSeats = null; if (confirmCommand != null) { confirmCommand.dispose(); confirmCommand = null; } } }