/*--------------------------------------------------
* 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;
// 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();
/*--------------------------------------------------
* 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;
/*--------------------------------------------------
* 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;
// 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();
/*--------------------------------------------------
* 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.displayMgr.popDisplayable();
}
}
/*--------------------------------------------------
* ComparatorInt.java
*
* Sorts rms records based on todo item priority
* Provides compare() method for RecordEnumerator
* 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 ComparatorInt implements RecordComparator
{ private byte[] record = new byte[10];
// Read from a specified byte array private ByteArrayInputStream strmBytes = null;
// Read Java data types from the above byte array private DataInputStream strmDataType = null;
public void compareIntClose()
{ try
{ if (strmBytes != null)
strmBytes.close(); if (strmDataType != null)
strmDataType.close();
} catch (Exception e)
{}
}
public int compare(byte[] rec1, byte[] rec2)
{ int x1, x2;
try
{
// If either record is larger than our buffer, reallocate int maxsize = Math.max(rec1.length, rec2.length); if (maxsize > record.length)
record = new byte[maxsize];
// Read record #1
// We want the priority which is first "field"
strmBytes = new ByteArrayInputStream(rec1);
strmDataType = new DataInputStream(strmBytes);
x1 = strmDataType.readInt();
// Read record #2
strmBytes = new ByteArrayInputStream(rec2);
strmDataType = new DataInputStream(strmBytes);
x2 = strmDataType.readInt();
// Compare record #1 and #2 if (x1 == x2) return RecordComparator.EQUIVALENT; else if (x1 < x2) return RecordComparator.PRECEDES; else return RecordComparator.FOLLOWS;
/*--------------------------------------------------
* TodoItem.java
*
* Holds data/methods for a single todo item
* 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 TodoItem
{ private int priority; private String text; private int recordId;
public TodoItem(int priority, String text, int recordId)
{ this.priority = priority; this.text = text; this.recordId = recordId;
}
public int getPriority()
{ return priority;
}
public void setPriority(int priority)
{ this.priority = priority;
}
public String getText()
{ return text;
}
public void setText(String text)
{ this.text = text;
} public int getRecordId()
{ return recordId;
}
}
/*--------------------------------------------------
* FormPrefs.java
*
* Form for specifying user preferences
* 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 FormPrefs extends Form implements CommandListener
{ private Command cmBack,
cmSave; private TodoMIDlet midlet; private ChoiceGroup cgPrefs;
public FormPrefs(String title, TodoMIDlet midlet, boolean flags[])
{
// 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);
// Choicegroup for sort order and showing priority
cgPrefs = new ChoiceGroup("Preferences", Choice.MULTIPLE);
cgPrefs.append("Sort by Priority", null);
cgPrefs.append("Show Priority", null);
// Set the current status of each entry
cgPrefs.setSelectedFlags(flags);
// Add to form and listen for events
append(cgPrefs);
addCommand(cmBack);
addCommand(cmSave);
setCommandListener(this);
}
public void commandAction(Command c, Displayable s)
{ if (c == cmSave)
{
// Save the preferences
midlet.savePreferences(cgPrefs.isSelected(0),
cgPrefs.isSelected(1));
}
// Any other event and we go back to the main form...
// Pop the last displayable off the stack
midlet.displayMgr.popDisplayable();
}
}
You can share your information about this topic using the form below!
Please do not post your questions with this form! Thanks.