|
This example implements a Todo Management Midlet.
/*--------------------------------------------------
* TodoMIDlet.java
*
* The main class for todo list MIDlet
*
* Example from the book: Core J2ME Technology
* Copyright John W. Muchow http://www.CoreJ2ME.com
* You may use/modify for any non-commercial purpose
*-------------------------------------------------*/
import java.io.*;
import java.util.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
public class TodoMIDlet extends MIDlet implements ItemStateListener, CommandListener
{
private Display display; // Our display
private Form fmMain; // Main Form
private FormAdd fmAdd; // Form to add todo item
private Command cmAdd, // Command to add todo
cmPrefs, // Command to set preferences
cmExit; // Command to exit
private Vector vecTodo; // The "master" list of todo items
private ChoiceGroup cgTodo; // Todo items (read from vecTodo)
protected DisplayManager displayMgr; // Class to help manage screens
//-------------------------------------------------
// Record Stores. One for todo, one for preferences
//-------------------------------------------------
private RecordStore rsTodo;
private RecordStore rsPref;
private static final String REC_STORE_TODO = "TodoList";
private static final String REC_STORE_PREF = "TodoPrefs";
private boolean flagSortByPriority = false, // Sort by priority?
flagShowPriority = true; // Show priorities ?
//-------------------------------------------------
// Re-use these input streams throughout the MIDlet
//-------------------------------------------------
// Read from a specified byte array
private ByteArrayInputStream istrmBytes = null;
// Read Java data types from the above byte array
private DataInputStream istrmDataType = null;
// If you change length of a todo entry, bump thisbyte[] recData = new byte[25];
//-------------------------------------------------
// Re-use these output streams throughout the MIDlet
//-------------------------------------------------
// Write data into an internal byte array
ByteArrayOutputStream ostrmBytes = null;
// Write Java data types into the above byte array
DataOutputStream ostrmDataType = null;
//-------------------------------------------------
// Record Enumerator and compare class
//-------------------------------------------------
private RecordEnumeration e = null;
private ComparatorInt comp = null;
/*--------------------------------------------------
* MIDlet constructor.
*-------------------------------------------------*/
public TodoMIDlet()
{
display = Display.getDisplay(this);
// Create 'main' and 'add todo item' forms
// Form for setting prefs is in commandAction()
fmMain = new Form("Todo List");
fmAdd = new FormAdd("Add Todo", this);
// Todo list and vector
cgTodo = new ChoiceGroup("", Choice.MULTIPLE);
vecTodo = new Vector();
// Commands
cmAdd = new Command("Add Todo", Command.SCREEN, 2);
cmPrefs = new Command("Preferences", Command.SCREEN, 3);
cmExit = new Command("Exit", Command.EXIT, 1);
// Add all to form and listen for events
fmMain.addCommand(cmAdd);
fmMain.addCommand(cmPrefs);
fmMain.addCommand(cmExit);
fmMain.append(cgTodo);
fmMain.setCommandListener(this);
fmMain.setItemStateListener(this);
// Create a display manager object
displayMgr = new DisplayManager(display, fmMain);
// Open/create the record stores
rsTodo = openRecStore(REC_STORE_TODO);
rsPref = openRecStore(REC_STORE_PREF);
// Initialize the streams
initInputStreams();
initOutputStreams();
// Read preferences from rms
refreshPreferences();
// Initialize the enumeration for todo rms
initEnumeration();
// Read rms into vector
writeRMS2Vector();
// Build the todo list (choice group)
rebuildTodoList();
}
/*--------------------------------------------------
* Show the main Form
*-------------------------------------------------*/
public void startApp ()
{
display.setCurrent(fmMain);
}
/*--------------------------------------------------
* Shutting down. Cleanup all we created
*-------------------------------------------------*/
public void destroyApp (boolean unconditional)
{
// Cleanup for enumerator
if (comp != null)
comp.compareIntClose();
if (e != null)
e.destroy();
// Cleanup streams
try
{
if (istrmDataType != null)
istrmDataType.close();
if (istrmBytes != null)
istrmBytes.close();
if (ostrmDataType != null)
ostrmDataType.close();
if (ostrmBytes != null)
ostrmBytes.close();
}
catch (Exception e)
{
db(e.toString());
}
// Cleanup rms
closeRecStore(rsTodo);
closeRecStore(rsPref);
}
/*--------------------------------------------------
* No pause code necessary
*-------------------------------------------------*/
public void pauseApp ()
{ }
/*--------------------------------------------------
* Open input streams
*-------------------------------------------------*/
private void initInputStreams()
{
istrmBytes = new ByteArrayInputStream(recData);
istrmDataType = new DataInputStream(istrmBytes);
}
/*--------------------------------------------------
* Open output streams
*-------------------------------------------------*/
private void initOutputStreams()
{
ostrmBytes = new ByteArrayOutputStream();
ostrmDataType = new DataOutputStream(ostrmBytes);
}
/*--------------------------------------------------
* Initialize enumeration for todo rms
*-------------------------------------------------*/
private void initEnumeration()
{
// Are we to bother with sorting?
if (flagSortByPriority)
comp = new ComparatorInt();
else
// We must set this to null to clear out
// any previous setting
comp = null;
try
{
e = rsTodo.enumerateRecords(null, comp, false);
}
catch (Exception e)
{
db(e.toString());
}
}
/*--------------------------------------------------
* Open a record store
*-------------------------------------------------*/
private RecordStore openRecStore(String name)
{
try
{
// Open the Record Store, creating it if necessary
return RecordStore.openRecordStore(name, true);
}
catch (Exception e)
{
db(e.toString());
return null;
}
}
/*--------------------------------------------------
* Close a record store
*-------------------------------------------------*/
private void closeRecStore(RecordStore rs)
{
try
{
rs.closeRecordStore();
}
catch (Exception e)
{
db(e.toString());
}
}
/*--------------------------------------------------
* Delete a record store
*-------------------------------------------------*/
private void deleteRecStore(String name)
{
try
{
RecordStore.deleteRecordStore(name);
}
catch (Exception e)
{
db(e.toString());
}
}
/*--------------------------------------------------
* Write new todo item
* - Write a new record into the rms
* - Write a new item into the vector
* - Recreate the vector from the rms (which will
* use the proper sort (using rms enumeration)
* - Rebuild todo list from vector
*-------------------------------------------------*/
protected void addTodoItem(int priority, String text)
{
try
{
// Toss any data in the internal array so writes
// starts at beginning (of the internal array)
ostrmBytes.reset();
// Write priority and todo text
ostrmDataType.writeInt(priority);
ostrmDataType.writeUTF(text);
// Clear any buffered data
ostrmDataType.flush();
// Get stream data into byte array and write record
byte[] record = ostrmBytes.toByteArray();
int recordId = rsTodo.addRecord(record, 0, record.length);
// Create a new Todo item and insert it into our Vector
TodoItem item = new TodoItem(priority, text, recordId);
vecTodo.addElement(item);
}
catch (Exception e)
{
db(e.toString());
}
// Read rms into vector
writeRMS2Vector();
// Rebuild todo list
rebuildTodoList();
}
/*--------------------------------------------------
* Save preferences to record store
*-------------------------------------------------*/
protected void savePreferences(boolean sort, boolean showSort)
{
// No changes we made
if (sort == flagSortByPriority && showSort == flagShowPriority)
return;
// Save the current sort status
boolean previouslySorted = flagSortByPriority;
boolean previouslyShowPriority = flagShowPriority;
try
{
// Update prefs in private variables
flagSortByPriority = sort;
flagShowPriority = showSort;
// Toss any data in the internal array so writes
// starts at beginning (of the internal array)
ostrmBytes.reset();
// Write the sort order and keep completed flags
ostrmDataType.writeBoolean(flagSortByPriority);
ostrmDataType.writeBoolean(flagShowPriority);
// Clear any buffered data
ostrmDataType.flush();
// Get stream data into byte array and write record
byte[] record = ostrmBytes.toByteArray();
// Always write preferences at first record
// We cannot request to set the first record unless
// the record store has contents.
// If empty => add a record
// If not => overwrite the first record
if (rsPref.getNumRecords() == 0)
rsPref.addRecord(record, 0, record.length);
else
rsPref.setRecord(1, record, 0, record.length);
}
catch (Exception e)
{
db(e.toString());
}
// If the sort order was changed, rebuild enumeration
if (previouslySorted != flagSortByPriority)
initEnumeration();
// If we are going from non-sorted to sorted
// or changing whether or not to show priority
// then we must update what's currently displayed
if ((!previouslySorted && flagSortByPriority) ||
(previouslyShowPriority != flagShowPriority))
{
// Read rms into vector
writeRMS2Vector();
// Rebuild todo list
rebuildTodoList();
}
}
/*--------------------------------------------------
* Read preferences from record store
*-------------------------------------------------*/
private void refreshPreferences()
{
try
{
// Record store is empty
if (rsPref.getNumRecords() == 0)
{
// Write into the store the default preferences
savePreferences(flagSortByPriority, flagShowPriority);
return;
}
// Reset input back to the beginning
istrmBytes.reset();
// Read configuration data stored in the first record
rsPref.getRecord(1, recData, 0);
flagSortByPriority = istrmDataType.readBoolean();
flagShowPriority = istrmDataType.readBoolean();
System.out.println("Sort: " + flagSortByPriority);
System.out.println("Show: " + flagShowPriority);
}
catch (Exception e)
{
db(e.toString());
}
}
/*--------------------------------------------------
* Create the vector from record store contents
*-------------------------------------------------*/
private void writeRMS2Vector()
{
// Cleanout the vector
vecTodo.removeAllElements();
try
{
// Rebuild enumeration for any changes
e.rebuild();
while (e.hasNextElement())
{
// Reset input back to the beginning
istrmBytes.reset();
// Get data into the byte array
int id = e.nextRecordId();
rsTodo.getRecord(id, recData, 0);
// Create a new Todo item and insert it into our Vector
TodoItem item = new TodoItem(istrmDataType.readInt(), istrmDataType.readUTF(), id);
vecTodo.addElement(item);
}
}
catch (Exception e)
{
db(e.toString());
}
}
/*--------------------------------------------------
* Store the current vector contents to the rms
*-------------------------------------------------*/
private void writeVector2RMS()
{
try
{
byte[] record;
for (int i = 0; i < vecTodo.size(); i++)
{
TodoItem item = (TodoItem) vecTodo.elementAt(i);
int priority = item.getPriority();
String text = item.getText();
// Toss any data in the internal array so writes
// starts at beginning (of the internal array)
ostrmBytes.reset();
// Write priority and todo text
ostrmDataType.writeInt(priority);
ostrmDataType.writeUTF(text);
// Clear any buffered data
ostrmDataType.flush();
// Get stream data into byte array and write record
record = ostrmBytes.toByteArray();
rsTodo.addRecord(record, 0, record.length);
}
}
catch (Exception e)
{
db(e.toString());
}
}
/*--------------------------------------------------
* Rebuild todo list (ChoiceGroup) from the Vector
*-------------------------------------------------*/
protected void rebuildTodoList()
{
// Clear out the ChoiceGroup.
for (int i = cgTodo.size(); i > 0; i--)
cgTodo.delete(i - 1);
TodoItem item;
int priority;
String text;
StringBuffer strb;
for (int i = 0; i < vecTodo.size(); i++)
{
// Get a todo item from vector
item = (TodoItem) vecTodo.elementAt(i);
// Read values from todoitem class
priority = item.getPriority();
text = item.getText();
// Are we are to show priority as part of the text?
strb = new StringBuffer((flagShowPriority ? (Integer.toString(priority) + "-"): ""));
strb.append(text);
// Append to todo choicegroup
cgTodo.append(strb.toString(), null);
}
}
/*--------------------------------------------------
* This method is called when a todo item has been
* selected in the choicegroup. We treat this as
* a request to delete the item
*-------------------------------------------------*/
public void itemStateChanged(Item item)
{
ChoiceGroup cg;
// Cast the item to a ChoiceGroup type
cg = (ChoiceGroup) item;
// Create an array that mirrors the ChoiceGroup
// and populate with those items selected
boolean selected[] = new boolean[cg.size()];
cg.getSelectedFlags(selected);
// Unfortunately, there is no (easy) way to determine
// which item in the choiceGroup was "clicked" to
// initiate this event. The best we can do is look at
// each entry and determine its current selection state
// For each element, see if it is selected
// If so, delete it. Once we have found a selected
// item, we can exit - there will never be more than
// one item selected at any time
for (int i = 0; i < cg.size(); i++)
{
if (selected[i])
{
// Get the record id from the todoItem
// and delete record from rms
TodoItem todoitem = (TodoItem) vecTodo.elementAt(i);
try
{
rsTodo.deleteRecord(todoitem.getRecordId());
}
catch (Exception e)
{
db(e.toString());
}
break;
}
}
// Read rms into vector
writeRMS2Vector();
// Rebuild todo list
rebuildTodoList();
}
/*--------------------------------------------------
* Process events for the main form
*-------------------------------------------------*/
public void commandAction(Command c, Displayable d)
{
if (c == cmExit)
{
destroyApp(false);
notifyDestroyed();
}
else
{
if (c == cmAdd)
{
// Reset the textfield and choicegroup
// on the 'add todo' form
fmAdd.tfTodo.setString("");
fmAdd.cgPriority.setSelectedIndex(0, true);
// Push current displayable and activate 'add todo' form
displayMgr.pushDisplayable(fmAdd);
}
else if (c == cmPrefs)
{
boolean flags[] = {flagSortByPriority, flagShowPriority};
// Push current displayable and show preferences form
// passing in current preference settings
displayMgr.pushDisplayable(new FormPrefs("Preferences", this, flags));
}
}
}
/*--------------------------------------------------
* Simple message to console for debug/errors
*-------------------------------------------------*/
private void db(String str)
{
System.err.println("Msg: " + str);
}
}
/*--------------------------------------------------
* Use a stack to push and pop displayable objects
*
* public void pushDisplayable(Displayable)
* public void popDisplayable()
* public void home()
*
* Example from the book: Core J2ME Technology
* Copyright John W. Muchow http://www.CoreJ2ME.com
* You may use/modify for any non-commercial purpose
*-------------------------------------------------*/
class DisplayManager extends Stack
{
private Display display; // Reference to Display object
private Displayable mainDisplayable; // Main displayable for MIDlet
private Alert alStackError; // Alert for error conditions
/*--------------------------------------------------
* Display manager constructor
*-------------------------------------------------*/
public DisplayManager(Display display, Displayable mainDisplayable)
{
// Only one display object per midlet, this is it
this.display = display;
this.mainDisplayable = mainDisplayable;
// Create an alert displayed when an error occurs
alStackError = new Alert("Displayable Stack Error");
alStackError.setTimeout(Alert.FOREVER); // Modal
}
/*--------------------------------------------------
* Push the current displayable onto stack and set
* the passed in displayable as active
*-------------------------------------------------*/
public void pushDisplayable(Displayable newDisplayable)
{
push(display.getCurrent());
display.setCurrent(newDisplayable);
}
/*--------------------------------------------------
* Return to the main displayable object of MIDlet
*-------------------------------------------------*/
public void home()
{
while (elementCount > 1)
pop();
display.setCurrent(mainDisplayable);
}
/*--------------------------------------------------
* Pop displayable from stack and set as active
*-------------------------------------------------*/
public void popDisplayable()
{
// If the stack is not empty, pop next displayable
if (empty() == false)
display.setCurrent((Displayable) pop());
else
// On error show an alert
// Once acknowldeged, set 'mainDisplayable' as active
display.setCurrent(alStackError, mainDisplayable);
}
}
/*--------------------------------------------------
* FormAdd.java
*
* Form for adding new todoitems
* Supporting class for TodoMIDlet
*
* Example from the book: Core J2ME Technology
* Copyright John W. Muchow http://www.CoreJ2ME.com
* You may use/modify for any non-commercial purpose
*-------------------------------------------------*/
class FormAdd extends Form implements CommandListener
{
private Command cmBack,
cmSave;
protected TextField tfTodo;
protected ChoiceGroup cgPriority;
private TodoMIDlet midlet;
public FormAdd(String title, TodoMIDlet midlet)
{
// Call the Form constructor
super(title);
// Save reference to MIDlet so we can access
// the display manager class and rms
this.midlet = midlet;
// Commands
cmSave = new Command("Save", Command.SCREEN, 1);
cmBack = new Command("Back", Command.BACK, 2);
// Create textfield for entering todo items
tfTodo = new TextField("Todo", null, 15, TextField.ANY);
// Create choicegroup and append options (no images)
cgPriority = new ChoiceGroup("Priority", Choice.EXCLUSIVE);
cgPriority.append("Today", null);
cgPriority.append("Tomorrow", null);
cgPriority.append("This Week", null);
cgPriority.append("This Month", null);
cgPriority.append("Someday", null);
// Add stuff to form and listen for events
addCommand(cmSave);
addCommand(cmBack);
append(tfTodo);
append(cgPriority);
setCommandListener(this);
}
public void commandAction(Command c, Displayable s)
{
if (c == cmSave)
{
// Add a new todo item
// Notice we bump priority by 1. This is because the
// choicegroup entries start at zero. We would like
// the records in the rms to store priorities starting
// at 1. Thus, if a user requests to display priorities
// on the todo list, the highest priority is 1 (not zero)
midlet.addTodoItem(cgPriority.getSelectedIndex() + 1,
tfTodo.getString());
}
// Any other event and we go back to the main form...
// Pop the last displayable off the stack
midlet.displayM | |