001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package javax.microedition.lcdui;
028:
029: /**
030: * An alert is a screen that shows data to the user and waits for a certain
031: * period of time before proceeding to the next
032: * <code>Displayable</code>. An alert can
033: * contain a text string and an image.
034: * The intended use of <code>Alert</code> is to inform the user about
035: * errors and other
036: * exceptional conditions.
037: *
038: * <P>The application can set the alert time to be infinity with
039: * <code> setTimeout(Alert.FOREVER)</code>
040: * in which case the <code>Alert</code> is considered to be <em>modal</em> and
041: * the implementation provide a feature that allows the
042: * user to "dismiss" the alert, whereupon the next
043: * <code>Displayable</code>
044: * is displayed as if the timeout had expired immediately.</P>
045: *
046: * <P>If an application specifies an alert to be of a
047: * timed variety <em>and</em> gives it too much content such that it must
048: * scroll,
049: * then it automatically becomes a modal alert.</P>
050: *
051: * <P> An alert may have an <code>AlertType</code> associated with it
052: * to provide an indication of the nature of the alert.
053: * The implementation may use this type to play an
054: * appropriate sound when the <code>Alert</code> is presented to the user.
055: * See {@link AlertType#playSound(javax.microedition.lcdui.Display)
056: * AlertType.playSound()}.</P>
057: *
058: * <P>An alert may contain an optional <code>Image</code>. The
059: * <code>Image</code> may be mutable or
060: * immutable. If the <code>Image</code> is mutable, the effect is as
061: * if a snapshot of its
062: * contents is taken at the time the <code>Alert</code> is constructed
063: * with this <code>Image</code> and
064: * when <code>setImage</code> is called with an <code>Image</code>.
065: * This snapshot is used whenever the contents of the
066: * <code>Alert</code> are to be
067: * displayed. Even if the application subsequently draws into the
068: * <code>Image</code>, the
069: * snapshot is not modified until the next call to <code>setImage</code>. The
070: * snapshot is <em>not</em> updated when the <code>Alert</code>
071: * becomes current or becomes
072: * visible on the display. (This is because the application does not have
073: * control over exactly when <code>Displayables</code> appear and
074: * disappear from the
075: * display.)</P>
076: *
077: * <a name="indicator"></a>
078: * <h3>Activity Indicators</h3>
079: *
080: * <P>An alert may contain an optional {@link Gauge} object that is used as an
081: * activity or progress indicator. By default, an <code>Alert</code>
082: * has no activity
083: * indicator; one may be set with the {@link #setIndicator} method.
084: * The <code>Gauge</code>
085: * object used for the activity indicator must conform to all of the following
086: * restrictions:</P>
087: *
088: * <ul>
089: * <li>it must be non-interactive;</li>
090: * <li>it must not be owned by another container (<code>Alert</code>
091: * or <code>Form</code>);</li>
092: * <li>it must not have any <code>Commands</code>;</li>
093: * <li>it must not have an <code>ItemCommandListener</code>;</li>
094: * <li>it must not have a label (that is, its label must be
095: * <code>null</code>;</li>
096: * <li>its preferred width and height must both be unlocked; and</li>
097: * <li>its layout value must be <code>LAYOUT_DEFAULT</code>.</li>
098: * </ul>
099: *
100: * <P>It is an error for the application to attempt to use a
101: * <code>Gauge</code> object that
102: * violates any of these restrictions. In addition, when the
103: * <code>Gauge</code> object is
104: * being used as the indicator within an <code>Alert</code>, the
105: * application is prevented
106: * from modifying any of these pieces of the <code>Gauge's</code> state.</P>
107: *
108: * <a name="commands"></a>
109: * <h3>Commands and Listeners</h3>
110: *
111: * <P>Like the other <code>Displayable</code> classes, an
112: * <code>Alert</code> can accept <code>Commands</code>, which
113: * can be delivered to a <code>CommandListener</code> set by the
114: * application. The <code>Alert</code>
115: * class adds some special behavior for <code>Commands</code> and listeners.</P>
116: *
117: * <P>When it is created, an <code>Alert</code> implicitly has the
118: * special <code>Command</code>
119: * {@link #DISMISS_COMMAND} present on it. If the application adds any
120: * other <code>Commands</code> to the <code>Alert</code>,
121: * <code>DISMISS_COMMAND</code> is implicitly removed. If the
122: * application removes all other <code>Commands</code>,
123: * <code>DISMISS_COMMAND</code> is implicitly
124: * restored. Attempts to add or remove <code>DISMISS_COMMAND</code>
125: * explicitly are
126: * ignored. Thus, there is always at least one <code>Command</code>
127: * present on an <code>Alert</code>.
128: * </P>
129: *
130: * <P>If there are two or more <code>Commands</code> present on the
131: * <code>Alert</code>, it is
132: * automatically turned into a modal <code>Alert</code>, and the
133: * timeout value is always
134: * {@link #FOREVER}. The <code>Alert</code> remains on the display
135: * until a <code>Command</code> is
136: * invoked. If the Alert has one Command (whether it is DISMISS_COMMAND or it
137: * is one provided by the application), the <code>Alert</code> may have
138: * the timed behavior
139: * as described above. When a timeout occurs, the effect is the same as if
140: * the user had invoked the <code>Command</code> explicitly.</P>
141: *
142: * <P>When it is created, an <code>Alert</code> implicitly has a
143: * <code>CommandListener</code> called the
144: * <em>default listener</em> associated with it. This listener may be
145: * replaced by an application-provided listener through use of the {@link
146: * #setCommandListener} method. If the application removes its listener by
147: * passing <code>null</code> to the <code>setCommandListener</code> method,
148: * the default listener is implicitly restored.</P>
149: *
150: * <P>The {@link Display#setCurrent(Alert, Displayable)} method and the {@link
151: * Display#setCurrent(Displayable)} method (when called with an
152: * <code>Alert</code>) define
153: * special behavior for automatically advancing to another
154: * <code>Displayable</code> after
155: * the <code>Alert</code> is dismissed. This special behavior occurs
156: * only when the default
157: * listener is present on the <code>Alert</code> at the time it is
158: * dismissed or when a
159: * command is invoked. If the user invokes a <code>Command</code> and
160: * the default listener
161: * is present, the default listener ignores the <code>Command</code>
162: * and implements the
163: * automatic-advance behavior.</P>
164: *
165: * <P>If the application has set its own <code>CommandListener</code>, the
166: * automatic-advance behavior is disabled. The listener code is responsible
167: * for advancing to another <code>Displayable</code>. When the
168: * application has provided a
169: * listener, <code>Commands</code> are invoked normally by passing
170: * them to the listener's
171: * <code>commandAction</code> method. The <code>Command</code> passed
172: * will be one of the
173: * <code>Commands</code> present on the <code>Alert</code>: either
174: * <code>DISMISS_COMMAND</code> or one of the
175: * application-provided <code>Commands</code>.</P>
176: *
177: * <P>The application can restore the default listener by passing
178: * <code>null</code> to the <code>setCommandListener</code> method.</P>
179: *
180: * <P>
181: * <strong>Note:</strong> An application may set a {@link Ticker Ticker}
182: * with {@link Displayable#setTicker Displayable.setTicker} on an
183: * <code>Alert</code>, however it may not be displayed due to
184: * implementation restrictions.
185: * </P>
186: *
187: * @see AlertType
188: * @since MIDP 1.0
189: */
190:
191: public class Alert extends Screen {
192:
193: // *****************************************************
194: // Public members
195: // *****************************************************
196:
197: /**
198: * <code>FOREVER</code> indicates that an <code>Alert</code> is
199: * kept visible until the user
200: * dismisses it. It is used as a value for the parameter to
201: * {@link #setTimeout(int) setTimeout()}
202: * to indicate that the alert is modal. Instead of waiting for a
203: * specified period of time, a modal <code>Alert</code> will wait
204: * for the user to take
205: * some explicit action, such as pressing a button, before proceeding to
206: * the next <code>Displayable</code>.
207: *
208: * <P>Value <code>-2</code> is assigned to <code>FOREVER</code>.</P>
209: */
210: public final static int FOREVER = -2;
211:
212: /**
213: * A <code>Command</code> delivered to a listener to indicate that
214: * the <code>Alert</code> has been
215: * dismissed. This Command is implicitly present an on
216: * <code>Alert</code> whenever
217: * there are no other Commands present. The field values of
218: * <code>DISMISS_COMMAND</code> are as follows:
219: *
220: * <ul>
221: * <li>label = "" (an empty string)</li>
222: * <li>type = Command.OK</li>
223: * <li>priority = 0</li>
224: * </ul>
225: *
226: * <p>The label value visible to the application must be as specified
227: * above. However, the implementation may display
228: * <code>DISMISS_COMMAND</code> to the
229: * user using an implementation-specific label.</p>
230: *
231: * <p>Attempting to add or remove <code>DISMISS_COMMAND</code>
232: * from an <code>Alert</code> has no
233: * effect. However, <code>DISMISS_COMMAND</code> is treated as an
234: * ordinary <code>Command</code> if
235: * it is used with other <code>Displayable</code> types.</p>
236: *
237: */
238: public final static Command DISMISS_COMMAND = new Command("",
239: Command.OK, 0);
240:
241: // *****************************************************
242: // Constructor(s)
243: // *****************************************************
244:
245: /**
246: * Constructs a new, empty <code>Alert</code> object with the
247: * given title. If <code>null</code> is
248: * passed, the <code>Alert</code> will have no title. Calling
249: * this constructor is
250: * equivalent to calling
251: *
252: * <pre>
253: * <code>Alert(title, null, null, null)</code>
254: * </pre>
255: *
256: * @param title the title string, or <code>null</code>
257: *
258: * @see #Alert(String, String, Image, AlertType)
259: */
260: public Alert(String title) {
261: this (title, null, null, null);
262: }
263:
264: /**
265: * Constructs a new <code>Alert</code> object with the given title,
266: * content
267: * string and image, and alert type.
268: * The layout of the contents is implementation dependent.
269: * The timeout value of this new alert is the same value that is
270: * returned by <code>getDefaultTimeout()</code>.
271: * The <code>Image</code> provided may either be mutable or immutable.
272: * The handling and behavior of specific <code>AlertTypes</code>
273: * is described in
274: * {@link AlertType}. <code>null</code> is allowed as the value
275: * of the <code>alertType</code>
276: * parameter and indicates that the <code>Alert</code> is not to
277: * have a specific alert
278: * type. <code>DISMISS_COMMAND</code> is the only
279: * <code>Command</code> present on the new
280: * <code>Alert</code>. The <code>CommandListener</code>
281: * associated with the new <code>Alert</code> is the
282: * <em>default listener</em>. Its behavior is described in more detail in
283: * the section <a href="#commands">Commands and Listeners</a>.
284: *
285: * @param title the title string, or <code>null</code> if there is no title
286: * @param alertText the string contents, or <code>null</code> if there
287: * is no string
288: * @param alertImage the image contents, or <code>null</code> if there
289: * is no image
290: * @param alertType the type of the <code>Alert</code>, or
291: * <code>null</code>
292: * if the <code>Alert</code> has no
293: * specific type
294: */
295: public Alert(String title, String alertText, Image alertImage,
296: AlertType alertType) {
297:
298: super (title);
299:
300: synchronized (Display.LCDUILock) {
301: this .text = alertText;
302: this .type = alertType;
303:
304: setImageImpl(alertImage);
305:
306: displayableLF = alertLF = LFFactory.getFactory()
307: .getAlertLF(this );
308:
309: this .time = alertLF.lGetDefaultTimeout();
310:
311: // Call addCommandImpl to avoid notification to AlertLF
312: // cause we know this Alert is not yet visible
313: addCommandImpl(alertLF.lGetDismissCommand());
314:
315: // Note that we have to call super.setCommandListener since
316: // this.setCommandListener will set application's command
317: // listener
318: super .setCommandListener(implicitListener);
319: }
320: }
321:
322: // *****************************************************
323: // Public methods
324: // *****************************************************
325:
326: /**
327: * Gets the default time for showing an <code>Alert</code>. This
328: * is either a
329: * positive value, which indicates a time in milliseconds, or the special
330: * value
331: * {@link #FOREVER FOREVER},
332: * which indicates that <code>Alerts</code> are modal by default. The
333: * value returned will vary across implementations and is presumably
334: * tailored to be suitable for each.
335: *
336: * @return default timeout in milliseconds, or <code>FOREVER</code>
337: */
338: public int getDefaultTimeout() {
339: synchronized (Display.LCDUILock) {
340: return alertLF.lGetDefaultTimeout();
341: }
342: }
343:
344: /**
345: * Gets the time this <code>Alert</code> will be shown. This is
346: * either a positive
347: * value, which indicates a time in milliseconds, or the special value
348: * <code>FOREVER</code>, which indicates that this
349: * <code>Alert</code> is modal. This value is not
350: * necessarily the same value that might have been set by the
351: * application
352: * in a call to {@link #setTimeout}. In particular, if the
353: * <code>Alert</code> is made
354: * modal because its contents is large enough to scroll, the value
355: * returned by <code>getTimeout</code> will be <code>FOREVER</code>.
356: *
357: * @return timeout in milliseconds, or <code>FOREVER</code>
358: * @see #setTimeout
359: */
360: public int getTimeout() {
361: synchronized (Display.LCDUILock) {
362: if (alertLF.lIsModal()) {
363: return FOREVER;
364: } else {
365: return time;
366: }
367: }
368: }
369:
370: /**
371: * Set the time for which the <code>Alert</code> is to be shown.
372: * This must either
373: * be a positive time value in milliseconds, or the special value
374: * <code>FOREVER</code>.
375: *
376: * @param time timeout in milliseconds, or <code>FOREVER</code>
377: * @throws IllegalArgumentException if time is not positive and is
378: * not <code>FOREVER</code>
379: * @see #getTimeout
380: */
381: public void setTimeout(int time) {
382: if (time <= 0 && time != FOREVER) {
383: throw new IllegalArgumentException();
384: }
385:
386: synchronized (Display.LCDUILock) {
387: this .time = time;
388: alertLF.lSetTimeout(time);
389: }
390: }
391:
392: /**
393: * Gets the type of the <code>Alert</code>.
394: * @return a reference to an instance of <code>AlertType</code>,
395: * or <code>null</code>
396: * if the <code>Alert</code>
397: * has no specific type
398: * @see #setType
399: */
400: public AlertType getType() {
401: // SYNC NOTE: return of atomic value, no locking necessary
402: return type;
403: }
404:
405: /**
406: * Sets the type of the <code>Alert</code>.
407: * The handling and behavior of specific <code>AlertTypes</code>
408: * is described in
409: * {@link AlertType}.
410: * @param type an <code>AlertType</code>, or <code>null</code> if the
411: * <code>Alert</code> has no
412: * specific type
413: * @see #getType
414: */
415: public void setType(AlertType type) {
416: synchronized (Display.LCDUILock) {
417: if (this .type != type) {
418: this .type = type;
419: alertLF.lSetType(type);
420: }
421: }
422: }
423:
424: /**
425: * Gets the text string used in the <code>Alert</code>.
426: * @return the <code>Alert's</code> text string, or <code>null</code>
427: * if there is no text
428: * @see #setString
429: */
430: public String getString() {
431: // SYNC NOTE: no locking necessary
432: return text;
433: }
434:
435: /**
436: * Sets the text string used in the <code>Alert</code>.
437: *
438: * <p>If the <code>Alert</code> is visible on the display when its
439: * contents are updated
440: * through a call to <code>setString</code>, the display will be
441: * updated with the new
442: * contents as soon as it is feasible for the implementation to do so.
443: * </p>
444: *
445: * @param str the <code>Alert's</code> text string, or <code>null</code>
446: * if there is no text
447: * @see #getString
448: */
449: public void setString(String str) {
450: synchronized (Display.LCDUILock) {
451: if (str == text || (str != null && str.equals(text))) {
452: return;
453: }
454:
455: String oldStr = text;
456: text = str;
457: alertLF.lSetString(oldStr, str);
458: }
459: }
460:
461: /**
462: * Gets the <code>Image</code> used in the <code>Alert</code>.
463: * @return the <code>Alert's</code> image, or <code>null</code>
464: * if there is no image
465: * @see #setImage
466: */
467: public Image getImage() {
468: synchronized (Display.LCDUILock) {
469: if (mutableImage != null) {
470: return mutableImage;
471: } else {
472: return image;
473: }
474: }
475: }
476:
477: /**
478: * Sets the <code>Image</code> used in the <code>Alert</code>.
479: * The <code>Image</code> may be mutable or
480: * immutable. If <code>img</code> is <code>null</code>, specifies
481: * that this <code>Alert</code> has no image.
482: * If <code>img</code> is mutable, the effect is as if a snapshot is taken
483: * of <code>img's</code> contents immediately prior to the call to
484: * <code>setImage</code>. This
485: * snapshot is used whenever the contents of the
486: * <code>Alert</code> are to be
487: * displayed. If <code>img</code> is already the
488: * <code>Image</code> of this <code>Alert</code>, the effect
489: * is as if a new snapshot of img's contents is taken. Thus, after
490: * painting into a mutable image contained by an <code>Alert</code>, the
491: * application can call
492: *
493: * <TABLE BORDER="2">
494: * <TR>
495: * <TD ROWSPAN="1" COLSPAN="1">
496: * <pre><code>
497: * alert.setImage(alert.getImage()); </code></pre>
498: * </TD>
499: * </TR>
500: * </TABLE>
501: * <p>to refresh the <code>Alert's</code> snapshot of its
502: * <code>Image</code>.</p>
503: *
504: * <p>If the <code>Alert</code> is visible on the display when its
505: * contents are updated
506: * through a call to <code>setImage</code>, the display will be
507: * updated with the new
508: * snapshot as soon as it is feasible for the implementation to do so.
509: * </p>
510: *
511: * @param img the <code>Alert's</code> image, or <code>null</code>
512: * if there is no image
513: * @see #getImage
514: */
515: public void setImage(Image img) {
516: synchronized (Display.LCDUILock) {
517: Image oldImg = image;
518: if (setImageImpl(img)) {
519: // Always pass the immutable image snapshot as new image
520: alertLF.lSetImage(oldImg, image);
521: }
522: }
523: }
524:
525: /**
526: * Sets an activity indicator on this <code>Alert</code>. The
527: * activity indicator is a
528: * {@link Gauge} object. It must be in a restricted state in order for it
529: * to be used as the activity indicator for an <code>Alert</code>.
530: * The restrictions
531: * are listed <a href="#indicator">above</a>. If the
532: * <code>Gauge</code> object
533: * violates any of these restrictions,
534: * <code>IllegalArgumentException</code> is thrown.
535: *
536: * <p>If <code>indicator</code> is <code>null</code>, this removes any
537: * activity indicator present on this <code>Alert</code>.</p>
538: *
539: * @param indicator the activity indicator for this <code>Alert</code>,
540: * or <code>null</code> if
541: * there is to be none
542: *
543: * @throws IllegalArgumentException if <code>indicator</code> does not
544: * meet the restrictions for its use in an <code>Alert</code>
545: * @see #getIndicator
546: */
547: public void setIndicator(Gauge indicator) {
548:
549: synchronized (Display.LCDUILock) {
550: // do nothing if indicator is the same
551: // that includes both indicators (old and new) being null
552: if (this .indicator == indicator) {
553: return;
554: }
555:
556: Gauge oldIndicator = this .indicator;
557:
558: if (indicator == null) {
559: // The Alert no longer owns this Gauge;
560: // We do not need to check if this.indicator != null
561: // since we already returned if they are both null
562: oldIndicator.lSetOwner(null);
563: } else {
564: if (!isConformantIndicator(indicator)) {
565: throw new IllegalArgumentException(
566: "Gauge in wrong state");
567: }
568: indicator.lSetOwner(this );
569:
570: // if old indicator is not null
571: // it is no longer is owned by this alert
572: if (oldIndicator != null) {
573: oldIndicator.lSetOwner(null);
574: }
575: }
576:
577: this .indicator = indicator;
578:
579: alertLF.lSetIndicator(oldIndicator, indicator);
580: }
581: }
582:
583: /**
584: * Gets the activity indicator for this <code>Alert</code>.
585: *
586: * @return a reference to this <code>Alert's</code> activity indicator,
587: * or <code>null</code> if
588: * there is none
589: * @see #setIndicator
590: */
591: public Gauge getIndicator() {
592: // SYNC NOTE: no locking necessary
593: return indicator;
594: }
595:
596: /**
597: * Similar to {@link Displayable#addCommand}, however when the
598: * application first adds a command to an <code>Alert</code>,
599: * {@link #DISMISS_COMMAND} is implicitly removed. Calling this
600: * method with <code>DISMISS_COMMAND</code> as the parameter has
601: * no effect.
602: *
603: * @param cmd the command to be added
604: *
605: * @throws NullPointerException if cmd is <code>null</code>
606: */
607: public void addCommand(Command cmd) {
608: if (cmd == null) {
609: throw new NullPointerException();
610: }
611:
612: if (cmd == DISMISS_COMMAND) {
613: return;
614: }
615:
616: synchronized (Display.LCDUILock) {
617: Command dismissCmd = alertLF.lGetDismissCommand();
618:
619: if (commands[0] == dismissCmd) {
620: super .removeCommand(dismissCmd);
621: }
622: super .addCommand(cmd);
623: }
624: }
625:
626: /**
627: * Similar to {@link Displayable#removeCommand}, however when the
628: * application removes the last command from an
629: * <code>Alert</code>, {@link #DISMISS_COMMAND} is implicitly
630: * added. Calling this method with <code>DISMISS_COMMAND</code>
631: * as the parameter has no effect.
632: *
633: * @param cmd the command to be removed
634: */
635: public void removeCommand(Command cmd) {
636: if (cmd == DISMISS_COMMAND) {
637: return;
638: }
639:
640: synchronized (Display.LCDUILock) {
641: super .removeCommand(cmd);
642: if (numCommands == 0) {
643: super .addCommand(alertLF.lGetDismissCommand());
644: }
645: }
646: }
647:
648: /**
649: * The same as {@link Displayable#setCommandListener} but with the
650: * following additional semantics. If the listener parameter is
651: * <code>null</code>, the <em>default listener</em> is restored.
652: * See <a href="#commands">Commands and Listeners</a> for the definition
653: * of the behavior of the default listener.
654: *
655: * @param l the new listener, or <code>null</code>
656: */
657: public void setCommandListener(CommandListener l) {
658: synchronized (Display.LCDUILock) {
659: userCommandListener = l;
660: }
661: }
662:
663: // *****************************************************
664: // Package private methods
665: // *****************************************************
666:
667: /**
668: * Set the screen that the display should return to
669: * when this Alert is dismissed.
670: *
671: * @param d The Displayable to display when this Alert is completed
672: */
673: void setReturnScreen(Displayable d) {
674: this .returnScreen = d;
675: }
676:
677: /**
678: * Get the screen that the display should return to
679: * when this Alert is dismissed.
680: * @return The Displayable to display when this Alert is completed
681: */
682: Displayable getReturnScreen() {
683: return returnScreen;
684: }
685:
686: /**
687: * Dismisses this alert.
688: */
689: void lDismiss() {
690: Display dpy = alertLF.lGetCurrentDisplay();
691: if (dpy != null && returnScreen != null) {
692: dpy.clearAlert(this , returnScreen);
693: }
694: }
695:
696: /**
697: * LF notifies that the Alert is dismissed due to timeout,
698: * instead of user action.
699: * Commandlistener will be notified with the default Command.
700: */
701: void uNotifyTimeout() {
702: try {
703: synchronized (Display.calloutLock) {
704: listener.commandAction(commands[0], this );
705: }
706: } catch (Throwable thr) {
707: Display.handleThrowable(thr);
708: }
709: }
710:
711: // *****************************************************
712: // Private methods
713: // *****************************************************
714:
715: /**
716: * Verify the activity indicator is conformant with the spec
717: * requirements for addition to an Alert.
718: *
719: * @param ind The indicator to be verified
720: * @return boolean True if the gauge is conformant; false otherwise
721: */
722: private boolean isConformantIndicator(Gauge ind) {
723: return ((ind.interactive == false) && (ind.owner == null)
724: && (ind.numCommands == 0)
725: && (ind.commandListener == null) && (ind.label == null)
726: && (ind.layout == Item.LAYOUT_DEFAULT)
727: && (ind.lockedWidth == -1) && (ind.lockedHeight == -1));
728: }
729:
730: /**
731: * Set the Image for this Alert.
732: *
733: * @param img The img to use for this Alert
734: * @return true if look&feel object has to be notified of an image change
735: */
736: private boolean setImageImpl(Image img) {
737: if (img != null && img.isMutable()) {
738: this .image = Image.createImage(img); // use immutable copy of img
739: this .mutableImage = img;
740: } else {
741: if (image == img) {
742: return false;
743: }
744: this .image = img;
745: this .mutableImage = null; // Make sure to clear mutableImage
746: }
747: return true;
748: }
749:
750: // *****************************************************
751: // Package private members
752: // *****************************************************
753:
754: /**
755: * The type of this alert
756: */
757: AlertType type;
758:
759: /**
760: * The layout object for the alert text string
761: */
762: String text;
763:
764: /**
765: * The image of this alert
766: */
767: Image image;
768:
769: /**
770: * A reference to the original, mutable Image passed to setImage(). This
771: * is only so getImage() can return the correct Image Object.
772: */
773: private Image mutableImage;
774:
775: /**
776: * The activity indicator for this alert
777: */
778: Gauge indicator;
779:
780: /**
781: * The timeout value of this alert
782: */
783: int time;
784:
785: /**
786: * The screen which the display will return to when this Alert
787: * is completed
788: */
789: Displayable returnScreen;
790:
791: /**
792: * The application's command listener
793: */
794: CommandListener userCommandListener;
795:
796: /** The Alert look&feel object associated with this Alert */
797: AlertLF alertLF;
798:
799: // *****************************************************
800: // Private members
801: // *****************************************************
802:
803: /**
804: * Special CommandListener instance to handle execution of
805: * the default "OK" Command
806: */
807: private CommandListener implicitListener = new CommandListener() {
808: /**
809: * Handle the execution of the given Command and Displayable.
810: * Caller of this function should hold calloutLock and catch Throwable.
811: *
812: * @param c The Command to execute
813: * @param s The Displayable from which the Command originated
814: */
815: public void commandAction(Command c, Displayable s) {
816: CommandListener listenerToCall = null;
817:
818: synchronized (Display.LCDUILock) {
819: if (userCommandListener != null) {
820: // translate 'OK' to 'DISMISS_COMMAND
821: if (c == alertLF.lGetDismissCommand()) {
822: c = DISMISS_COMMAND;
823: }
824: // To be called outside LCDUILock
825: listenerToCall = userCommandListener;
826: } else {
827: // Treat all commands as if they were 'DISMISS'
828: lDismiss();
829: }
830: } // synchronized
831:
832: // SYNC NOTE: We are protected by the calloutLock obtained
833: // previously. (either in Display or the timeout task)
834: // We do not need to re-acquire the calloutLock when
835: // calling the application's command listener.
836: if (listenerToCall != null) {
837: listenerToCall.commandAction(c, s);
838: }
839: }
840: };
841: }
|