Teams Winter 2011/team1/BlackBerry/Add Send Email Option
9. Adding Send Email Functionality
9.1. Add couple of private variables to the ViewStudentApp
:
private static ServiceRecord[] _mailServiceRecords;
public MessagesViewScreen _messagesViewScreen;
9.2. Add the Send email option to the menu and implement it:
// Send email to student
ImageMenuItem emailItem = new ImageMenuItem("Email Student", 400, 4, MENU_EMAIL);
emailItem.setCommand(new Command(new CommandHandler()
{
public void execute(ReadOnlyCommandMetadata metadata, Object context)
{
Student student = (Student) _keywordFilterField.getSelectedElement();
if (student != null)
{
try
{
ComposeScreen composeScreen = new ComposeScreen(null, _store, student.getEmail());
pushScreen(composeScreen);
}
catch(Exception ex)
{
Dialog.alert("composing screen: " + ex.getMessage());
}
}
}
}));
_mainScreen.addMenuItem(emailItem);
9.3 Add four new Screen classes and a helper class to the project:
-
ComposeScreen.java
- start screen where email is composed -
MessageScreen.java
- screen showing the email -
MessagesViewScreen.java
- to view the created email -
MessageListField.java
- handles the drawing of the list of messages -
FoldersViewScreen.java
- view emails in the Outbox folder
The main functionality is taken from the Sample provided with blackberry plug-in: BlackBerryMailDemo
9.4. Following is the modified code to accommodate the application:
ComposeScreen.java
- pass the student e-mail as "To:" parameter:
package cs.ecl.team1.project;
import java.util.*;
import net.rim.blackberry.api.mail.*;
import net.rim.device.api.command.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.util.*;
/**
* The ComposeScreen is a screen which displays either a new or saved message.
* It adds the functionality of saving and sending messages to its parent class,
* MessageScreen.
*/
public final class ComposeScreen extends MessageScreen
{
private static final int FIRST = 0;
private static final int SEND_MENU_ITEM_INDEX = 0;
private Store _store;
private MessagesViewScreen _messagesViewScreen;
/**
* Creates a new ComposeScreen object
* @param message A message in the process of being composed, or null if a new message is to be composed
* @param store The message store for this application
*/
public ComposeScreen(Message message, Store store, String email)
{
super(message, true, email);
_store = store;
_messagesViewScreen = new MessagesViewScreen();
// If a new message is to be created, indicate this in the title
if( message == null )
{
setTitle("New Message");
}
// Create and add menu items specific to the Compose action (addTo,
// addBcc, addCc, etc...).
AddHeaderFieldAction addToMenuItem = new AddHeaderFieldAction(Message.RecipientType.TO, "Add To: ", "To: ");
AddHeaderFieldAction addCcMenuItem = new AddHeaderFieldAction(Message.RecipientType.CC, "Add Cc: ", "Cc: ");
AddHeaderFieldAction addBccMenuItem = new AddHeaderFieldAction(Message.RecipientType.BCC, "Add Bcc: ", "Bcc: ");
// MenuItem to save a message
MenuItem saveMenuItem = new MenuItem(new StringProvider("Save Message"), 0x230020, 1);
saveMenuItem.setCommand(new Command(new CommandHandler()
{
/**
* @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, Object)
*/
public void execute(ReadOnlyCommandMetadata metadata, Object context)
{ // If the save is completed, then discard this screen
if( onSave() )
{
close();
}
else
// If the message could not be saved, alert the user
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("Message could not be saved");
}
});
}
}
}));
// MenuItem to send a message
MenuItem sendMenuItem = new MenuItem(new StringProvider("Send Message"), 0x230010, 0);
sendMenuItem.setCommand(new Command(new CommandHandler()
{
/**
* @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, Object)
*/
public void execute(ReadOnlyCommandMetadata metadata, Object context)
{ // If the save is completed, then discard this screen
try
{
_message = getMessage();
if( _message != null )
{
// Send the message
Transport.send(_message);
UiApplication.getUiApplication().pushScreen(_messagesViewScreen);
close();
}
}
catch( MessagingException e )
{
ViewStudentApp.errorDialog("Transport.send(Message) threw " + e.toString());
}
}
}));
addMenuItem(sendMenuItem);
addMenuItem(saveMenuItem);
addMenuItem(addToMenuItem);
addMenuItem(addCcMenuItem);
addMenuItem(addBccMenuItem);
}
/**
* Overrides MessageScreen.displayMessage(). The message's 'sent' properties
* are not displayed since the message is still in the process of editing.
*/
void displayMessage(String email)
{
// If the message does not exist then compose a new message
if( _message == null )
{
// Add a To line
EditField toField = new EditField("To: ", email, 40, BasicEditField.FILTER_EMAIL);
addTextFieldToTableAndScreen(toField, Message.RecipientType.TO);
// Add a subject line
EditField subjectField = new EditField("Subject: ", "");
addTextFieldToTableAndScreen(subjectField, SUBJECT);
// Add a separator between the body and the headers
add(new SeparatorField());
// Add a body field
EditField bodyField = new EditField();
addTextFieldToTableAndScreen(bodyField, BODY);
}
else
// The message exists so display it
{
displayHeader();
add(new SeparatorField());
displayMessageBody();
}
}
/**
* Gets a message for sending or saving
* @return A new message
*/
Message getMessage()
{
// Find an outbox folder and use it to construct a new message
Folder outbox = _store.findFolder("Outbox")[ FIRST ];
Message message = new Message(outbox);
// Add all the current headers
for( int keyNo = 0; keyNo < HEADER_KEYS.length; keyNo++ )
{
Vector fieldsByType = (Vector) _fieldTable.get(HEADER_KEYS[ keyNo ]);
if( fieldsByType != null )
{
// Build a vector of all the addresses
Vector addressVector = new Vector();
int size = fieldsByType.size();
for( int fieldNo = 0; fieldNo < size; fieldNo++ )
{
TextField addressField = (TextField) fieldsByType.elementAt(fieldNo);
// Try to create a new address object wrapping the email
// address and add it to the address vector.
try
{
addressVector.addElement(new Address(addressField.getText(), ""));
}
catch( AddressException e ) // Invalid address
{
ViewStudentApp.errorDialog("Address(String, String) threw " + e.toString());
}
}
// Dump the vector of addresses into an array to send the message
Address[] addresses = new Address[ addressVector.size() ];
addressVector.copyInto(addresses);
// Try to add the addresses to the message's list of recipients
try
{
message.addRecipients(HEADER_KEYS[ keyNo ], addresses);
}
catch( MessagingException e )
{
ViewStudentApp.errorDialog("Message#addRecipients(int, Address[]) threw " + e.toString());
}
}
}
// Add the subject
Vector subjectFields = (Vector) _fieldTable.get(SUBJECT);
TextField subjectField = (TextField) subjectFields.elementAt(FIRST);
if( subjectFields != null && subjectFields.size() > 0 )
{
message.setSubject(subjectField.getText());
}
// Add the body by adding all the body fields into one multipart
Vector bodyFields = (Vector) _fieldTable.get(BODY);
if( bodyFields != null )
{
int size = bodyFields.size();
Multipart content = new Multipart();
for( int fieldNo = 0; fieldNo < size; fieldNo++ )
{
TextField body = (TextField) bodyFields.elementAt(fieldNo);
content.addBodyPart(new TextBodyPart(content, body.getText()));
}
try
{
message.setContent(content);
}
catch( MessagingException e )
{
ViewStudentApp.errorDialog("Message#setContent(Object) threw " + e.toString());
}
}
else
{
ViewStudentApp.errorDialog("Error: no body field available");
return null;
}
// Set the date
message.setSentDate(Calendar.getInstance().getTime());
return message;
}
/**
* @see net.rim.device.api.ui.Screen#onSave()
*/
protected boolean onSave()
{
// Save the message to the outbox
try
{
Message newMessage = getMessage();
if( newMessage != null )
{
// Retrieve an outbox to save the message in
Store store = Session.waitForDefaultSession().getStore();
Folder[] allOutboxFolders = store.list(Folder.OUTBOX);
Folder outbox = null;
for( int i = allOutboxFolders.length - 1; i >= 0 ; --i )
{
if( allOutboxFolders[ i ].getParent().getName().startsWith("Mailbox") )
{
outbox = allOutboxFolders[ i ];
break;
}
}
// Save the new message and replace the old one if it exists
outbox.appendMessage(newMessage);
if( _message != null )
{
outbox.deleteMessage(_message, true);
}
_message = newMessage;
// Set the status to composing and flag that it has been saved
_message.setStatus(Message.Status.TX_COMPOSING, Message.Status.TX_ERROR);
_message.setFlag(Message.Flag.SAVED, true);
return true;
}
return false;
}
catch( MessagingException e )
{
return false;
}
}
/**
* Make "Send" the default menu item.
*
* @see net.rim.device.api.ui.container.MainScreen#makeMenu(Menu,int)
*/
protected void makeMenu(Menu menu, int instance)
{
super.makeMenu(menu, instance);
// menu.setDefault(SEND_MENU_ITEM_INDEX);
}
/**
* This class is responsible for adding the various header fields to the
* compose screen (To, Bcc, CC).
*/
private final class AddHeaderFieldAction extends MenuItem
{
private String _fieldLabelText;
private int _headerType;
/**
* Constructs a menu item which adds a header of a specified type to the
* compose screen.
*
* @param headerType One of the Message.RecipientType fields
* @param menuItemText String to use for the menu item
* @param fieldLabelText String to use for the label of this field
*/
AddHeaderFieldAction(int headerType, String menuItemText, String fieldLabelText)
{
super(new StringProvider(menuItemText), 0x240010, 2);
_fieldLabelText = fieldLabelText;
_headerType = headerType;
this.setCommand(new Command(new CommandHandler()
{
/**
* Adds a new header field to the message. The field is placed so that
* the header types are grouped together and the most recently added one
* is closest to the bottom.
* @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, Object)
*/
public void execute(ReadOnlyCommandMetadata metadata, Object context)
{
EditField newField = new EditField(_fieldLabelText, "");
// Find out where the last field of this type was added to the
// screen.
Vector fieldsByType = (Vector) _fieldTable.get(_headerType);
int lastInsertedIndex;
if( fieldsByType == null )
{
// If a field of _headerType was not made yet, then create the
// vector which contains all of the fields of _headerType.
fieldsByType = new Vector();
_fieldTable.put(_headerType, fieldsByType);
lastInsertedIndex = getIndexForNewFieldType();
}
else
{
lastInsertedIndex = getIndexOfLastFieldOfType(_headerType);
}
// Add the new field to both the screen and the vector keeping track
// of all the fields of the same type.
ComposeScreen.this.insert(newField, lastInsertedIndex + 1);
fieldsByType.addElement(newField);
newField.setFocus();
}
}));
}
/**
* Given the existing field type of this instance of the class,
* determine where to place new header fields in the screen.
*
* @return The index at which to insert the new header field
*/
private int getIndexForNewFieldType()
{
// Note: we don't handle TO here since there ALWAYS must be one TO
// field.
switch( _headerType )
{
// Find the last TO field and use the next index as the
// insertion point.
case Message.RecipientType.CC:
return getIndexOfLastFieldOfType(Message.RecipientType.TO);
// Try to find the last CC field and use it as the next
// insertion point. If no CC field exists then find the last
// TO field and use its index as the insertion point.
case Message.RecipientType.BCC:
int index = getIndexOfLastFieldOfType(Message.RecipientType.CC);
if( index == -1 )
return getIndexOfLastFieldOfType(Message.RecipientType.TO);
return index;
default:
throw new IllegalStateException("Mail Demo: Unrecognized recipient type");
}
}
/**
* Retrieves the index of the last field added of a specified type.
*
* @param type The type of header field to retrieve the last index of
* @return The index of the most recently added field of the specified
* type, -1 if a field of the specified type has not been added
* yet.
*/
private int getIndexOfLastFieldOfType(int type)
{
Vector fields = (Vector) _fieldTable.get(type);
if( fields == null )
{
return -1;
}
Field field = (Field) fields.lastElement();
return field.getIndex();
}
}
}
MessageScreen.java
package cs.ecl.team1.project;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.util.IntHashtable;
import javax.microedition.pim.Contact;
import java.util.*;
import net.rim.blackberry.api.mail.*;
/**
* The MessageScreen class allows a user to view a selected message and
* edit the message if the screen is marked editable. It manages the different
* TextFields using a hashtable where the type of information that is held
* in a given TextField is the key while the value is a Vector of TextFields
* associated with that information type. This class supports displaying
* plain text, Mime, supported and unsupported attachments and pdap contacts.
*/
public class MessageScreen extends MainScreen
{
// Constants
public final static String NO_SUBJECT = "<No Subject>";
public final static String UNKNOWN_NAME = "<?>";
protected final static int SUBJECT = 0;
protected final static int BODY = 1;
protected final static int INFO = 2;
protected final static int[] HEADER_KEYS = { Message.RecipientType.TO, Message.RecipientType.CC, Message.RecipientType.BCC };
protected final static String[] HEADER_NAMES = { "To: ", "Cc: ", "Bcc: " };
private final static int MAX_CHARS = 128;
protected IntHashtable _fieldTable;
protected Message _message;
private boolean _editable;
/**
* Creates a new MessageScreen object
* @param message The message to display
* @param editable True is the message is editable, otherwise false
*/
public MessageScreen(Message message, boolean editable, String email)
{
_fieldTable = new IntHashtable();
_editable = editable;
// Set the message and display its subject as the title if the
// message exists.
_message = message;
if( _message != null )
setTitle(_message.getSubject());
displayMessage(email);
}
/**
* Displays the message
*/
void displayMessage(String email)
{
displayMessageInformation();
add(new SeparatorField());
displayHeader();
add(new SeparatorField());
displayMessageBody();
}
/**
* Displays information about the message's send and recieve properties
*/
protected void displayMessageInformation()
{
// Add a field describing the source service
ServiceConfiguration sc = _message.getFolder().getStore().getServiceConfiguration();
EditField service = new EditField("Service: ", sc.getName(), MAX_CHARS, EditField.READONLY | EditField.NON_FOCUSABLE);
addTextFieldToTableAndScreen(service, INFO);
// Add the folder field
EditField folder = new EditField("Folder: ", _message.getFolder().getName(), MAX_CHARS, EditField.READONLY
| EditField.NON_FOCUSABLE);
addTextFieldToTableAndScreen(folder, INFO);
// Add the status of the message
String statusString = getStatusString(_message);
EditField status = new EditField("Status: ", statusString, MAX_CHARS, EditField.READONLY | EditField.NON_FOCUSABLE);
addTextFieldToTableAndScreen(status, INFO);
}
/**
* Displays information about the destination and source of the message as
* well as its subject.
*/
protected void displayHeader()
{
// Assign the appropriate EditField style property
long editableStyle = _editable ? EditField.EDITABLE : EditField.READONLY;
// Display the headers (To:, Cc:, Bcc:)
for( int key = 0; key < HEADER_KEYS.length; key++ )
{
try
{
Address[] addresses = _message.getRecipients(HEADER_KEYS[ key ]);
for( int index = 0; index < addresses.length; index++ )
{
// Retrieve the name
String name = addresses[ index ].getName();
if( name == null || name.length() == 0 )
{
name = addresses[ index ].getAddr();
}
// Create the edit field, associate the address to the field
// and add it to the screen and collection of fields.
EditField headerField = new EditField(HEADER_NAMES[ key ], name, EditField.DEFAULT_MAXCHARS, editableStyle);
headerField.setCookie(addresses[ index ]);
addTextFieldToTableAndScreen(headerField, HEADER_KEYS[ key ]);
}
}
catch( MessagingException e )
{
ViewStudentApp.errorDialog("Error: could not retrieve message header.");
close();
}
}
// Display the 'Sent' date if it is available
Date sent = _message.getSentDate();
if( sent != null )
{
EditField sentDate = new EditField("Sent: ", Util.getDateAsString(sent), EditField.DEFAULT_MAXCHARS, EditField.READONLY
| EditField.NON_FOCUSABLE);
// Change the label to "Saved: " if the message hasn't been sent yet
if( _message.getStatus() == Message.Status.TX_COMPOSING )
sentDate.setLabel("Saved: ");
add(sentDate);
}
// Display the subject field
String subject = _message.getSubject();
if( subject == null )
subject = NO_SUBJECT;
EditField subjectField = new EditField("Subject: ", subject, EditField.DEFAULT_MAXCHARS, editableStyle);
addTextFieldToTableAndScreen(subjectField, SUBJECT);
}
/**
* Displays the message body
*/
protected void displayMessageBody()
{
// Retrieve the parent of the message body
Object obj = _message.getContent();
Multipart parent = null;
if( obj instanceof MimeBodyPart || obj instanceof TextBodyPart )
{
BodyPart bp = (BodyPart) obj;
parent = bp.getParent();
}
else
{
parent = (Multipart) obj;
}
// Display the message body
String mpType = parent.getContentType();
if( mpType.equals(BodyPart.ContentType.TYPE_MULTIPART_ALTERNATIVE_STRING)
|| mpType.equals(BodyPart.ContentType.TYPE_MULTIPART_MIXED_STRING) )
{
displayMultipart(parent);
}
// Ensure there is at least one body field if nothing was displayed
Vector bodyVector = (Vector) _fieldTable.get(BODY);
if( bodyVector == null || bodyVector.size() == 0 )
{
if( _editable )
{
addTextFieldToTableAndScreen(new EditField("", ""), BODY);
}
else
{
addTextFieldToTableAndScreen(new RichTextField(""), BODY);
}
}
}
/**
* Processes a multi-part message by displaying its body parts. Text body
* parts are displayed before attachments and if a multi body part is
* encountered, then it is processed through recursion by calling this method
* on it.
*
* @param multipart The multi-part to display
* @param editable True if this multi-part is editable
*/
protected void displayMultipart(Multipart multipart)
{
// This vector stores fields which are to be displayed only after all
// of the body fields are displayed. (Attachments and Contacts).
Vector delayedFields = new Vector();
// Process each part of the multi-part, taking the appropriate action
// depending on the part's type. This loop should: display text and
// html body parts, recursively display multi-parts and store
// attachments and contacts to display later.
for( int index = 0; index < multipart.getCount(); index++ )
{
BodyPart bodyPart = multipart.getBodyPart(index);
// If this body part is text then display all of it
if( bodyPart instanceof TextBodyPart )
{
TextBodyPart textBodyPart = (TextBodyPart) bodyPart;
// If there are missing parts of the text, try to retrieve the
// rest of it.
if( textBodyPart.hasMore() )
{
try
{
Transport.more(textBodyPart, true);
}
catch( Exception e )
{
ViewStudentApp.errorDialog("Transport.more(BodyPart, boolean) threw " + e.toString());
}
}
String plainText = (String) textBodyPart.getContent();
// Display the plain text, using an EditField if the message is
// editable or a RichTextField if it is not editable. Note: this
// does not add any empty fields.
if( plainText.length() != 0 )
{
if( _editable )
{
addTextFieldToTableAndScreen(new EditField("", plainText), BODY);
}
else
{
addTextFieldToTableAndScreen(new RichTextField(plainText), BODY);
}
}
}
else if( bodyPart instanceof MimeBodyPart )
{
MimeBodyPart mimeBodyPart = (MimeBodyPart) bodyPart;
// If the content is text then display it
String contentType = mimeBodyPart.getContentType();
if( contentType.startsWith(BodyPart.ContentType.TYPE_TEXT_HTML_STRING) )
{
Object obj = mimeBodyPart.getContent();
if( obj != null )
{
String htmlText = new String((byte[]) obj);
addTextFieldToTableAndScreen(new RichTextField(htmlText), BODY);
}
}
else if( contentType.equals(BodyPart.ContentType.TYPE_MULTIPART_ALTERNATIVE_STRING) )
{
// If the body part is a multi-part and it has the the
// content type of TYPE_MULTIPART_ALTERNATIVE_STRING, then
// recursively display the multi-part.
Object obj = mimeBodyPart.getContent();
if( obj instanceof Multipart )
{
Multipart childMultipart = (Multipart) obj;
String childMultipartType = childMultipart.getContentType();
if( childMultipartType.equals(BodyPart.ContentType.TYPE_MULTIPART_ALTERNATIVE_STRING) )
{
displayMultipart(childMultipart);
}
}
}
}
else if( bodyPart instanceof SupportedAttachmentPart || bodyPart instanceof UnsupportedAttachmentPart )
{
// Extract the content type and name from the attachments
String contentType = bodyPart.getContentType();
String name;
if( bodyPart instanceof UnsupportedAttachmentPart )
{
UnsupportedAttachmentPart uap = (UnsupportedAttachmentPart) bodyPart;
name = uap.getName();
}
else // The bodyPart is a SupportedAttachmentPart
{
SupportedAttachmentPart sap = (SupportedAttachmentPart) bodyPart;
name = sap.getName();
}
// Format the content type and name to display and store
// the field.
StringBuffer sb = new StringBuffer(contentType.length() + name.length() + 2);
sb.append(contentType);
sb.append('[');
sb.append(name);
sb.append(']');
delayedFields.addElement(new RichTextField(sb.toString()));
}
else if( bodyPart instanceof PDAPContactAttachmentPart )
{
Contact contact = (Contact) bodyPart.getContent();
// Build the contact name
StringBuffer sb = new StringBuffer("Contact: ");
if( contact.countValues(Contact.NAME) > 0 )
{
String[] name = contact.getStringArray(Contact.NAME, 0);
if( name[ Contact.NAME_PREFIX ] != null )
{
sb.append(name[ Contact.NAME_PREFIX ]);
sb.append(' ');
}
if( name[ Contact.NAME_GIVEN ] != null )
{
sb.append(name[ Contact.NAME_GIVEN ]);
sb.append(' ');
}
if( name[ Contact.NAME_FAMILY ] != null )
{
sb.append(name[ Contact.NAME_FAMILY ]);
}
// Trim the last space of the name if it exists
int lastChar = sb.length() - 1;
if( sb.charAt(lastChar) == ' ' )
sb.deleteCharAt(lastChar);
}
else
{
sb.append(UNKNOWN_NAME);
}
// Create the contact attachment field and store it
RichTextField contactAttachment = new RichTextField(sb.toString());
contactAttachment.setCookie(contact);
delayedFields.addElement(contactAttachment);
}
}
// Now that the body parts have been displayed, display the queued
// fields while separating them by inserting a separator field.
for( int index = 0; index < delayedFields.size(); index++ )
{
add(new SeparatorField());
addTextFieldToTableAndScreen((TextField) delayedFields.elementAt(index), BODY);
}
}
/**
* Compiles the status of a message into a readable string.
*
* @param message The message whose status is to be compiled into a string
* @return The string displaying the status of the message
*/
public static String getStatusString(Message message)
{
StringBuffer statusStrBuffer = new StringBuffer();
// Add any errors to the status string if it applies
int status = message.getStatus();
if( status == Message.Status.RX_ERROR )
{
statusStrBuffer.append("RX ERROR, ");
}
if( status == Message.Status.TX_GENERAL_FAILURE )
{
statusStrBuffer.append("RX ERROR, ");
}
if( status == Message.Status.TX_ERROR )
{
statusStrBuffer.append("TX ERROR, ");
}
// Use the flags to add any message statuses
int flags = message.getFlags();
if( 0 != (flags & Message.Flag.OPENED) )
{
statusStrBuffer.append("Opened, ");
}
if( 0 != (flags & Message.Flag.SAVED) )
{
statusStrBuffer.append("Saved, ");
}
if( 0 != (flags & Message.Flag.FILED) )
{
statusStrBuffer.append("Filed, ");
}
// Check if the message has a high or low priority
byte messagePriority = message.getPriority();
if( messagePriority == Message.Priority.HIGH )
{
statusStrBuffer.append("High Priority, ");
}
else if( messagePriority == Message.Priority.LOW )
{
statusStrBuffer.append("Low Priority, ");
}
// If there are any characters in the status string then delete the last
// two characters if there are any characters to delete. Should be
// either ", " or " ".
statusStrBuffer.delete(statusStrBuffer.length() - 2, statusStrBuffer.length());
return statusStrBuffer.toString();
}
/**
* Add a new field to the hashtable of TextFields and to the screen
*
* @param field The field to add
* @param type The type of field to add
*/
protected void addTextFieldToTableAndScreen(TextField field, int type)
{
Vector fieldsByType = (Vector) _fieldTable.get(type);
// If the vector of fields associated with the type is not made yet,
// initialize one and put it into the fields collection.
if( fieldsByType == null )
{
fieldsByType = new Vector(1);
_fieldTable.put(type, fieldsByType);
}
fieldsByType.addElement(field);
add(field);
}
/**
* @see net.rim.device.api.ui.Screen#onClose()
*/
public boolean onClose()
{
// If the message status is "received", mark it "read"
if( _message != null && _message.getStatus() == Message.Status.RX_RECEIVED )
{
_message.setStatus(Message.Status.TX_READ, Message.Status.TX_ERROR);
_message.setFlag(Message.Flag.OPENED, true);
}
return super.onClose();
}
}
Other classes stay unchanged.
9.5. Run the application, select a user from the list, and select Email Student from the menu:
9.6. Type in the subject and some text in the body, and select Send Email from the menu:
9.7. The messageList screen is displayed showing the created email. Select Folder View from the menu to see the Outbox folder: