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 com.sun.midp.chameleon;
028:
029: import com.sun.midp.chameleon.layers.*;
030: import com.sun.midp.chameleon.skins.*;
031: import com.sun.midp.log.Logging;
032: import com.sun.midp.log.LogChannels;
033:
034: import javax.microedition.lcdui.*;
035:
036: /**
037: * The MIDPWindow class is a concrete instance of a CWindow which
038: * implements the MIDP specification and its graphical elements,
039: * such as a title bar, soft buttons, ticker, etc.
040: */
041: public class MIDPWindow extends CWindow {
042:
043: // The order of layers id is impotant during creation and updating
044:
045: /** Id of layer containing the alert wash */
046: public static final int ALERT_WASH_LAYER = 0;
047:
048: /** Id of layer containing the alert displayable */
049: public static final int ALERT_LAYER = 1;
050:
051: /** Id of layer containing the mail */
052: public static final int WASH_LAYER = 2;
053:
054: /** Id of layer rendering the soft button controls */
055: public static final int BTN_LAYER = 3;
056:
057: /** Id of layer containing the ticker of the current displayable */
058: public static final int TICKER_LAYER = 4;
059:
060: /** Id of layer containing the title of the current displayable */
061: public static final int TITLE_LAYER = 5;
062:
063: /** Id of layer containing the pti contents */
064: public static final int PTI_LAYER = 6;
065:
066: /** Id of layer containing the current displayable's contents */
067: public static final int BODY_LAYER = 7;
068:
069: /** Number of main layers*/
070: public static final int LAST_LAYER = 8;
071:
072: /** Used to call back into the Display class from this package */
073: ChamDisplayTunnel tunnel;
074:
075: /** Cached typed references to the namded layers */
076: private WashLayer washLayer;
077: private WashLayer alertWashLayer;
078: private AlertLayer alertLayer;
079: private TitleLayer titleLayer;
080: private TickerLayer tickerLayer;
081: private BodyLayer bodyLayer;
082: private SoftButtonLayer buttonLayer;
083: private PTILayer ptiLayer;
084:
085: // layout modes
086: /**
087: * Normal screen mode
088: */
089: private static final int NORMAL_MODE = 0;
090:
091: /**
092: * Full screen mode when the current displayable
093: * is occupying as much screen as possible
094: */
095: private static final int FULL_SCR_MODE = 1;
096:
097: /**
098: * Current screen mode
099: */
100: int screenMode;
101:
102: /** Cache of screen commands */
103: Command[] scrCmdCache;
104:
105: /** Number of screen commands in the cache */
106: int scrCmdCount;
107:
108: /** Listener to notify when a screen command is selected */
109: CommandListener scrCmdListener;
110:
111: /** Cache of selected item commands */
112: Command[] itemCmdCache;
113:
114: /** Number of item commands in the cache */
115: int itemCmdCount;
116:
117: /** Listener to notify when an item command is selected */
118: ItemCommandListener itemCmdListener;
119:
120: CLayer[] mainLayers = new CLayer[LAST_LAYER];
121:
122: /** Determines whether area of the window has been changed */
123: boolean sizeChangedOccured = false;
124:
125: /**
126: * Construct a new MIDPWindow given the tunnel to the desired
127: * MIDP Display instance
128: *
129: * @param tunnel the "tunnel" to make calls from this java package
130: * back into the Display object in another package
131: */
132: public MIDPWindow(ChamDisplayTunnel tunnel) {
133: super (ScreenSkin.IMAGE_BG, ScreenSkin.COLOR_BG);
134:
135: this .tunnel = tunnel;
136:
137: for (int i = LAST_LAYER - 1; i >= 0; i--) {
138: createLayer(i);
139: }
140: }
141:
142: /**
143: * Request a repaint. This method does not require any bounds
144: * information as it is contained in each of the Chameleon layers.
145: * This method simply results in a repaint event being placed in
146: * the event queue for a future callback.
147: */
148: public void requestRepaint() {
149: if (tunnel != null) {
150: tunnel.scheduleRepaint();
151: }
152: }
153:
154: /**
155: * Set the title of this MIDPWindow. This would typically
156: * correspond to the title of the current displayable, and
157: * may result in the title layer appearing or disappearing.
158: *
159: * @param title the value of the title. null indicates there
160: * is no title.
161: */
162: public void setTitle(String title) {
163: if (titleLayer.setTitle(title)) {
164: resize();
165: }
166: requestRepaint();
167: }
168:
169: /**
170: * Set the ticker of this MIDPWindow. This would typically
171: * correspond to the ticker of the current displayable, and
172: * may result in the ticker layer appearing or disappearing.
173: *
174: * @param ticker the current Ticker object. null indicates there
175: * is no ticker.
176: */
177: public void setTicker(Ticker ticker) {
178: if (tickerLayer.setText((ticker != null) ? ticker.getString()
179: : null)) {
180: resize();
181: }
182: requestRepaint();
183: }
184:
185: /**
186: * Alert this MIDPWindow that the given displayable is now current
187: * and should be shown on the screen.
188: *
189: * This will establish the given displayable on the screen,
190: * as well as reflect the displayable's title and ticker (if any).
191: * Special circumstances may occur if the displayable is an Alert,
192: * such as maintaining the current screen contents and showing the
193: * Alert in a popup.
194: *
195: * @param displayable the newly current displayable to show
196: * @param height the preferred height of the new displayable
197: */
198: public void showDisplayable(Displayable displayable, int height) {
199: bodyLayer.opaque = (displayable instanceof Canvas);
200:
201: Ticker t = displayable.getTicker();
202: tickerLayer.setText((t != null) ? t.getString() : null);
203:
204: if (displayable instanceof Alert) {
205: tickerLayer.toggleAlert(true);
206: buttonLayer.toggleAlert(true);
207:
208: alertLayer.setAlert(true, (Alert) displayable, height);
209:
210: paintWash(false);
211: addLayer(alertLayer);
212: } else {
213: titleLayer.setTitle(displayable.getTitle());
214: bodyLayer.setVisible(true);
215: }
216:
217: resize();
218: requestRepaint();
219: }
220:
221: /**
222: * Alert this MIDPWindow that the given displayable is no longer
223: * current and should be removed from the screen.
224: *
225: * Special circumstances may occur if the displayable is an Alert,
226: * such as removing the popup and re-instating the previous
227: * displayable which was visible before the Alert popped up.
228: *
229: * @param displayable the newly current displayable to show
230: */
231: public void hideDisplayable(Displayable displayable) {
232: if (displayable instanceof Alert) {
233: buttonLayer.toggleAlert(false);
234: tickerLayer.toggleAlert(false);
235:
236: alertLayer.setAlert(false, null, 0);
237: paintWash(false);
238: removeLayer(alertLayer);
239: } else {
240: bodyLayer.setVisible(false);
241: }
242:
243: buttonLayer.dismissMenu();
244:
245: // Make sure that not of the popups are shown
246: clearPopups();
247: }
248:
249: /**
250: * Determines if the system menu is currently visible. This can be useful
251: * in determining the current isShown() status of the displayable.
252: *
253: * @return true if the system menu is up
254: */
255: public boolean systemMenuUp() {
256: return buttonLayer.systemMenuUp();
257: }
258:
259: /**
260: * Request a repaint of a region of the current displayable.
261: * This method specifically marks a region of the body layer
262: * (which renders the displayable's contents) as dirty and
263: * results in a repaint request being scheduled. The coordinates
264: * are in the space of the displayable itself - that is, 0,0
265: * represents the top left corner of the body layer.
266: *
267: * @param x the x coordinate of the dirty region
268: * @param y the y coordinate of the dirty region
269: * @param w the width of the dirty region
270: * @param h the height of the dirty region
271: */
272: public void repaintDisplayable(int x, int y, int w, int h) {
273: // We mark the body layer as dirty
274: if (alertLayer.visible) {
275: alertLayer.addDirtyRegion(x, y, w, h);
276: } else {
277: bodyLayer.addDirtyRegion(x, y, w, h);
278: }
279: requestRepaint();
280: }
281:
282: /**
283: * Add the given layer to this window. This method is
284: * overridden from CWindow in order to special case
285: * popup layers. Popup layers can have their own commands
286: * which supercede those of the current displayable.
287: *
288: * @param layer the CLayer to add to this window
289: * @return true if new layer was added, false otherwise
290: */
291: public boolean addLayer(CLayer layer) {
292: boolean added = super .addLayer(layer);
293:
294: if (added && layer instanceof PopupLayer) {
295: PopupLayer popup = (PopupLayer) layer;
296: popup.setDirty();
297: popup.visible = true;
298:
299: Command[] cmds = popup.getCommands();
300: if (cmds != null) {
301: buttonLayer.updateCommandSet(null, 0, null, cmds,
302: cmds.length, popup.getCommandListener());
303: }
304: }
305:
306: if (added && layer instanceof PTILayer) {
307: ptiLayer = (PTILayer) layer;
308: mainLayers[PTI_LAYER] = layer;
309: resize();
310: }
311:
312: return added;
313: }
314:
315: /**
316: * Remove the given layer from this window. This method is
317: * overridden from CWindow in order to special case popup
318: * layers. Popup layers can have their own commands which
319: * supercede those of the current displayable. In this case,
320: * the popup is removed and the commands in the soft button
321: * bar are restored to either the next top-most popup layer
322: * or the current displayable itself.
323: *
324: * @param layer the CLayer to remove from this window
325: * @return true if the layer was able to be removed
326: */
327: public boolean removeLayer(CLayer layer) {
328: if (super .removeLayer(layer)) {
329: if (layer instanceof PopupLayer) {
330: if (layer == mainLayers[PTI_LAYER]) {
331: ptiLayer = null;
332: mainLayers[PTI_LAYER] = null;
333: resize();
334: }
335:
336: // Now we update the command set with either the
337: // next top most popup or the original cached commands
338: PopupLayer p = getTopMostPopup();
339: if (p != null && p.getCommands() != null) {
340: Command[] cmds = p.getCommands();
341: buttonLayer.updateCommandSet(null, 0, null, cmds,
342: cmds.length, p.getCommandListener());
343: } else {
344: buttonLayer.updateCommandSet(itemCmdCache,
345: itemCmdCount, itemCmdListener, scrCmdCache,
346: scrCmdCount, scrCmdListener);
347: }
348: } // instanceof
349: return true;
350: } // removeLayer
351: return false;
352: }
353:
354: /**
355: * Return bounds of BodyLayer currently
356: * @return array of bounds
357: */
358: public int[] getBodyLayerBounds() {
359: int[] innerBounds = new int[4];
360: System.arraycopy(bodyLayer.bounds, 0, innerBounds, 0, 4);
361: return innerBounds;
362:
363: }
364:
365: /**
366: * Update this MIDPWindow's current command set to match the
367: * current displayable and possibly item selection.
368: *
369: * @param itemCommands the set of item specific commands
370: * @param itemCmdCount the number of item commands
371: * @param itemCmdListener the notification listener for item commands
372: * @param scrCommands the set of screen specific commands
373: * @param scrCmdCount the number of screen commands
374: * @param scrCmdListener the notification listener for screen commands
375: */
376: public void updateCommandSet(Command[] itemCommands,
377: int itemCmdCount, ItemCommandListener itemCmdListener,
378: Command[] scrCommands, int scrCmdCount,
379: CommandListener scrCmdListener) {
380: // We cache commands to easily reset them when a
381: // popup takes precedence and then is dismissed
382: this .itemCmdCache = itemCommands;
383: this .itemCmdCount = itemCmdCount;
384: this .itemCmdListener = itemCmdListener;
385: this .scrCmdCache = scrCommands;
386: this .scrCmdCount = scrCmdCount;
387: this .scrCmdListener = scrCmdListener;
388:
389: buttonLayer.updateCommandSet(itemCommands, itemCmdCount,
390: itemCmdListener, scrCommands, scrCmdCount,
391: scrCmdListener);
392: }
393:
394: /**
395: * Set this MIDPWindow's displayable to "fullscreen" mode. This
396: * will expand the region occupied by the current displayable to
397: * include the area previously occupied by the title and ticker
398: * if present
399: *
400: * @param onOff true if the displayable should be in fullscreen mode
401: */
402: public void setFullScreen(boolean onOff) {
403: if (onOff) {
404: setMode(FULL_SCR_MODE);
405: } else {
406: setMode(NORMAL_MODE);
407: }
408: }
409:
410: /**
411: * Update the current layout
412: */
413: public void updateLayout() {
414: resize();
415: requestRepaint();
416: }
417:
418: /**
419: * Changes layout mode.
420: *
421: * @param mode the mode to be set
422: */
423: private void setMode(int mode) {
424: screenMode = mode;
425: updateLayout();
426: }
427:
428: /**
429: * Determines if window is in full screen mode.
430: *
431: * @return true if in full screen mode
432: */
433: public boolean isInFullScreenMode() {
434: return screenMode == FULL_SCR_MODE;
435: }
436:
437: /**
438: * Called to paint a wash over the background of this window.
439: * Used by SoftButtonLayer when the system menu pops up, and
440: * internally when an Alert is shown.
441: *
442: * @param onOff A flag indicating if the wash should be on or off
443: */
444: public void paintWash(boolean onOff) {
445: if (alertLayer.visible) {
446: addLayer(washLayer);
447: if (onOff) {
448: addLayer(alertWashLayer);
449: } else {
450: removeLayer(alertWashLayer);
451:
452: // IMPL_NOTES: interface has to be fixed
453: alertLayer.setScrollInd(ScrollIndLayer
454: .getInstance(ScrollIndSkin.MODE));
455:
456: // IMPL_NOTES: need to be removed as soon as removeLayer algorithm
457: // takes into account layers interaction
458: tickerLayer.addDirtyRegion();
459: alertLayer.addDirtyRegion();
460: }
461: } else {
462: removeLayer(alertWashLayer);
463: if (onOff) {
464: addLayer(washLayer);
465: } else {
466: removeLayer(washLayer);
467:
468: // IMPL_NOTES: interface has to be fixed
469: bodyLayer.setScrollInd(ScrollIndLayer
470: .getInstance(ScrollIndSkin.MODE));
471:
472: // IMPL_NOTES: need to be removed as soon as removeLayer algorithm
473: // takes into account layers interaction
474: tickerLayer.addDirtyRegion();
475: titleLayer.addDirtyRegion();
476:
477: if (ptiLayer != null) {
478: ptiLayer.addDirtyRegion();
479: }
480: }
481: }
482: }
483:
484: /**
485: * Returns the left soft button (one).
486: *
487: * @return the command that's tied to the left soft button
488: */
489: public Command getSoftOne() {
490: return buttonLayer.getSoftOne();
491: }
492:
493: /**
494: * Returns the command array tied to the right soft button (two).
495: *
496: * @return the command array that's tied to the right soft button
497: */
498: public Command[] getSoftTwo() {
499: return buttonLayer.getSoftTwo();
500: }
501:
502: /**
503: * Returns true if the point lies in the bounds of commnad layer
504: * @param x the "x" coordinate of the point
505: * @param y the "y" coordinate of the point
506: * @return true if the point lies in the bounds of commnad layer
507: */
508: public boolean belongToCmdLayers(int x, int y) {
509: return buttonLayer.belongToCmdLayers(x, y);
510: }
511:
512: /**
513: * Set the current vertical scroll position and proportion.
514: *
515: * @param scrollPosition vertical scroll position.
516: * @param scrollProportion vertical scroll proportion.
517: * @return true if set vertical scroll occues
518: */
519: public boolean setVerticalScroll(int scrollPosition,
520: int scrollProportion) {
521: if (alertLayer.isVisible()) {
522: return alertLayer.setVerticalScroll(scrollPosition,
523: scrollProportion);
524: }
525: if (bodyLayer.setVerticalScroll(scrollPosition,
526: scrollProportion)) {
527: setDirty();
528: sizeChangedOccured = true;
529: return true;
530: }
531: return false;
532: }
533:
534: /**
535: * Get the current x anchor coordinate for the body layer (the body
536: * layer renders the contents of the current displayable).
537: *
538: * @return the x anchor coordinate of the body layer
539: */
540: public int getBodyAnchorX() {
541: return bodyLayer.bounds[X];
542: }
543:
544: /**
545: * Get the current y anchor coordinate for the body layer (the body
546: * layer renders the contents of the current displayable).
547: *
548: * @return the y anchor coordinate of the body layer
549: */
550: public int getBodyAnchorY() {
551: return bodyLayer.bounds[Y];
552: }
553:
554: /**
555: * Get the current width of the body layer (the body
556: * layer renders the contents of the current displayable).
557: *
558: * @return the width of the body layer
559: */
560: public int getBodyWidth() {
561: return bodyLayer.bounds[W];
562: }
563:
564: /**
565: * Get the current height of the body layer (the body
566: * layer renders the contents of the current displayable).
567: *
568: * @return the height of the body layer
569: */
570: public int getBodyHeight() {
571: return bodyLayer.bounds[H];
572: }
573:
574: /**
575: * Utility method to determine if the given point lies within
576: * the bounds of body layer. The point should be in the coordinate
577: * space of this layer's containing CWindow.
578: *
579: * @param x the "x" coordinate of the point
580: * @param y the "y" coordinate of the point
581: * @return true if the coordinate lies in the bounds of this layer
582: */
583: public boolean bodyContainsPoint(int x, int y) {
584: return bodyLayer.containsPoint(x, y);
585: }
586:
587: /**
588: * MIDPWindow overrides the parent paint method in order to
589: * do special effects such as paint a "wash" over the background
590: * when a dialog is up. Also in an effort to call
591: * {@link javax.microedition.lcdui.Displayable#sizeChanged }
592: * method before painting. This implementation determine whether size
593: * has been changed and calls <code>sizeChanged()</code> if it's so.
594: * Anyway it invokes the base class's {@link CWindow#paint} method.
595: *
596: * @param g The graphics object to use to paint this MIDP window.
597: * @param refreshQ The chameleon graphics queue.
598: */
599: public void callPaint(Graphics g, CGraphicsQ refreshQ) {
600: if (sizeChangedOccured) {
601: if (tunnel != null) {
602: int w = getBodyWidth();
603: int h = getBodyHeight();
604: tunnel.callSizeChanged(w, h);
605: sizeChangedOccured = false;
606: }
607: }
608: super .paint(g, refreshQ);
609: }
610:
611: /**
612: * This method is an optimization which allows Display to bypass
613: * the Chameleon paint engine logic and directly paint an animating
614: * canvas. Display will call this method with the graphics context
615: * and this method will either return false, indicating the Chameleon
616: * paint engine should not be bypassed, or will return true and will
617: * setup the graphics context for the canvas to be painted directly.
618: *
619: * @param g the graphics context to setup
620: * @return true if Chameleon's paint logic can be bypassed and the
621: * canvas can be rendered directly.
622: */
623: public boolean setGraphicsForCanvas(Graphics g) {
624: // IMPL_NOTE: Only Canvas painting specially doesn't change
625: // dirty state of the owner window, however it is not enough
626: // to bypass the Chameleon paint engine. Body layer holding
627: // the Canvas should be opaque and be not overlapped with
628: // any visible higher layer also. The check for overlapping
629: // is to be added later.
630: if (super .dirty || !bodyLayer.opaque) {
631: return false;
632: }
633:
634: // NOTE: note the two different orders of clip and translate
635: // below. That is because the layer's bounds are stored in
636: // the coordinate space of the window. But its internal dirty
637: // region is stored in the coordinate space of the layer itself.
638: // Thus, for the first one, the clip can be set and then translated,
639: // but in the second case, the translate must be done first and then
640: // the clip set.
641: if (bodyLayer.isDirty()) {
642: if (bodyLayer.isEmptyDirtyRegions()) {
643: g.setClip(bodyLayer.bounds[X], bodyLayer.bounds[Y],
644: bodyLayer.bounds[W], bodyLayer.bounds[H]);
645: g.translate(bodyLayer.bounds[X], bodyLayer.bounds[Y]);
646:
647: } else {
648: g.translate(bodyLayer.bounds[X], bodyLayer.bounds[Y]);
649: g.setClip(bodyLayer.dirtyBounds[X],
650: bodyLayer.dirtyBounds[Y],
651: bodyLayer.dirtyBounds[W],
652: bodyLayer.dirtyBounds[H]);
653: }
654: bodyLayer.cleanDirty();
655: } else {
656: // NOTE: the layer can be not dirty, e.g. in the case an empty
657: // area was requested for repaint, set empty clip area then.
658: g.translate(bodyLayer.bounds[X], bodyLayer.bounds[Y]);
659: g.setClip(0, 0, 0, 0);
660: }
661:
662: return true;
663: }
664:
665: /**
666: * Internal method to resize window and its content layers
667: * according to a size changes in the loaded skins.
668: * This is important to re-calculate whenever things such as
669: * titles, tickers, fullscreen mode, etc. change state.
670: */
671: public void resize() {
672: super .resize();
673:
674: int oldHeight = bodyLayer.bounds[H];
675: int oldWidth = bodyLayer.bounds[W];
676: switch (screenMode) {
677: case FULL_SCR_MODE:
678: // TODO: scroll arrows (bar? ) indicator has to be hidden?
679: titleLayer.visible = false;
680: tickerLayer.visible = false;
681: buttonLayer.visible = buttonLayer.isInteractive();
682: break;
683: case NORMAL_MODE:
684: titleLayer.visible = (titleLayer.getTitle() != null);
685: tickerLayer.visible = (tickerLayer.getText() != null);
686: buttonLayer.visible = true;
687: break;
688: default:
689: Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
690: "MIDPWindow: screenMode=" + screenMode);
691: return;
692: }
693:
694: for (int i = 0; i < LAST_LAYER; i++) {
695: CLayer l = mainLayers[i];
696: if (l != null && l.visible) {
697: l.update(mainLayers);
698: }
699: }
700:
701: if (bodyLayer.bounds[W] != oldWidth
702: || bodyLayer.bounds[H] != oldHeight) {
703: setDirty();
704: sizeChangedOccured = true;
705: }
706: }
707:
708: /**
709: * Internal method to clear all current popups. This occurs if a
710: * change of displayable occurs, as all popups are treated as belonging
711: * to the current displayable.
712: */
713: protected void clearPopups() {
714: synchronized (super .layers) {
715: for (CLayerElement le = super .layers.getTop(); le != null; le = le
716: .getLower()) {
717: CLayer l = le.getLayer();
718: if (l instanceof PopupLayer) {
719: removeLayer(l);
720: }
721: }
722: }
723: }
724:
725: /**
726: * Gets the "top" most Popup layer added to this body layer.
727: * If there are no popups, this method returns null.
728: *
729: * @return the top most popup layer, or null if there are none.
730: */
731: public PopupLayer getTopMostPopup() {
732: synchronized (super .layers) {
733: for (CLayerElement le = super .layers.getTop(); le != null; le = le
734: .getLower()) {
735: CLayer l = le.getLayer();
736: if (l instanceof PopupLayer) {
737: return (PopupLayer) l;
738: }
739: }
740: }
741: return null;
742: }
743:
744: /**
745: * create new layer by id and launch addLayer()
746: * @param id - layer id
747: */
748: private void createLayer(int id) {
749: switch (id) {
750: case PTI_LAYER:
751: break;
752: case TITLE_LAYER:
753: titleLayer = new TitleLayer();
754: mainLayers[id] = titleLayer;
755: addLayer(titleLayer);
756: break;
757: case TICKER_LAYER:
758: tickerLayer = new TickerLayer();
759: mainLayers[id] = tickerLayer;
760: addLayer(tickerLayer);
761: break;
762: case BTN_LAYER:
763: buttonLayer = new SoftButtonLayer(tunnel);
764: mainLayers[id] = buttonLayer;
765: addLayer(buttonLayer);
766: break;
767: case ALERT_LAYER:
768: alertLayer = new AlertLayer(tunnel);
769: mainLayers[id] = alertLayer;
770: break;
771: case WASH_LAYER:
772: washLayer = new WashLayer();
773: mainLayers[id] = washLayer;
774: break;
775: case ALERT_WASH_LAYER:
776: alertWashLayer = new WashLayer();
777: mainLayers[id] = alertWashLayer;
778: break;
779: case BODY_LAYER:
780: bodyLayer = new BodyLayer(tunnel);
781: mainLayers[id] = bodyLayer;
782: addLayer(bodyLayer);
783: break;
784: }
785: }
786: }
|