001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /*
043: * WaitScreen.java
044: *
045: * Created on August 11, 2005, 1:33 PM
046: *
047: */
048:
049: package org.netbeans.microedition.lcdui;
050:
051: import javax.microedition.lcdui.Alert;
052: import javax.microedition.lcdui.Command;
053: import javax.microedition.lcdui.CommandListener;
054: import javax.microedition.lcdui.Display;
055: import javax.microedition.lcdui.Displayable;
056: import org.netbeans.microedition.util.CancellableTask;
057:
058: /**
059: * This component suits as a wait screen, which let the user to execute a blocking
060: * background task (e.g. a network communication) and waits for it until finished.
061: * <p/>
062: * The background task is being started immediately prior the component is being
063: * shown on the screen.
064: * <p/>
065: * When the background task is finished, this component calls commandAction method
066: * on assigned CommandListener object. In the case of success, the commandAction method
067: * is called with SUCCESS_COMMAND as parameter, in the case of failure, the commandAction
068: * method is called with FAILURE_COMMAND as parameter.
069: * <p/>
070: * The functionality from previous version, where the component automatically swiches
071: * to another <code>Displayable</code> objects is still available, but has beeen
072: * deprecated.
073: * <p/>
074: * The deprecated behavior is the following - in the case of success (i.e. the
075: * task finished successfully), it switches to displayable(s) supplied by
076: * <code>setNextDisplayable()</code> methods, in the case of failure, it switched to displaybles(s)
077: * supplied by <code>setFailureDisplayable()</code> methods. In the case there is not
078: * set failure displayable, <code>WaitScreen</code> even in the
079: * case of failure switches to displayables specified by the <code>setNextDisplayable()</code>
080: * method. In the case there is even no next displayable specified, after the
081: * task is finished, <code>WaitScreen</code> switches back to the screen it was
082: * previously visible on the display.
083: *
084: * @author breh
085: */
086: public class WaitScreen extends AbstractInfoScreen {
087:
088: private CancellableTask task = null;
089: private Thread backgroundExecutor = null;
090:
091: private Displayable failureDisplayble;
092: private Alert failureAlert;
093:
094: /**
095: * Command fired when the background task was finished succesfully
096: */
097: public static final Command SUCCESS_COMMAND = new Command(
098: "Success", Command.OK, 0);
099:
100: /**
101: * Command fired when the background task failed (threw exception)
102: */
103: public static final Command FAILURE_COMMAND = new Command(
104: "Failure", Command.OK, 0);
105:
106: /**
107: * Creates a new instance of WaitScreen for given <code>Display</code> object.
108: * @param display A non-null display object.
109: * @throws IllegalArgumentException when the supplied argument is null
110: */
111: public WaitScreen(Display display) throws IllegalArgumentException {
112: super (display);
113: }
114:
115: /**
116: * Sets the displayable to be used to switch to in the case of the background
117: * task failure.
118: * @param failureDisplayble displayable, or null if the component should switch to <code>nextDisplayable</code>
119: * even in the case of failure.
120: *
121: * @deprecated - use FAILURE_COMMAND in CommandListener.commandAction() to handle failure event
122: */
123: public void setFailureDisplayable(Displayable failureDisplayble) {
124: this .failureDisplayble = failureDisplayble;
125: }
126:
127: /**
128: * Requests that the specified Alert is going to be shown in the case of
129: * failure, and failureDisplayable be made current after the Alert is dismissed.
130: * <p/>
131: * The failureDisplayable parameter cannot be Alert and in the case
132: * failureAlert is not null, it also cannot be null.
133: * @param failureAlert alert to be shown, or null if the component should always switch to nextDisplayable
134: * @param failureDisplayble a displayable to be shown after the alert is being dismissed. This displayable
135: * cannot be null if the <code>failureAlert</code> is not null and it also cannot be
136: * Alert.
137: * @throws java.lang.IllegalArgumentException If the failureAlert is not null and failureDisplay is null at the same time, or
138: * if the failureDisplayable is instance of <code>Alert</code>
139: *
140: * @deprecated - use FAILURE_COMMAND in CommandListener.commandAction() to handle failure event
141: */
142: public void setFailureDisplayable(Alert failureAlert,
143: Displayable failureDisplayble)
144: throws IllegalArgumentException {
145: if ((failureAlert != null) && (failureDisplayble == null))
146: throw new IllegalArgumentException(
147: "A failureDisplayable parameter cannot be null if the failureAlert parameter is not null.");
148: if (failureDisplayble instanceof Alert)
149: throw new IllegalArgumentException(
150: "failureDisplayable paremter cannot be Alert.");
151: this .failureAlert = failureAlert;
152: this .failureDisplayble = failureDisplayble;
153: }
154:
155: /**
156: * Sets the task to be run on the background.
157: * @param task task to be executed
158: */
159: public void setTask(CancellableTask task) {
160: this .task = task;
161: }
162:
163: /**
164: * Gets the background task.
165: * @return task being executed in background while this component is being shown
166: * on the screen
167: */
168: public CancellableTask getTask() {
169: return task;
170: }
171:
172: /**
173: * starts the supplied task
174: */
175: protected void showNotify() {
176: super .showNotify();
177: // and start the task
178: if (task != null) {
179: if (backgroundExecutor == null) {
180: backgroundExecutor = new Thread(new BackgroundExecutor(
181: task));
182: backgroundExecutor.start();
183: }
184: } else {
185: // switch to next displayable immediatelly - no task was assigned
186: // do it when the task is repainted - on some devices there are
187: // some race-conditions
188: getDisplay().callSerially(new Runnable() {
189: public void run() {
190: doAction();
191: }
192: });
193: }
194: }
195:
196: // private stuff
197: // private stuff
198: private void doAction() {
199: CommandListener cl = getCommandListener();
200: if (cl != null) {
201: if ((task != null) && task.hasFailed()) {
202: cl.commandAction(FAILURE_COMMAND, this );
203: } else {
204: // task didn't failed - success !!!
205: cl.commandAction(SUCCESS_COMMAND, this );
206: }
207: } else {
208: // old behavior - now deprecated
209: if ((task != null) && task.hasFailed()
210: && (failureDisplayble != null)) {
211: switchToDisplayable(getDisplay(), failureAlert,
212: failureDisplayble);
213: } else {
214: switchToNextDisplayable();
215: }
216: }
217:
218: }
219:
220: /**
221: * BackgroundExecutor task
222: */
223: private class BackgroundExecutor implements Runnable {
224:
225: private CancellableTask task;
226:
227: public BackgroundExecutor(CancellableTask task)
228: throws IllegalArgumentException {
229: if (task == null)
230: throw new IllegalArgumentException(
231: "Task parameter cannot be null");
232: this .task = task;
233: }
234:
235: public void run() {
236: try {
237: task.run();
238: } finally {
239: getDisplay().callSerially(new Runnable() {
240: public void run() {
241: WaitScreen.this.backgroundExecutor = null;
242: doAction();
243: }
244: });
245:
246: }
247: }
248: }
249:
250: }
|