001: /*
002: * Copyright (c) 2007, Sun Microsystems, Inc.
003: *
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * * Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: * * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in
014: * the documentation and/or other materials provided with the
015: * distribution.
016: * * Neither the name of Sun Microsystems, Inc. nor the names of its
017: * contributors may be used to endorse or promote products derived
018: * from this software without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
023: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
024: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032: package example.mmademo;
033:
034: import javax.microedition.midlet.*;
035: import javax.microedition.lcdui.*;
036: import java.util.*;
037:
038: /**
039: * A base class for MIDLets that provide a list as display.
040: * A history of displayed pages is maintained, to provide
041: * user flow with automatic <i>back</i> functionality.
042: *
043: * @version 1.4
044: */
045: public abstract class BaseListMidlet extends MIDlet implements
046: CommandListener {
047:
048: // often needed commands.
049: // their functionality is provided in this class
050: // but child class has to add it to the list in fillList
051: protected Command exitCommand = new Command("Exit", Command.EXIT, 1);
052: protected Command backCommand = new Command("Back", Command.BACK, 1);
053: protected Command playCommand = new Command("Play", Command.ITEM, 1);
054: protected Command selectCommand = new Command("Select",
055: Command.ITEM, 1);
056:
057: private List list;
058: private Stack history;
059:
060: private Displayable currDisplayable; // default: null
061:
062: /**
063: * If true, then the menu will be
064: * shown on startApp().
065: */
066: private boolean firstTime = true;
067:
068: public BaseListMidlet(String title) {
069: history = new Stack();
070: list = new List(title, Choice.IMPLICIT);
071: list.setCommandListener(this );
072: fillList(list);
073: history.setSize(0);
074: }
075:
076: /**
077: * displays the last page that was displayed
078: */
079: public Displayable goBack() {
080: Displayable d;
081: if (Utils.DEBUG) {
082: Utils.debugOut("before goBack: (" + history.size()
083: + " elements)");
084: for (int i = history.size() - 1; i >= 0; i--) {
085: Utils.debugOut(" " + i + ": "
086: + history.elementAt(i).toString());
087: }
088: }
089: if (!history.empty()) {
090: d = (Displayable) history.pop();
091: Utils.debugOut("History: " + history.size() + " elements.");
092: } else {
093: exit();
094: return null;
095: }
096: return replaceCurrent(d);
097: }
098:
099: /**
100: * displays the given page. The current one is added to the history.
101: */
102: public Displayable go(Displayable d) {
103: Displayable curr = getCurrentDisplayable();
104: if (curr != null) {
105: history.push(curr);
106: }
107: if (Utils.DEBUG) {
108: Utils.debugOut("after go: (" + history.size()
109: + " elements)");
110: for (int i = history.size() - 1; i >= 0; i--) {
111: Utils.debugOut(" " + i + ": "
112: + history.elementAt(i).toString());
113: }
114: }
115: return replaceCurrent(d);
116: }
117:
118: /**
119: * Replaces current displaying page with
120: * the given one. The current page is not added
121: * to the history.
122: */
123: public Displayable replaceCurrent(Displayable d) {
124: getDisplay().setCurrent(d);
125: if (!(d instanceof Alert)) {
126: // Alerts come back automatically
127: currDisplayable = d;
128: }
129: Utils.debugOut("SetCurrent: " + d.toString());
130: return d;
131: }
132:
133: public Displayable getCurrentDisplayable() {
134: //return getDisplay().getCurrent();
135: return currDisplayable;
136: }
137:
138: protected List getList() {
139: return list;
140: }
141:
142: protected Display getDisplay() {
143: return Display.getDisplay(this );
144: }
145:
146: /**
147: * Child classes must implement this to insert
148: * the displayed list items and commands.
149: */
150: protected abstract void fillList(List list);
151:
152: /**
153: * Child classes must implement this in response to
154: * a selection in the list
155: */
156: protected abstract void selectCommand(int index);
157:
158: /**
159: * Called when this MIDlet is started for the first
160: * time, or when it returns from paused mode.
161: * When it's started for the first time, the
162: * firstTime flag is true and the list is
163: * displayed. Otherwise, if the current Displayable
164: * implements Utils.Interruptable, its resumeApp
165: * method is called.
166: *
167: */
168: public final void startApp() {
169: if (firstTime) {
170: go(getList());
171: firstTime = false;
172: } else {
173: Displayable curr = getCurrentDisplayable();
174: if (curr instanceof Utils.Interruptable) {
175: ((Utils.Interruptable) curr).resumeApp();
176: }
177: }
178: }
179:
180: /**
181: * Called when this MIDlet is paused.
182: * If the current Displayable
183: * implements Utils.Interruptable, its pauseApp
184: * method is called.
185: */
186: public final void pauseApp() {
187: Displayable curr = getCurrentDisplayable();
188: if (curr instanceof Utils.Interruptable) {
189: ((Utils.Interruptable) curr).pauseApp();
190: }
191: }
192:
193: /**
194: * Called when this MIDlet is destroyed.
195: * Subclasses should implement this for clean-up.
196: */
197: public void destroyApp(boolean unconditional) {
198: }
199:
200: /**
201: * Actively finish this MIDlet
202: */
203: public final void exit() {
204: destroyApp(false);
205: notifyDestroyed();
206: }
207:
208: /*
209: * Respond to commands, including exit
210: * On the exit command, cleanup and notify that the MIDlet has
211: * been destroyed.
212: */
213: public void commandAction(Command c, Displayable s) {
214: if (c == exitCommand) {
215: exit();
216: } else if (c == backCommand) {
217: goBack();
218: } else if ((s == list && c == List.SELECT_COMMAND)
219: || c == playCommand || c == selectCommand) {
220: selectCommand(getList().getSelectedIndex());
221: }
222: }
223:
224: }
|