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

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.Transition;
  28. import com.sun.lwuit.layouts.BorderLayout;
  29. import com.sun.lwuit.layouts.FlowLayout;
  30. import com.sun.lwuit.layouts.Layout;
  31. import com.sun.lwuit.plaf.UIManager;
  32. import com.sun.lwuit.geom.Dimension;
  33. import com.sun.lwuit.geom.Rectangle;
  34. import com.sun.lwuit.plaf.LookAndFeel;
  35. import java.util.Vector;
  36. /**
  37.  * A composite pattern with {@link Component}, allows nesting and arranging multiple
  38.  * components using a pluggable layout manager architecture. Containers can be nested
  39.  * one within the other to form elaborate UI's.
  40.  *
  41.  * @see com.sun.lwuit.layouts
  42.  * @see Component
  43.  * @author Chen Fishbein
  44.  */
  45. public class Container extends Component {
  46.     private Layout layout;
  47.     private java.util.Vector components = new java.util.Vector();
  48.     private boolean shouldLayout = true;
  49.     private boolean scrollableX;
  50.     private boolean scrollableY;
  51.     private java.util.Vector cmpTransitions;
  52.     private int scrollIncrement = 20;
  53.     
  54.     /**
  55.      * Constructs a new Container with a new layout manager.
  56.      * 
  57.      * @param layout the specified layout manager
  58.      */
  59.     public Container(Layout layout) {
  60.         super();
  61.         setUIID("Container");
  62.         this.layout = layout;
  63.         setFocusable(false);
  64.         LookAndFeel laf = UIManager.getInstance().getLookAndFeel();
  65.         setSmoothScrolling(laf.isDefaultSmoothScrolling());
  66.     }
  67.     /** 
  68.      * Constructs a new Container, with a {@link FlowLayout}. 
  69.      */
  70.     public Container() {
  71.         this(new FlowLayout());
  72.     }
  73.     /**
  74.      * Returns the layout manager responsible for arranging this container
  75.      * 
  76.      * @return the container layout manager
  77.      */
  78.     public Layout getLayout() {
  79.         return layout;
  80.     }
  81.     /**
  82.      * Sets the layout manager responsible for arranging this container
  83.      * 
  84.      * @param layout the specified layout manager
  85.      */
  86.     public void setLayout(Layout layout) {
  87.         this.layout = layout;
  88.     }
  89.     /**
  90.      * Same as setShouldCalcPreferredSize(true) but made accessible for 
  91.      * layout managers
  92.      */
  93.     public void invalidate() {
  94.         setShouldCalcPreferredSize(true);
  95.     }
  96.     /**
  97.      * @inheritDoc
  98.      */
  99.     protected void setShouldCalcPreferredSize(boolean shouldCalcPreferredSize) {
  100.         super.setShouldCalcPreferredSize(shouldCalcPreferredSize);
  101.         shouldLayout = shouldCalcPreferredSize;
  102.         if (shouldLayout) {
  103.             int size = components.size();
  104.             for(int iter = 0 ; iter < size ; iter++) {
  105.                 Component cmp = (Component) components.elementAt(iter);
  106.                 if (cmp instanceof Container) {
  107.                     ((Container) cmp).setShouldCalcPreferredSize(shouldCalcPreferredSize);
  108.                 }
  109.             }
  110.         }
  111.         Form f = getComponentForm();
  112.         if (f != null) {
  113.             f.clearFocusVectors();
  114.         }
  115.     }
  116.     /**
  117.      * Returns the width for layout manager purposes, this takes scrolling
  118.      * into consideration unlike the getWidth method.
  119.      * 
  120.      * @return the layout width
  121.      */
  122.     public int getLayoutWidth() {
  123.         if (isScrollableX()) {
  124.             return Math.max(getWidth(), getPreferredW());
  125.         } else {
  126.             Container parent = getScrollableParent();
  127.             if (parent != null && parent.isScrollableX()) {
  128.                 return Math.max(getWidth(), getPreferredW());
  129.             }
  130.             int width = getWidth();
  131.             if (width <= 0) {
  132.                 return getPreferredW();
  133.             }
  134.             return width;
  135.         }
  136.     }
  137.     /**
  138.      * Invokes apply/setRTL recursively on all the children components of this container
  139.      * 
  140.      * @param rtl right to left bidi indication
  141.      * @see Component#setRTL(boolean) 
  142.      */
  143.     public void applyRTL(boolean rtl) {
  144.         setRTL(rtl);
  145.         int c = getComponentCount();
  146.         for(int iter = 0 ; iter < c ; iter++) {
  147.             Component current = getComponentAt(iter);
  148.             if(current instanceof Container) {
  149.                 ((Container)current).applyRTL(rtl);
  150.             } else {
  151.                 current.setRTL(rtl);
  152.             }
  153.         }
  154.     }
  155.     /**
  156.      * Returns the height for layout manager purposes, this takes scrolling
  157.      * into consideration unlike the getWidth method.
  158.      * 
  159.      * @return the layout height
  160.      */
  161.     public int getLayoutHeight() {
  162.         if (isScrollableY()) {
  163.             return Math.max(getHeight(), getPreferredH());
  164.         } else {
  165.             Container parent = getScrollableParent();
  166.             if (parent != null && parent.isScrollableY()) {
  167.                 return Math.max(getHeight(), getPreferredH());
  168.             }
  169.             int height = getHeight();
  170.             if (height <= 1) {
  171.                 return getPreferredH();
  172.             }
  173.             return height;
  174.         }
  175.     }
  176.     /**
  177.      * Returns a parent container that is scrollable or null if no parent is 
  178.      * scrollable.
  179.      * 
  180.      * @return a parent container that is scrollable or null if no parent is 
  181.      * scrollable.
  182.      */
  183.     private Container getScrollableParent() {
  184.         Container parent = getParent();
  185.         while (parent != null) {
  186.             if (parent.isScrollable()) {
  187.                 return parent;
  188.             }
  189.             parent = parent.getParent();
  190.         }
  191.         return null;
  192.     }
  193.     /**
  194.      * Adds a Component to the Container
  195.      * 
  196.      * @param cmp the component to be added
  197.      */
  198.     public void addComponent(Component cmp) {
  199.         layout.addLayoutComponent(null, cmp, this);
  200.         insertComponentAt(components.size(), cmp);
  201.     }
  202.     /**
  203.      * Adds a Component to the Container
  204.      * 
  205.      * @param constraints this method is useful when the Layout requires a constraint
  206.      * such as the BorderLayout.
  207.      * In this case you need to specify an additional data when you add a Component,
  208.      * such as "CENTER", "NORTH"...
  209.      *
  210.      * @param cmp component to add
  211.      */
  212.     public void addComponent(Object constraints, Component cmp) {
  213.         layout.addLayoutComponent(constraints, cmp, this);
  214.         insertComponentAt(components.size(), cmp);
  215.     }
  216.     /**
  217.      * Adds a Component to the Container
  218.      * 
  219.      * @param index location to insert the Component
  220.      * @param constraints this method is useful when the Layout requires a constraint
  221.      * such as the BorderLayout.
  222.      * In this case you need to specify an additional data when you add a Component,
  223.      * such as "CENTER", "NORTH"...
  224.      * @param cmp component to add
  225.      */
  226.     public void addComponent(int index, Object constraints, Component cmp) {
  227.         layout.addLayoutComponent(constraints, cmp, this);
  228.         insertComponentAt(index, cmp);
  229.     }
  230.     private void insertComponentAt(int index, Component cmp) {
  231.         if (cmp.getParent() != null) {
  232.             throw new IllegalArgumentException("Component is already contained in Container: " + cmp.getParent());
  233.         }
  234.         if (cmp instanceof Form) {
  235.             throw new IllegalArgumentException("A form cannot be added to a container");
  236.         }
  237.         cmp.setParent(this);
  238.         components.insertElementAt(cmp, index);
  239.         setShouldCalcPreferredSize(true);
  240.         if (isInitialized()) {
  241.             cmp.initComponentImpl();
  242.         }
  243.         Form f = getComponentForm();
  244.         if (f != null) {
  245.             f.clearFocusVectors();
  246.         }
  247.     //repaint();
  248.     }
  249.     /**
  250.      * This method adds the Component at a specific index location in the Container
  251.      * Components array.
  252.      * 
  253.      * @param index location to insert the Component
  254.      * @param cmp the Component to add
  255.      * @throws ArrayIndexOutOfBoundsException if index is out of bounds
  256.      * @throws IllegalArgumentException if Component is already contained or
  257.      * the cmp is a Form Component
  258.      */
  259.     public void addComponent(int index, Component cmp) {
  260.         insertComponentAt(index, cmp);
  261.     }
  262.     /**
  263.      * This method replaces the current Component with the next Component.
  264.      * Current Component must be contained in this Container.
  265.      * This method returns when transition has finished.
  266.      * 
  267.      * @param current a Component to remove from the Container
  268.      * @param next a Component that replaces the current Component
  269.      * @param t a Transition between the add and removal of the Components
  270.      *  a Transition can be null
  271.      */
  272.     public void replaceAndWait(final Component current, final Component next, final Transition t) {
  273.         replaceComponents(current, next, t, true);
  274.     }
  275.     /**
  276.      * This method replaces the current Component with the next Component.
  277.      * Current Component must be contained in this Container.
  278.      * This method return immediately.
  279.      * 
  280.      * @param current a Component to remove from the Container
  281.      * @param next a Component that replaces the current Component
  282.      * @param t a Transition between the add and removal of the Components
  283.      *  a Transition can be null
  284.      */
  285.     public void replace(final Component current, final Component next, final Transition t) {
  286.         replaceComponents(current, next, t, false);
  287.     }
  288.     private void replaceComponents(final Component current, final Component next, final Transition t, boolean wait) {
  289.         if (!contains(current)) {
  290.             throw new IllegalArgumentException("Component " + current + " is not contained in this Container");
  291.         }
  292.         if (t == null || !isVisible() || getComponentForm() == null) {
  293.             replace(current, next);
  294.             return;
  295.         }
  296.         next.setX(current.getX());
  297.         next.setY(current.getY());
  298.         next.setWidth(current.getWidth());
  299.         next.setHeight(current.getHeight());
  300.         next.setParent(this);
  301.         if (next instanceof Container) {
  302.             ((Container) next).layoutContainer();
  303.         }
  304.         final Anim anim = new Anim(this, current, next, t);
  305.         // register the transition animation
  306.         getComponentForm().registerAnimatedInternal(anim);
  307.         //wait until animation has finished
  308.         if (wait) {
  309.             Display.getInstance().invokeAndBlock(anim);
  310.         }
  311.     }
  312.     private boolean isParentOf(Component c) {
  313.         c = c.getParent();
  314.         if (c == null || c instanceof Form) {
  315.             return false;
  316.         }
  317.         return (c == this) || isParentOf(c);
  318.     }
  319.     private boolean requestFocusChild() {
  320.         for (int iter = 0; iter < getComponentCount(); iter++) {
  321.             Component c = getComponentAt(iter);
  322.             if (c.isFocusable()) {
  323.                 c.requestFocus();
  324.                 return true;
  325.             }
  326.             if (c instanceof Container && ((Container) c).requestFocusChild()) {
  327.                 return true;
  328.             }
  329.         }
  330.         return false;
  331.     }
  332.     void replace(final Component current, final Component next) {
  333.         int index = components.indexOf(current);
  334.         boolean currentFocused = false;
  335.         if (current.getComponentForm() != null) {
  336.             Component currentF = current.getComponentForm().getFocused();
  337.             currentFocused = currentF == current;
  338.             if (!currentFocused && current instanceof Container && currentF != null && ((Container) current).isParentOf(currentF)) {
  339.                 currentFocused = true;
  340.             }
  341.         }
  342.         if (layout instanceof BorderLayout) {
  343.             Object constraint = layout.getComponentConstraint(current);
  344.             removeComponentImpl(current);
  345.             layout.addLayoutComponent(constraint, next, Container.this);
  346.         } else {
  347.             removeComponentImpl(current);
  348.         }
  349.         next.setParent(null);
  350.         if (index < 0) {
  351.             index = 0;
  352.         }
  353.         insertComponentAt(index, next);
  354.         if (currentFocused) {
  355.             if (next.isFocusable()) {
  356.                 next.requestFocus();
  357.             } else {
  358.                 if (next instanceof Container) {
  359.                     ((Container) next).requestFocusChild();
  360.                 }
  361.             }
  362.         }
  363.     }
  364.     /**
  365.      * @inheritDoc
  366.      */
  367.     void initComponentImpl() {
  368.         if (!isInitialized()) {
  369.             super.initComponentImpl();
  370.         }
  371.         int size = components.size();
  372.         for(int iter = 0 ; iter < size ; iter++) {
  373.             ((Component) components.elementAt(iter)).initComponentImpl();
  374.         }
  375.     }
  376.     /**
  377.      * removes a Component from the Container
  378.      *
  379.      * @param cmp the removed component
  380.      */
  381.     public void removeComponent(Component cmp) {
  382.         removeComponentImpl(cmp);
  383.     }
  384.     /**
  385.      * removes a Component from the Container
  386.      * 
  387.      * @param cmp the removed component
  388.      */
  389.     void removeComponentImpl(Component cmp) {
  390.         Form parentForm = cmp.getComponentForm();
  391.         layout.removeLayoutComponent(cmp);
  392.         cmp.deinitializeImpl();
  393.         components.removeElement(cmp);
  394.         cmp.setParent(null);
  395.         cmp.setShouldCalcPreferredSize(true);
  396.         if (parentForm != null) {
  397.             if (parentForm.getFocused() == cmp || cmp instanceof Container && ((Container) cmp).contains(parentForm.getFocused())) {
  398.                 parentForm.setFocused(null);
  399.             }
  400.             parentForm.clearFocusVectors();
  401.             if (cmp.isSmoothScrolling()) {
  402.                 parentForm.deregisterAnimatedInternal(cmp);
  403.             }
  404.         }
  405.         setShouldCalcPreferredSize(true);
  406.     }
  407.     /**
  408.      * Cleansup the initialization flags in the hierachy
  409.      */
  410.     void deinitializeImpl() {
  411.         super.deinitializeImpl();
  412.         int size = components.size();
  413.         for (int iter = 0; iter < size; iter++) {
  414.             ((Component) components.elementAt(iter)).deinitializeImpl();
  415.         }
  416.         flushReplace();
  417.     }
  418.     /**
  419.      * Flushes ongoing replace operations to prevent two concurrent replace operations from colliding.
  420.      * If there is no ongoing replace nothing will occur
  421.      */
  422.     public void flushReplace() {
  423.         if (cmpTransitions != null) {
  424.             int size = cmpTransitions.size();
  425.             for (int iter = 0; iter < size; iter++) {
  426.                 ((Anim) cmpTransitions.elementAt(iter)).destroy();
  427.             }
  428.             cmpTransitions.removeAllElements();
  429.             cmpTransitions = null;
  430.         }
  431.     }
  432.     /**
  433.      * remove all Components from container
  434.      */
  435.     public void removeAll() {
  436.         Form parentForm = getComponentForm();
  437.         if (parentForm != null) {
  438.             Component focus = parentForm.getFocused();
  439.             if (focus != null && contains(focus)) {
  440.                 parentForm.setFocused(null);
  441.             }
  442.         }
  443.         Object[] arr = new Object[components.size()];
  444.         components.copyInto(arr);
  445.         for (int i = 0; i < arr.length; i++) {
  446.             removeComponent((Component) arr[i]);
  447.         }
  448.     }
  449.     /**
  450.      * Re-layout the container, this is useful when we modify the container hierarchy and
  451.      * need to redo the layout
  452.      */
  453.     public void revalidate() {
  454.         setShouldCalcPreferredSize(true);
  455.         Form root = getComponentForm();
  456.         
  457.         if (root != null) {
  458.             root.layoutContainer();
  459.             root.repaint();
  460.         } else {
  461.             layoutContainer();
  462.             repaint();
  463.         }
  464.     }
  465.     /**
  466.      * @inheritDoc
  467.      */
  468.     public void paint(Graphics g) {
  469.         layoutContainer();
  470.         g.translate(getX(), getY());
  471.         int size = components.size();
  472.         for (int i = 0; i < size; i++) {
  473.             Component cmp = (Component)components.elementAt(i);
  474.             cmp.paintInternal(g, false);
  475.         }
  476.         g.translate(-getX(), -getY());
  477.     }
  478.     void paintIntersecting(Graphics g, Component cmp, int x, int y, int w, int h, boolean above) {
  479.         if (layout.isOverlapSupported() && components.contains(cmp)) {
  480.             int indexOfComponent = components.indexOf(cmp);
  481.             
  482.             int startIndex;
  483.             int endIndex;
  484.             if (above) {
  485.                 startIndex = indexOfComponent + 1;
  486.                 endIndex = components.size();
  487.             } else {
  488.                 startIndex = 0;
  489.                 endIndex = indexOfComponent;
  490.             }
  491.             for (int i = startIndex; i < endIndex; i++) {
  492.                 Component cmp2 = (Component) components.elementAt(i);
  493.                 if(Rectangle.intersects(x, y, w, h,
  494.                         cmp2.getAbsoluteX() + cmp2.getScrollX(),
  495.                         cmp2.getAbsoluteY() + cmp2.getScrollY(),
  496.                         cmp2.getBounds().getSize().getWidth(),
  497.                         cmp2.getBounds().getSize().getHeight())){
  498.                     cmp2.paintInternal(g, false);
  499.                 }
  500.             }
  501.         }
  502.     }
  503.     /**
  504.      * Performs the layout of the container if a layout is necessary
  505.      */
  506.     public void layoutContainer() {
  507.         //will compute the container + components and will layout the components.
  508.         if (shouldLayout) {
  509.             shouldLayout = false;
  510.             doLayout();
  511.         }
  512.     }
  513.     /**
  514.      * Lays out the container
  515.      */
  516.     void doLayout() {
  517.         layout.layoutContainer(this);
  518.         int count = getComponentCount();
  519.         for (int i = 0; i < count; i++) {
  520.             Component c = getComponentAt(i);
  521.             if (c instanceof Container) {
  522.                 ((Container) c).doLayout();
  523.             }else{
  524.                 c.laidOut();
  525.             }
  526.         }
  527.         laidOut();
  528.     }
  529.     /**
  530.      * Returns the number of components
  531.      * 
  532.      * @return the Component count
  533.      */
  534.     public int getComponentCount() {
  535.         return components.size();
  536.     }
  537.     /**
  538.      * Returns the Component at a given index
  539.      * 
  540.      * @param index of the Component you wish to get
  541.      * @return a Component
  542.      * @throws ArrayIndexOutOfBoundsException if an invalid index was given.
  543.      */
  544.     public Component getComponentAt(
  545.             int index) {
  546.         return (Component) components.elementAt(index);
  547.     }
  548.     /**
  549.      * Returns the Component index in the Container
  550.      * 
  551.      * @param cmp the component to search for
  552.      * @return the Component index in the Container or -1 if not found
  553.      */
  554.     public int getComponentIndex(Component cmp) {
  555.         int count = getComponentCount();
  556.         for (int i = 0; i <
  557.                 count; i++) {
  558.             Component c = getComponentAt(i);
  559.             if (c.equals(cmp)) {
  560.                 return i;
  561.             }
  562.         }
  563.         return -1;
  564.     }
  565.     /**
  566.      * Returns true if the given component is within the hierarchy of this container
  567.      *
  568.      * @param cmp a Component to check
  569.      * @return true if this Component contains in this Container
  570.      */
  571.     public boolean contains(Component cmp) {
  572.         boolean found = false;
  573.         int count = getComponentCount();
  574.         for (int i = 0; i < count; i++) {
  575.             Component c = getComponentAt(i);
  576.             if (c.equals(cmp)) {
  577.                 return true;
  578.             }
  579.             if (c instanceof Container) {
  580.                 found = ((Container) c).contains(cmp);
  581.                 if (found) {
  582.                     return true;
  583.                 }
  584.             }
  585.         }
  586.         return false;
  587.     }
  588.     /**
  589.      * Makes sure the component is visible in the scroll if this container is 
  590.      * scrollable
  591.      * 
  592.      * @param c the component that will be scrolling for visibility
  593.      */
  594.     protected void scrollComponentToVisible(Component c) {
  595.         if (isScrollable()) {
  596.             if (c != null) {
  597.                 Rectangle r = c.getVisibleBounds();
  598.                 if (c.getParent() != null) {
  599.                     // special case for the first component to allow the user to scroll all the 
  600.                     // way to the top
  601.                     Form f = getComponentForm();
  602.                     if (f != null && f.getFocusPosition(c) == 0) {
  603.                         // support this use case only if the component doesn't explicitly declare visible bounds
  604.                         if(r == c.getBounds()) {
  605.                             scrollRectToVisible(new Rectangle(0, 0, 
  606.                                     c.getX() + Math.min(c.getWidth(), getWidth()), 
  607.                                     c.getY() + Math.min(c.getHeight(), getHeight())), this);
  608.                             return;
  609.                         }
  610.                     }
  611.                 }
  612.                 scrollRectToVisible(r.getX(), r.getY(), 
  613.                         Math.min(r.getSize().getWidth(), getWidth()), 
  614.                         Math.min(r.getSize().getHeight(), getHeight()), c);
  615.             }
  616.         }
  617.     }
  618.     /**
  619.      * This method scrolls the Container if Scrollable towards the given 
  620.      * Component based on the given direction.
  621.      * 
  622.      * @param direction is the direction of the navigation (Display.GAME_UP, 
  623.      * Display.GAME_DOWN, ...) 
  624.      * @param next the Component to move the scroll towards.
  625.      * 
  626.      * @return true if next Component is now visible.
  627.      */    
  628.     boolean moveScrollTowards(int direction, Component next) {
  629.         if (isScrollable()) {
  630.             Component current = null;
  631.             Form f = getComponentForm();
  632.             if (f != null) {
  633.                 current = f.getFocused();
  634.             }
  635.             int position = f.getFocusPosition(current);
  636.             boolean edge = false;
  637.             boolean currentLarge = false;
  638.             boolean scrollOutOfBounds = false;
  639.             
  640.             int x = getScrollX();
  641.             int y = getScrollY();
  642.             int w = getWidth();
  643.             int h = getHeight();
  644.             switch (direction) {
  645.                 case Display.GAME_UP:
  646.                     y = getScrollY() - scrollIncrement;
  647.                     edge = (position == 0);
  648.                     currentLarge = (current != null && current.getVisibleBounds().getSize().getHeight() > getHeight());
  649.                     scrollOutOfBounds = y < 0;
  650.                     break;
  651.                 case Display.GAME_DOWN:
  652.                     y = getScrollY() + scrollIncrement;
  653.                     edge = (position == f.getFocusCount() - 1);
  654.                     currentLarge = (current != null && current.getVisibleBounds().getSize().getHeight() > getHeight());
  655.                     scrollOutOfBounds = y > getScrollDimension().getHeight() - getHeight();
  656.                     break;
  657.                 case Display.GAME_RIGHT:
  658.                     x = getScrollX() + scrollIncrement;
  659.                     edge = (position == f.getFocusCount() - 1);
  660.                     currentLarge = (current != null && current.getVisibleBounds().getSize().getWidth() > getWidth());
  661.                     scrollOutOfBounds = x > getScrollDimension().getWidth() - getWidth();
  662.                     break;
  663.                 case Display.GAME_LEFT:
  664.                     x = getScrollX() - scrollIncrement;
  665.                     edge = (position == 0);
  666.                     currentLarge = (current != null && current.getVisibleBounds().getSize().getWidth() > getWidth());
  667.                     scrollOutOfBounds = x < 0;
  668.                     break;
  669.             }
  670.             //if the Form doesn't contain a focusable Component simply move the 
  671.             //viewport by pixels
  672.             if(next == null){
  673.                 scrollRectToVisible(x, y, w, h, this);
  674.                 return false;
  675.             }
  676.             
  677.             boolean nextIntersects = Rectangle.intersects(next.getAbsoluteX(),
  678.                     next.getAbsoluteY(),
  679.                     next.getWidth(),
  680.                     next.getHeight(),
  681.                     getAbsoluteX() + x,
  682.                     getAbsoluteY() + y,
  683.                     w,
  684.                     h);
  685.             if (nextIntersects && !currentLarge && !edge) {
  686.                 scrollComponentToVisible(next);
  687.                 return true;
  688.             } else {
  689.                 if (!scrollOutOfBounds) {
  690.                     scrollRectToVisible(x, y, w, h, this);
  691.                     //if after moving the scroll the current focus is out of the
  692.                     //view port and the next focus is in the view port move 
  693.                     //the focus
  694.                     if (nextIntersects && !Rectangle.intersects(current.getAbsoluteX(),
  695.                             current.getAbsoluteY(),
  696.                             current.getWidth(),
  697.                             current.getHeight(),
  698.                             getAbsoluteX() + x,
  699.                             getAbsoluteY() + y,
  700.                             w,
  701.                             h)) {
  702.                         return true;
  703.                     }
  704.                     return false;
  705.                 } else {
  706.                     scrollComponentToVisible(next);
  707.                     return true;
  708.                 }
  709.             }
  710.         }
  711.         return true;
  712.     }
  713.     /**
  714.      * Returns a Component that exists in the given x, y coordinates by traversing
  715.      * component objects and invoking contains
  716.      * 
  717.      * @param x absolute screen location
  718.      * @param y absolute screen location
  719.      * @return a Component if found, null otherwise
  720.      * @see Component#contains
  721.      */
  722.     public Component getComponentAt(int x, int y) {
  723.         int count = getComponentCount();
  724.         boolean overlaps = getLayout().isOverlapSupported();
  725.         Component component = null;
  726.         for (int i = count - 1; i >= 0; i--) {
  727.             Component cmp = getComponentAt(i);
  728.             if (cmp.contains(x, y)) {
  729.                 component = cmp;
  730.                 if (!overlaps && component.isFocusable()) {
  731.                     return component;
  732.                 }
  733.                 if (cmp instanceof Container) {
  734.                     component = ((Container) cmp).getComponentAt(x, y);
  735.                 }
  736.                 if (!overlaps || component.isFocusable()) {
  737.                     return component;
  738.                 }
  739.             }
  740.         }
  741.         if (component != null){
  742.             return component;
  743.         }
  744.         if (contains(x, y)) {
  745.             return this;
  746.         }
  747.         return null;
  748.     }
  749.     /**
  750.      * @inheritDoc
  751.      */
  752.     public void pointerHover(int[] x, int[] y) {
  753.         if(!isDragActivated()) {
  754.             Component c = getComponentAt(x[0], y[0]);
  755.             if(c != null && c.isFocusable()) {
  756.                 c.requestFocus();
  757.             }
  758.         }
  759.         super.pointerDragged(x[0], y[0]);
  760.     }
  761.     
  762.     /**
  763.      * @inheritDoc
  764.      */
  765.     public void pointerPressed(int x, int y) {
  766.         clearDrag();
  767.         setDragActivated(false);
  768.         Component cmp = getComponentAt(x, y);
  769.         if (cmp == this) {
  770.             super.pointerPressed(x, y);
  771.         } else if (cmp != null) {
  772.             cmp.pointerPressed(x, y);
  773.         }
  774.     }
  775.     /**
  776.      * @inheritDoc
  777.      */
  778.     protected Dimension calcPreferredSize() {
  779.         Dimension d = layout.getPreferredSize(this);
  780.         return d;
  781.     }
  782.     /**
  783.      * @inheritDoc
  784.      */
  785.     protected String paramString() {
  786.         String className = layout.getClass().getName();
  787.         String layoutStr = className.substring(className.lastIndexOf('.') + 1);
  788.         return super.paramString() + ", layout = " + layoutStr +
  789.                 ", scrollableX = " + scrollableX +
  790.                 ", scrollableY = " + scrollableY +
  791.                 ", components = " + getComponentsNames();
  792.     }
  793.     /**
  794.      * Return the conatainer components objects as list of Strings
  795.      * @return the conatainer components objects as list of Strings
  796.      */
  797.     private String getComponentsNames() {
  798.         String ret = "[";
  799.         int size = components.size();
  800.         for(int iter = 0 ; iter < size ; iter++) {
  801.             String className = components.elementAt(iter).getClass().getName();
  802.             ret += className.substring(className.lastIndexOf('.') + 1) + ", ";
  803.         }
  804.         if (ret.length() > 1) {
  805.             ret = ret.substring(0, ret.length() - 2);
  806.         }
  807.         ret = ret + "]";
  808.         return ret;
  809.     }
  810.     /**
  811.      * @inheritDoc
  812.      */
  813.     public void refreshTheme() {
  814.         super.refreshTheme();
  815.         int size = components.size();
  816.         for(int iter = 0 ; iter < size ; iter++) {
  817.             Component cmp = (Component) components.elementAt(iter);
  818.             cmp.refreshTheme();
  819.         }
  820.     }
  821.     /**
  822.      * @inheritDoc
  823.      */
  824.     public boolean isScrollableX() {
  825.         return scrollableX && getScrollDimension().getWidth() > getWidth();
  826.     }
  827.     /**
  828.      * @inheritDoc
  829.      */
  830.     public boolean isScrollableY() {
  831.         return scrollableY && getScrollDimension().getHeight() > getHeight();
  832.     }
  833.     /**
  834.      * Sets whether the component should/could scroll on the X axis
  835.      * 
  836.      * @param scrollableX whether the component should/could scroll on the X axis
  837.      */
  838.     public void setScrollableX(boolean scrollableX) {
  839.         this.scrollableX = scrollableX;
  840.     }
  841.     /**
  842.      * Sets whether the component should/could scroll on the Y axis
  843.      * 
  844.      * @param scrollableY whether the component should/could scroll on the Y axis
  845.      */
  846.     public void setScrollableY(boolean scrollableY) {
  847.         this.scrollableY = scrollableY;
  848.     }
  849.     /**
  850.      * The equivalent of calling both setScrollableY and setScrollableX
  851.      * 
  852.      * @param scrollable whether the component should/could scroll on the 
  853.      * X and Y axis
  854.      */
  855.     public void setScrollable(boolean scrollable) {
  856.         setScrollableX(scrollable);
  857.         setScrollableY(scrollable);
  858.     }
  859.     /**
  860.      * @inheritDoc
  861.      */
  862.     public void setCellRenderer(boolean cellRenderer) {
  863.         if (isCellRenderer() != cellRenderer) {
  864.             super.setCellRenderer(cellRenderer);
  865.             int size = getComponentCount();
  866.             for (int iter = 0; iter <
  867.                     size; iter++) {
  868.                 getComponentAt(iter).setCellRenderer(cellRenderer);
  869.             }
  870.         }
  871.     }
  872.     /**
  873.      * Determines the scroll increment size of this Container.
  874.      * This value is in use when the current foucs element within this Container
  875.      * is larger than this Container size.
  876.      *
  877.      * @param scrollIncrement the size in pixels.
  878.      */
  879.     public void setScrollIncrement(int scrollIncrement) {
  880.         this.scrollIncrement = scrollIncrement;
  881.     }
  882.     /**
  883.      * Gets the Container scroll increment
  884.      *
  885.      * @return the scroll increment in pixels.
  886.      */
  887.     public int getScrollIncrement() {
  888.         return scrollIncrement;
  889.     }
  890.     class Anim implements Animation, Runnable {
  891.         private Transition t;
  892.         private Component current;
  893.         private Component next;
  894.         private boolean started = false;
  895.         private Container thisContainer;
  896.         private boolean finished = false;
  897.         private Form parent;
  898.         
  899.         public Anim(Container thisContainer, Component current, Component next, Transition t) {
  900.             this.t = t;
  901.             this.next = next;
  902.             this.current = current;
  903.             this.thisContainer = thisContainer;
  904.             this.parent = thisContainer.getComponentForm();
  905.         }
  906.         public boolean animate() {
  907.             if (!started) {
  908.                 t.init(current, next);
  909.                 t.initTransition();
  910.                 started = true;
  911.                 if (cmpTransitions == null) {
  912.                     cmpTransitions = new Vector();
  913.                 }
  914.                 cmpTransitions.addElement(this);
  915.             }
  916.             boolean notFinished = t.animate();
  917.             if (!notFinished) {
  918.                 cmpTransitions.removeElement(this);
  919.                 destroy();
  920.             }
  921.             return notFinished;
  922.         }
  923.         public void destroy() {
  924.             parent.deregisterAnimatedInternal(this);
  925.             next.setParent(null);
  926.             thisContainer.replace(current, next);
  927.             //release the events blocking
  928.             t.cleanup();
  929.             if(cmpTransitions.size() == 0){
  930.                 parent.revalidate();
  931.             }
  932.             finished = true;
  933.         }
  934.         public void paint(Graphics g) {
  935.             t.paint(g);
  936.         }
  937.         public boolean isFinished() {
  938.             return finished;
  939.         }
  940.         public void run() {
  941.             while (!isFinished()) {
  942.                 try {
  943.                     Thread.sleep(10);
  944.                 } catch (InterruptedException ex) {
  945.                     ex.printStackTrace();
  946.                 }
  947.             }
  948.         }
  949.     }
  950. }