Form.java
上传用户:haobig99
上传日期:2022-06-15
资源大小:369k
文件大小:104k
源码类别:

J2ME

开发平台:

Java

  1. /*
  2.  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
  3.  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4.  *
  5.  * This code is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License version 2 only, as
  7.  * published by the Free Software Foundation.  Sun designates this
  8.  * particular file as subject to the "Classpath" exception as provided
  9.  * by Sun in the LICENSE file that accompanied this code.
  10.  *
  11.  * This code is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * version 2 for more details (a copy is included in the LICENSE file that
  15.  * accompanied this code).
  16.  *
  17.  * You should have received a copy of the GNU General Public License version
  18.  * 2 along with this work; if not, write to the Free Software Foundation,
  19.  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20.  *
  21.  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22.  * CA 95054 USA or visit www.sun.com if you need additional information or
  23.  * have any questions.
  24.  */
  25. package com.sun.lwuit;
  26. import com.sun.lwuit.animations.Animation;
  27. import com.sun.lwuit.animations.CommonTransitions;
  28. import com.sun.lwuit.geom.Rectangle;
  29. import com.sun.lwuit.geom.Dimension;
  30. import com.sun.lwuit.plaf.Style;
  31. import com.sun.lwuit.animations.Transition;
  32. import com.sun.lwuit.events.ActionEvent;
  33. import com.sun.lwuit.events.ActionListener;
  34. import com.sun.lwuit.list.ListCellRenderer;
  35. import com.sun.lwuit.layouts.BorderLayout;
  36. import com.sun.lwuit.layouts.FlowLayout;
  37. import com.sun.lwuit.layouts.GridLayout;
  38. import com.sun.lwuit.layouts.Layout;
  39. import com.sun.lwuit.plaf.LookAndFeel;
  40. import com.sun.lwuit.plaf.UIManager;
  41. import com.sun.lwuit.util.EventDispatcher;
  42. import java.util.Hashtable;
  43. import java.util.Vector;
  44. /**
  45.  * Top level component that serves as the root for the UI, this {@link Container}
  46.  * handles the menus and title while placing content between them. By default a 
  47.  * forms central content (the content pane) is scrollable.
  48.  *
  49.  * Form contains Title bar, MenuBar and a ContentPane.
  50.  * Calling to addComponent on the Form is delegated to the contenPane.addComponent
  51.  * 
  52.  * *<pre>
  53.  *
  54.  *       **************************
  55.  *       *         Title          *
  56.  *       **************************
  57.  *       *                        *
  58.  *       *                        *
  59.  *       *      ContentPane       *
  60.  *       *                        *
  61.  *       *                        *
  62.  *       **************************
  63.  *       *         MenuBar        *
  64.  *       **************************
  65.  *</pre> 
  66.  * @author Chen Fishbein
  67.  */
  68. public class Form extends Container {
  69.     Command selectMenuItem;
  70.     Command cancelMenuItem;
  71.     private Painter glassPane;
  72.     private Container contentPane = new Container(new FlowLayout());
  73.     private Label title = new Label("", "Title");
  74.     private MenuBar menuBar = new MenuBar();
  75.     private Command selectCommand;
  76.     private Command defaultCommand;
  77.     private Component dragged;
  78.     /**
  79.      * Indicates the command that is defined as the back command out of this form.
  80.      * A back command can be used both to map to a hardware button (e.g. on the Sony Ericsson devices)
  81.      * and by elements such as transitions etc. to change the behavior based on 
  82.      * direction (e.g. slide to the left to enter screen and slide to the right to exit with back).
  83.      */
  84.     private Command backCommand;
  85.     /**
  86.      * Used by the combo box to block some default LWUIT behaviors
  87.      */
  88.     static boolean comboLock;
  89.     /**
  90.      * Indicates the command that is defined as the clear command out of this form similar
  91.      * in spirit to the back command
  92.      */
  93.     private Command clearCommand;
  94.     /**
  95.      * Contains a list of components that would like to animate their state
  96.      */
  97.     private Vector animatableComponents;
  98.     /**
  99.      * Contains a list of components that would like to animate their state
  100.      */
  101.     private Vector internalAnimatableComponents;
  102.     /**
  103.      * This member holds the left soft key value
  104.      */
  105.     static int leftSK = -6;
  106.     /**
  107.      * This member holds the right soft key value
  108.      */
  109.     static int rightSK = -7;
  110.     /**
  111.      * This member holds the 2nd right soft key value
  112.      * this is used for different BB devices
  113.      */
  114.     static int rightSK2 = -7;
  115.     /**
  116.      * This member holds the back command key value
  117.      */
  118.     static int backSK = -11;
  119.     /**
  120.      * This member holds the clear command key value
  121.      */
  122.     static int clearSK = -8;
  123.     static int backspaceSK = -8;
  124.     //private FormSwitcher formSwitcher;
  125.     private Component focused;
  126.     private Vector mediaComponents;
  127.     /**
  128.      * This member allows us to define an animation that will draw the transition for
  129.      * entering this form. A transition is an animation that would occur when 
  130.      * switching from one form to another.
  131.      */
  132.     private Transition transitionInAnimator;
  133.     /**
  134.      * This member allows us to define a an animation that will draw the transition for
  135.      * exiting this form. A transition is an animation that would occur when 
  136.      * switching from one form to another.
  137.      */
  138.     private Transition transitionOutAnimator;
  139.     /**
  140.      * a listener that is invoked when a command is clicked allowing multiple commands
  141.      * to be handled by a single block
  142.      */
  143.     private EventDispatcher commandListener;
  144.     private EventDispatcher pointerPressedListeners;
  145.     private EventDispatcher pointerReleasedListeners;
  146.     private EventDispatcher pointerDraggedListeners;
  147.     /**
  148.      * Relevant for modal forms where the previous form should be rendered underneath
  149.      */
  150.     private Form previousForm;
  151.     /**
  152.      * Indicates that this form should be tinted when painted
  153.      */
  154.     private boolean tint;
  155.     /**
  156.      * Default color for the screen tint when a dialog or a menu is shown
  157.      */
  158.     private int tintColor;
  159.     /**
  160.      * Allows us to cache the next focus component ordered from top to down, this
  161.      * vector is guaranteed to have all focusable children in it.
  162.      */
  163.     private Vector focusDownSequence;
  164.     /**
  165.      * Allows us to cache the next focus component ordered from left to right, this
  166.      * vector is guaranteed to have all focusable children in it.
  167.      */
  168.     private Vector focusRightSequence;
  169.     /**
  170.      * Listeners for key release events 
  171.      */
  172.     private Hashtable keyListeners;
  173.     /**
  174.      * Listeners for game key release events 
  175.      */
  176.     private Hashtable gameKeyListeners;
  177.     /**
  178.      * Indicates whether focus should cycle within the form
  179.      */
  180.     private boolean cyclicFocus = true;
  181.     private int tactileTouchDuration;
  182.     /**
  183.      * Default constructor creates a simple form
  184.      */
  185.     public Form() {
  186.         super(new BorderLayout());
  187.         setUIID("Form");
  188.         // forms/dialogs are not visible by default
  189.         setVisible(false);
  190.         Style formStyle = getStyle();
  191.         int w = Display.getInstance().getDisplayWidth() - (formStyle.getMargin(isRTL(), Component.LEFT) + formStyle.getMargin(isRTL(), Component.RIGHT));
  192.         int h = Display.getInstance().getDisplayHeight() - (formStyle.getMargin(false, Component.TOP) + formStyle.getMargin(false, Component.BOTTOM));
  193.         setWidth(w);
  194.         setHeight(h);
  195.         setPreferredSize(new Dimension(w, h));
  196.         title.setEndsWith3Points(false);
  197.         super.addComponent(BorderLayout.NORTH, title);
  198.         super.addComponent(BorderLayout.CENTER, contentPane);
  199.         super.addComponent(BorderLayout.SOUTH, menuBar);
  200.         contentPane.setUIID("ContentPane");
  201.         contentPane.setScrollableY(true);
  202.         LookAndFeel laf = UIManager.getInstance().getLookAndFeel();
  203.         initLaf(laf);
  204.         tintColor = laf.getDefaultFormTintColor();
  205.         selectMenuItem = createMenuSelectCommand();
  206.         cancelMenuItem = createMenuCancelCommand();
  207.         
  208.         // hardcoded, anything else is just pointless...
  209.         formStyle.setBgTransparency(0xFF);
  210.     }
  211.     /**
  212.      * Sets the style of the menu bar programmatically
  213.      * 
  214.      * @param s new style
  215.      * @deprecated use setSoftButtonStyle instead
  216.      */
  217.     public void setMenuStyle(Style s) {
  218.         menuBar.setStyle(s);
  219.     }
  220.     /**
  221.      * Sets the style of the menu bar programmatically
  222.      * 
  223.      * @param s new style
  224.      */
  225.     public void setSoftButtonStyle(Style s) {
  226.         menuBar.setUnSelectedStyle(s);
  227.     }
  228.     /**
  229.      * Retrieves the style of the menu bar programmatically
  230.      * 
  231.      * @return the style of the softbutton
  232.      */
  233.     public Style getSoftButtonStyle() {
  234.         return menuBar.getStyle();
  235.     }
  236.     /**
  237.      * This method is only invoked when the underlying canvas for the form is hidden
  238.      * this method isn't called for form based events and is generally usable for
  239.      * suspend/resume based behavior
  240.      */
  241.     protected void hideNotify() {
  242.     }
  243.     /**
  244.      * This method is only invoked when the underlying canvas for the form is shown
  245.      * this method isn't called for form based events and is generally usable for
  246.      * suspend/resume based behavior
  247.      */
  248.     protected void showNotify() {
  249.     }
  250.     /**
  251.      * This method is only invoked when the underlying canvas for the form gets
  252.      * a size changed event.
  253.      * This method will trigger a relayout of the Form.
  254.      * This method will get the callback only if this Form is the Current Form
  255.      *
  256.      * @param w the new width of the Form
  257.      * @param h the new height of the Form
  258.      */
  259.     protected void sizeChanged(int w, int h) {
  260.     }
  261.     /**
  262.      * This method is only invoked when the underlying canvas for the form gets
  263.      * a size changed event.
  264.      * This method will trigger a relayout of the Form.
  265.      * This method will get the callback only if this Form is the Current Form
  266.      * @param w the new width of the Form
  267.      * @param h the new height of the Form
  268.      */
  269.     void sizeChangedInternal(int w, int h) {
  270.         sizeChanged(w, h);
  271.         setSize(new Dimension(w, h));
  272.         setShouldCalcPreferredSize(true);
  273.         doLayout();        
  274.         repaint();
  275.     }
  276.     /**
  277.      * Allows a developer that doesn't derive from the form to draw on top of the 
  278.      * form regardless of underlying changes or animations. This is useful for
  279.      * watermarks or special effects (such as tinting) it is also useful for generic
  280.      * drawing of validation errors etc... A glass pane is generally 
  281.      * transparent or translucent and allows the the UI bellow to be seen.
  282.      * 
  283.      * @param glassPane a new glass pane to install. It is generally recommended to
  284.      * use a painter chain if more than one painter is required.
  285.      */
  286.     public void setGlassPane(Painter glassPane) {
  287.         this.glassPane = glassPane;
  288.         repaint();
  289.     }
  290.     /**
  291.      * Allows a developer that doesn't derive from the form to draw on top of the 
  292.      * form regardless of underlying changes or animations. This is useful for
  293.      * watermarks or special effects (such as tinting) it is also useful for generic
  294.      * drawing of validation errors etc... A glass pane is generally 
  295.      * transparent or translucent and allows the the UI bellow to be seen.
  296.      * 
  297.      * @return the instance of the glass pane for this form
  298.      * @see com.sun.lwuit.painter.PainterChain#installGlassPane(Form, com.sun.lwuit.Painter) 
  299.      */
  300.     public Painter getGlassPane() {
  301.         return glassPane;
  302.     }
  303.     /**
  304.      * Sets the style of the title programmatically
  305.      * 
  306.      * @param s new style
  307.      */
  308.     public void setTitleStyle(Style s) {
  309.         title.setUnSelectedStyle(s);
  310.     }
  311.     /**
  312.      * Allows modifying the title attributes beyond style (e.g. setting icon/alignment etc.)
  313.      * 
  314.      * @return the component representing the title for the form
  315.      */
  316.     public Label getTitleComponent() {
  317.         return title;
  318.     }
  319.     /**
  320.      * Allows replacing the title with a different title component, thus allowing
  321.      * developers to create more elaborate title objects.
  322.      *
  323.      * @param title new title component
  324.      */
  325.     public void setTitleComponent(Label title) {
  326.         super.replace(this.title, title);
  327.         this.title = title;
  328.     }
  329.     /**
  330.      * Allows replacing the title with a different title component, thus allowing
  331.      * developers to create more elaborate title objects. This version of the
  332.      * method allows special effects for title replacement such as transitions
  333.      * for title entering
  334.      *
  335.      * @param title new title component
  336.      * @param t transition for title replacement
  337.      */
  338.     public void setTitleComponent(Label title, Transition t) {
  339.         super.replace(this.title, title, t);
  340.         this.title = title;
  341.     }
  342.     /**
  343.      * Add a key listener to the given keycode for a callback when the key is released
  344.      * 
  345.      * @param keyCode code on which to send the event
  346.      * @param listener listener to invoke when the key code released.
  347.      */
  348.     public void addKeyListener(int keyCode, ActionListener listener) {
  349.         if (keyListeners == null) {
  350.             keyListeners = new Hashtable();
  351.         }
  352.         addKeyListener(keyCode, listener, keyListeners);
  353.     }
  354.     /**
  355.      * Removes a key listener from the given keycode 
  356.      * 
  357.      * @param keyCode code on which the event is sent
  358.      * @param listener listener instance to remove
  359.      */
  360.     public void removeKeyListener(int keyCode, ActionListener listener) {
  361.         if (keyListeners == null) {
  362.             return;
  363.         }
  364.         removeKeyListener(keyCode, listener, keyListeners);
  365.     }
  366.     /**
  367.      * Removes a game key listener from the given game keycode 
  368.      * 
  369.      * @param keyCode code on which the event is sent
  370.      * @param listener listener instance to remove
  371.      */
  372.     public void removeGameKeyListener(int keyCode, ActionListener listener) {
  373.         if (gameKeyListeners == null) {
  374.             return;
  375.         }
  376.         removeKeyListener(keyCode, listener, gameKeyListeners);
  377.     }
  378.     private void addKeyListener(int keyCode, ActionListener listener, Hashtable keyListeners) {
  379.         if (keyListeners == null) {
  380.             keyListeners = new Hashtable();
  381.         }
  382.         Integer code = new Integer(keyCode);
  383.         Vector vec = (Vector) keyListeners.get(code);
  384.         if (vec == null) {
  385.             vec = new Vector();
  386.             vec.addElement(listener);
  387.             keyListeners.put(code, vec);
  388.             return;
  389.         }
  390.         if (!vec.contains(listener)) {
  391.             vec.addElement(listener);
  392.         }
  393.     }
  394.     private void removeKeyListener(int keyCode, ActionListener listener, Hashtable keyListeners) {
  395.         if (keyListeners == null) {
  396.             return;
  397.         }
  398.         Integer code = new Integer(keyCode);
  399.         Vector vec = (Vector) keyListeners.get(code);
  400.         if (vec == null) {
  401.             return;
  402.         }
  403.         vec.removeElement(listener);
  404.         if (vec.size() == 0) {
  405.             keyListeners.remove(code);
  406.         }
  407.     }
  408.     /**
  409.      * Add a game key listener to the given gamekey for a callback when the 
  410.      * key is released
  411.      * 
  412.      * @param keyCode code on which to send the event
  413.      * @param listener listener to invoke when the key code released.
  414.      */
  415.     public void addGameKeyListener(int keyCode, ActionListener listener) {
  416.         if (gameKeyListeners == null) {
  417.             gameKeyListeners = new Hashtable();
  418.         }
  419.         addKeyListener(keyCode, listener, gameKeyListeners);
  420.     }
  421.     /**
  422.      * Returns the number of buttons on the menu bar for use with getSoftButton()
  423.      * 
  424.      * @return the number of softbuttons
  425.      */
  426.     public int getSoftButtonCount() {
  427.         return menuBar.getSoftButtons().length;
  428.     }
  429.     /**
  430.      * Returns the button representing the softbutton, this allows modifying softbutton
  431.      * attributes and behavior programmatically rather than by using the command API.
  432.      * Notice that this API behavior is fragile since the button mapped to a particular
  433.      * offset might change based on the command API
  434.      * 
  435.      * @param offset the offest of the softbutton
  436.      * @return a button that can be manipulated
  437.      */
  438.     public Button getSoftButton(int offset) {
  439.         return menuBar.getSoftButtons()[offset];
  440.     }
  441.     /**
  442.      * Returns the style of the menu
  443.      * 
  444.      * @return the style of the menu
  445.      */
  446.     public Style getMenuStyle() {
  447.         return menuBar.getMenuStyle();
  448.     }
  449.     /**
  450.      * Returns the style of the title
  451.      * 
  452.      * @return the style of the title
  453.      */
  454.     public Style getTitleStyle() {
  455.         return title.getStyle();
  456.     }
  457.     /**
  458.      * Allows the display to skip the menu dialog if that is the current form
  459.      */
  460.     Form getPreviousForm() {
  461.         return previousForm;
  462.     }
  463.     /**
  464.      * @inheritDoc
  465.      */
  466.     void initLaf(LookAndFeel laf) {
  467.         transitionOutAnimator = laf.getDefaultFormTransitionOut();
  468.         transitionInAnimator = laf.getDefaultFormTransitionIn();
  469.     }
  470.     /**
  471.      * Resets the cache focus vectors, this is a good idea when we remove
  472.      * or add an element to the layout.
  473.      */
  474.     void clearFocusVectors() {
  475.         focusDownSequence = null;
  476.         focusRightSequence = null;
  477.     }
  478.     /**
  479.      * Sets the current dragged Component
  480.      */
  481.     void setDraggedComponent(Component dragged) {
  482.         this.dragged = dragged;
  483.     }
  484.     synchronized void initFocusRight() {
  485.         if (focusRightSequence == null) {
  486.             focusRightSequence = new Vector();
  487.             findAllFocusable(contentPane, focusRightSequence, true);
  488.         }
  489.     }
  490.     synchronized void initFocusDown() {
  491.         if (focusDownSequence == null) {
  492.             focusDownSequence = new Vector();
  493.             findAllFocusable(contentPane, focusDownSequence, false);
  494.         }
  495.     }
  496.     /**
  497.      * Adds a component to the vector in the appropriate location based on its
  498.      * focus order
  499.      */
  500.     private void addSortedComponentRight(Vector components, Component c) {
  501.         int componentCount = components.size();
  502.         int componentX = c.getAbsoluteX();
  503.         int bestSpot = 0;
  504.         boolean rtl = isRTL();
  505.         Component scrollableParent = findScrollableAncestor(c);
  506.         // find components in the same row and add the component either at the end
  507.         // of the line or at its start
  508.         for (int iter = 0; iter < componentCount; iter++) {
  509.             Component current = (Component) components.elementAt(iter);
  510.             // this component is in the same row...
  511.             Component currentScrollParent = findScrollableAncestor(current);
  512.             if (currentScrollParent == scrollableParent) {
  513.                 if (isInSameRow(current, c)) {
  514.                     int currentX = current.getAbsoluteX();
  515.                     if (((!rtl) && (currentX > componentX)) ||
  516.                      ((rtl) && (currentX < componentX))) {
  517.                         continue;
  518.                     }
  519.                     bestSpot = iter + 1;
  520.                     continue;
  521.                 }
  522.             } else {
  523.                 Component tempScrollableParent = scrollableParent;
  524.                 if (scrollableParent == null) {
  525.                     tempScrollableParent = c;
  526.                 }
  527.                 Component tempCurrentScrollParent = currentScrollParent;
  528.                 if (currentScrollParent == null) {
  529.                     tempCurrentScrollParent = current;
  530.                 }
  531.                 if (((!rtl) && (tempCurrentScrollParent.getAbsoluteX() > tempScrollableParent.getAbsoluteX())) ||
  532.                  ((rtl) && (tempCurrentScrollParent.getAbsoluteX() < tempScrollableParent.getAbsoluteX()))) {
  533.                     continue;
  534.                 }
  535.                 if (isInSameRow(tempCurrentScrollParent, tempScrollableParent)) {
  536.                     bestSpot = iter + 1;
  537.                     continue;
  538.                 }
  539.             }
  540.             if (current.getAbsoluteY() < c.getAbsoluteY()) {
  541.                 bestSpot = iter + 1;
  542.             }
  543.         }
  544.         components.insertElementAt(c, bestSpot);
  545.     }
  546.     /**
  547.      * Returns the first scrollable ancestor for this component or null if no
  548.      * such ancestor exists
  549.      */
  550.     private Component findScrollableAncestor(Component c) {
  551.         c = c.getParent();
  552.         if (c == null || c.isScrollable()) {
  553.             return c;
  554.         }
  555.         return findScrollableAncestor(c);
  556.     }
  557.     /**
  558.     `     * Adds a component to the vector in the appropriate location based on its
  559.      * focus order
  560.      */
  561.     private void addSortedComponentDown(Vector components, Component c) {
  562.         int componentCount = components.size();
  563.         int componentY = c.getAbsoluteY();
  564.         int bestSpot = 0;
  565.         boolean rtl = isRTL();
  566.         Component scrollableParent = findScrollableAncestor(c);
  567.         // find components in the same column and add the component either at the end
  568.         // of the line or at its start
  569.         for (int iter = 0; iter < componentCount; iter++) {
  570.             Component current = (Component) components.elementAt(iter);
  571.             // this component is in the same column...
  572.             Component currentScrollParent = findScrollableAncestor(current);
  573.             if (currentScrollParent == scrollableParent) {
  574.                 if (isInSameColumn(current, c)) {
  575.                     int currentY = current.getAbsoluteY();
  576.                     if (currentY > componentY) {
  577.                         continue;
  578.                     }
  579.                     bestSpot = iter + 1;
  580.                     continue;
  581.                 }
  582.             } else {
  583.                 Component tempScrollableParent = scrollableParent;
  584.                 if (scrollableParent == null) {
  585.                     tempScrollableParent = c;
  586.                 }
  587.                 Component tempCurrentScrollParent = currentScrollParent;
  588.                 if (currentScrollParent == null) {
  589.                     tempCurrentScrollParent = current;
  590.                 }
  591.                 if (tempCurrentScrollParent.getAbsoluteY() > tempScrollableParent.getAbsoluteY()) {
  592.                     continue;
  593.                 }
  594.                 if (isInSameColumn(tempCurrentScrollParent, tempScrollableParent)) {
  595.                     bestSpot = iter + 1;
  596.                     continue;
  597.                 }
  598.             }
  599.             if (((!rtl) && (current.getAbsoluteX() < c.getAbsoluteX())) ||
  600.              ((rtl) && (current.getAbsoluteX() > c.getAbsoluteX()))) {
  601.                 bestSpot = iter + 1;
  602.             }
  603.         }
  604.         components.insertElementAt(c, bestSpot);
  605.     }
  606.     /**
  607.      * Returns true if the given dest component is in the column of the source component
  608.      */
  609.     private boolean isInSameColumn(Component source, Component dest) {
  610.         return Rectangle.intersects(source.getAbsoluteX(), source.getAbsoluteY(),
  611.                 source.getWidth(), Integer.MAX_VALUE, dest.getAbsoluteX(), dest.getAbsoluteY(),
  612.                 dest.getWidth(), dest.getHeight());
  613.     }
  614.     /**
  615.      * Returns true if the given dest component is in the row of the source component
  616.      */
  617.     private boolean isInSameRow(Component source, Component dest) {
  618.         return Rectangle.intersects(source.getAbsoluteX(), source.getAbsoluteY(),
  619.                 Integer.MAX_VALUE, source.getHeight(), dest.getAbsoluteX(), dest.getAbsoluteY(),
  620.                 dest.getWidth(), dest.getHeight());
  621.     }
  622.     /**
  623.      * Adds a component to the vector in the appropriate location based on its
  624.      * focus order
  625.      */
  626.     private void addSortedComponent(Vector components, Component c, boolean toTheRight) {
  627.         if (toTheRight) {
  628.             addSortedComponentRight(components, c);
  629.         } else {
  630.             addSortedComponentDown(components, c);
  631.         }
  632.     }
  633.     /**
  634.      * Default command is invoked when a user presses fire, this functionality works
  635.      * well in some situations but might collide with elements such as navigation
  636.      * and combo boxes. Use with caution.
  637.      * 
  638.      * @param defaultCommand the command to treat as default
  639.      */
  640.     public void setDefaultCommand(Command defaultCommand) {
  641.         this.defaultCommand = defaultCommand;
  642.     }
  643.     /**
  644.      * Default command is invoked when a user presses fire, this functionality works
  645.      * well in some situations but might collide with elements such as navigation
  646.      * and combo boxes. Use with caution.
  647.      * 
  648.      * @return the command to treat as default
  649.      */
  650.     public Command getDefaultCommand() {
  651.         if (selectCommand != null) {
  652.             return selectCommand;
  653.         }
  654.         return defaultCommand;
  655.     }
  656.     /**
  657.      * Indicates the command that is defined as the clear command in this form.
  658.      * A clear command can be used both to map to a "clear" hardware button 
  659.      * if such a button exists.
  660.      * 
  661.      * @param clearCommand the command to treat as the clear Command
  662.      */
  663.     public void setClearCommand(Command clearCommand) {
  664.         this.clearCommand = clearCommand;
  665.     }
  666.     /**
  667.      * Indicates the command that is defined as the clear command in this form.
  668.      * A clear command can be used both to map to a "clear" hardware button 
  669.      * if such a button exists.
  670.      * 
  671.      * @return the command to treat as the clear Command
  672.      */
  673.     public Command getClearCommand() {
  674.         return clearCommand;
  675.     }
  676.     /**
  677.      * Indicates the command that is defined as the back command out of this form.
  678.      * A back command can be used both to map to a hardware button (e.g. on the Sony Ericsson devices)
  679.      * and by elements such as transitions etc. to change the behavior based on 
  680.      * direction (e.g. slide to the left to enter screen and slide to the right to exit with back).
  681.      * 
  682.      * @param backCommand the command to treat as the back Command
  683.      */
  684.     public void setBackCommand(Command backCommand) {
  685.         this.backCommand = backCommand;
  686.     }
  687.     /**
  688.      * Indicates the command that is defined as the back command out of this form.
  689.      * A back command can be used both to map to a hardware button (e.g. on the Sony Ericsson devices)
  690.      * and by elements such as transitions etc. to change the behavior based on 
  691.      * direction (e.g. slide to the left to enter screen and slide to the right to exit with back).
  692.      * 
  693.      * @return the command to treat as the back Command
  694.      */
  695.     public Command getBackCommand() {
  696.         return backCommand;
  697.     }
  698.     /**
  699.      * Finds all focusable components in the hierarchy 
  700.      */
  701.     private void findAllFocusable(Container c, Vector v, boolean toTheRight) {
  702.         int size = c.getComponentCount();
  703.         for (int iter = 0; iter < size; iter++) {
  704.             Component current = c.getComponentAt(iter);
  705.             if (current instanceof Container) {
  706.                 findAllFocusable((Container) current, v, toTheRight);
  707.             }
  708.             if (current.isFocusable()) {
  709.                 addSortedComponent(v, current, toTheRight);
  710.             }
  711.         }
  712.     }
  713.     /**
  714.      * Sets the title after invoking the constructor
  715.      * 
  716.      * @param title the form title
  717.      */
  718.     public Form(String title) {
  719.         this();
  720.         this.title.setText(title);
  721.     }
  722.     /**
  723.      * This method returns the Content pane instance
  724.      * 
  725.      * @return a content pane instance
  726.      */
  727.     public Container getContentPane() {
  728.         return contentPane;
  729.     }
  730.     /**
  731.      * Removes all Components from the Content Pane
  732.      */
  733.     public void removeAll() {
  734.         contentPane.removeAll();
  735.     }
  736.     /**
  737.      * Sets the background image to show behind the form
  738.      * 
  739.      * @param bgImage the background image
  740.      */
  741.     public void setBgImage(Image bgImage) {
  742.         getStyle().setBgImage(bgImage);
  743.     }
  744.     /**
  745.      * @inheritDoc
  746.      */
  747.     public void setLayout(Layout layout) {
  748.         contentPane.setLayout(layout);
  749.     }
  750.     /**
  751.      * Sets the Form title to the given text
  752.      * 
  753.      * @param title the form title
  754.      */
  755.     public void setTitle(String title) {
  756.         this.title.setText(title);
  757.         if(isInitialized() && this.title.isTickerEnabled()) {
  758.             if(this.title.shouldTickerStart()) {
  759.                 this.title.startTicker(UIManager.getInstance().getLookAndFeel().getTickerSpeed(), true);
  760.             } else {
  761.                 if(this.title.isTickerRunning()) {
  762.                     this.title.stopTicker();
  763.                 }
  764.             }
  765.         }
  766.     }
  767.     /**
  768.      * Returns the Form title text
  769.      * 
  770.      * @return returns the form title
  771.      */
  772.     public String getTitle() {
  773.         return title.getText();
  774.     }
  775.     /**
  776.      * Adds Component to the Form's Content Pane
  777.      * 
  778.      * @param cmp the added param
  779.      */
  780.     public void addComponent(Component cmp) {
  781.         contentPane.addComponent(cmp);
  782.     }
  783.     /**
  784.      * @inheritDoc
  785.      */
  786.     public void addComponent(Object constraints, Component cmp) {
  787.         contentPane.addComponent(constraints, cmp);
  788.     }
  789.     /**
  790.      * @inheritDoc
  791.      */
  792.     public void addComponent(int index, Object constraints, Component cmp) {
  793.         contentPane.addComponent(index, constraints, cmp);
  794.     }
  795.     /**
  796.      * Adds Component to the Form's Content Pane
  797.      * 
  798.      * @param cmp the added param
  799.      */
  800.     public void addComponent(int index, Component cmp) {
  801.         contentPane.addComponent(index, cmp);
  802.     }
  803.     /**
  804.      * @inheritDoc
  805.      */
  806.     public void replace(Component current, Component next, Transition t) {
  807.         contentPane.replace(current, next, t);
  808.     }
  809.     /**
  810.      * @inheritDoc
  811.      */
  812.     public void replaceAndWait(Component current, Component next, Transition t) {
  813.         contentPane.replaceAndWait(current, next, t);
  814.     }
  815.     /**
  816.      * Removes a component from the Form's Content Pane
  817.      * 
  818.      * @param cmp the component to be removed
  819.      */
  820.     public void removeComponent(Component cmp) {
  821.         contentPane.removeComponent(cmp);
  822.     }
  823.     /**
  824.      * Registering media component to this Form, that like to receive 
  825.      * animation events
  826.      * 
  827.      * @param mediaCmp the Form media component to be registered
  828.      */
  829.     void registerMediaComponent(Component mediaCmp) {
  830.         if (mediaComponents == null) {
  831.             mediaComponents = new Vector();
  832.         }
  833.         if (!mediaComponents.contains(mediaCmp)) {
  834.             mediaComponents.addElement(mediaCmp);
  835.         }
  836.     }
  837.     /**
  838.      * Used by the implementation to prevent flickering when flushing the double buffer
  839.      * 
  840.      * @return true if the form has media components within it
  841.      */
  842.     public final boolean hasMedia() {
  843.         return mediaComponents != null && mediaComponents.size() > 0;
  844.     }
  845.     /**
  846.      * Indicate that cmp would no longer like to receive animation events
  847.      * 
  848.      * @param cmp component that would no longer receive animation events
  849.      */
  850.     void deregisterMediaComponent(Component mediaCmp) {
  851.         mediaComponents.removeElement(mediaCmp);
  852.     }
  853.     /**
  854.      * The given component is interested in animating its appearance and will start
  855.      * receiving callbacks when it is visible in the form allowing it to animate
  856.      * its appearance. This method would not register a compnent instance more than once
  857.      * 
  858.      * @param cmp component that would be animated
  859.      */
  860.     public void registerAnimated(Animation cmp) {
  861.         if (animatableComponents == null) {
  862.             animatableComponents = new Vector();
  863.         }
  864.         if (!animatableComponents.contains(cmp)) {
  865.             animatableComponents.addElement(cmp);
  866.         }
  867.         Display.getInstance().notifyDisplay();
  868.     }
  869.     /**
  870.      * Identical to the none-internal version, the difference between the internal/none-internal
  871.      * is that it references a different vector that is unaffected by the user actions.
  872.      * That is why we can dynamically register/deregister without interfearing with user interaction.
  873.      */
  874.     void registerAnimatedInternal(Animation cmp) {
  875.         if (internalAnimatableComponents == null) {
  876.             internalAnimatableComponents = new Vector();
  877.         }
  878.         if (!internalAnimatableComponents.contains(cmp)) {
  879.             internalAnimatableComponents.addElement(cmp);
  880.         }
  881.         Display.getInstance().notifyDisplay();
  882.     }
  883.     /**
  884.      * Identical to the none-internal version, the difference between the internal/none-internal
  885.      * is that it references a different vector that is unaffected by the user actions.
  886.      * That is why we can dynamically register/deregister without interfearing with user interaction.
  887.      */
  888.     void deregisterAnimatedInternal(Animation cmp) {
  889.         if (internalAnimatableComponents != null) {
  890.             internalAnimatableComponents.removeElement(cmp);
  891.         }
  892.     }
  893.     /**
  894.      * Indicate that cmp would no longer like to receive animation events
  895.      * 
  896.      * @param cmp component that would no longer receive animation events
  897.      */
  898.     public void deregisterAnimated(Animation cmp) {
  899.         if (animatableComponents != null) {
  900.             animatableComponents.removeElement(cmp);
  901.         }
  902.     }
  903.     /**
  904.      * Returns the offset of the component within the up/down focus sequence
  905.      * 
  906.      * @return offset between 0 and number of components or -1 for an error
  907.      */
  908.     int getFocusPosition(Component c) {
  909.         initFocusDown();
  910.         return focusDownSequence.indexOf(c);
  911.     }
  912.     
  913.     int getFocusCount() {
  914.         initFocusDown();
  915.         return focusDownSequence.size();
  916.     }
  917.     
  918.     /**
  919.      * Makes sure all animations are repainted so they would be rendered in every
  920.      * frame
  921.      */
  922.     void repaintAnimations() {
  923.         if (animatableComponents != null) {
  924.             loopAnimations(animatableComponents, null);
  925.         }
  926.         if (internalAnimatableComponents != null) {
  927.             loopAnimations(internalAnimatableComponents, animatableComponents);
  928.         }
  929.     }
  930.     private void loopAnimations(Vector v, Vector notIn) {
  931.         // we don't save size() in a varible since the animate method may deregister
  932.         // the animation thus invalidating the size
  933.         for (int iter = 0; iter < v.size(); iter++) {
  934.             Animation c = (Animation) v.elementAt(iter);
  935.             if(c == null || notIn != null && notIn.contains(c)) {
  936.                 continue;
  937.             }
  938.             if (c.animate()) {
  939.                 if (c instanceof Component) {
  940.                     Rectangle rect = ((Component) c).getDirtyRegion();
  941.                     if (rect != null) {
  942.                         Dimension d = rect.getSize();
  943.                         
  944.                         // this probably can't happen but we got a really weird partial stack trace to this
  945.                         // method and this check doesn't hurt
  946.                         if(d != null) {
  947.                             ((Component) c).repaint(rect.getX(), rect.getY(), d.getWidth(), d.getHeight());
  948.                         }
  949.                     } else {
  950.                         ((Component) c).repaint();
  951.                     }
  952.                 } else {
  953.                     Display.getInstance().repaint(c);
  954.                 }
  955.             }
  956.         }
  957.     }
  958.     /**
  959.      * If this method returns true the EDT won't go to sleep indefinitely
  960.      * 
  961.      * @return true is form has animation; otherwise false
  962.      */
  963.     boolean hasAnimations() {
  964.         return (animatableComponents != null && animatableComponents.size() > 0)
  965.                 || (internalAnimatableComponents != null && internalAnimatableComponents.size() > 0);
  966.     }
  967.     /**
  968.      * @inheritDoc
  969.      */
  970.     public void refreshTheme() {
  971.         // when changing the theme when a title/menu bar is not visible the refresh
  972.         // won't apply to them. We need to protect against this occurance.
  973.         if (menuBar != null) {
  974.             menuBar.refreshTheme();
  975.         }
  976.         if (title != null) {
  977.             title.refreshTheme();
  978.         }
  979.         super.refreshTheme();
  980.     }
  981.     /**
  982.      * Exposing the background painting for the benefit of animations
  983.      * 
  984.      * @param g the form graphics
  985.      */
  986.     public void paintBackground(Graphics g) {
  987.         super.paintBackground(g);
  988.     }
  989.     /**
  990.      * This property allows us to define a an animation that will draw the transition for
  991.      * entering this form. A transition is an animation that would occur when 
  992.      * switching from one form to another.
  993.      * 
  994.      * @return the Form in transition
  995.      */
  996.     public Transition getTransitionInAnimator() {
  997.         return transitionInAnimator;
  998.     }
  999.     /**
  1000.      * This property allows us to define a an animation that will draw the transition for
  1001.      * entering this form. A transition is an animation that would occur when 
  1002.      * switching from one form to another.
  1003.      * 
  1004.      * @param transitionInAnimator the Form in transition
  1005.      */
  1006.     public void setTransitionInAnimator(Transition transitionInAnimator) {
  1007.         this.transitionInAnimator = transitionInAnimator;
  1008.     }
  1009.     /**
  1010.      * This property allows us to define a an animation that will draw the transition for
  1011.      * exiting this form. A transition is an animation that would occur when 
  1012.      * switching from one form to another.
  1013.      * 
  1014.      * @return the Form out transition
  1015.      */
  1016.     public Transition getTransitionOutAnimator() {
  1017.         return transitionOutAnimator;
  1018.     }
  1019.     /**
  1020.      * This property allows us to define a an animation that will draw the transition for
  1021.      * exiting this form. A transition is an animation that would occur when 
  1022.      * switching from one form to another.
  1023.      * 
  1024.      * @param transitionOutAnimator the Form out transition
  1025.      */
  1026.     public void setTransitionOutAnimator(Transition transitionOutAnimator) {
  1027.         this.transitionOutAnimator = transitionOutAnimator;
  1028.     }
  1029.     /**
  1030.      * A listener that is invoked when a command is clicked allowing multiple commands
  1031.      * to be handled by a single block
  1032.      * 
  1033.      * @param commandListener the command action listener
  1034.      * @deprecated use add/removeCommandListener instead
  1035.      */
  1036.     public void setCommandListener(ActionListener commandListener) {
  1037.         if(commandListener == null) {
  1038.             this.commandListener = null;
  1039.             return;
  1040.         }
  1041.         addCommandListener(commandListener);
  1042.     }
  1043.     /**
  1044.      * A listener that is invoked when a command is clicked allowing multiple commands
  1045.      * to be handled by a single block
  1046.      *
  1047.      * @param l the command action listener
  1048.      */
  1049.     public void addCommandListener(ActionListener l) {
  1050.         if(commandListener == null) {
  1051.             commandListener = new EventDispatcher();
  1052.         }
  1053.         commandListener.addListener(l);
  1054.     }
  1055.     /**
  1056.      * A listener that is invoked when a command is clicked allowing multiple commands
  1057.      * to be handled by a single block
  1058.      *
  1059.      * @param l the command action listener
  1060.      */
  1061.     public void removeCommandListener(ActionListener l) {
  1062.         commandListener.removeListener(l);
  1063.     }
  1064.     /**
  1065.      * Invoked to allow subclasses of form to handle a command from one point
  1066.      * rather than implementing many command instances. All commands selected 
  1067.      * on the form will trigger this method implicitly.
  1068.      * 
  1069.      * @param cmd the form commmand object
  1070.      */
  1071.     protected void actionCommand(Command cmd) {
  1072.     }
  1073.     /**
  1074.      * Dispatches a command via the standard form mechanism of firing a command event
  1075.      * 
  1076.      * @param cmd The command to dispatch
  1077.      * @param ev the event to dispatch 
  1078.      */
  1079.     public void dispatchCommand(Command cmd, ActionEvent ev) {
  1080.         cmd.actionPerformed(ev);
  1081.         if(!ev.isConsumed()) {
  1082.             actionCommandImpl(cmd, ev);
  1083.         }
  1084.     }
  1085.     /**
  1086.      * Invoked to allow subclasses of form to handle a command from one point
  1087.      * rather than implementing many command instances
  1088.      */
  1089.     void actionCommandImpl(Command cmd) {
  1090.         actionCommandImpl(cmd, new ActionEvent(cmd));
  1091.     }
  1092.     /**
  1093.      * Invoked to allow subclasses of form to handle a command from one point
  1094.      * rather than implementing many command instances
  1095.      */
  1096.     void actionCommandImpl(Command cmd, ActionEvent ev) {
  1097.         if (cmd == null) {
  1098.             return;
  1099.         }
  1100.         if(comboLock) {
  1101.             if(cmd == cancelMenuItem) {
  1102.                 actionCommand(cmd);
  1103.                 return;
  1104.             }
  1105.             Component c = getFocused();
  1106.             if (c != null) {
  1107.                 c.fireClicked();
  1108.             }
  1109.             return;
  1110.         }
  1111.         if (cmd != selectCommand) {
  1112.             if (commandListener != null) {
  1113.                 commandListener.fireActionEvent(ev);
  1114.                 if(ev.isConsumed()) {
  1115.                     return;
  1116.                 }
  1117.             }
  1118.             actionCommand(cmd);
  1119.         } else {
  1120.             Component c = getFocused();
  1121.             if (c != null) {
  1122.                 c.fireClicked();
  1123.             }
  1124.         }
  1125.     }
  1126.     void initFocused() {
  1127.         if (focused == null) {
  1128.             setFocused(findFirstFocusable(contentPane));
  1129.             layoutContainer();
  1130.             initFocusDown();
  1131.             if(focusDownSequence == null) {
  1132.                 initFocusDown();
  1133.                 if (focusDownSequence.size() > 0) {
  1134.                     setFocused((Component) focusDownSequence.elementAt(0));
  1135.                 }
  1136.             } else {
  1137.                 if (focusDownSequence.size() > 0) {
  1138.                     setFocused((Component) focusDownSequence.elementAt(0));
  1139.                 }
  1140.             }
  1141.         }
  1142.     }
  1143.     /**
  1144.      * Displays the current form on the screen
  1145.      */
  1146.     public void show() {
  1147.         show(false);
  1148.     }
  1149.     /**
  1150.      * Displays the current form on the screen, this version of the method is
  1151.      * useful for "back" navigation since it reverses the direction of the transition.
  1152.      */
  1153.     public void showBack() {
  1154.         show(true);
  1155.     }
  1156.     /**
  1157.      * Displays the current form on the screen
  1158.      */
  1159.     private void show(boolean reverse) {
  1160.         if (transitionOutAnimator == null && transitionInAnimator == null) {
  1161.             initLaf(UIManager.getInstance().getLookAndFeel());
  1162.         }
  1163.         initFocused();
  1164.         onShow();
  1165.         tint = false;
  1166.         com.sun.lwuit.Display.getInstance().setCurrent(this, reverse);
  1167.     }
  1168.     /**
  1169.      * @inheritDoc
  1170.      */
  1171.     void initComponentImpl() {
  1172.         super.initComponentImpl();
  1173.         tactileTouchDuration = UIManager.getInstance().getLookAndFeel().getTactileTouchDuration();
  1174.         if(title.getText() != null && title.shouldTickerStart()) {
  1175.             title.startTicker(UIManager.getInstance().getLookAndFeel().getTickerSpeed(), true);
  1176.         }
  1177.     }
  1178.     /**
  1179.      * @inheritDoc
  1180.      */
  1181.     public void setSmoothScrolling(boolean smoothScrolling) {
  1182.         // invoked by the constructor for component
  1183.         if (contentPane != null) {
  1184.             contentPane.setSmoothScrolling(smoothScrolling);
  1185.         }
  1186.     }
  1187.     /**
  1188.      * @inheritDoc
  1189.      */
  1190.     public boolean isSmoothScrolling() {
  1191.         return contentPane.isSmoothScrolling();
  1192.     }
  1193.     /**
  1194.      * @inheritDoc
  1195.      */
  1196.     public int getScrollAnimationSpeed() {
  1197.         return contentPane.getScrollAnimationSpeed();
  1198.     }
  1199.     /**
  1200.      * @inheritDoc
  1201.      */
  1202.     public void setScrollAnimationSpeed(int animationSpeed) {
  1203.         contentPane.setScrollAnimationSpeed(animationSpeed);
  1204.     }
  1205.     /**
  1206.      * Allows subclasses to bind functionality that occurs when
  1207.      * a specific form or dialog appears on the screen
  1208.      */
  1209.     protected void onShow() {
  1210.     }
  1211.     /**
  1212.      * Allows subclasses to bind functionality that occurs when
  1213.      * a specific form or dialog is "really" showing hence when
  1214.      * the transition is totally complete (unlike onShow which is called
  1215.      * on intent). The necessity for this is for special cases like
  1216.      * media that might cause artifacts if played during a transition.
  1217.      */
  1218.     protected void onShowCompleted() {
  1219.     }
  1220.     /**
  1221.      * This method shows the form as a modal alert allowing us to produce a behavior
  1222.      * of an alert/dialog box. This method will block the calling thread even if the
  1223.      * calling thread is the EDT. Notice that this method will not release the block
  1224.      * until dispose is called even if show() from another form is called!
  1225.      * <p>Modal dialogs Allow the forms "content" to "hang in mid air" this is especially useful for
  1226.      * dialogs where you would want the underlying form to "peek" from behind the 
  1227.      * form. 
  1228.      * 
  1229.      * @param top space in pixels between the top of the screen and the form
  1230.      * @param bottom space in pixels between the bottom of the screen and the form
  1231.      * @param left space in pixels between the left of the screen and the form
  1232.      * @param right space in pixels between the right of the screen and the form
  1233.      * @param includeTitle whether the title should hang in the top of the screen or
  1234.      * be glued onto the content pane
  1235.      * @param modal indictes if this is a modal or modeless dialog true for modal dialogs
  1236.      */
  1237.     void showModal(int top, int bottom, int left, int right, boolean includeTitle, boolean modal, boolean reverse) {
  1238.         Display.getInstance().flushEdt();
  1239.         if (previousForm == null){
  1240.             previousForm = Display.getInstance().getCurrent();
  1241.             // special case for application opening with a dialog before any form is shown
  1242.             if (previousForm == null) {
  1243.                 previousForm = new Form();
  1244.                 previousForm.show();
  1245.             } else {
  1246.                 if(previousForm instanceof Dialog) {
  1247.                     Dialog previousDialog = (Dialog)previousForm;
  1248.                     if(previousDialog.isDisposed()) {
  1249.                         previousForm = Display.getInstance().getCurrentUpcoming();
  1250.                     }
  1251.                 }
  1252.             }
  1253.             previousForm.tint = true;
  1254.         }
  1255.         Painter p = getStyle().getBgPainter();
  1256.         if (top > 0 || bottom > 0 || left > 0 || right > 0) {
  1257.             Style titleStyle = title.getStyle();
  1258.             Style contentStyle = contentPane.getUnselectedStyle();
  1259.             if (includeTitle) {
  1260.                 titleStyle.setMargin(Component.TOP, top, true);
  1261.                 titleStyle.setMargin(Component.BOTTOM, 0, true);
  1262.                 titleStyle.setMargin(Component.LEFT, left, true);
  1263.                 titleStyle.setMargin(Component.RIGHT, right, true);
  1264.                 contentStyle.setMargin(Component.TOP, 0, true);
  1265.                 contentStyle.setMargin(Component.BOTTOM, bottom, true);
  1266.                 contentStyle.setMargin(Component.LEFT, left, true);
  1267.                 contentStyle.setMargin(Component.RIGHT, right, true);
  1268.             } else {
  1269.                 titleStyle.setMargin(Component.TOP, 0, true);
  1270.                 titleStyle.setMargin(Component.BOTTOM, 0, true);
  1271.                 titleStyle.setMargin(Component.LEFT, 0, true);
  1272.                 titleStyle.setMargin(Component.RIGHT, 0, true);
  1273.                 contentStyle.setMargin(Component.TOP, top, true);
  1274.                 contentStyle.setMargin(Component.BOTTOM, bottom, true);
  1275.                 contentStyle.setMargin(Component.LEFT, left, true);
  1276.                 contentStyle.setMargin(Component.RIGHT, right, true);
  1277.             }
  1278.             if (p instanceof BGPainter && ((BGPainter) p).getPreviousForm() != null) {
  1279.                 ((BGPainter) p).setPreviousForm(previousForm);
  1280.                 ((BGPainter) p).setParent(this);
  1281.             } else {
  1282.                 BGPainter b = new BGPainter(this, p);
  1283.                 b.setIgnorCoordinates(true);
  1284.                 getStyle().setBgPainter(b);
  1285.                 b.setPreviousForm(previousForm);
  1286.             }
  1287.             revalidate();
  1288.         }
  1289.         initFocused();
  1290.         if (getTransitionOutAnimator() == null && getTransitionInAnimator() == null) {
  1291.             initLaf(UIManager.getInstance().getLookAndFeel());
  1292.         }
  1293.         
  1294.         initComponentImpl();
  1295.         Display.getInstance().setCurrent(this, reverse);
  1296.         onShow();
  1297.         if (modal) {
  1298.             // called to display a dialog and wait for modality  
  1299.             Display.getInstance().invokeAndBlock(new RunnableWrapper(this, p, reverse));
  1300.             // if the virtual keyboard was opend by the dialog close it
  1301.             if(Display.getInstance().isVirtualKeyboardShowingSupported()) {
  1302.                 Display.getInstance().setShowVirtualKeyboard(false);
  1303.             }
  1304.         }
  1305.     }
  1306.     /**
  1307.      * The default version of show modal shows the dialog occupying the center portion
  1308.      * of the screen.
  1309.      */
  1310.     void showModal(boolean reverse) {
  1311.         showDialog(true, reverse);
  1312.     }
  1313.     /**
  1314.      * The default version of show dialog shows the dialog occupying the center portion
  1315.      * of the screen.
  1316.      */
  1317.     void showDialog(boolean modal, boolean reverse) {
  1318.         int h = Display.getInstance().getDisplayHeight() - menuBar.getPreferredH() - title.getPreferredH();
  1319.         int w = Display.getInstance().getDisplayWidth();
  1320.         int topSpace = h / 100 * 20;
  1321.         int bottomSpace = h / 100 * 10;
  1322.         int sideSpace = w / 100 * 20;
  1323.         showModal(topSpace, bottomSpace, sideSpace, sideSpace, true, modal, reverse);
  1324.     }
  1325.     /**
  1326.      * Works only for modal forms by returning to the previous form
  1327.      */
  1328.     void dispose() {
  1329.         disposeImpl();
  1330.     }
  1331.     boolean isDisposed() {
  1332.         return false;
  1333.     }
  1334.     /**
  1335.      * Works only for modal forms by returning to the previous form
  1336.      */
  1337.     void disposeImpl() {
  1338.         if (previousForm != null) {
  1339.             previousForm.tint = false;
  1340.             if (previousForm instanceof Dialog) {
  1341.                 if (!((Dialog) previousForm).isDisposed()) {
  1342.                     Display.getInstance().setCurrent(previousForm, false);
  1343.                 }
  1344.             } else {
  1345.                 Display.getInstance().setCurrent(previousForm, false);
  1346.             }
  1347.             // enable GC to cleanup the previous form if no longer referenced
  1348.             previousForm = null;
  1349.         }
  1350.     }
  1351.     boolean isMenu() {
  1352.         return false;
  1353.     }
  1354.     /**
  1355.      * @inheritDoc
  1356.      */
  1357.     void repaint(Component cmp) {
  1358.         if (isVisible()) {
  1359.             Display.getInstance().repaint(cmp);
  1360.         }
  1361.     }
  1362.     /**
  1363.      * @inheritDoc
  1364.      */
  1365.     public final Form getComponentForm() {
  1366.         return this;
  1367.     }
  1368.     /**
  1369.      * Invoked by display to hide the menu during transition
  1370.      * 
  1371.      * @see restoreMenu
  1372.      */
  1373.     void hideMenu() {
  1374.         super.removeComponent(menuBar);
  1375.     }
  1376.     /**
  1377.      * Invoked by display to restore the menu after transition
  1378.      * 
  1379.      * @see hideMenu
  1380.      */
  1381.     void restoreMenu() {
  1382.         if (menuBar.getParent() == null) {
  1383.             super.addComponent(BorderLayout.SOUTH, menuBar);
  1384.         }
  1385.     }
  1386.     /**
  1387.      * Sets the focused component and fires the appropriate events to make it so
  1388.      * 
  1389.      * @param focused the newly focused component or null for no focus
  1390.      */
  1391.     public void setFocused(Component focused) {
  1392.         if (this.focused == focused && focused != null) {
  1393.             this.focused.repaint();
  1394.             return;
  1395.         }
  1396.         Component oldFocus = this.focused;
  1397.         this.focused = focused;
  1398.         boolean triggerRevalidate = false;
  1399.         if (oldFocus != null) {
  1400.             triggerRevalidate = changeFocusState(oldFocus, false);
  1401.             //if we need to revalidate no need to repaint the Component, it will
  1402.             //be painted from the Form
  1403.             if (!triggerRevalidate && oldFocus.getParent() != null) {
  1404.                 oldFocus.repaint();
  1405.             }
  1406.         }
  1407.         // a listener might trigger a focus change event essentially
  1408.         // invalidating focus so we shouldn't break that 
  1409.         if (focused != null && this.focused == focused) {
  1410.             triggerRevalidate = changeFocusState(focused, true) || triggerRevalidate;
  1411.             //if we need to revalidate no need to repaint the Component, it will
  1412.             //be painted from the Form
  1413.             if(!triggerRevalidate){
  1414.                 focused.repaint();
  1415.             }
  1416.         }
  1417.         if(triggerRevalidate){
  1418.             revalidate();
  1419.         }
  1420.     }
  1421.     /**
  1422.      * This method changes the cmp state to be focused/unfocused and fires the 
  1423.      * focus gained/lost events. 
  1424.      * @param cmp the Component to change the focus state
  1425.      * @param gained if true this Component needs to gain focus if false
  1426.      * it needs to lose focus
  1427.      * @return this method returns true if the state change needs to trigger a 
  1428.      * revalidate
  1429.      */
  1430.     private boolean changeFocusState(Component cmp, boolean gained){
  1431.         boolean trigger = false;
  1432.         Style selected = cmp.getSelectedStyle();
  1433.         Style unselected = cmp.getUnselectedStyle();
  1434.         //if selected style is different then unselected style there is a good 
  1435.         //chance we need to trigger a revalidate
  1436.         if(!selected.getFont().equals(unselected.getFont()) || 
  1437.                 selected.getPadding(false, Component.TOP) != unselected.getPadding(false, Component.TOP) ||
  1438.                 selected.getPadding(false, Component.BOTTOM) != unselected.getPadding(false, Component.BOTTOM) ||
  1439.                 selected.getPadding(isRTL(), Component.RIGHT) != unselected.getPadding(isRTL(), Component.RIGHT) ||
  1440.                 selected.getPadding(isRTL(), Component.LEFT) != unselected.getPadding(isRTL(), Component.LEFT) ||
  1441.                 selected.getMargin(false, Component.TOP) != unselected.getMargin(false, Component.TOP) ||
  1442.                 selected.getMargin(false, Component.BOTTOM) != unselected.getMargin(false, Component.BOTTOM) ||
  1443.                 selected.getMargin(isRTL(), Component.RIGHT) != unselected.getMargin(isRTL(), Component.RIGHT) ||
  1444.                 selected.getMargin(isRTL(), Component.LEFT) != unselected.getMargin(isRTL(), Component.LEFT)){
  1445.                 trigger = true;
  1446.         }
  1447.         int prefW = 0;
  1448.         int prefH = 0;
  1449.         if(trigger){
  1450.             Dimension d = cmp.getPreferredSize();
  1451.             prefW = d.getWidth();
  1452.             prefH = d.getHeight();
  1453.         }            
  1454.         
  1455.         if (gained) {
  1456.             cmp.setFocus(true);
  1457.             cmp.fireFocusGained();
  1458.             fireFocusGained(cmp);
  1459.         } else {
  1460.             cmp.setFocus(false);
  1461.             cmp.fireFocusLost();
  1462.             fireFocusLost(cmp);
  1463.         }
  1464.         //if the styles are different there is a chance the preffered size is 
  1465.         //still the same therefore make sure there is a real need to preform 
  1466.         //a revalidate
  1467.         if(trigger){
  1468.             cmp.setShouldCalcPreferredSize(true);
  1469.             Dimension d = cmp.getPreferredSize();
  1470.             if(prefW != d.getWidth() || prefH != d.getHeight()){
  1471.                 cmp.setShouldCalcPreferredSize(false);
  1472.                 trigger = false;
  1473.             }
  1474.         }            
  1475.         return trigger;
  1476.     }
  1477.     
  1478.     /**
  1479.      * Find the first focusable Component
  1480.      * 
  1481.      * @param c a Container that holds potential Component
  1482.      * @return a focusable Component or null if not exists;
  1483.      */
  1484.     private Component findFirstFocusable(Container c) {
  1485.         int size = c.getComponentCount();
  1486.         for (int iter = 0; iter < size; iter++) {
  1487.             Component current = c.getComponentAt(iter);
  1488.             if(current.isFocusable()){
  1489.                 return current;
  1490.             }
  1491.             if (current instanceof Container) {
  1492.                 Component cmp = findFirstFocusable((Container)current);
  1493.                 if(cmp != null){
  1494.                     return cmp;
  1495.                 }
  1496.             }
  1497.         }        
  1498.         return null;
  1499.     }    
  1500.     
  1501.     /**
  1502.      * Returns the current focus component for this form
  1503.      * 
  1504.      * @return the current focus component for this form
  1505.      */
  1506.     public Component getFocused() {
  1507.         return focused;
  1508.     }
  1509.     /**
  1510.      * @inheritDoc
  1511.      */
  1512.     protected void longKeyPress(int keyCode) {
  1513.         if (focused != null) {
  1514.             if (focused.getComponentForm() == this) {
  1515.                 focused.longKeyPress(keyCode);
  1516.             }
  1517.         }
  1518.     }
  1519.     /**
  1520.      * @inheritDoc
  1521.      */
  1522.     protected void longPointerPress(int x, int y){
  1523.         if (focused != null && focused.contains(x, y)) {
  1524.             if (focused.getComponentForm() == this) {
  1525.                 focused.longPointerPress(x, y);
  1526.             }
  1527.         }
  1528.     }
  1529.     /**
  1530.      * @inheritDoc
  1531.      */
  1532.     public void keyPressed(int keyCode) {
  1533.         int game = Display.getInstance().getGameAction(keyCode);
  1534.         if (keyCode == leftSK || (keyCode == rightSK || keyCode == rightSK2) || keyCode == backSK || 
  1535.                 (keyCode == clearSK && clearCommand != null) ||
  1536.                 (keyCode == backspaceSK && clearCommand != null) ||
  1537.                 (Display.getInstance().isThirdSoftButton() && game == Display.GAME_FIRE)) {
  1538.             menuBar.keyPressed(keyCode);
  1539.             return;
  1540.         }
  1541.         //Component focused = focusManager.getFocused();
  1542.         if (focused != null) {
  1543.             focused.keyPressed(keyCode);
  1544.             if(focused == null) {
  1545.                 initFocused();
  1546.                 return;
  1547.             }
  1548.             if (focused.handlesInput()) {
  1549.                 return;
  1550.             }
  1551.             if (focused.getComponentForm() == this) {
  1552.                 if (focused != null && focused.handlesInput()) {
  1553.                     return;
  1554.                 }
  1555.                 //if the arrow keys have been pressed update the focus.
  1556.                 updateFocus(Display.getInstance().getGameAction(keyCode));
  1557.             } else {
  1558.                 initFocused();
  1559.             }
  1560.         } else {
  1561.             initFocused();
  1562.             if(focused == null) {
  1563.                 contentPane.moveScrollTowards(Display.getInstance().getGameAction(keyCode), null);
  1564.                 return;
  1565.             }
  1566.         }
  1567.     }
  1568.     /**
  1569.      * @inheritDoc
  1570.      */
  1571.     public Layout getLayout() {
  1572.         return contentPane.getLayout();
  1573.     }
  1574.     /**
  1575.      * @inheritDoc
  1576.      */
  1577.     public void keyReleased(int keyCode) {
  1578.         int game = Display.getInstance().getGameAction(keyCode);
  1579.         if (keyCode == leftSK || (keyCode == rightSK || keyCode == rightSK2) || keyCode == backSK ||
  1580.                 (keyCode == clearSK && clearCommand != null) ||
  1581.                 (keyCode == backspaceSK && clearCommand != null) ||
  1582.                 (Display.getInstance().isThirdSoftButton() && game == Display.GAME_FIRE)) {
  1583.             menuBar.keyReleased(keyCode);
  1584.             return;
  1585.         }
  1586.         //Component focused = focusManager.getFocused();
  1587.         if (focused != null) {
  1588.             if (focused.getComponentForm() == this) {
  1589.                 focused.keyReleased(keyCode);
  1590.             }
  1591.         }
  1592.         // prevent the default action from stealing the behavior from the popup/combo box...
  1593.         if (game == Display.GAME_FIRE) {
  1594.             Command defaultCmd = getDefaultCommand();
  1595.             if (defaultCmd != null) {
  1596.                 defaultCmd.actionPerformed(new ActionEvent(defaultCmd, keyCode));
  1597.                 actionCommandImpl(defaultCmd);
  1598.             }
  1599.         }
  1600.         fireKeyEvent(keyListeners, keyCode);
  1601.         fireKeyEvent(gameKeyListeners, game);
  1602.     }
  1603.     private void fireKeyEvent(Hashtable keyListeners, int keyCode) {
  1604.         if (keyListeners != null) {
  1605.             Vector listeners = (Vector) keyListeners.get(new Integer(keyCode));
  1606.             if (listeners != null) {
  1607.                 ActionEvent evt = new ActionEvent(this, keyCode);
  1608.                 for (int iter = 0; iter < listeners.size(); iter++) {
  1609.                     ((ActionListener) listeners.elementAt(iter)).actionPerformed(evt);
  1610.                     if (evt.isConsumed()) {
  1611.                         return;
  1612.                     }
  1613.                 }
  1614.             }
  1615.         }
  1616.     }
  1617.     /**
  1618.      * @inheritDoc
  1619.      */
  1620.     public void keyRepeated(int keyCode) {
  1621.         if (focused != null) {
  1622.             focused.keyRepeated(keyCode);
  1623.             int game = Display.getInstance().getGameAction(keyCode);
  1624.             // this has issues in the WTK
  1625.             if (!focused.handlesInput() && 
  1626.                     (game == Display.GAME_DOWN || game == Display.GAME_UP || game == Display.GAME_LEFT || game == Display.GAME_RIGHT)) {
  1627.                 keyPressed(keyCode);
  1628.                 keyReleased(keyCode);
  1629.             }
  1630.         } else {
  1631.             keyPressed(keyCode);
  1632.             keyReleased(keyCode);
  1633.         }
  1634.     }
  1635.     private void tactileTouchVibe(Component cmp) {
  1636.         if(tactileTouchDuration > 0 && cmp.isTactileTouch()) {
  1637.             Display.getInstance().vibrate(tactileTouchDuration);
  1638.         }
  1639.     }
  1640.     /**
  1641.      * @inheritDoc
  1642.      */
  1643.     public void pointerPressed(int x, int y) {
  1644.         if(pointerPressedListeners != null) {
  1645.             pointerPressedListeners.fireActionEvent(new ActionEvent(this, x, y));
  1646.         }
  1647.         //if there is no popup on the screen an click is relevant to the menu bar.
  1648.         if (menuBar.contains(x, y)) {
  1649.             Component cmp = menuBar.getComponentAt(x, y);
  1650.             if (cmp != null) {
  1651.                 cmp.pointerPressed(x, y);
  1652.                 tactileTouchVibe(cmp);
  1653.             }
  1654.             return;
  1655.         }
  1656.         Component cmp = contentPane.getComponentAt(x, y);
  1657.         if (cmp != null && cmp.isFocusable()) {
  1658.             setFocused(cmp);
  1659.             cmp.pointerPressed(x, y);
  1660.             tactileTouchVibe(cmp);
  1661.         }
  1662.     }
  1663.     /**
  1664.      * Adds a listener to the pointer event
  1665.      * 
  1666.      * @param l callback to receive pointer events
  1667.      */
  1668.     public void addPointerPressedListener(ActionListener l) {
  1669.         if(pointerPressedListeners == null) {
  1670.             pointerPressedListeners = new EventDispatcher();
  1671.         }
  1672.         pointerPressedListeners.addListener(l);
  1673.     }
  1674.     /**
  1675.      * Removes the listener from the pointer event
  1676.      *
  1677.      * @param l callback to remove
  1678.      */
  1679.     public void removePointerPressedListener(ActionListener l) {
  1680.         if(pointerPressedListeners != null) {
  1681.             pointerPressedListeners.removeListener(l);
  1682.         }
  1683.     }
  1684.     /**
  1685.      * Adds a listener to the pointer event
  1686.      *
  1687.      * @param l callback to receive pointer events
  1688.      */
  1689.     public void addPointerReleasedListener(ActionListener l) {
  1690.         if(pointerReleasedListeners == null) {
  1691.             pointerReleasedListeners = new EventDispatcher();
  1692.         }
  1693.         pointerReleasedListeners.addListener(l);
  1694.     }
  1695.     /**
  1696.      * Removes the listener from the pointer event
  1697.      *
  1698.      * @param l callback to remove
  1699.      */
  1700.     public void removePointerReleasedListener(ActionListener l) {
  1701.         if(pointerReleasedListeners != null) {
  1702.             pointerReleasedListeners.removeListener(l);
  1703.         }
  1704.     }
  1705.     /**
  1706.      * Adds a listener to the pointer event
  1707.      *
  1708.      * @param l callback to receive pointer events
  1709.      */
  1710.     public void addPointerDraggedListener(ActionListener l) {
  1711.         if(pointerDraggedListeners == null) {
  1712.             pointerDraggedListeners = new EventDispatcher();
  1713.         }
  1714.         pointerDraggedListeners.addListener(l);
  1715.     }
  1716.     /**
  1717.      * Removes the listener from the pointer event
  1718.      *
  1719.      * @param l callback to remove
  1720.      */
  1721.     public void removePointerDraggedListener(ActionListener l) {
  1722.         if(pointerDraggedListeners != null) {
  1723.             pointerDraggedListeners.removeListener(l);
  1724.         }
  1725.     }
  1726.     /**
  1727.      * @inheritDoc
  1728.      */
  1729.     public void pointerDragged(int x, int y) {
  1730.         if(pointerDraggedListeners != null) {
  1731.             pointerDraggedListeners.fireActionEvent(new ActionEvent(this, x, y));
  1732.         }
  1733.         if (dragged != null) {
  1734.             dragged.pointerDragged(x, y);
  1735.             return;
  1736.         }
  1737.         Component cmp = contentPane.getComponentAt(x, y);
  1738.         if (cmp != null) {
  1739.             if (cmp.isFocusable()) {
  1740.                 setFocused(cmp);
  1741.             }
  1742.             cmp.pointerDragged(x, y);
  1743.             cmp.repaint();
  1744.         }
  1745.     }
  1746.     /**
  1747.      * @inheritDoc
  1748.      */
  1749.     public void pointerHoverReleased(int[] x, int[] y) {
  1750.         Component cmp = contentPane.getComponentAt(x[0], y[0]);
  1751.         if (cmp != null) {
  1752.             if (cmp.isFocusable()) {
  1753.                 setFocused(cmp);
  1754.             }
  1755.             cmp.pointerHoverReleased(x, y);
  1756.             cmp.repaint();
  1757.         }
  1758.     }
  1759.     /**
  1760.      * @inheritDoc
  1761.      */
  1762.     public void pointerHover(int[] x, int[] y) {
  1763.         Component cmp = contentPane.getComponentAt(x[0], y[0]);
  1764.         if (cmp != null) {
  1765.             if (cmp.isFocusable()) {
  1766.                 setFocused(cmp);
  1767.             }
  1768.             cmp.pointerHover(x, y);
  1769.             cmp.repaint();
  1770.         }
  1771.     }
  1772.     /**
  1773.      * Returns true if there is only one focusable member in this form. This is useful
  1774.      * so setHandlesInput would always be true for this case.
  1775.      * 
  1776.      * @return true if there is one focusable component in this form, false for 0 or more
  1777.      */
  1778.     public boolean isSingleFocusMode() {
  1779.         initFocusDown();
  1780.         return focusDownSequence.size() == 1;
  1781.     }
  1782.     /**
  1783.      * @inheritDoc
  1784.      */
  1785.     public void pointerReleased(int x, int y) {
  1786.         if(pointerReleasedListeners != null) {
  1787.             pointerReleasedListeners.fireActionEvent(new ActionEvent(this, x, y));
  1788.         }
  1789.         if (dragged == null) {
  1790.             //if the pointer was released on the menu invoke the appropriate
  1791.             //soft button.
  1792.             if (menuBar.contains(x, y)) {
  1793.                 Component cmp = menuBar.getComponentAt(x, y);
  1794.                 if (cmp != null) {
  1795.                     cmp.pointerReleased(x, y);
  1796.                 }
  1797.                 return;
  1798.             }
  1799.             Component cmp = contentPane.getComponentAt(x, y);
  1800.             if (cmp != null) {
  1801.                 cmp.pointerReleased(x, y);
  1802.                 if (cmp.isFocusable()) {
  1803.                     setFocused(cmp);
  1804.                 }
  1805.             }
  1806.         } else {
  1807.             dragged.pointerReleased(x, y);
  1808.             dragged = null;
  1809.         }
  1810.     }
  1811.     /**
  1812.      * @inheritDoc
  1813.      */
  1814.     public void setScrollableY(boolean scrollableY) {
  1815.         getContentPane().setScrollableY(scrollableY);
  1816.     }
  1817.     /**
  1818.      * @inheritDoc
  1819.      */
  1820.     public void setScrollableX(boolean scrollableX) {
  1821.         getContentPane().setScrollableX(scrollableX);
  1822.     }
  1823.     /**
  1824.      * @inheritDoc
  1825.      */
  1826.     public int getComponentIndex(Component cmp) {
  1827.         return getContentPane().getComponentIndex(cmp);
  1828.     }
  1829.     /**
  1830.      * Adds a command to the menu bar softkeys or into the menu dialog, 
  1831.      * this version of add allows us to place a command in an arbitrary location.
  1832.      * This allows us to force a command into the softkeys when order of command
  1833.      * addition can't be changed.
  1834.      * 
  1835.      * @param cmd the Form command to be added
  1836.      * @param offset position in which the command is added
  1837.      */
  1838.     public void addCommand(Command cmd, int offset) {
  1839.         menuBar.addCommand(cmd, offset);
  1840.     }
  1841.     /**
  1842.      * A helper method to check the amount of commands within the form menu
  1843.      * 
  1844.      * @return the number of commands
  1845.      */
  1846.     public int getCommandCount() {
  1847.         return menuBar.getCommandCount();
  1848.     }
  1849.     /**
  1850.      * Returns the command occupying the given index
  1851.      * 
  1852.      * @param index offset of the command
  1853.      * @return the command at the given index
  1854.      */
  1855.     public Command getCommand(int index) {
  1856.         return menuBar.getCommand(index);
  1857.     }
  1858.     /**
  1859.      * Adds a command to the menu bar softkeys.
  1860.      * The Commands are placed in the order they are added.
  1861.      * If the Form has 1 Command it will be placed on the right.
  1862.      * If the Form has 2 Commands the first one that was added will be placed on
  1863.      * the right and the second one will be placed on the left.
  1864.      * If the Form has more then 2 Commands the first one will stay on the left
  1865.      * and a Menu will be added with all the remain Commands.
  1866.      * 
  1867.      * @param cmd the Form command to be added
  1868.      */
  1869.     public void addCommand(Command cmd) {
  1870.         menuBar.addCommand(cmd);
  1871.     }
  1872.     /**
  1873.      * Removes the command from the menu bar softkeys
  1874.      * 
  1875.      * @param cmd the Form command to be removed
  1876.      */
  1877.     public void removeCommand(Command cmd) {
  1878.         menuBar.removeCommand(cmd);
  1879.     }
  1880.     /**
  1881.      * Indicates whether focus should cycle within the form
  1882.      * 
  1883.      * @param cyclicFocus marks whether focus should cycle
  1884.      */
  1885.     public void setCyclicFocus(boolean cyclicFocus) {
  1886.         this.cyclicFocus = cyclicFocus;
  1887.     }
  1888.     /**
  1889.      * Indicates whether focus should cycle within the form
  1890.      * 
  1891.      * @return true if focus should cycle
  1892.      */
  1893.     public boolean isCyclicFocus() {
  1894.         return cyclicFocus;
  1895.     }
  1896.     private void updateFocus(int gameAction) {
  1897.         Component focused = getFocused();
  1898.         switch (gameAction) {
  1899.             case Display.GAME_DOWN: {
  1900.                 Component down = focused.getNextFocusDown();
  1901.                 if ( down != null && down.getComponentForm() == this) {
  1902.                     focused = down;
  1903.                 } else {
  1904.                     initFocusDown();
  1905.                     int i = focusDownSequence.indexOf(focused) + 1;
  1906.                     if (focusDownSequence.size() > 0) {
  1907.                         if (i == focusDownSequence.size()) {
  1908.                             if (cyclicFocus) {
  1909.                                 i = 0;
  1910.                             } else {
  1911.                                 i = focusDownSequence.size() - 1;
  1912.                             }
  1913.                         }
  1914.                         focused = (Component) focusDownSequence.elementAt(i);
  1915.                     }
  1916.                 }
  1917.                 break;
  1918.             }
  1919.             case Display.GAME_UP: {
  1920.                 Component up = focused.getNextFocusUp();
  1921.                 if (up != null && up.getComponentForm() == this) {
  1922.                     focused = up;
  1923.                 } else {
  1924.                     initFocusDown();
  1925.                     if (focusDownSequence.size() > 0) {
  1926.                         int i = focusDownSequence.indexOf(focused) - 1;
  1927.                         if (i < 0) {
  1928.                             if (cyclicFocus) {
  1929.                                 i = focusDownSequence.size() - 1;
  1930.                             } else {
  1931.                                 i = 0;
  1932.                             }
  1933.                         }
  1934.                         focused = (Component) focusDownSequence.elementAt(i);
  1935.                     }
  1936.                 }
  1937.                 break;
  1938.             }
  1939.             case Display.GAME_RIGHT: {
  1940.                 Component right = focused.getNextFocusRight();
  1941.                 if (right != null && right.getComponentForm() == this) {
  1942.                     focused = right;
  1943.                 } else {
  1944.                     initFocusRight();
  1945.                     if (focusRightSequence.size() > 0) {
  1946.                         int i = focusRightSequence.indexOf(focused) + 1;
  1947.                         if (i == focusRightSequence.size()) {
  1948.                             if (cyclicFocus) {
  1949.                                 i = 0;
  1950.                             } else {
  1951.                                 i = focusRightSequence.size() - 1;
  1952.                             }
  1953.                         }
  1954.                         focused = (Component) focusRightSequence.elementAt(i);
  1955.                     }
  1956.                 }
  1957.                 break;
  1958.             }
  1959.             case Display.GAME_LEFT: {
  1960.                 Component left = focused.getNextFocusLeft();
  1961.                 if (left != null && left.getComponentForm() == this) {
  1962.                     focused = left;
  1963.                 } else {
  1964.                     initFocusRight();
  1965.                     if (focusRightSequence.size() > 0) {
  1966.                         int i = focusRightSequence.indexOf(focused) - 1;
  1967.                         if (i < 0) {
  1968.                             if (cyclicFocus) {
  1969.                                 i = focusRightSequence.size() - 1;
  1970.                             } else {
  1971.                                 i = 0;
  1972.                             }
  1973.                         }
  1974.                         focused = (Component) focusRightSequence.elementAt(i);
  1975.                     }
  1976.                 }
  1977.                 break;
  1978.             }
  1979.             default:
  1980.                 return;
  1981.         }
  1982.         
  1983.         //if focused is now visible we need to give it the focus.
  1984.         if(moveScrollTowards(gameAction, focused)){
  1985.             setFocused(focused);
  1986.         }
  1987.     }
  1988.     /**
  1989.      * @inheritDoc
  1990.      */
  1991.     boolean moveScrollTowards(int direction, Component c) {
  1992.         Container parent = c.getParent();
  1993.         while (parent != null) {
  1994.             if (parent.isScrollable()) {
  1995.                 return parent.moveScrollTowards(direction, c);
  1996.             }
  1997.             parent = parent.getParent();
  1998.         }
  1999.         return true;
  2000.     }
  2001.     /**
  2002.      * Makes sure the component is visible in the scroll if this container 
  2003.      * is scrollable
  2004.      * 
  2005.      * @param c the componant to be visible
  2006.      */
  2007.     public void scrollComponentToVisible(Component c) {
  2008.         initFocused();
  2009.         Container parent = c.getParent();
  2010.         while (parent != null) {
  2011.             if (parent.isScrollable()) {
  2012.                 parent.scrollComponentToVisible(c);
  2013.                 return;
  2014.             }
  2015.             parent = parent.getParent();
  2016.         }
  2017.     }
  2018.     /**
  2019.      * Determine the cell renderer used to render menu elements for themeing the 
  2020.      * look of the menu options
  2021.      * 
  2022.      * @param menuCellRenderer the menu cell renderer
  2023.      */
  2024.     public void setMenuCellRenderer(ListCellRenderer menuCellRenderer) {
  2025.         menuBar.setMenuCellRenderer(menuCellRenderer);
  2026.     }
  2027.     /**
  2028.      * Clear menu commands from the menu bar
  2029.      */
  2030.     public void removeAllCommands() {
  2031.         menuBar.removeAllCommands();
  2032.     }
  2033.     /**
  2034.      * Request focus for a form child component
  2035.      * 
  2036.      * @param cmp the form child component
  2037.      */
  2038.     void requestFocus(Component cmp) {
  2039.         if (cmp.isFocusable() && contains(cmp)) {
  2040.             scrollComponentToVisible(cmp);
  2041.             setFocused(cmp);
  2042.         }
  2043.     }
  2044.     /**
  2045.      * Factory method that returns the Form select Command.
  2046.      * This Command is used when Display.getInstance().isThirdSoftButton() 
  2047.      * returns true.
  2048.      * This method can be overridden to customize the Command on the Form.
  2049.      * 
  2050.      * @return Command
  2051.      */
  2052.     protected Command createSelectCommand(){
  2053.         return new Command(UIManager.getInstance().localize("select", "Select"));
  2054.     }
  2055.     /**
  2056.      * Factory method that returns the Form Menu select Command.
  2057.      * This method can be overridden to customize the Command on the Form.
  2058.      * 
  2059.      * @return Command
  2060.      */
  2061.     protected Command createMenuSelectCommand(){
  2062.         LookAndFeel lf = UIManager.getInstance().getLookAndFeel();
  2063.         return new Command(UIManager.getInstance().localize("select", "Select"), lf.getMenuIcons()[0]);
  2064.     }
  2065.     
  2066.     /**
  2067.      * @inheritDoc
  2068.      */
  2069.     public void setRTL(boolean r) {
  2070.         super.setRTL(r);
  2071.         contentPane.setRTL(r);
  2072.     }
  2073.     /**
  2074.      * Factory method that returns the Form Menu cancel Command.
  2075.      * This method can be overridden to customize the Command on the Form.
  2076.      * 
  2077.      * @return Command
  2078.      */
  2079.     protected Command createMenuCancelCommand(){
  2080.         LookAndFeel lf = UIManager.getInstance().getLookAndFeel();
  2081.         return new Command(UIManager.getInstance().localize("cancel", "Cancel"), lf.getMenuIcons()[1]);
  2082.     }
  2083.     
  2084.     /**
  2085.      * @inheritDoc
  2086.      */
  2087.     public void paint(Graphics g) {
  2088.         paintBackground(g);
  2089.         super.paint(g);
  2090.         if (tint) {
  2091.             g.setColor(tintColor);
  2092.             g.fillRect(0, 0, getWidth(), getHeight(), (byte) ((tintColor >> 24) & 0xff));
  2093.         }
  2094.     }
  2095.     /**
  2096.      * @inheritDoc
  2097.      */
  2098.     public void setScrollable(boolean scrollable) {
  2099.         contentPane.setScrollable(scrollable);
  2100.     }
  2101.     /**
  2102.      * @inheritDoc
  2103.      */
  2104.     public void setVisible(boolean visible) {
  2105.         super.setVisible(visible);
  2106.         if (mediaComponents != null) {
  2107.             int size = mediaComponents.size();
  2108.             for (int i = 0; i < size; i++) {
  2109.                 Component mediaCmp = (Component) mediaComponents.elementAt(i);
  2110.                 mediaCmp.setVisible(visible);
  2111.             }
  2112.         }
  2113.     }
  2114.     /**
  2115.      * Default color for the screen tint when a dialog or a menu is shown
  2116.      * 
  2117.      * @return the tint color when a dialog or a menu is shown
  2118.      */
  2119.     public int getTintColor() {
  2120.         return tintColor;
  2121.     }
  2122.     /**
  2123.      * Default color for the screen tint when a dialog or a menu is shown
  2124.      * 
  2125.      * @param tintColor the tint color when a dialog or a menu is shown
  2126.      */
  2127.     public void setTintColor(int tintColor) {
  2128.         this.tintColor = tintColor;
  2129.     }
  2130.     void addSelectCommand(String selectText) {
  2131.         if (Display.getInstance().isThirdSoftButton()) {
  2132.             if (selectCommand == null) {
  2133.                 selectCommand = createSelectCommand();
  2134.             }
  2135.             selectCommand.setCommandName(selectText);
  2136.             addCommand(selectCommand);
  2137.         }
  2138.     }
  2139.     void removeSelectCommand() {
  2140.         if (Display.getInstance().isThirdSoftButton()) {
  2141.             removeCommand(selectCommand);
  2142.         }
  2143.     }
  2144.     /**
  2145.      * Sets the menu transitions for showing/hiding the menu, can be null...
  2146.      * 
  2147.      * @param transitionIn the transition that will play when the menu appears
  2148.      * @param transitionOut the transition that will play when the menu is folded
  2149.      */
  2150.     public void setMenuTransitions(Transition transitionIn, Transition transitionOut) {
  2151.         menuBar.setTransitions(transitionIn, transitionOut);
  2152.     }
  2153.     /**
  2154.      * @inheritDoc
  2155.      */
  2156.     protected String paramString() {
  2157.         return super.paramString() + ", title = " + title +
  2158.                 ", visible = " + isVisible();
  2159.     }
  2160.     /**
  2161.      * A menu is implemented as a dialog, this method allows you to override dialog
  2162.      * display in order to customize the dialog menu in various ways
  2163.      * 
  2164.      * @param menu a dialog containing menu options that can be customized
  2165.      * @return the command selected by the user in the dialog (not menu) Select or Cancel
  2166.      */
  2167.     protected Command showMenuDialog(Dialog menu) {
  2168.         int marginLeft = (int) (Form.this.getWidth() * 0.25f);
  2169.         int marginRight = 0;
  2170.         boolean rtl = isRTL();
  2171.         if (isReverseSoftButtons()) {
  2172.             marginRight = marginLeft;
  2173.             marginLeft = 0;
  2174.         }
  2175.         int height = Form.this.getHeight() / 2;
  2176.         if(UIManager.getInstance().getLookAndFeel().isTouchMenus()) {
  2177.             marginLeft = 0;
  2178.             marginRight = 0;
  2179.         }
  2180.         return menu.show(height, 0, marginLeft, marginRight, true);
  2181.     }
  2182.     /**
  2183.      * Allows an individual form to reverse the layout direction of the softbuttons, this method is RTL
  2184.      * sensitive and might reverse the result based on RTL state
  2185.      * 
  2186.      * @return The value of UIManager.getInstance().getLookAndFeel().isReverseSoftButtons()
  2187.      */
  2188.     protected boolean isReverseSoftButtons() {
  2189.         LookAndFeel lf = UIManager.getInstance().getLookAndFeel();
  2190.         if(isRTL()) {
  2191.             return !lf.isReverseSoftButtons();
  2192.         }
  2193.         return lf.isReverseSoftButtons();
  2194.     }
  2195.     /**
  2196.      * Calculates the amount of columns to give to the touch commands within the grid
  2197.      * 
  2198.      * @param grid container that will be arranged in the grid containing the components
  2199.      * @return an integer representing the touch command grid size
  2200.      */
  2201.     protected int calculateTouchCommandGridColumns(Container grid) {
  2202.         int count = grid.getComponentCount();
  2203.         int maxWidth = 0;
  2204.         for(int iter = 0 ; iter < count ; iter++) {
  2205.             Component c = grid.getComponentAt(iter);
  2206.             Style s = c.getUnselectedStyle();
  2207.             
  2208.             // bidi doesn't matter since this is just a summary of width
  2209.             maxWidth = Math.max(maxWidth, c.getPreferredW() + s.getPadding(false, LEFT) + s.getPadding(false, RIGHT) +
  2210.                      s.getMargin(false, LEFT) + s.getMargin(false, RIGHT));
  2211.         }
  2212.         return Math.max(2, getWidth() / maxWidth);
  2213.     }
  2214.     /**
  2215.      * Creates a touch command for use as a touch menu item
  2216.      * 
  2217.      * @param c command to map into the returned button
  2218.      * @return a button that would fire the touch command appropriately
  2219.      */
  2220.     protected Button createTouchCommandButton(Command c) {
  2221.         Button b = new Button(c);
  2222.         b.setTactileTouch(true);
  2223.         b.setTextPosition(Label.BOTTOM);
  2224.         b.setAlignment(CENTER);
  2225.         b.setUIID("TouchCommand");
  2226.         return b;
  2227.     }
  2228.     /**
  2229.      * Creates the component containing the commands within the given vector
  2230.      * used for showing the menu dialog, this method calls the createCommandList
  2231.      * method by default however it allows more elaborate menu creation.
  2232.      *
  2233.      * @param commands list of command objects
  2234.      * @return Component that will result in the parent menu dialog recieving a command event
  2235.      */
  2236.     protected Component createCommandComponent(Vector commands) {
  2237.         // Create a touch based menu interface
  2238.         if(UIManager.getInstance().getLookAndFeel().isTouchMenus()) {
  2239.             Container menu = new Container();
  2240.             for(int iter = 0 ; iter < commands.size() ; iter++) {
  2241.                 Command c = (Command)commands.elementAt(iter);
  2242.                 menu.addComponent(createTouchCommandButton(c));
  2243.             }
  2244.             int cols = calculateTouchCommandGridColumns(menu);
  2245.             menu.setLayout(new GridLayout(Math.max(1, commands.size() / cols + 
  2246.                     commands.size() % cols != 0 ? 1:0 ), cols));
  2247.             return menu;
  2248.         }
  2249.         return createCommandList(commands);
  2250.     }
  2251.     /**
  2252.      * Creates the list component containing the commands within the given vector
  2253.      * used for showing the menu dialog
  2254.      * 
  2255.      * @param commands list of command objects
  2256.      * @return List object
  2257.      */
  2258.     protected List createCommandList(Vector commands) {
  2259.         List l = new List(commands);
  2260.         l.setUIID("CommandList");
  2261.         Component c = (Component) l.getRenderer();
  2262.         c.setUIID("Command");
  2263.         c = l.getRenderer().getListFocusComponent(l);
  2264.         c.setUIID("CommandFocus");
  2265.         l.setFixedSelection(List.FIXED_NONE_CYCLIC);
  2266.         return l;
  2267.     }
  2268.     Command getComponentSelectedCommand(Component cmp) {
  2269.         if(cmp instanceof List) {
  2270.             List l = (List)cmp;
  2271.             return (Command) l.getSelectedItem();
  2272.         } else {
  2273.             cmp = cmp.getComponentForm().getFocused();
  2274.             if(cmp instanceof Button) {
  2275.                 return ((Button)cmp).getCommand();
  2276.             }
  2277.         }
  2278.         // nothing to do for this case...
  2279.         return null;
  2280.     }
  2281.     MenuBar getMenuBar() {
  2282.         return menuBar;
  2283.     }
  2284.     
  2285.     class MenuBar extends Container implements ActionListener {
  2286.         private Command menuCommand;
  2287.         private Vector commands = new Vector();
  2288.         private Button[] soft;
  2289.         private Command[] softCommand;
  2290.         private Button left;
  2291.         private Button right;
  2292.         private Button main;
  2293.         private ListCellRenderer menuCellRenderer;
  2294.         private Transition transitionIn;
  2295.         private Transition transitionOut;
  2296.         private Component commandList;
  2297.         private Style menuStyle;
  2298.         private int topMargin, bottomMargin;
  2299.         
  2300.         public MenuBar() {
  2301.             LookAndFeel lf = UIManager.getInstance().getLookAndFeel();
  2302.             menuStyle = UIManager.getInstance().getComponentStyle("Menu");
  2303.             setUnSelectedStyle(UIManager.getInstance().getComponentStyle("SoftButton"));
  2304.             menuCommand = new Command(UIManager.getInstance().localize("menu", "Menu"), lf.getMenuIcons()[2]);
  2305.             // use the slide transition by default
  2306.             if (lf.getDefaultMenuTransitionIn() != null || lf.getDefaultMenuTransitionOut() != null) {
  2307.                 transitionIn = lf.getDefaultMenuTransitionIn();
  2308.                 transitionOut = lf.getDefaultMenuTransitionOut();
  2309.             } else {
  2310.                 transitionIn = CommonTransitions.createSlide(CommonTransitions.SLIDE_VERTICAL, true, 300, true);
  2311.                 transitionOut = CommonTransitions.createSlide(CommonTransitions.SLIDE_VERTICAL, false, 300, true);
  2312.             }
  2313.             menuCellRenderer = lf.getMenuRenderer();
  2314.             if (Display.getInstance().getImplementation().getSoftkeyCount() > 1) {
  2315.                 if (Display.getInstance().isThirdSoftButton()) {
  2316.                     setLayout(new GridLayout(1, 3));
  2317.                     soft = new Button[]{createSoftButton(), createSoftButton(), createSoftButton()};
  2318.                     main = soft[0];
  2319.                     main.setAlignment(Label.CENTER);
  2320.                     left = soft[1];
  2321.                     right = soft[2];
  2322.                     if (Form.this.isRTL()) {
  2323.                      addComponent(right);
  2324.                      addComponent(main);
  2325.                      addComponent(left);
  2326.                     } else {
  2327.                      addComponent(left);
  2328.                      addComponent(main);
  2329.                      addComponent(right);
  2330.                     }
  2331.                     if (isReverseSoftButtons()) {
  2332.                         Button b = soft[1];
  2333.                         soft[1] = soft[2];
  2334.                         soft[2] = b;
  2335.                     }
  2336.                 } else {
  2337.                     setLayout(new GridLayout(1, 2));
  2338.                     soft = new Button[]{createSoftButton(), createSoftButton()};
  2339.                     main = soft[0];
  2340.                     left = soft[0];
  2341.                     right = soft[1];
  2342.                     if (Form.this.isRTL()) {
  2343.                     addComponent(right);
  2344.                     addComponent(left);
  2345.                     } else {
  2346.                     addComponent(left);
  2347.                     addComponent(right);
  2348.                     }
  2349.                     if (isReverseSoftButtons()) {
  2350.                         Button b = soft[0];
  2351.                         soft[0] = soft[1];
  2352.                         soft[1] = b;
  2353.                     }
  2354.                 }
  2355.                 // It doesn't make sense for softbuttons to have ... at the end
  2356.                 for(int iter = 0 ; iter < soft.length ; iter++) {
  2357.                     soft[iter].setEndsWith3Points(false);
  2358.                 }
  2359.             } else {
  2360.                 // special case for touch screens we still want the 3 softbutton areas...
  2361.                 if(Display.getInstance().isThirdSoftButton()) {
  2362.                     setLayout(new GridLayout(1, 3));
  2363.                     soft = new Button[]{createSoftButton(), createSoftButton(), createSoftButton()};
  2364.                     main = soft[0];
  2365.                     main.setAlignment(Label.CENTER);
  2366.                     left = soft[1];
  2367.                     right = soft[2];
  2368.                     addComponent(left);
  2369.                     addComponent(main);
  2370.                     addComponent(right);
  2371.                     if (isReverseSoftButtons()) {
  2372.                         Button b = soft[1];
  2373.                         soft[1] = soft[2];
  2374.                         soft[2] = b;
  2375.                     }
  2376.                 } else {
  2377.                     soft = new Button[]{createSoftButton()};
  2378.                 }
  2379.             }
  2380.             if (left != null) {
  2381.                 if (Form.this.isRTL()) {
  2382.                  left.setAlignment(Label.RIGHT);
  2383.                 right.setAlignment(Label.LEFT);
  2384.                 } else {
  2385.              left.setAlignment(Label.LEFT);
  2386.                 right.setAlignment(Label.RIGHT);
  2387.                 }
  2388.             }
  2389.             softCommand = new Command[soft.length];
  2390.         }
  2391.         /**
  2392.          * Updates the command mapping to the softbuttons
  2393.          */
  2394.         private void updateCommands() {
  2395.             if (soft.length > 1) {
  2396.                 soft[0].setText("");
  2397.                 soft[1].setText("");
  2398.                 soft[0].setIcon(null);
  2399.                 soft[1].setIcon(null);
  2400.                 int commandSize = commands.size();
  2401.                 if (soft.length > 2) {
  2402.                     soft[2].setText("");
  2403.                     if (commandSize > 2) {
  2404.                         if (commandSize > 3) {
  2405.                             softCommand[2] = menuCommand;
  2406.                         } else {
  2407.                             softCommand[2] = (Command) commands.elementAt(commands.size() - 3);
  2408.                         }
  2409.                         soft[2].setText(softCommand[2].getCommandName());
  2410.                         soft[2].setIcon(softCommand[2].getIcon());
  2411.                     } else {
  2412.                         softCommand[2] = null;
  2413.                     }
  2414.                 }
  2415.                 if (commandSize > 0) {
  2416.                     softCommand[0] = (Command) commands.elementAt(commands.size() - 1);
  2417.                     soft[0].setText(softCommand[0].getCommandName());
  2418.                     soft[0].setIcon(softCommand[0].getIcon());
  2419.                     if (commandSize > 1) {
  2420.                         if (soft.length == 2 && commandSize > 2) {
  2421.                             softCommand[1] = menuCommand;
  2422.                         } else {
  2423.                             softCommand[1] = (Command) commands.elementAt(commands.size() - 2);
  2424.                         }
  2425.                         soft[1].setText(softCommand[1].getCommandName());
  2426.                         soft[1].setIcon(softCommand[1].getIcon());
  2427.                     } else {
  2428.                         softCommand[1] = null;
  2429.                     }
  2430.                 } else {
  2431.                     softCommand[0] = null;
  2432.                     softCommand[1] = null;
  2433.                 }
  2434.                 // we need to add the menu bar to an already visible form
  2435.                 if (commandSize == 1) {
  2436.                     if (Form.this.isVisible()) {
  2437.                         Form.this.revalidate();
  2438.                     }
  2439.                 }
  2440.                 repaint();
  2441.             }
  2442.         }
  2443.         /**
  2444.          * Invoked when a softbutton is pressed
  2445.          */
  2446.         public void actionPerformed(ActionEvent evt) {
  2447.             if (evt.isConsumed()) {
  2448.                 return;
  2449.             }
  2450.             Object src = evt.getSource();
  2451.             if (commandList == null) {
  2452.                 Button source = (Button) src;
  2453.                 for (int iter = 0; iter < soft.length; iter++) {
  2454.                     if (source == soft[iter]) {
  2455.                         if (softCommand[iter] == menuCommand) {
  2456.                             showMenu();
  2457.                             return;
  2458.                         }
  2459.                         if (softCommand[iter] != null) {
  2460.                             ActionEvent e = new ActionEvent(softCommand[iter]);
  2461.                             softCommand[iter].actionPerformed(e);
  2462.                             if (!e.isConsumed()) {
  2463.                                 actionCommandImpl(softCommand[iter]);
  2464.                             }
  2465.                         }
  2466.                         return;
  2467.                     }
  2468.                 }
  2469.             } else {
  2470.                 // the list for the menu sent the event
  2471.                 if (src instanceof Button) {
  2472.                     for (int iter = 0; iter < soft.length; iter++) {
  2473.                         if (src == soft[iter]) {
  2474.                             Container parent = commandList.getParent();
  2475.                             while (parent != null) {
  2476.                                 if (parent instanceof Dialog) {
  2477.                                     ((Dialog) parent).actionCommand(softCommand[iter]);
  2478.                                     return;
  2479.                                 }
  2480.                                 parent = parent.getParent();
  2481.                             }
  2482.                         }
  2483.                     }
  2484.                 }
  2485.                 Command c = getComponentSelectedCommand(commandList);
  2486.                 Container parent = commandList.getParent();
  2487.                 while (parent != null) {
  2488.                     if (parent instanceof Dialog) {
  2489.                         ((Dialog) parent).actionCommand(c);
  2490.                         return;
  2491.                     }
  2492.                     parent = parent.getParent();
  2493.                 }
  2494.             }
  2495.         }
  2496.         private Button createSoftButton() {
  2497.             Button b = new Button();
  2498.             b.addActionListener(this);
  2499.             b.setFocusPainted(false);
  2500.             b.setFocusable(false);
  2501.             b.setTactileTouch(true);
  2502.             updateSoftButtonStyle(b);
  2503.             return b;
  2504.         }
  2505.         private void updateSoftButtonStyle(Button b) {
  2506.             Style s = new Style(getUnselectedStyle());
  2507.             b.setUnSelectedStyle(s);
  2508.             b.setPressedStyle(s);
  2509.             s.setBgImage(null);
  2510.             s.setBorder(null);
  2511.             s.setBackgroundType(Style.BACKGROUND_IMAGE_SCALED);
  2512.             if(soft != null && soft.length > 1) {
  2513.                 s.setMargin(topMargin, bottomMargin, 2, 2);
  2514.             } else {
  2515.                 s.setMargin(0, 0, 0, 0);
  2516.                 s.setPadding(0, 0, 0, 0);
  2517.             }
  2518.             s.setBgTransparency(0);
  2519.             
  2520.         }
  2521.         public void setUnSelectedStyle(Style style) {
  2522.             topMargin = style.getMargin(false, Component.TOP);
  2523.             bottomMargin = style.getMargin(false, Component.BOTTOM);
  2524.             style.setMargin(Component.TOP, 0, true);
  2525.             style.setMargin(Component.BOTTOM, 0, true);
  2526.             super.setUnSelectedStyle(style);
  2527.             if(soft != null){
  2528.                 for (int iter = 0; iter < soft.length; iter++) {
  2529.                     updateSoftButtonStyle(soft[iter]);
  2530.                 }
  2531.             }
  2532.         }
  2533.         
  2534.         /**
  2535.          * Prevents scaling down of the menu when there is no text on the menu bar 
  2536.          */
  2537.         protected Dimension calcPreferredSize() {
  2538.             if (soft.length > 1) {
  2539.                 Dimension d = super.calcPreferredSize();
  2540.                 if ((soft[0].getText() == null || soft[0].getText().equals("")) &&
  2541.                         (soft[1].getText() == null || soft[1].getText().equals("")) &&
  2542.                         soft[0].getIcon() == null && soft[1].getIcon() == null) {
  2543.                     d.setHeight(0);
  2544.                 }
  2545.                 return d;
  2546.             }
  2547.             return super.calcPreferredSize();
  2548.         }
  2549.         /**
  2550.          * Sets the menu transitions for showing/hiding the menu, can be null...
  2551.          */
  2552.         public void setTransitions(Transition transitionIn, Transition transitionOut) {
  2553.             this.transitionIn = transitionIn;
  2554.             this.transitionOut = transitionOut;
  2555.         }
  2556.         private void showMenu() {
  2557.             final Dialog d = new Dialog();
  2558.             d.setDisposeWhenPointerOutOfBounds(true);
  2559.             d.setDialogStyle(new Style(menuStyle));
  2560.             d.setMenu(true);
  2561.             d.setSoftButtonStyle(new Style(getSoftButtonStyle()));
  2562.             menuStyle.removeStyleListener(d.getContentPane());
  2563.             d.setTransitionInAnimator(transitionIn);
  2564.             d.setTransitionOutAnimator(transitionOut);
  2565.             d.setLayout(new BorderLayout());
  2566.             d.setScrollable(false);
  2567.             ((Form) d).menuBar.commandList = createCommandComponent(commands);
  2568.             if (menuCellRenderer != null && ((Form) d).menuBar.commandList instanceof List) {
  2569.                 ((List)((Form) d).menuBar.commandList).setListCellRenderer(menuCellRenderer);
  2570.             }
  2571.             d.getContentPane().getStyle().setMargin(0, 0, 0, 0);
  2572.             d.addComponent(BorderLayout.CENTER, ((Form) d).menuBar.commandList);
  2573.             if (Display.getInstance().isThirdSoftButton()) {
  2574.                 d.addCommand(selectMenuItem);
  2575.                 d.addCommand(cancelMenuItem);
  2576.             } else {
  2577.                 d.addCommand(cancelMenuItem);
  2578.                 if(soft.length > 1) {
  2579.                     d.addCommand(selectMenuItem);
  2580.                 }
  2581.             }
  2582.             d.setClearCommand(cancelMenuItem);
  2583.             d.setBackCommand(cancelMenuItem);
  2584.             if(((Form) d).menuBar.commandList instanceof List) {
  2585.                 ((List)((Form) d).menuBar.commandList).addActionListener(((Form) d).menuBar);
  2586.             }
  2587.             Command result = showMenuDialog(d);
  2588.             if (result != cancelMenuItem) {
  2589.                 Command c = null;
  2590.                 if (result == selectMenuItem) {
  2591.                     c = getComponentSelectedCommand(((Form) d).menuBar.commandList);
  2592.                     if (c != null) {
  2593.                         ActionEvent e = new ActionEvent(c);
  2594.                         c.actionPerformed(e);
  2595.                     }
  2596.                 } else {
  2597.                     c = result;
  2598.                     // a touch menu will always send its commands on its own...
  2599.                     if(!UIManager.getInstance().getLookAndFeel().isTouchMenus()) {
  2600.                         c = result;
  2601.                         if (c != null) {
  2602.                             ActionEvent e = new ActionEvent(c);
  2603.                             c.actionPerformed(e);
  2604.                         }
  2605.                     }
  2606.                 }
  2607.                 // menu item was handled internally in a touch interface that is not a touch menu
  2608.                 if (c != null) {
  2609.                     actionCommandImpl(c);
  2610.                 }
  2611.             }
  2612.             if(((Form) d).menuBar.commandList instanceof List) {
  2613.                 ((List)((Form) d).menuBar.commandList).removeActionListener(((Form) d).menuBar);
  2614.             }
  2615.             
  2616.             Form upcoming = Display.getInstance().getCurrentUpcoming();
  2617.             if (upcoming == Form.this) {
  2618.                 d.disposeImpl();
  2619.             } else {
  2620.                 Form.this.tint = (upcoming instanceof Dialog);
  2621.             }
  2622.         }
  2623.         public Button[] getSoftButtons() {
  2624.             return soft;
  2625.         }
  2626.         public String getUIID() {
  2627.             return "SoftButton";
  2628.         }
  2629.         public void addCommand(Command cmd) {
  2630.             // prevent duplicate commands which might happen in some edge cases
  2631.             // with the select command
  2632.             if (commands.contains(cmd)) {
  2633.                 return;
  2634.             }
  2635.             // special case for default commands which are placed at the end and aren't overriden later
  2636.             if (soft.length > 2 && cmd == getDefaultCommand()) {
  2637.                 commands.addElement(cmd);
  2638.             } else {
  2639.                 commands.insertElementAt(cmd, 0);
  2640.             }
  2641.             updateCommands();
  2642.         }
  2643.         /**
  2644.          * Returns the command occupying the given index
  2645.          * 
  2646.          * @param index offset of the command
  2647.          * @return the command at the given index
  2648.          */
  2649.         public Command getCommand(int index) {
  2650.             return (Command) commands.elementAt(index);
  2651.         }
  2652.         public int getCommandCount() {
  2653.             return commands.size();
  2654.         }
  2655.         public void addCommand(Command cmd, int index) {
  2656.             // prevent duplicate commands which might happen in some edge cases
  2657.             // with the select command
  2658.             if (commands.contains(cmd)) {
  2659.                 return;
  2660.             }
  2661.             commands.insertElementAt(cmd, index);
  2662.             updateCommands();
  2663.         }
  2664.         public void removeAllCommands() {
  2665.             commands.removeAllElements();
  2666.             updateCommands();
  2667.         }
  2668.         public void removeCommand(Command cmd) {
  2669.             commands.removeElement(cmd);
  2670.             updateCommands();
  2671.         }
  2672.         public void setMenuCellRenderer(ListCellRenderer menuCellRenderer) {
  2673.             this.menuCellRenderer = menuCellRenderer;
  2674.         }
  2675.         public Style getMenuStyle() {
  2676.             return menuStyle;
  2677.         }
  2678.         public void keyPressed(int keyCode) {
  2679.             if (commands.size() > 0) {
  2680.                 if (keyCode == leftSK) {
  2681.                     if (left != null) {
  2682.                         left.pressed();
  2683.                     }
  2684.                 } else {
  2685.                     // it might be a back command or the fire...
  2686.                     if ((keyCode == rightSK || keyCode == rightSK2)) {
  2687.                         if (right != null) {
  2688.                             right.pressed();
  2689.                         }
  2690.                     } else {
  2691.                         if (Display.getInstance().getGameAction(keyCode) == Display.GAME_FIRE) {
  2692.                             main.pressed();
  2693.                         }
  2694.                     }
  2695.                 }
  2696.             }
  2697.         }
  2698.         public void keyReleased(int keyCode) {
  2699.             if (commands.size() > 0) {
  2700.                 if (Display.getInstance().getImplementation().getSoftkeyCount() < 2 && keyCode == leftSK) {
  2701.                     if (commandList != null) {
  2702.                         Container parent = commandList.getParent();
  2703.                         while (parent != null) {
  2704.                             if (parent instanceof Dialog && ((Dialog) parent).isMenu()) {
  2705.                                 return;
  2706.                             }
  2707.                             parent = parent.getParent();
  2708.                         }
  2709.                     }
  2710.                     showMenu();
  2711.                     return;
  2712.                 } else {
  2713.                     if (keyCode == leftSK) {
  2714.                         if (left != null) {
  2715.                             left.released();
  2716.                         }
  2717.                         return;
  2718.                     } else {
  2719.                         // it might be a back command...
  2720.                         if ((keyCode == rightSK || keyCode == rightSK2)) {
  2721.                             if (right != null) {
  2722.                                 right.released();
  2723.                             }
  2724.                             return;
  2725.                         } else {
  2726.                             if (Display.getInstance().getGameAction(keyCode) == Display.GAME_FIRE) {
  2727.                                 main.released();
  2728.                                 return;
  2729.                             }
  2730.                         }
  2731.                     }
  2732.                 }
  2733.             }
  2734.             // allows a back/clear command to occur regardless of whether the
  2735.             // command was added to the form
  2736.             Command c = null;
  2737.             if (keyCode == backSK) {
  2738.                 // the back command should be invoked
  2739.                 c = getBackCommand();
  2740.             } else {
  2741.                 if (keyCode == clearSK || keyCode == backspaceSK) {
  2742.                     c = getClearCommand();
  2743.                 }
  2744.             }
  2745.             if (c != null) {
  2746.                 ActionEvent ev = new ActionEvent(c, keyCode);
  2747.                 c.actionPerformed(ev);
  2748.                 if(!ev.isConsumed()) {
  2749.                     actionCommandImpl(c);
  2750.                 }
  2751.             }
  2752.         }
  2753.         public void refreshTheme() {
  2754.             super.refreshTheme();
  2755.             if (menuStyle.isModified()) {
  2756.                 menuStyle.merge(UIManager.getInstance().getComponentStyle("Menu"));
  2757.             } else {
  2758.                 menuStyle = UIManager.getInstance().getComponentStyle("Menu");
  2759.             }
  2760.             if (menuCellRenderer != null) {
  2761.                 List tmp = new List();
  2762.                 tmp.setListCellRenderer(menuCellRenderer);
  2763.                 tmp.refreshTheme();
  2764.             }
  2765.             for (int iter = 0; iter < soft.length; iter++) {
  2766.                 updateSoftButtonStyle(soft[iter]);
  2767.             }
  2768.             
  2769.             revalidate();
  2770.         }
  2771.     }
  2772. }