Source Code Cross Referenced for FormLFImpl.java in  » 6.0-JDK-Modules » j2me » javax » microedition » lcdui » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » javax.microedition.lcdui 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *
0003:         * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0004:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0005:         * 
0006:         * This program is free software; you can redistribute it and/or
0007:         * modify it under the terms of the GNU General Public License version
0008:         * 2 only, as published by the Free Software Foundation.
0009:         * 
0010:         * This program is distributed in the hope that it will be useful, but
0011:         * WITHOUT ANY WARRANTY; without even the implied warranty of
0012:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0013:         * General Public License version 2 for more details (a copy is
0014:         * included at /legal/license.txt).
0015:         * 
0016:         * You should have received a copy of the GNU General Public License
0017:         * version 2 along with this work; if not, write to the Free Software
0018:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0019:         * 02110-1301 USA
0020:         * 
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0022:         * Clara, CA 95054 or visit www.sun.com if you need additional
0023:         * information or have any questions.
0024:         */
0025:
0026:        package javax.microedition.lcdui;
0027:
0028:        import com.sun.midp.log.Logging;
0029:        import com.sun.midp.log.LogChannels;
0030:        import com.sun.midp.configurator.Constants;
0031:
0032:        /**
0033:         * Look and feel class for <code>Form</code>.
0034:         */
0035:        class FormLFImpl extends DisplayableLFImpl implements  FormLF {
0036:            /**
0037:             * Creates <code>FormLF</code> associated with passed in form.
0038:             * <code>FormLFImpl</code> maintains an array of views associated
0039:             * with its items.
0040:             *
0041:             * @param form the <code>Form</code> object associated with this
0042:             *             <code>FormLF</code>
0043:             * @param items the array of Items using which the passed in
0044:             *              <code>Form</code> was created
0045:             * @param numOfItems current number of elements
0046:             */
0047:            FormLFImpl(Form form, Item items[], int numOfItems) {
0048:                super (form);
0049:
0050:                // Initialize the in-out rect for Item traversal
0051:                visRect = new int[4];
0052:
0053:                width -= Constants.VERT_SCROLLBAR_WIDTH;
0054:
0055:                if (items == null) {
0056:                    itemLFs = new ItemLFImpl[GROW_SIZE];
0057:                    // numOfLFs was initialized to 0
0058:                    // so there is no need to update it
0059:                } else {
0060:                    this .itemLFs = new ItemLFImpl[items.length > GROW_SIZE ? items.length
0061:                            : GROW_SIZE];
0062:
0063:                    for (int i = 0; i < numOfItems; i++) {
0064:                        itemLFs[i] = (ItemLFImpl) items[i].getLF();
0065:                    }
0066:
0067:                    // right now we have the same number of views as items
0068:                    numOfLFs = numOfItems;
0069:                }
0070:            }
0071:
0072:            /**
0073:             * Creates <code>FormLF</code> for the passed in screen.
0074:             * Passed in <code>ItemLF</code> is added as the only itemLF present.
0075:             * This constructor is used by <code>List</code> and <code>TextBox</code>.
0076:             *
0077:             * @param screen the <code>Screen</code> object associated with this
0078:             *               <code>FormLFImpl</code>
0079:             * @param item the <code>Item</code> to be added to this screen
0080:             */
0081:            FormLFImpl(Screen screen, Item item) {
0082:                super (screen);
0083:
0084:                itemLFs = new ItemLFImpl[1];
0085:                itemLFs[0] = (ItemLFImpl) item.getLF();
0086:                numOfLFs = 1;
0087:
0088:                // Initialize the in-out rect for Item traversal
0089:                visRect = new int[4];
0090:            }
0091:
0092:            // ************************************************************
0093:            //  public methods - FormLF interface implementation
0094:            // ************************************************************
0095:
0096:            /**
0097:             * Returns the width in pixels of the displayable area available for
0098:             * items.
0099:             * The value may depend on how the device uses the screen and may be
0100:             * affected by the presence or absence of the ticker, title,
0101:             * or commands.
0102:             * The <code>Item</code>s of the <code>Form</code> are
0103:             * laid out to fit within this width.
0104:             *
0105:             * @return the width of the <code>Form</code> in pixels
0106:             */
0107:            public int lGetWidth() {
0108:                return width;
0109:            }
0110:
0111:            /**
0112:             * Returns the height in pixels of the displayable area available
0113:             * for items.
0114:             * This value is the height of the form that can be displayed without
0115:             * scrolling.
0116:             * The value may depend on how the device uses the screen and may be
0117:             * affected by the presence or absence of the ticker, title,
0118:             * or commands.
0119:             *
0120:             * @return the height of the displayable area of the
0121:             *         <code>Form</code> in pixels
0122:             */
0123:            public int lGetHeight() {
0124:                return height;
0125:            }
0126:
0127:            /**
0128:             * Set the current traversal location to the given <code>Item</code>.
0129:             * This call has no effect if the given <code>Item</code> is the
0130:             * current traversal item, or if the given <code>Item</code> is not
0131:             * part of this <code>Form</code>. Note that null can be passed in
0132:             * clear the previously set current item.
0133:             *
0134:             * @param item the <code>Item</code> to make the current traversal item
0135:             */
0136:            public void uItemMakeVisible(Item i) {
0137:
0138:                synchronized (Display.LCDUILock) {
0139:
0140:                    if (i == null) {
0141:                        pendingCurrentItem = null;
0142:                    }
0143:
0144:                    /**
0145:                     * Display could be made visible using display.setCurrentItem()
0146:                     * call. In those cases foregroung will be granted after there
0147:                     * there is a screen change event and after uItemMakeVisible()
0148:                     * is called. In such cases we need to set pendingCurrentItem and
0149:                     * call uItemMakeVisible() again when the FormLF changes its
0150:                     * state to SHOWN.
0151:                     */
0152:                    if (state != SHOWN) {
0153:                        pendingCurrentItem = i;
0154:                        return;
0155:                    }
0156:                }
0157:            }
0158:
0159:            /**
0160:             * Notifies look&amp;feel object of an item set in the corresponding
0161:             * <code>Form</code>.
0162:             *
0163:             * @param itemNum the index of the item set
0164:             * @param item the item set in the corresponding <code>Form</code>
0165:             */
0166:            public void lSet(int itemNum, Item item) {
0167:
0168:                itemLFs[itemNum] = (ItemLFImpl) item.getLF();
0169:                itemsModified = true;
0170:
0171:                // Focus index remains at the same location
0172:
0173:                lRequestInvalidate();
0174:            }
0175:
0176:            /**
0177:             * Notifies look&amp;feel object of an item inserted in the corresponding
0178:             * <code>Form</code>.
0179:             *
0180:             * @param itemNum the index of the inserted item
0181:             * @param item the item inserted in the corresponding <code>Form</code>
0182:             */
0183:            public void lInsert(int itemNum, Item item) {
0184:                if (itemLFs.length == numOfLFs) {
0185:                    ItemLFImpl newItemLFs[] = new ItemLFImpl[numOfLFs
0186:                            + GROW_SIZE];
0187:                    System.arraycopy(itemLFs, 0, newItemLFs, 0, itemNum);
0188:                    System.arraycopy(itemLFs, itemNum, newItemLFs, itemNum + 1,
0189:                            numOfLFs - itemNum);
0190:                    itemLFs = newItemLFs;
0191:                } else {
0192:                    // if we're not appending
0193:                    if (itemNum != numOfLFs) {
0194:                        System.arraycopy(itemLFs, itemNum, itemLFs,
0195:                                itemNum + 1, numOfLFs - itemNum);
0196:                    }
0197:                }
0198:
0199:                itemLFs[itemNum] = (ItemLFImpl) item.getLF();
0200:
0201:                numOfLFs++;
0202:                itemsModified = true;
0203:                // Focus remains on the same item
0204:                if (traverseIndex >= itemNum) {
0205:                    traverseIndex++;
0206:                }
0207:                lRequestInvalidate();
0208:            }
0209:
0210:            /**
0211:             * Notifies look&amp;feel object of an item deleted in the corresponding
0212:             * <code>Form</code>.
0213:             *
0214:             * @param itemNum the index of the deleted item
0215:             * @param deleteditem the item deleted in the corresponding form
0216:             */
0217:            public void lDelete(int itemNum, Item deleteditem) {
0218:
0219:                // if the previous item has new line after, or the next item has
0220:                // new line before, and it's not the last item,
0221:                // than we could just mark the next item as actualBoundsInvalid[Y]
0222:                if (itemNum < (numOfLFs - 1)) {
0223:                    if (((itemNum > 0) && (itemLFs[itemNum - 1].equateNLA()) || itemLFs[itemNum + 1]
0224:                            .equateNLB())
0225:                            && itemLFs[itemNum + 1].isNewLine) {
0226:
0227:                        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0228:                            Logging.report(Logging.INFORMATION,
0229:                                    LogChannels.LC_HIGHUI_FORM_LAYOUT,
0230:                                    " setting actualBoundsInvalid[Y] #"
0231:                                            + (itemNum + 1));
0232:                            if (itemNum > 0) {
0233:                                Logging.report(Logging.INFORMATION,
0234:                                        LogChannels.LC_HIGHUI_FORM_LAYOUT,
0235:                                        " | itemLFs[itemNum-1] = "
0236:                                                + itemLFs[itemNum - 1]);
0237:                            }
0238:                            Logging
0239:                                    .report(Logging.INFORMATION,
0240:                                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
0241:                                            " | itemLFs[itemNum] = "
0242:                                                    + itemLFs[itemNum]);
0243:                            if (itemNum < numOfLFs - 1) {
0244:                                Logging.report(Logging.INFORMATION,
0245:                                        LogChannels.LC_HIGHUI_FORM_LAYOUT,
0246:                                        " | itemLFs[itemNum+1] = "
0247:                                                + itemLFs[itemNum + 1]);
0248:                            }
0249:                        }
0250:                        itemLFs[itemNum + 1].actualBoundsInvalid[Y] = true;
0251:                    } else {
0252:                        itemLFs[itemNum + 1].actualBoundsInvalid[X] = true;
0253:                    }
0254:                }
0255:
0256:                if (traverseIndex == itemNum) {
0257:                    lastTraverseItem = itemLFs[traverseIndex];
0258:                }
0259:
0260:                if (traverseIndex >= 0 && traverseIndex >= itemNum) {
0261:                    traverseIndex--;
0262:                }
0263:
0264:                numOfLFs--;
0265:                itemsModified = true;
0266:
0267:                if (itemNum < numOfLFs) {
0268:                    System.arraycopy(itemLFs, itemNum + 1, itemLFs, itemNum,
0269:                            numOfLFs - itemNum);
0270:                }
0271:
0272:                // Delete reference to the last item view
0273:                // that was left after array copy
0274:                itemLFs[numOfLFs] = null;
0275:
0276:                if (pendingCurrentItem == deleteditem) {
0277:                    pendingCurrentItem = null;
0278:                }
0279:
0280:                lRequestInvalidate();
0281:            }
0282:
0283:            /**
0284:             * Notifies look&amp;feel object that all items are deleted in
0285:             * the corresponding <code>Form</code>.
0286:             */
0287:            public void lDeleteAll() {
0288:                if (traverseIndex != -1) {
0289:                    lastTraverseItem = itemLFs[traverseIndex];
0290:                }
0291:                // Dereference all ItemLFImpls so they can be GC'ed
0292:                while (numOfLFs > 0) {
0293:                    itemLFs[--numOfLFs] = null;
0294:                }
0295:                traverseIndex = -1;
0296:                itemsModified = true;
0297:                pendingCurrentItem = null;
0298:                lRequestInvalidate();
0299:            }
0300:
0301:            /**
0302:             * This method is responsible for:
0303:             * (1) Re-validate the contents of this <code>Form</code>, possibly due
0304:             * to an individual item
0305:             * (2) setup the viewable/scroll position
0306:             * (3) repaint the currently visible <code>Item</code>s
0307:             */
0308:            public void uCallInvalidate() {
0309:
0310:                super .uCallInvalidate();
0311:
0312:                int new_width = Display.getScreenWidth0();
0313:                int new_height = Display.getScreenHeight0();
0314:
0315:                // It could be that setCurrentItem() was called and we
0316:                // have done an 'artificial' traversal. In this case, we
0317:                // manually call traverseOut() on the last traversed item
0318:                // if there is one.
0319:
0320:                if (lastTraverseItem != null) {
0321:                    try {
0322:                        lastTraverseItem.uCallTraverseOut();
0323:                    } catch (Throwable t) {
0324:                        if (Logging.REPORT_LEVEL <= Logging.WARNING) {
0325:                            Logging.report(Logging.WARNING,
0326:                                    LogChannels.LC_HIGHUI,
0327:                                    "Throwable while traversing out");
0328:                        }
0329:                    }
0330:                    lastTraverseItem = null;
0331:                    updateCommandSet();
0332:                }
0333:
0334:                synchronized (Display.LCDUILock) {
0335:                    // Do nothing if paint is suspended in current Display
0336:                    if (!lIsShown()) {
0337:                        return;
0338:                    }
0339:                    // Do not reset the Form from the top since this is an update
0340:                    resetToTop = false;
0341:                }
0342:
0343:                // Setup items and show form native resource
0344:                // SYNC NOTE: 
0345:                // called without LCDUILock, since it may end up calling into a MIDlet
0346:                if (new_width != width || new_height != height) {
0347:                    width = new_width;
0348:                    height = new_height;
0349:                    firstShown = true;
0350:                }
0351:                // IMPL NOTES: Remove this line after UDPATE_LAYOUT is fixed
0352:                firstShown = true;
0353:                // Update contents
0354:                uShowContents(false);
0355:
0356:                // SYNC NOTE:
0357:                // 1. We are on event dispatch thread, currentDisplay won't change.
0358:                // 2. We are on event dispatch thread, call paint synchronously.
0359:                // 3. Since we could call into app's functions, like traverse(),
0360:                //    showNotify() and paint(), do this outside LCDUILock block.
0361:                currentDisplay.callPaint(0, 0, width, height, null);
0362:            }
0363:
0364:            /**
0365:             * Paint the contents of this <code>Form</code>.
0366:             *
0367:             * @param g the <code>Graphics</code> object to paint on
0368:             * @param target the target Object of this repaint
0369:             */
0370:            public void uCallPaint(Graphics g, Object target) {
0371:                int count;
0372:                synchronized (Display.LCDUILock) {
0373:                    // super.lCallPaint(g, target); -- obsolete
0374:
0375:                    if (numOfLFs == 0) {
0376:                        return;
0377:                    }
0378:
0379:                    // SYNC NOTE: since we may call into CustomItem.paint(),
0380:                    // we have to do it outside LCDUILock. So make a copy of the
0381:                    // itemLFs array.
0382:                    if (target instanceof  Item) {
0383:                        if (((Item) target).owner == this .owner) {
0384:                            ensureDispatchItemArray(1);
0385:                            dispatchItemLFs[0] = (ItemLFImpl) ((Item) target).itemLF;
0386:                            count = 1;
0387:                        } else {
0388:                            count = 0;
0389:                        }
0390:                    } else {
0391:                        ensureDispatchItemArray(numOfLFs);
0392:                        System.arraycopy(itemLFs, 0, dispatchItemLFs, 0,
0393:                                numOfLFs);
0394:                        count = numOfLFs;
0395:                    }
0396:                }
0397:
0398:                // Call paint on the copied itemLFs array
0399:                for (int i = 0; i < count; i++) {
0400:                    uPaintItem(dispatchItemLFs[i], g);
0401:                }
0402:
0403:                // Dereference ItemLFImpl objects in dispatchItemLFs
0404:                // But leave the shrinking to uCallHide
0405:                resetDispatchItemArray(false);
0406:            }
0407:
0408:            /**
0409:             * Notify this <code>Form</code> that it is being shown.
0410:             */
0411:            public void uCallShow() {
0412:                // Create native resources with title and ticker
0413:                super .uCallShow();
0414:                // Setup items and show form native resource
0415:                // SYNC NOTE: May call into app code to collect sizes.
0416:                // Call it outside LCDUILock
0417:                uShowContents(true);
0418:
0419:                synchronized (Display.LCDUILock) {
0420:
0421:                    if (pendingCurrentItem != null) {
0422:                        lScrollToItem(pendingCurrentItem);
0423:                        pendingCurrentItem = null;
0424:                    }
0425:                }
0426:            }
0427:
0428:            /**
0429:             * Notify this <code>Form</code> that it is being hidden.
0430:             */
0431:
0432:            public void uCallHide() {
0433:
0434:                synchronized (Display.LCDUILock) {
0435:                    pendingCurrentItem = null;
0436:                }
0437:
0438:                uCallItemHide();
0439:                // Delete Form's native resource including title and ticker
0440:                super .uCallHide();
0441:            }
0442:
0443:            /**
0444:             * Notify this <code>Form</code> that it is being frozen.
0445:             */
0446:
0447:            public void uCallFreeze() {
0448:
0449:                if (state == SHOWN) {
0450:                    resetToTop = false;
0451:                }
0452:                uCallItemHide();
0453:                // Delete Form's native resource including title and ticker
0454:                super .uCallFreeze();
0455:            }
0456:
0457:            /**
0458:             * Hide items when Form is frozen or hidden
0459:             */
0460:            void uCallItemHide() {
0461:                // No more than one custom item can be in focus at a time
0462:                ItemLFImpl customItemToTraverseOut = null;
0463:                ItemLFImpl[] itemsCopy = null;
0464:                int count = 0;
0465:
0466:                synchronized (Display.LCDUILock) {
0467:
0468:                    // We need to loop through our Items to identify those
0469:                    // that traverseOut and hideNotify need to be called.
0470:                    //
0471:                    // SYNC NOTE:
0472:                    // We cannot call into app code while holding LCDUILock.
0473:                    // For CustomItems, we postpone calls to outside this
0474:                    // sync. block.
0475:
0476:                    itemsCopy = new ItemLFImpl[numOfLFs];
0477:
0478:                    for (int x = 0; x < numOfLFs; x++) {
0479:                        try {
0480:                            // callTraverseOut needs to happen on the item in focus
0481:                            if (itemLFs[x].hasFocus) {
0482:                                if (itemLFs[x] instanceof  CustomItemLFImpl) {
0483:                                    customItemToTraverseOut = itemLFs[x];
0484:                                } else {
0485:                                    // SYNC NOTE: Items other than CustomItem do not
0486:                                    // call into app code in their traverseOut.
0487:                                    // We can call it while holding the LCDUILock.
0488:                                    itemLFs[x].uCallTraverseOut();
0489:                                }
0490:                            }
0491:
0492:                            itemLFs[x].lHideNativeResource();
0493:                            // Free native resource of each ItemLF
0494:                            itemLFs[x].deleteNativeResource();
0495:
0496:                            // Items that are visible in the viewport
0497:                            // should set their visibleInViewport flag to false and
0498:                            // CustomItems should call app's hideNotify() as well
0499:                            if (itemLFs[x].visibleInViewport) {
0500:                                if (itemLFs[x] instanceof  CustomItemLFImpl) {
0501:                                    // Remember it in temporary array
0502:                                    itemsCopy[count++] = itemLFs[x];
0503:                                } else {
0504:                                    itemLFs[x].lCallHideNotify();
0505:                                }
0506:                            }
0507:
0508:                        } catch (Throwable t) {
0509:                            // do nothing... move on
0510:                        }
0511:                    }
0512:
0513:                } // synchronized
0514:
0515:                // Call CustomItem traverseOut outside LCDUILock
0516:                if (customItemToTraverseOut != null) {
0517:                    customItemToTraverseOut.uCallTraverseOut();
0518:                }
0519:
0520:                // Call CustomItem hideNotify outside LCDUILock
0521:                for (count--; count >= 0; count--) {
0522:                    itemsCopy[count].uCallHideNotify();
0523:                }
0524:            }
0525:
0526:            /**
0527:             * Called by <code>Display</code> to notify an <code>ItemLF</code>
0528:             * in current <code>FormLF</code> of a change in its peer state.
0529:             * If the the peerId matches the nativeId of this <code>FormLF</code>,
0530:             * uViewportChanged() will be called to process the scroll
0531:             * notification.
0532:             * Otherwise, if there is an <code>ItemLF</code> that matches the peerId,
0533:             * the <code>ItemLF</code> will be called to process this notification.
0534:             * Otherwise, this is treated as a special notification to this
0535:             * <code>FormLF</code> upon focus changed between items, and
0536:             * parameter 'hint' will contain the index of the new current
0537:             * <code>ItemLF</code>.
0538:             *
0539:             * @param modelVersion the version of the peer's data model
0540:             * @param peerId one of the following:
0541:             *  <ul> <li> the id of this <code>FormLF</code> if viewport
0542:             *            has changed in the corresponding native resource
0543:             *            of this <code>FormLF</code>
0544:             *            (current scroll position is passed as hint)
0545:             *       <li> the id of the <code>ItemLF</code> whose peer state
0546:             *            has changed
0547:             *	     <li> <code>INVALID_NATIVE_ID</code> if a focus
0548:             *            changed notification.
0549:             * @param hint some value that is interpreted only between the peers
0550:             */
0551:            public void uCallPeerStateChanged(int modelVersion, int peerId,
0552:                    int hint) {
0553:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0554:                    Logging.report(Logging.INFORMATION,
0555:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
0556:                            "-=-=- FormLF: dsPeerStateChanged " + peerId + "/"
0557:                                    + hint);
0558:                }
0559:
0560:                int notifyType;
0561:                ItemLFImpl oldFocus = null, itemLFToNotify = null;
0562:
0563:                synchronized (Display.LCDUILock) {
0564:                    if (modelVersion != super .modelVersion) {
0565:                        return; // model version out of sync, ignore the event
0566:                    }
0567:
0568:                    // If not matching ItemLF, this is a focus changed notification
0569:                    // 'hint' is the id of the new focused itemLF
0570:                    if (peerId == INVALID_NATIVE_ID) {
0571:                        notifyType = 1; // focus changed
0572:                        oldFocus = getItemInFocus();
0573:                        itemLFToNotify = id2Item(hint);
0574:                    } else if (peerId == nativeId) {
0575:                        // there is a scroll event from the native peer,
0576:                        // we call show/hide Notify outside of the synchronized block
0577:                        notifyType = 2; // viewport changed
0578:                    } else {
0579:                        // peerId identified the ItemLF, notify it
0580:                        notifyType = 3; // item peer state changed
0581:                        itemLFToNotify = id2Item(peerId);
0582:                    }
0583:                }
0584:
0585:                // SYNC NOTE: Following calls may end in app code.
0586:                // 	      So do it outside LCDUILock
0587:                switch (notifyType) {
0588:
0589:                case 1: // Focus notification
0590:                    uFocusChanged(itemLFToNotify);
0591:                    break;
0592:
0593:                case 2: // Scrolling notification
0594:                    // 'hint' is the new viewport position
0595:                    uViewportChanged(hint, hint + viewportHeight);
0596:
0597:                    // Spec requires CustomItem's paint() to be called after
0598:                    // its showNotify() is called and before hideNotify()
0599:                    // it is safe to pass null as both parameters
0600:                    // because only CustomItems will be repainted and they
0601:                    // use their own Graphics
0602:                    uCallPaint(null, null);
0603:                    break;
0604:
0605:                case 3: // Item peer notification
0606:                    if (itemLFToNotify != null
0607:                            && itemLFToNotify.uCallPeerStateChanged(hint)) {
0608:                        // Notify the itemStateListener
0609:                        owner.uCallItemStateChanged(itemLFToNotify.item);
0610:                    }
0611:                    break;
0612:
0613:                default:
0614:                    // for safety/completeness.
0615:                    Logging.report(Logging.WARNING,
0616:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
0617:                            "FormLFImpl: notifyType=" + notifyType);
0618:                    break;
0619:                }
0620:            }
0621:
0622:            /**
0623:             * Update current item index and notify related item of the change.
0624:             * Item specific abstract commands will also be shown.
0625:             *
0626:             * @param newFocus the new item in focus.
0627:             */
0628:            private void uFocusChanged(ItemLFImpl newFocus) {
0629:                ItemLFImpl oldFocus = null;
0630:                synchronized (Display.LCDUILock) {
0631:                    pendingCurrentItem = null;
0632:                    int focusIndex = item2Index(newFocus); // Could be -1
0633:                    if (focusIndex == traverseIndex) {
0634:                        oldFocus = newFocus;
0635:                    } else {
0636:                        oldFocus = traverseIndex > 0 ? itemLFs[traverseIndex]
0637:                                : null;
0638:                        traverseIndex = focusIndex;
0639:                    }
0640:                }
0641:
0642:                if (oldFocus != newFocus) {
0643:                    if (oldFocus != null) {
0644:                        oldFocus.uCallTraverseOut();
0645:                    }
0646:                    if (newFocus != null) {
0647:                        itemTraverse = uCallItemTraverse(newFocus,
0648:                                CustomItem.NONE);
0649:                    }
0650:                    updateCommandSet();
0651:                    // call paint for custom items
0652:                    uRequestPaint();
0653:                }
0654:            }
0655:
0656:            /**
0657:             * This method is used in repaint, in order to determine the translation
0658:             * of the draw coordinates.
0659:             *
0660:             * @return <code>true</code>, if the scroll responsibility is on the
0661:             *         native platform.
0662:             *         <code>false</code>, if the scroll is done at Java level.
0663:             */
0664:            public boolean uIsScrollNative() {
0665:                // only native form overrides this and returns true
0666:                return true;
0667:            }
0668:
0669:            // *****************************************************
0670:            //  Package private methods
0671:            // *****************************************************
0672:
0673:            /**
0674:             * Check the key and return true if it's navigation key
0675:             * @param key key code
0676:             * @return true if the key is navigation key false otherwise 
0677:             */
0678:            private boolean isNavigationKey(int key) {
0679:                return key == Canvas.UP || key == Canvas.LEFT
0680:                        || key == Canvas.DOWN || key == Canvas.RIGHT;
0681:            }
0682:
0683:            /**
0684:             * Set status of screen rotation
0685:             * @param newStatus
0686:             * @return
0687:             */
0688:            public boolean uSetRotatedStatus(boolean newStatus) {
0689:                boolean status = super .uSetRotatedStatus(newStatus);
0690:                if (status) {
0691:                    firstShown = true;
0692:                }
0693:                return status;
0694:            }
0695:
0696:            /**
0697:             * Handle a key press.
0698:             *
0699:             * @param keyCode the key code of the key which was pressed
0700:             */
0701:            void uCallKeyPressed(int keyCode) {
0702:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0703:                    Logging.report(Logging.INFORMATION,
0704:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
0705:                            "got callKeyPressed: " + keyCode);
0706:                }
0707:                int dir = KeyConverter.getGameAction(keyCode);
0708:                if (isNavigationKey(dir)) {
0709:                    uTraverse(dir);
0710:                } else {
0711:                    ItemLFImpl v = null;
0712:                    synchronized (Display.LCDUILock) {
0713:                        v = getItemInFocus();
0714:                    }
0715:
0716:                    // pass the keypress onto the current item
0717:                    if (v != null && v instanceof  CustomItemLFImpl) {
0718:
0719:                        // NOTE: customItem.getInteractionModes() determines
0720:                        // the supported events. The Zaurus platform implementation
0721:                        // does not support traversal in any direction.
0722:                        // if it is desired to support horizontal and/or vertical
0723:                        // traversal, than the proper flags must be set accordingly.
0724:
0725:                        // pass all key events to the CustomItem, including arrows
0726:                        v.uCallKeyPressed(keyCode);
0727:                    }
0728:                }
0729:            }
0730:
0731:            /**
0732:             * Handle a key release event.
0733:             *
0734:             * @param keyCode the key which was released
0735:             */
0736:            void uCallKeyReleased(int keyCode) {
0737:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0738:                    Logging.report(Logging.INFORMATION,
0739:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
0740:                            "got callKeyReleased: " + keyCode);
0741:                }
0742:
0743:                if (!isNavigationKey(KeyConverter.getGameAction(keyCode))) {
0744:                    ItemLFImpl v = null;
0745:                    synchronized (Display.LCDUILock) {
0746:                        v = getItemInFocus();
0747:                    } // synchronized
0748:
0749:                    // SYNC NOTE: formMode can only change as a result of a
0750:                    // traversal, which can only occur serially on the event
0751:                    // thread, so its safe to use it outside of the lock
0752:
0753:                    if (v != null && v instanceof  CustomItemLFImpl) {
0754:                        v.uCallKeyReleased(keyCode);
0755:                    }
0756:                }
0757:            }
0758:
0759:            /**
0760:             * Handle a key repeat.
0761:             *
0762:             * @param keyCode the key code of the key which was repeated
0763:             */
0764:            void uCallKeyRepeated(int keyCode) {
0765:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0766:                    Logging.report(Logging.INFORMATION,
0767:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
0768:                            "got callKeyRepeated: " + keyCode);
0769:                }
0770:                if (isNavigationKey(KeyConverter.getGameAction(keyCode))) {
0771:                    uCallKeyPressed(keyCode);
0772:                } else {
0773:                    ItemLFImpl v = null;
0774:                    synchronized (Display.LCDUILock) {
0775:                        v = getItemInFocus();
0776:                    } // synchronized
0777:
0778:                    // SYNC NOTE: formMode can only change as a result of a
0779:                    // traversal, which can only occur serially on the event
0780:                    // thread, so its safe to use it outside of the lock
0781:
0782:                    if (v != null && v instanceof  CustomItemLFImpl) {
0783:                        v.uCallKeyRepeated(keyCode);
0784:                    }
0785:                }
0786:            }
0787:
0788:            /**
0789:             * Handle a pointer pressed event.
0790:             *
0791:             * @param x The x coordinate of the press
0792:             * @param y The y coordinate of the press
0793:             */
0794:            void uCallPointerPressed(int x, int y) {
0795:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0796:                    Logging.report(Logging.INFORMATION,
0797:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
0798:                            "got callPointerPressed: " + x + "," + y);
0799:                }
0800:
0801:                ItemLFImpl v = null;
0802:
0803:                synchronized (Display.LCDUILock) {
0804:
0805:                    v = getItemInFocus();
0806:
0807:                    // stop here if no current item to handle the key
0808:                    if (v == null) {
0809:                        return;
0810:                    }
0811:
0812:                } // synchronized
0813:
0814:                // SYNC NOTE: formMode can only change as a result of a
0815:                // traversal, which can only occur serially on the event
0816:                // thread, so its safe to use it outside of the lock
0817:
0818:                if (v instanceof  CustomItemLFImpl) {
0819:                    v.uCallPointerPressed(x, y);
0820:                }
0821:            }
0822:
0823:            /**
0824:             * Handle a pointer released event.
0825:             *
0826:             * @param x The x coordinate of the release
0827:             * @param y The y coordinate of the release
0828:             */
0829:            void uCallPointerReleased(int x, int y) {
0830:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0831:                    Logging.report(Logging.INFORMATION,
0832:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
0833:                            "got callPointerReleased: " + x + "," + y);
0834:                }
0835:
0836:                ItemLFImpl v = null;
0837:
0838:                synchronized (Display.LCDUILock) {
0839:
0840:                    v = getItemInFocus();
0841:
0842:                    // stop here if no current item to handle the key
0843:                    if (v == null) {
0844:                        return;
0845:                    }
0846:
0847:                } // synchronized
0848:
0849:                // SYNC NOTE: formMode can only change as a result of a
0850:                // traversal, which can only occur serially on the event
0851:                // thread, so its safe to use it outside of the lock
0852:
0853:                if (v instanceof  CustomItemLFImpl) {
0854:                    v.uCallPointerReleased(x, y);
0855:                }
0856:            }
0857:
0858:            /**
0859:             * Handle a pointer dragged event.
0860:             *
0861:             * @param x The x coordinate of the drag
0862:             * @param y The y coordinate of the drag
0863:             */
0864:            void uCallPointerDragged(int x, int y) {
0865:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0866:                    Logging.report(Logging.INFORMATION,
0867:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
0868:                            "got callPointerDragged: " + x + "," + y);
0869:                }
0870:
0871:                ItemLFImpl v = null;
0872:
0873:                synchronized (Display.LCDUILock) {
0874:
0875:                    v = getItemInFocus();
0876:
0877:                    // stop here if no current item to handle the key
0878:                    if (v == null) {
0879:                        return;
0880:                    }
0881:
0882:                } // synchronized
0883:
0884:                // SYNC NOTE: formMode can only change as a result of a
0885:                // traversal, which can only occur serially on the event
0886:                // thread, so its safe to use it outside of the lock
0887:
0888:                if (v instanceof  CustomItemLFImpl) {
0889:                    v.uCallPointerDragged(x, y);
0890:                }
0891:            }
0892:
0893:            /**
0894:             * Gets item currently in focus.
0895:             *
0896:             * @return the item currently in focus in this form;
0897:             *         if there are no items in focus, <code>null</code> is returned
0898:             */
0899:            public Item lGetCurrentItem() {
0900:                ItemLFImpl v = getItemInFocus();
0901:
0902:                if (v == null) {
0903:                    return null;
0904:                }
0905:
0906:                return v.item;
0907:            }
0908:
0909:            /**
0910:             * Paint an item.
0911:             *
0912:             * @param itemLF the <code>ItemLFImpl</code> to paint
0913:             * @param g the <code>Graphics</code> object to paint to
0914:             */
0915:            void uPaintItem(ItemLFImpl itemLF, Graphics g) {
0916:                synchronized (Display.LCDUILock) {
0917:                    // NOTE: Its possible, that an Item is in an invalid state
0918:                    // during a requested repaint. Its ok to simply return,
0919:                    // because it means there is a validation event coming on
0920:                    // the event thread. When the form re-validates, the Item
0921:                    // will be given a proper bounds and will be repainted
0922:                    if (itemLF.actualBoundsInvalid[X]
0923:                            || itemLF.actualBoundsInvalid[Y]
0924:                            || itemLF.actualBoundsInvalid[WIDTH]
0925:                            || itemLF.actualBoundsInvalid[HEIGHT]
0926:                            || itemLF.nativeId == INVALID_NATIVE_ID) {
0927:                        return;
0928:                    }
0929:                }
0930:
0931:                // repaint only visible in viewport items
0932:                if (itemLF.visibleInViewport) {
0933:                    // CustomItem uses its own off screen graphics for painting
0934:                    // and the rest of the items do not need to repaint
0935:                    itemLF.uCallPaint(null, itemLF.bounds[WIDTH],
0936:                            itemLF.bounds[HEIGHT]);
0937:                }
0938:            }
0939:
0940:            /**
0941:             * Paint an <code>Item</code> contained in this <code>Screen</code>.
0942:             * The <code>Item</code> requests a paint in its own coordinate space.
0943:             * <code>Screen</code> translates those coordinates into the overall
0944:             * coordinate space and schedules the repaint
0945:             *
0946:             * @param item the <code>Item</code> requesting the repaint
0947:             * @param x the x-coordinate of the origin of the dirty region
0948:             * @param y the y-coordinate of the origin of the dirty region
0949:             * @param w the width of the dirty region
0950:             * @param h the height of the dirty region
0951:             */
0952:            void lRequestPaintItem(Item item, int x, int y, int w, int h) {
0953:
0954:                ItemLFImpl iLF = (ItemLFImpl) item.getLF();
0955:
0956:                lRequestPaint(iLF.bounds[X] + x, iLF.bounds[Y] + y, w, h, item);
0957:            }
0958:
0959:            /**
0960:             * Create native resource for this <code>Form</code>.
0961:             * <code>Item</code>s' resources are not created here.
0962:             */
0963:            void createNativeResource() {
0964:                setScrollPosition0(0);
0965:                nativeId = createNativeResource0(owner.title,
0966:                        owner.ticker == null ? null : owner.ticker.getString());
0967:            }
0968:
0969:            /**
0970:             * Service method - returns the <code>ItemLFImpl</code> that has focus.
0971:             *
0972:             * @return the current <code>ItemLFImpl</code>, or <code>null</code>
0973:             *         if there is no current.
0974:             */
0975:            ItemLFImpl getItemInFocus() {
0976:                if (traverseIndex < 0) {
0977:                    return null;
0978:                } else {
0979:                    return itemLFs[traverseIndex];
0980:                }
0981:            }
0982:
0983:            // ***************************************************************
0984:
0985:            /**
0986:             * Scroll to show an <code>Item</code> and give focus to it if possible.
0987:             *
0988:             * @param nativeId native resource id of the <code>Form</code>
0989:             * @param itemId native resource id for the focused <code>Item</code>
0990:             * @param yOffset offset for the y co-ordinate of the
0991:             *                focused <code>Item</code>
0992:             */
0993:            native void setCurrentItem0(int nativeId, int itemId, int yOffset);
0994:
0995:            /**
0996:             * Current Y position in a scrollable form.
0997:             *
0998:             * @return current scroll Y position
0999:             */
1000:            native int getScrollPosition0();
1001:
1002:            /**
1003:             * Set Y position in a scrollable form.
1004:             *
1005:             */
1006:            native void setScrollPosition0(int pos);
1007:
1008:            /**
1009:             * Create the native resource of this <code>Form</code>.
1010:             *
1011:             * @param title the title text of the <code>Form</code>
1012:             * @param tickerText the text of the <code>Ticker</code>,
1013:             *                   <code>Null</code> if no ticker.
1014:             *
1015:             * @return native resource id
1016:             *
1017:             * @exception OutOfMemoryException - if out of native resource
1018:             */
1019:            private native int createNativeResource0(String title,
1020:                    String tickerText);
1021:
1022:            /**
1023:             * Populate the native <code>Form</code> with visible <code>ItemLF</code>s
1024:             * and then show.
1025:             *
1026:             * @param nativeId native resource id
1027:             * @param modelVersion initial model version number for this visible period
1028:             * @param w width of the virtual Form without scrolling
1029:             * @param h height of the virtual Form without scrolling
1030:             *
1031:             * @exception OutOfMemoryException - if out of native resource
1032:             */
1033:            private native void showNativeResource0(int nativeId,
1034:                    int modelVersion, int w, int h);
1035:
1036:            /**
1037:             * Current viewport height in the native resource
1038:             *
1039:             * @return current viewport height
1040:             */
1041:            private native int getViewportHeight0();
1042:
1043:            /**
1044:             * Make sure all items have native resource and
1045:             * all <code>CustomItem</code>s have their minimum and preferred sizes
1046:             * cached.
1047:             */
1048:            private void uEnsureResourceAndRequestedSizes() {
1049:                int i, count = 0;
1050:                ItemLFImpl[] itemsCopy = null;
1051:
1052:                synchronized (Display.LCDUILock) {
1053:                    if (nativeId == INVALID_NATIVE_ID) {
1054:                        return;
1055:                    }
1056:                    // Make a temporary copy of ItemLFs we need to collect sizes from
1057:                    itemsCopy = new ItemLFImpl[numOfLFs];
1058:
1059:                    // Make sure each Item has native resource
1060:                    // and remember all the CustomItemLFImpls
1061:                    for (i = 0; i < numOfLFs; i++) {
1062:                        if (itemLFs[i].nativeId == INVALID_NATIVE_ID) {
1063:                            itemLFs[i].createNativeResource(super .nativeId);
1064:                            // layout(UPDATE_LAYOUT) later will not call
1065:                            // setSize/setLocation on an ItemLF that has valid bounds
1066:                            // already. But the native resource is recreated
1067:                            // above, we make up these two calls here.
1068:                            itemLFs[i].initNativeResource();
1069:                            // Every native resource is default to be visible in
1070:                            // viewport. It's up to the native container to maintain
1071:                            // viewport.
1072:                            itemLFs[i].lShowNativeResource();
1073:                        }
1074:
1075:                        if (itemLFs[i] instanceof  CustomItemLFImpl) {
1076:                            // Remember this in temporary array
1077:                            itemsCopy[count++] = itemLFs[i];
1078:                        }
1079:                    }
1080:                } // synchronized
1081:
1082:                // Collect min and preferred sizes from CustomItems
1083:                // SYNC NOTE: This may call into app code like
1084:                // CustomItem.getPrefContentWidth(). So do it outside LCDUILock
1085:                for (i = 0; i < count; i++) {
1086:                    ((CustomItemLFImpl) itemsCopy[i]).uCallSizeRefresh();
1087:                }
1088:
1089:            }
1090:
1091:            /**
1092:             * Show all items and give focus to current item.
1093:             * SYNC NOTE: caller must NOT hold LCDUILock since this function may
1094:             * call into app code like getPrefContentWidth(), sizeChanged or paint()
1095:             * of CustomItem. 
1096:             * @param initialTraverse the flag to indicate this is the initial 
1097:             *               traversal focus setup when this Form is being shown
1098:             */
1099:            private void uShowContents(boolean initialTraverse) {
1100:
1101:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1102:                    Logging.report(Logging.INFORMATION,
1103:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
1104:                            "\nFormLFImpl: showContents()");
1105:                }
1106:
1107:                synchronized (Display.LCDUILock) {
1108:                    if (firstShown) {
1109:                        for (int i = 0; i < numOfLFs; i++) {
1110:                            itemLFs[i].cachedWidth = ItemLFImpl.INVALID_SIZE;
1111:                        }
1112:                    }
1113:                }
1114:
1115:                // Ensure resources for all items and requested sizes for CustomItems
1116:                uEnsureResourceAndRequestedSizes();
1117:
1118:                ItemLFImpl[] itemsCopy = null;
1119:                int itemsCopyCount = 0;
1120:                int traverseIndexCopy = -1;
1121:
1122:                // Layout
1123:                synchronized (Display.LCDUILock) {
1124:                    if (nativeId == INVALID_NATIVE_ID) {
1125:                        return;
1126:                    }
1127:
1128:                    if (firstShown) {
1129:                        LayoutManager.instance().lLayout(
1130:                                LayoutManager.FULL_LAYOUT, itemLFs, numOfLFs,
1131:                                width, height, viewable);
1132:                        firstShown = false;
1133:
1134:                    } else {
1135:                        LayoutManager.instance().lLayout(
1136:                                LayoutManager.UPDATE_LAYOUT, itemLFs, numOfLFs,
1137:                                width, height, viewable);
1138:                    }
1139:
1140:                    if (resetToTop) {
1141:                        traverseIndex = -1;
1142:                        setScrollPosition0(0);
1143:                    }
1144:
1145:                    itemsCopy = new ItemLFImpl[numOfLFs];
1146:                    itemsCopyCount = numOfLFs;
1147:                    System.arraycopy(itemLFs, 0, itemsCopy, 0, numOfLFs);
1148:                    traverseIndexCopy = traverseIndex;
1149:                    itemsModified = false;
1150:
1151:                    // Set native Form's window viewable size (logical Form size)
1152:                    // and make it shown if not yet
1153:                    showNativeResource0(nativeId, modelVersion, width,
1154:                            viewable[HEIGHT]);
1155:
1156:                    // update viewport height
1157:                    viewportHeight = getViewportHeight0();
1158:
1159:                    // correct scroll position if any
1160:                    if (viewable[HEIGHT] <= viewportHeight) {
1161:                        // if viewable height is less than viewport
1162:                        // height just reset viewable y
1163:                        setScrollPosition0(0);
1164:                    } else if (getScrollPosition0() > (viewable[HEIGHT] - viewportHeight)) {
1165:                        // if viewable y exceeds the max value set it to the max
1166:                        // height just reset viewable y
1167:                        setScrollPosition0(viewable[HEIGHT] - viewportHeight);
1168:                    }
1169:
1170:                } // synchronized
1171:
1172:                uInitItemsInViewport(CustomItem.NONE, itemsCopy,
1173:                        traverseIndexCopy);
1174:
1175:                if (initialTraverse) {
1176:                    updateCommandSet();
1177:                }
1178:
1179:                for (int index = 0; index < itemsCopyCount; index++) {
1180:                    if (itemsCopy[index].sizeChanged) {
1181:                        itemsCopy[index].uCallSizeChanged(
1182:                                itemsCopy[index].bounds[WIDTH],
1183:                                itemsCopy[index].bounds[HEIGHT]);
1184:                        itemsCopy[index].sizeChanged = false;
1185:                    }
1186:                }
1187:            }
1188:
1189:            /**
1190:             * Perform a traversal. This method handles traversal within a
1191:             * "page" after the initial page has been shown via the 
1192:             * uInitItemsInViewport() routine. At the point this method is 
1193:             * called, the following conditions must be true:
1194:             *
1195:             * 1.) There are no interactive items at all on the current page
1196:             * or
1197:             * 2.) There is at least one interactive item on the current page
1198:             *     and the traverseIndex is currently set to that item. In this
1199:             *     case, itemTraverse represents the return value of that item's
1200:             *     initial traverse() call.
1201:             *
1202:             * Based on these conditions, this method will either:
1203:             *
1204:             * 1.) Continue the internal traversal on the current item (scrolling
1205:             *     as necessary to display the item's internal traversal location)
1206:             * or
1207:             * 2.) Perform a traversal to the next interactive item on the page
1208:             * or
1209:             * 3.) Perform a page flip (uScrollViewport()) and call the 
1210:             *     uInitItemsInViewport() routine to select an appropriate 
1211:             *     traversal item
1212:             *
1213:             * SYNC NOTE: Maybe call into CustomItem.traverse().
1214:             * So caller must not hold LCDUILock.
1215:             *
1216:             * @param dir the direction of traversal
1217:             */
1218:            void uTraverse(int dir) {
1219:
1220:                ItemLFImpl[] itemsCopy;
1221:                int traverseIndexCopy;
1222:                synchronized (Display.LCDUILock) {
1223:                    itemsCopy = new ItemLFImpl[numOfLFs];
1224:                    traverseIndexCopy = traverseIndex;
1225:                    System.arraycopy(itemLFs, 0, itemsCopy, 0, numOfLFs);
1226:                    itemsModified = false;
1227:                }
1228:
1229:                // itemTraverse indicates the return value of the
1230:                // last call to the current item's traverse method.
1231:                // 'true' indicates it is doing internal traversal,
1232:                // 'false' indicates we may traverse out of that item
1233:                // if we have something else to traverse to or scrolling
1234:                // that needs to be done
1235:                if (itemTraverse) {
1236:
1237:                    if (traverseIndexCopy == -1) {
1238:                        itemTraverse = false;
1239:                        return;
1240:                    }
1241:
1242:                    itemTraverse = uCallItemTraverse(
1243:                            itemsCopy[traverseIndexCopy], dir);
1244:
1245:                    if (itemTraverse) {
1246:                        // We may have to scroll to accommodate the new
1247:                        // traversal location 
1248:                        if (scrollForBounds(dir, visRect)) {
1249:                            uRequestPaint();
1250:                        }
1251:                        return;
1252:                    }
1253:                }
1254:
1255:                // We are done with the traversal of the current item, so
1256:                // we look to see if another interactive item is available on
1257:                // current page
1258:                int nextIndex = getNextInteractiveItem(itemsCopy, dir,
1259:                        traverseIndexCopy);
1260:
1261:                if (nextIndex != -1) {
1262:                    // NOTE: In traverse(), if there is a "next" interactive
1263:                    // item, there must have been a "first" interactive item
1264:                    // (which was set initially in uInitItemsInViewport())
1265:                    // so traverseIndex should always be valid
1266:
1267:                    // We need to traverse out of the previous item, now that
1268:                    // we've found a new item to traverse to
1269:
1270:                    // NOTE WELL: traverseIndex (and thus traverseIndexCopy) may well 
1271:                    // be invalid if there is no currently focused item, the app adds 
1272:                    // a focusable item, and then the user traverses before the 
1273:                    // resulting invalidation can be processed. Thus, this value must 
1274:                    // be guarded anyway. See CR#6254765.
1275:
1276:                    if (traverseIndexCopy != -1) {
1277:                        itemsCopy[traverseIndexCopy].uCallTraverseOut();
1278:                        synchronized (Display.LCDUILock) {
1279:                            itemsCopy[traverseIndexCopy].lRequestPaint();
1280:                        }
1281:                    }
1282:
1283:                    /*
1284:                     * NOTE: Although we update traverseIndex in a synchronized block
1285:                     * and call "lRefreshItems()" to update itemsCopy[] & 
1286:                     * traverseIndexCopy, 
1287:                     * original itemLFs[] & traverseIndex can change after sync block - 
1288:                     * so we still have a risk of referring to a non-existent item...
1289:                     */
1290:                    synchronized (Display.LCDUILock) {
1291:                        if (itemsModified) {
1292:                            // SYNCHRONIZE itemLFs & itemsCopy ...
1293:                            itemsCopy = lRefreshItems(itemsCopy,
1294:                                    traverseIndexCopy, nextIndex);
1295:                        } else {
1296:                            // Update our traverse index to the new item
1297:                            traverseIndex = nextIndex;
1298:                        }
1299:                        traverseIndexCopy = traverseIndex;
1300:                    }
1301:
1302:                    if (traverseIndexCopy != -1) {
1303:                        // We then need to traverse to the next item
1304:                        itemTraverse = uCallItemTraverse(
1305:                                itemsCopy[traverseIndexCopy], dir);
1306:
1307:                        if (scrollForBounds(dir, visRect)) {
1308:                            uRequestPaint(); // request to paint contents area
1309:                        } else {
1310:                            synchronized (Display.LCDUILock) {
1311:                                itemsCopy[traverseIndexCopy].lRequestPaint();
1312:                            }
1313:                        }
1314:                    }
1315:
1316:                    int scrollPos = getScrollPosition0();
1317:                    // There is a special case when traversing to the very last
1318:                    // item on a Form
1319:                    if (traverseIndexCopy == (itemsCopy.length - 1)
1320:                            && !itemCompletelyVisible(itemsCopy[traverseIndexCopy])) {
1321:                        // Since its the last item, we may need to
1322:                        // perform a partial scroll to fit it.                
1323:                        if (scrollPos + viewportHeight != itemsCopy[traverseIndexCopy].bounds[Y]
1324:                                + itemsCopy[traverseIndexCopy].bounds[HEIGHT]) {
1325:                            scrollPos = viewable[HEIGHT] - viewportHeight;
1326:
1327:                            // We make sure we don't go past the top of the
1328:                            // item, as we must have been going down to reach
1329:                            // the last item
1330:                            if (scrollPos > itemsCopy[traverseIndexCopy].bounds[Y]) {
1331:                                scrollPos = itemsCopy[traverseIndexCopy].bounds[Y];
1332:                            }
1333:                            uRequestPaint();
1334:                        }
1335:                    }
1336:
1337:                    // Likewise, there is a special case when traversing up to
1338:                    // the very first item on a Form
1339:                    if (traverseIndexCopy == 0) {
1340:                        // Since its the first item, we may need to
1341:                        // perform a partial scroll to fit it.
1342:                        if (scrollPos != itemsCopy[traverseIndexCopy].bounds[Y]) {
1343:                            scrollPos = itemsCopy[traverseIndexCopy].bounds[Y];
1344:
1345:                            // We make sure we don't go past the bottom of the
1346:                            // item, as we must have been going up to get to
1347:                            // the first item
1348:                            if (itemsCopy[traverseIndexCopy].bounds[HEIGHT] > viewportHeight) {
1349:                                scrollPos = itemsCopy[traverseIndexCopy].bounds[HEIGHT]
1350:                                        - viewportHeight;
1351:                            }
1352:                            uRequestPaint();
1353:                        }
1354:                    }
1355:                    setScrollPosition0(scrollPos);
1356:                    updateCommandSet();
1357:                } else {
1358:
1359:                    // There is no more interactive items wholly visible on
1360:                    // the current page. We may need to scroll to the next page,
1361:                    // if we do, then traverse out of the current item and 
1362:                    // scroll the page
1363:
1364:                    int scrollPos = getScrollPosition0();
1365:                    if ((dir == Canvas.LEFT || dir == Canvas.UP)
1366:                            && scrollPos > 0) {
1367:                        // Special case. We're at the top-most interactive item, but
1368:                        // its internal traversal doesn't allow the very top to be
1369:                        // seen, we just scroll the view to show it
1370:                        if (traverseIndexCopy != -1
1371:                                && (scrollPos > itemsCopy[traverseIndexCopy].bounds[Y])) {
1372:                            scrollPos -= (viewportHeight - PIXELS_LEFT_ON_PAGE);
1373:                            if (scrollPos < 0) {
1374:                                scrollPos = 0;
1375:                            }
1376:                            setScrollPosition0(scrollPos);
1377:                            uRequestPaint();
1378:                        } else {
1379:                            // page up
1380:                            uScrollViewport(Canvas.UP, itemsCopy);
1381:                            uInitItemsInViewport(Canvas.UP, itemsCopy,
1382:                                    traverseIndexCopy);
1383:                            updateCommandSet();
1384:                            return;
1385:                        }
1386:                    } else if ((dir == Canvas.RIGHT || dir == Canvas.DOWN)
1387:                            && (scrollPos + viewportHeight < viewable[HEIGHT])) {
1388:                        // Special case. We're at the bottom-most interactive item,
1389:                        // but its internal traversal doesn't allow the very bottom
1390:                        // to be seen, we just scroll the view to show it
1391:                        if (traverseIndexCopy != -1
1392:                                && ((itemsCopy[traverseIndexCopy].bounds[Y] + itemsCopy[traverseIndex].bounds[HEIGHT]) > (scrollPos + viewportHeight))) {
1393:                            scrollPos += (viewportHeight - PIXELS_LEFT_ON_PAGE);
1394:                            if (scrollPos > (viewable[HEIGHT] - viewportHeight)) {
1395:                                scrollPos = viewable[HEIGHT] - viewportHeight;
1396:                            }
1397:                            setScrollPosition0(scrollPos);
1398:                            uRequestPaint();
1399:                        } else {
1400:                            // page down
1401:                            uScrollViewport(Canvas.DOWN, itemsCopy);
1402:                            uInitItemsInViewport(Canvas.DOWN, itemsCopy,
1403:                                    traverseIndexCopy);
1404:                            updateCommandSet();
1405:                            return;
1406:                        }
1407:                    }
1408:
1409:                    // If we don't need to scroll the page and there is nothing
1410:                    // to traverse to, we reset the itemTraverse result as if
1411:                    // the Item wishes to proceed with internal traversal (as long
1412:                    // as there was some initial traverse in the first place, ie,
1413:                    // traverseIndex != -1)
1414:                    if (traverseIndexCopy != -1) {
1415:                        itemTraverse = true;
1416:                    }
1417:                    updateCommandSet();
1418:                }
1419:            }
1420:
1421:            /**
1422:             * Perform a page flip in the given direction. This method will
1423:             * attempt to scroll the view to show as much of the next page
1424:             * as possible. It uses the locations and bounds of the items on
1425:             * the page to best determine a new location - taking into account
1426:             * items which may lie on page boundaries as well as items which
1427:             * may span several pages.
1428:             *
1429:             * @param dir the direction of the flip, either DOWN or UP
1430:             * @param items the set of items on the Form, used to determine
1431:             *        the best suited scroll locations
1432:             */
1433:            void uScrollViewport(int dir, ItemLFImpl[] items) {
1434:                int scrollPos = getScrollPosition0();
1435:
1436:                if (dir == Canvas.UP) {
1437:                    int newY = scrollPos
1438:                            - (viewportHeight - PIXELS_LEFT_ON_PAGE);
1439:                    if (newY < 0) {
1440:                        newY = 0;
1441:                    }
1442:
1443:                    // We loop upwards until we find the first item which is
1444:                    // currently at least partially visible
1445:                    int firstVis = items.length;
1446:                    for (int i = items.length - 1; i >= 0; i--) {
1447:                        if (items[i].visibleInViewport) {
1448:                            firstVis = i;
1449:                        }
1450:                    }
1451:
1452:                    // case 1. We're at the top of the item so just
1453:                    // traverse normally
1454:                    if (items[firstVis].bounds[Y] >= scrollPos) {
1455:                        scrollPos = newY;
1456:                        setScrollPosition0(scrollPos);
1457:                        return;
1458:                    }
1459:
1460:                    // case 2. We try to fit as much of the partially visible
1461:                    // item onscreen as possible.
1462:                    int fitY = (items[firstVis].bounds[Y] + items[firstVis].bounds[HEIGHT])
1463:                            - viewportHeight;
1464:
1465:                    if (fitY > newY && scrollPos > fitY) {
1466:                        newY = fitY;
1467:                    }
1468:
1469:                    scrollPos = newY;
1470:                    setScrollPosition0(scrollPos);
1471:                    return;
1472:
1473:                } else if (dir == Canvas.DOWN) {
1474:                    int newY = scrollPos
1475:                            + (viewportHeight - PIXELS_LEFT_ON_PAGE);
1476:                    if (newY > viewable[HEIGHT] - viewportHeight) {
1477:                        newY = viewable[HEIGHT] - viewportHeight;
1478:                    }
1479:
1480:                    // We loop downwards until we find the last item which is
1481:                    // at least partially visible
1482:                    int lastVis = -1;
1483:                    for (int i = 0; i < items.length; i++) {
1484:                        if (items[i].visibleInViewport) {
1485:                            lastVis = i;
1486:                        }
1487:                    }
1488:
1489:                    // case 1. We're at the bottom of the item so just
1490:                    // traverse normally
1491:                    if (items[lastVis].bounds[Y]
1492:                            + items[lastVis].bounds[HEIGHT] <= scrollPos
1493:                            + viewportHeight) {
1494:                        scrollPos = newY;
1495:                        setScrollPosition0(scrollPos);
1496:                        return;
1497:                    }
1498:
1499:                    // case 2. We try to fit as much of the partially visible
1500:                    // item onscreen as possible unless we're already at the top
1501:                    // of the item from a previous scroll
1502:                    if (newY > items[lastVis].bounds[Y]
1503:                            && scrollPos < items[lastVis].bounds[Y]) {
1504:                        newY = items[lastVis].bounds[Y];
1505:                    }
1506:
1507:                    scrollPos = newY;
1508:                    setScrollPosition0(scrollPos);
1509:                    return;
1510:                }
1511:            }
1512:
1513:            /**
1514:             * Determine if scrolling is needed for a given bounding box,
1515:             * and perform such scrolling if necessary.
1516:             *
1517:             * @param dir the direction of travel
1518:             * @param bounds the bounding box of the traversal location
1519:             * @return <code>true</code> if it was necessary to scroll the view 
1520:             *         in order to best accommodate the bounding box
1521:             */
1522:            boolean scrollForBounds(int dir, int bounds[]) {
1523:                if (bounds == null || bounds[0] == -1) {
1524:                    return false;
1525:                }
1526:
1527:                int scrollPos = getScrollPosition0();
1528:
1529:                // There is a special case whereby the CustomItem
1530:                // spec mandates the upper left corner of the internal
1531:                // traversal rect be visible if the rect is larger than
1532:                // the available viewport
1533:                if (bounds[HEIGHT] >= viewportHeight && scrollPos != bounds[Y]) {
1534:                    setScrollPosition0(bounds[Y]);
1535:                    return true;
1536:                }
1537:
1538:                switch (dir) {
1539:                case Canvas.LEFT:
1540:                case Canvas.UP:
1541:                    if (bounds[Y] >= scrollPos) {
1542:                        return false;
1543:                    }
1544:
1545:                    scrollPos -= (viewportHeight - PIXELS_LEFT_ON_PAGE);
1546:                    if (scrollPos < 0) {
1547:                        scrollPos = 0;
1548:                    }
1549:                    setScrollPosition0(scrollPos);
1550:                    return true;
1551:                case Canvas.RIGHT:
1552:                case Canvas.DOWN:
1553:                    if (bounds[Y] + bounds[HEIGHT] <= scrollPos
1554:                            + viewportHeight) {
1555:                        return false;
1556:                    }
1557:
1558:                    scrollPos += (viewportHeight - PIXELS_LEFT_ON_PAGE);
1559:                    if (scrollPos > bounds[Y]) {
1560:                        scrollPos = bounds[Y];
1561:                    }
1562:                    if (scrollPos + viewportHeight > viewable[HEIGHT]) {
1563:                        scrollPos = viewable[HEIGHT] - viewportHeight;
1564:                    }
1565:                    setScrollPosition0(scrollPos);
1566:                    return true;
1567:                default:
1568:                    // for safety/completeness, don't scroll.
1569:                    Logging.report(Logging.ERROR,
1570:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
1571:                            "FormLFImpl: bounds, dir=" + dir);
1572:                    break;
1573:                }
1574:                return false;
1575:            }
1576:
1577:            /**
1578:             * This method will return the index of the next interactive
1579:             * item which is wholly visible on the screen given the traversal
1580:             * direction, or -1 if no visible items in that traversal direction
1581:             * are interactive (or completely visible).
1582:             *
1583:             * @param items the set of items to search
1584:             * @param dir the direction of traversal
1585:             * @param index the "anchor" of the index to start from
1586:             * @return the index of the next interactive item, or -1 if one is
1587:             *         not completely visible or available in the given direction
1588:             */
1589:            int getNextInteractiveItem(ItemLFImpl[] items, int dir, int index) {
1590:
1591:                try {
1592:                    int scrollPos = getScrollPosition0();
1593:
1594:                    while (true) {
1595:                        switch (dir) {
1596:                        case Canvas.UP:
1597:                        case Canvas.LEFT:
1598:                            index -= 1;
1599:                            break;
1600:                        case Canvas.DOWN:
1601:                        case Canvas.RIGHT:
1602:                            index += 1;
1603:                            break;
1604:                        case CustomItem.NONE:
1605:                            // no - op
1606:                            break;
1607:                        default:
1608:                            // for safety/completeness.
1609:                            Logging.report(Logging.ERROR,
1610:                                    LogChannels.LC_HIGHUI_FORM_LAYOUT,
1611:                                    "FormLFImpl: dir=" + dir);
1612:                            return index;
1613:                        }
1614:                        // If we've exhausted the set, stop looking                
1615:                        if (index < 0 || index >= items.length) {
1616:                            break;
1617:                        }
1618:
1619:                        // If we've found a non-interactive item, continue
1620:
1621:                        if (!items[index].item.acceptFocus()) {
1622:                            continue;
1623:                        }
1624:
1625:                        // If we've found a completely visible, interactive
1626:                        // item, stop and traverse to it
1627:                        if (itemCompletelyVisible(items[index])) {
1628:                            break;
1629:                        }
1630:
1631:                        // If we've found a partially visible, interactive
1632:                        // item, there is some special casing involved with
1633:                        // how to scroll appropriately
1634:                        if (itemPartiallyVisible(items[index])) {
1635:                            if (dir == Canvas.RIGHT || dir == Canvas.DOWN) {
1636:
1637:                                // If we're paging down and the item's top
1638:                                // is at the top of the viewport, stop and
1639:                                // traverse to that item (its bigger than the
1640:                                // viewport
1641:                                if (items[index].bounds[Y] == scrollPos) {
1642:                                    break;
1643:                                }
1644:
1645:                                // If we're paging down and the item's bottom
1646:                                // is the very last thing in the view, stop and
1647:                                // keep traversal on that item (item is bigger
1648:                                // than the viewport and we can go no further)
1649:                                if (items[index].bounds[Y]
1650:                                        + items[index].bounds[HEIGHT] == viewable[HEIGHT]) {
1651:                                    break;
1652:                                }
1653:                            } else if (dir == Canvas.LEFT || dir == Canvas.UP) {
1654:
1655:                                // If we're paging up and the item's bottom is the
1656:                                // very bottom of the viewport, stop and keep
1657:                                // traversal on that item (item is bigger than the
1658:                                // viewport and we start at the bottom)
1659:                                if (items[index].bounds[Y]
1660:                                        + items[index].bounds[HEIGHT] == viewable[HEIGHT]) {
1661:                                    break;
1662:                                }
1663:
1664:                                // If we're paging up and the item's top is at
1665:                                // the top of the viewport, stop and traverse
1666:                                // to that item (its bigger than the viewport
1667:                                // and we should show the top of it before leaving)
1668:                                if (items[index].bounds[Y] == scrollPos
1669:                                        && scrollPos == 0) {
1670:                                    break;
1671:                                }
1672:                            }
1673:                        }
1674:                    } // while                
1675:                } catch (Throwable t) {
1676:                    if (Logging.REPORT_LEVEL <= Logging.WARNING) {
1677:                        Logging
1678:                                .report(Logging.WARNING, LogChannels.LC_HIGHUI,
1679:                                        "Throwable while finding next item for traversal");
1680:                    }
1681:                    return -1;
1682:                }
1683:
1684:                // This means there was no interactive item in the currently
1685:                // visible viewport
1686:                if (index < 0 || index >= items.length) {
1687:                    return -1;
1688:                }
1689:
1690:                return index;
1691:            }
1692:
1693:            /**
1694:             * Determine if the given item is at least partially visible
1695:             * in the current viewport.
1696:             *
1697:             * @param item the item to determine visibility
1698:             * @return true if at least part of the item is visible
1699:             */
1700:            boolean itemPartiallyVisible(ItemLFImpl item) {
1701:                // If the Form is hidden, all the items are
1702:                // hidden and we just return false
1703:                if (super .state == HIDDEN) {
1704:                    return false;
1705:                }
1706:                int scrollPos = getScrollPosition0();
1707:                // If the Item's top is within the viewport, return true
1708:                return !(item.bounds[Y] > scrollPos + viewportHeight || item.bounds[Y]
1709:                        + item.bounds[HEIGHT] < scrollPos);
1710:            }
1711:
1712:            /**
1713:             * Determine if the given item is at completely visible
1714:             * in the current viewport.
1715:             *
1716:             * @param item the item to determine visibility
1717:             * @return true if at the item is entirely visible
1718:             */
1719:            boolean itemCompletelyVisible(ItemLFImpl item) {
1720:                // If the Form is being hidden, all the items are
1721:                // hidden and we just return false
1722:                if (super .state == HIDDEN) {
1723:                    return false;
1724:                }
1725:
1726:                // If the Item's top and bottom are within the viewport,
1727:                // return true
1728:                int scrollPos = getScrollPosition0();
1729:                return (item.bounds[Y] >= scrollPos)
1730:                        && (item.bounds[Y] + item.bounds[HEIGHT] <= scrollPos
1731:                                + viewportHeight);
1732:            }
1733:
1734:            /**
1735:             * Calculate the rectangle representing the region of the item that is
1736:             * currently visible. This region might have zero area if no part of the
1737:             * item is visible, for example, if it is scrolled offscreen.
1738:             * @param item item
1739:             * @param visRect  It must be an int[4] array. The information in this array is
1740:             * a rectangle of the form [x,y,w,h]  where (x,y) is the location of the
1741:             * upper-left corner of the rectangle relative to the item's origin, and
1742:             * (w,h) are the width and height of the rectangle.
1743:             */
1744:            private void setVisRect(ItemLFImpl item, int[] visRect) {
1745:                synchronized (Display.LCDUILock) {
1746:                    // Initialize the in-out rect for traversal
1747:                    visRect[X] = 0;
1748:                    visRect[WIDTH] = width;
1749:
1750:                    // take the coordinates from the overall
1751:                    // coordinate space 
1752:
1753:                    int itemY1 = item.bounds[Y];
1754:                    int itemY2 = item.bounds[Y] + item.bounds[HEIGHT];
1755:
1756:                    // vpY1 the y coordinate of the top left visible pixel
1757:                    // current scroll position
1758:                    int vpY1 = getScrollPosition0();
1759:                    ;
1760:                    // vpY2 the y coordinate of bottom left pixel
1761:                    int vpY2 = vpY1 + height;
1762:
1763:                    // return only the visible region of item
1764:
1765:                    // item completely visible in viewport
1766:                    visRect[Y] = 0;
1767:                    visRect[HEIGHT] = item.bounds[HEIGHT];
1768:
1769:                    if ((itemY1 >= vpY2) || (itemY2 <= vpY1)) {
1770:                        // no part of the item is visible
1771:                        // so this region has zero area
1772:                        visRect[WIDTH] = 0;
1773:                        visRect[HEIGHT] = 0;
1774:                    } else {
1775:                        if (itemY1 < vpY1) {
1776:                            // upper overlap
1777:                            visRect[Y] = vpY1 - itemY1;
1778:                            visRect[HEIGHT] -= (vpY1 - itemY1);
1779:                        }
1780:                        if (itemY2 > vpY2) {
1781:                            // lower overlap
1782:                            visRect[HEIGHT] -= (itemY2 - vpY2);
1783:                        }
1784:                    }
1785:                }
1786:            }
1787:
1788:            /**
1789:             * Perform an internal traversal on the given item in
1790:             * the given direction. The only assertion here is that
1791:             * the item provided must be interactive (or otherwise
1792:             * be a CustomItem). When this method returns, visRect[]
1793:             * will hold the bounding box of the item's internal
1794:             * traversal (in the Form's coordinate space).
1795:             *
1796:             * @param item the item to traverse within
1797:             * @param dir the direction of traversal
1798:             * @return true if this item performed an internal traversal
1799:             *         in the given direction.
1800:             */
1801:            boolean uCallItemTraverse(ItemLFImpl item, int dir) {
1802:
1803:                boolean ret = false;
1804:
1805:                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1806:                    Logging.report(Logging.INFORMATION,
1807:                            LogChannels.LC_HIGHUI_FORM_LAYOUT,
1808:                            "[F] uCallItemTraverse: dir=" + dir
1809:                                    + " traverseIndex=" + traverseIndex);
1810:                }
1811:
1812:                // The visRect is supposed to show the bounds of the Item
1813:                // currently visible on the screen
1814:                setVisRect(item, visRect);
1815:
1816:                // Whether the item performs an internal traversal or not,
1817:                // it has the current input focus
1818:                //item.hasFocus = true;
1819:
1820:                // Call traverse() outside LCDUILock
1821:                if (item.uCallTraverse(dir, width, viewportHeight, visRect)) {
1822:                    synchronized (Display.LCDUILock) {
1823:                        // It's possible that this newFocus item has
1824:                        // been just removed from this Form since we
1825:                        // are outside LCDUILock. Check again.
1826:                        if (item.nativeId != INVALID_NATIVE_ID) {
1827:                            setCurrentItem0(nativeId, item.nativeId, visRect[Y]);
1828:                        }
1829:                    }
1830:
1831:                    ret = true;
1832:                }
1833:
1834:                // Since visRect is sent to the Item in its own coordinate
1835:                // space, we translate it back into the overall Form's
1836:                // coordinate space
1837:                visRect[X] += item.bounds[X];
1838:                visRect[Y] += item.bounds[Y];
1839:
1840:                return ret;
1841:            }
1842:
1843:            /**
1844:             * Scrolls to the passed in Item.
1845:             * @param item The Item that should be shown on the screen.
1846:             */
1847:            private void lScrollToItem(Item item) {
1848:
1849:                if (item == null || item.owner != owner) {
1850:                    return;
1851:                }
1852:
1853:                int index = -1;
1854:
1855:                ItemLFImpl itemLF = null;
1856:                if (traverseIndex != -1
1857:                        && (itemLFs[traverseIndex].item == item)) {
1858:                    index = traverseIndex;
1859:                } else {
1860:                    for (int i = 0; i < numOfLFs; i++) {
1861:                        if (itemLFs[i].item == item) {
1862:                            index = i;
1863:                            break;
1864:                        }
1865:                    }
1866:                }
1867:
1868:                // item not found
1869:                if (index == -1) {
1870:                    return;
1871:                }
1872:
1873:                itemLF = itemLFs[index];
1874:
1875:                if (index != traverseIndex) {
1876:                    // Ensure the item is visible
1877:                    if (!itemCompletelyVisible(itemLF)) {
1878:                        int scrollPos = itemLF.bounds[Y];
1879:                        if (scrollPos + viewportHeight > viewable[HEIGHT]) {
1880:                            scrollPos = viewable[HEIGHT] - viewportHeight;
1881:                        }
1882:                        setScrollPosition0(scrollPos);
1883:                    }
1884:
1885:                    // We record the present traverseItem because if it
1886:                    // is valid, we will have to call traverseOut() on that
1887:                    // item when we process the invalidate call.
1888:                    if (traverseIndex != -1) {
1889:                        lastTraverseItem = itemLFs[traverseIndex];
1890:                    }
1891:
1892:                    // If the item is not interactive, we just leave it
1893:                    // visible on the screen, but set traverseIndex to -1
1894:                    // so that any interactive item which is visible will
1895:                    // be traversed to when the invalidate occurs
1896:                    traverseIndex = itemLF.item.acceptFocus() ? index : -1;
1897:                    lRequestInvalidate();
1898:                } else {
1899:                    // Ensure the item is visible
1900:                    if (!itemPartiallyVisible(itemLF)) {
1901:                        int scrollPos = itemLF.bounds[Y];
1902:                        if (scrollPos + viewportHeight > viewable[HEIGHT]) {
1903:                            scrollPos = viewable[HEIGHT] - viewportHeight;
1904:                        }
1905:                        setScrollPosition0(scrollPos);
1906:                    }
1907:                }
1908:            }
1909:
1910:            /**
1911:             * Initialize the current page of items, perform a traverse if possible.
1912:             * This method is always called when a page is initially "shown".
1913:             * This occurs when the form gains visibility for the very first
1914:             * time as well as after every page up/page down occurs.
1915:             *
1916:             * This method searches for the most appropriate item on the form
1917:             * to receive the interaction focus.
1918:             *
1919:             * @param dir the direction of travel. Can be NONE when a page is
1920:             *        first shown or as the result of an invalidate.
1921:             * @param itemsCopy a copy of the set of ItemLFImpls in this form.
1922:             * @param traverseIndexCopy a copy of taverseIndex to work with itesCopy[]
1923:             */
1924:            void uInitItemsInViewport(int dir, ItemLFImpl[] itemsCopy,
1925:                    int traverseIndexCopy) {
1926:                // Create a copy of the current index for comparisons, below.
1927:                if (itemsCopy.length == 0) {
1928:                    return;
1929:                }
1930:
1931:                // Hide & Show Items 
1932:                int pos = getScrollPosition0();
1933:                uViewportChanged(pos, pos + viewportHeight);
1934:
1935:                // The result of an invalidate() call
1936:                if (traverseIndexCopy != -1 && dir == CustomItem.NONE) {
1937:                    itemTraverse = uCallItemTraverse(
1938:                            itemsCopy[traverseIndexCopy], dir);
1939:
1940:                    uRequestPaint(); // request to paint contents area
1941:                    return;
1942:                }
1943:
1944:                // Special case: It could be that no item in the current view
1945:                // is interactive, and thus the traverseIndexCopy is -1. If we
1946:                // are scrolling upwards, we artificially set it to be the last
1947:                // item on the form (+1) so that the getNextInteractiveItem()
1948:                // routine will subsequently reduce it by 1 and start searching
1949:                // for an interactive item from the bottom of the form upwards.
1950:                if (dir == Canvas.UP && traverseIndexCopy == -1) {
1951:                    traverseIndexCopy = itemsCopy.length;
1952:                }
1953:
1954:                // If paging "down", we find the interactive item by moving
1955:                // left to right - this ensures we move line by line searching
1956:                // for an interactive item. When paging "up", we search from
1957:                // right to left.
1958:                int nextIndex = (dir == Canvas.DOWN || dir == CustomItem.NONE) ? getNextInteractiveItem(
1959:                        itemsCopy, Canvas.RIGHT, traverseIndexCopy)
1960:                        : getNextInteractiveItem(
1961:
1962:                        itemsCopy, Canvas.LEFT, traverseIndexCopy);
1963:
1964:                if (traverseIndexCopy > -1
1965:                        && traverseIndexCopy < itemsCopy.length) {
1966:                    if (nextIndex != -1
1967:                            || !itemCompletelyVisible(itemsCopy[traverseIndexCopy])) {
1968:                        // It could be we need to traverse out of a current
1969:                        // item before paging
1970:                        itemsCopy[traverseIndexCopy].uCallTraverseOut();
1971:                        synchronized (Display.LCDUILock) {
1972:                            traverseIndex = -1; // reset real index
1973:                            traverseIndexCopy = traverseIndex;
1974:                        }
1975:                    }
1976:                }
1977:                /*
1978:                 * NOTE: between these two sync sections itemLFs[] & traverseIndex
1979:                 * can change again ...
1980:                 */
1981:                synchronized (Display.LCDUILock) {
1982:                    if (itemsModified) {
1983:                        // SYNCHRONIZE itemLFs & itemsCopy, update traverseIndex ...
1984:                        itemsCopy = lRefreshItems(itemsCopy, traverseIndexCopy,
1985:                                nextIndex);
1986:                    } else if ((nextIndex > -1) && (nextIndex < numOfLFs)) {
1987:                        traverseIndex = nextIndex;
1988:                    }
1989:                    traverseIndexCopy = traverseIndex;
1990:                }
1991:
1992:                if (traverseIndexCopy == -1
1993:                        || traverseIndexCopy == itemsCopy.length) {
1994:                    // If there is no traversable item on the current page,
1995:                    // we simply return, and on the next 'traverse' we will
1996:                    // perform a page scroll and repeat this method
1997:                } else {
1998:                    // If there is a traversable item, we go ahead and traverse
1999:                    // to it. We do *not* scroll at all under these circumstances
2000:                    // because we have just performed a fresh page view (or scroll)
2001:                    itemTraverse = uCallItemTraverse(
2002:                            itemsCopy[traverseIndexCopy], dir);
2003:                }
2004:
2005:                uRequestPaint(); // request to paint contents area                
2006:            }
2007:
2008:            /**
2009:             * Called by the system to notify that viewport scroll location
2010:             * or height has been changed.
2011:             *
2012:             * @param vpY1 the y coordinate of the top left visible pixel
2013:             * @param vpY2 the y coordinate of bottom left pixel 
2014:             *             immediately below the viewport
2015:             */
2016:            private void uViewportChanged(int vpY1, int vpY2) {
2017:
2018:                int i, showCount, hideCount, size;
2019:                ItemLFImpl[] itemsCopy = null;
2020:
2021:                synchronized (Display.LCDUILock) {
2022:
2023:                    itemsCopy = new ItemLFImpl[numOfLFs];
2024:                    size = numOfLFs;
2025:
2026:                    showCount = 0;
2027:                    hideCount = numOfLFs;
2028:
2029:                    for (i = 0; i < numOfLFs; i++) {
2030:                        if (itemLFs[i].bounds[Y] + itemLFs[i].bounds[HEIGHT]
2031:                                - 1 > vpY1
2032:                                && itemLFs[i].bounds[Y] < vpY2) {
2033:                            // should become visible
2034:                            if (itemLFs[i].visibleInViewport == false) {
2035:                                itemsCopy[showCount++] = itemLFs[i];
2036:                            }
2037:                        } else {
2038:                            // should not be visible
2039:                            if (itemLFs[i].visibleInViewport) {
2040:                                itemsCopy[--hideCount] = itemLFs[i];
2041:                            }
2042:                        }
2043:                    }
2044:                } // synchronized (LCDUILock)
2045:
2046:                for (i = 0; i < showCount; i++) {
2047:                    itemsCopy[i].uCallShowNotify();
2048:                }
2049:
2050:                for (i = hideCount; i < size; i++) {
2051:                    itemsCopy[i].uCallHideNotify();
2052:                }
2053:            }
2054:
2055:            /**
2056:             * Service method - find the <code>ItemLFImpl</code> from a given 
2057:             * native id.
2058:             *
2059:             * @param nativeId native id to search
2060:             *
2061:             * @return the <code>ItemLFImpl</code>, or <code>null</code> not found
2062:             */
2063:            private ItemLFImpl id2Item(int nativeId) {
2064:
2065:                ItemLFImpl focus = getItemInFocus();
2066:
2067:                if (focus != null && focus.nativeId == nativeId) {
2068:                    return focus;
2069:                } else {
2070:                    for (int i = 0; i < numOfLFs; i++) {
2071:                        if (itemLFs[i].nativeId == nativeId) {
2072:                            return itemLFs[i];
2073:                        }
2074:                    }
2075:                    // there is no matching ItemLFImpl
2076:                    return null;
2077:                }
2078:            }
2079:
2080:            /**
2081:             * Service method - find the <code>ItemLFImpl</code> index.
2082:             *
2083:             * @param itemLF itemLF to map
2084:             *
2085:             * @return index of the item. -1 if not found.
2086:             */
2087:            private int item2Index(ItemLFImpl itemLF) {
2088:
2089:                for (int i = 0; i < numOfLFs; i++) {
2090:                    if (itemLFs[i] == itemLF) {
2091:                        return i;
2092:                    }
2093:                }
2094:
2095:                return -1;
2096:            }
2097:
2098:            /**
2099:             * Ensure that dispatchItemLFs array has enough space for use.
2100:             * SYNC NOTE: This function must only be used in event dispatch thread.
2101:             *
2102:             * @param size maximum number of itemLFs needed
2103:             */
2104:            private static void ensureDispatchItemArray(int size) {
2105:                if (size > dispatchItemLFs.length) {
2106:                    dispatchItemLFs = new ItemLFImpl[size];
2107:                }
2108:            }
2109:
2110:            /**
2111:             * Clear contents of dispatchItemLFs array after use.
2112:             * SYNC NOTE: This function must only be used in event dispatch thread.
2113:             *
2114:             * @param alsoShrink true if the array size should be minimized
2115:             */
2116:            private static void resetDispatchItemArray(boolean alsoShrink) {
2117:
2118:                if (alsoShrink
2119:                        && dispatchItemLFs.length > DISPATCH_ITEM_ARRAY_BLOCK) {
2120:                    dispatchItemLFs = new ItemLFImpl[DISPATCH_ITEM_ARRAY_BLOCK];
2121:                } else {
2122:                    // Only clean up existing array contents
2123:                    for (int i = 0; i < dispatchItemLFs.length; i++) {
2124:                        dispatchItemLFs[i] = null;
2125:                    }
2126:                }
2127:            }
2128:
2129:            /**
2130:             * Synchronizes itemLFs[] array with itemsCopy[] array, 
2131:             * as well as traverseIndex with traverseIndexCopy & nextIndex. 
2132:             *
2133:             * Since most of work with copies occurs outside of LCDUILock
2134:             * (this is, BTW, the reason, why copies are used instead of original
2135:             * fields), there is a risk, that
2136:             * itemLFs[] content can be changed (ex. insert/delete/replace Item): 
2137:             * traverseIndexCopy can point to a different object 
2138:             * (including non-interactive), 
2139:             * or outside of changed itemLFs array (throws exception), 
2140:             * or we can refer to a deleted item (deleted in itemLFs, 
2141:             * but still exists in a copy).
2142:             *
2143:             * This method tries to find item, referred by nextIndex in itemsCopy[], 
2144:             * in itelLFs[], and if found, sets traverseIndex to foundItem, 
2145:             * else sets traverse index to -1.
2146:             *
2147:             * This method indended to be called in LCDUILock-protected code, 
2148:             * from uInitItemsInViewport(...) & uTraverse(...).
2149:             *
2150:             * @param itemsCopy a copy of the set of ItemLFImpls in this form.
2151:             * @param traverseIndexCopy a copy of traverseIndex to work with itemsCopy
2152:             * @param nextIndex suggested new value of traverseIndex, 
2153:             *        the item from itemsCopy[] to be found in changed itemLFs[]
2154:             *
2155:             * @return updated itemsCopy[] array, synchronized with itemLFs[]
2156:             */
2157:            private ItemLFImpl[] lRefreshItems(ItemLFImpl[] itemsCopy,
2158:                    int traverseIndexCopy, int nextIndex) {
2159:
2160:                final int nextIndexInLFs = nextIndex
2161:                        + (traverseIndex - traverseIndexCopy);
2162:                traverseIndex = ((traverseIndex > -1) &&
2163:                /* (traverseIndex < numOfLFs) && */
2164:                (traverseIndexCopy > -1) &&
2165:                /* (traverseIndexCopy < itemsCopy.length) && */
2166:                (nextIndex > -1) &&
2167:                /* (nextIndex < itemsCopy.length) && */
2168:                (nextIndexInLFs > -1) && (nextIndexInLFs < numOfLFs) && !itemLFs[nextIndexInLFs].item
2169:                        .acceptFocus())
2170:                /* (itemsCopy[nextIndex] == itemLFs[nextIndexInLFs])) */
2171:                /*
2172:                 * Assume that:
2173:                 * 1). traverseIndex has always valid value: 
2174:                 * i.e. -1 or within [0..numOfLFs[ range of itemLFs[] array.
2175:                 * 2). traverseIndexCopy & nextIndex have always valid values: 
2176:                 * i.e. -1 or within [0..itemsCopy.length[ range  
2177:                 * of itemsCopy[] array.
2178:                 * As the result we need to check them only for "-1" value.
2179:                 * Computed "nextIndexInLFs" needs to be checked for 
2180:                 * being in bounds of itemLFs[].
2181:                 *
2182:                 * Need revisit : if last condition in the above  "IF" is needed,
2183:                 * however it ensures, that the  next current item 
2184:                 * will be exactly the same item that has been found 
2185:                 * by "getNext...". 
2186:                 * Without thast statement we have a risk to point to 
2187:                 * a completely different item: still valid & 
2188:                 * in the range, but probably NON-interactive :-( 
2189:                 * To avoid this, "shouldSkipTraverse()" could be used insead ...
2190:                 */
2191:                ? nextIndexInLFs : -1;
2192:
2193:                // refresh itemsCopy array ...
2194:                itemsCopy = new ItemLFImpl[numOfLFs];
2195:                System.arraycopy(itemLFs, 0, itemsCopy, 0, numOfLFs);
2196:                itemsModified = false;
2197:                return itemsCopy;
2198:            }
2199:
2200:            /** 
2201:             * A bit mask to capture the horizontal layout directive of an item.
2202:             */
2203:            final static int LAYOUT_HMASK = 0x03;
2204:
2205:            /** 
2206:             * A bit mask to capture the vertical layout directive of an item.
2207:             */
2208:            final static int LAYOUT_VMASK = 0x30;
2209:
2210:            /** 
2211:             * Do a full layout.
2212:             */
2213:            final static int FULL_LAYOUT = -1;
2214:
2215:            /** 
2216:             * Only update layout.
2217:             */
2218:            final static int UPDATE_LAYOUT = -2;
2219:
2220:            /**
2221:             * This is the rate at which the internal array of Items grows if
2222:             * it gets filled up.
2223:             */
2224:            private static final int GROW_SIZE = 4;
2225:
2226:            /**
2227:             * This is the number of pixels left from the previous "page"
2228:             * when a page up or down occurs
2229:             */
2230:            static final int PIXELS_LEFT_ON_PAGE = 15;
2231:
2232:            /** The item index which has the traversal focus */
2233:            int traverseIndex = -1;
2234:
2235:            /**
2236:             * Item that was made visible using display.setCurrentItem() call
2237:             * while FormLF was in HIDDEN or FROZEN state.
2238:             */
2239:            Item pendingCurrentItem = null;
2240:
2241:            /** 
2242:             * This is a special case variable which tracks the last
2243:             * traversed item when a new item is traversed to via the
2244:             * setCurrentItem() call.
2245:             */
2246:            ItemLFImpl lastTraverseItem;
2247:
2248:            /** 
2249:             * A flag indicating the return value of the currently
2250:             * selected Item from its traverse() method
2251:             */
2252:            boolean itemTraverse;
2253:
2254:            /** 
2255:             * A flag that shows that itemLFs[] storage has been modified
2256:             * (items inserted/deleted) and earlier made copies (extends itemsCopy[])
2257:             * are outdated. 
2258:             * flag is set by item insert/delete operations, 
2259:             * cleared when copy operation is performed. 
2260:             */
2261:            boolean itemsModified;
2262:
2263:            /**
2264:             * When a Form calls an Item's traverse() method, it passes in
2265:             * an in-out int[] that represents the Item's traversal
2266:             * bounds. This gets cached in the visRect variable
2267:             */
2268:            int[] visRect;
2269:
2270:            /**
2271:             * Array of <code>ItemLF</code>s that correspond to the array of items 
2272:             * in <code>Form</code>.
2273:             */
2274:            private ItemLFImpl[] itemLFs;
2275:
2276:            /**
2277:             * Block size of the temporary array of <code>ItemLF</code>s used 
2278:             * in dispatch.
2279:             */
2280:            private final static int DISPATCH_ITEM_ARRAY_BLOCK = 10;
2281:
2282:            /**
2283:             * Temporary array of <code>ItemLF</code>s that is ONLY used in 
2284:             * dispatch thread during show, hide and re-layout this <code>Form</code>.
2285:             *
2286:             * ensureDispatchItemArray() should be called before use and
2287:             * resetDispatchItemArray() should be called when it is no longer needed,
2288:             * to allow <code>ItemLFImpl</code> objects been GC'ed.
2289:             */
2290:            private static ItemLFImpl[] dispatchItemLFs = new ItemLFImpl[DISPATCH_ITEM_ARRAY_BLOCK];
2291:
2292:            /**
2293:             * The number of views present in this <code>FormLF</code>.
2294:             */
2295:            private int numOfLFs;
2296:
2297:            /**
2298:             * This helps an optimization.
2299:             */
2300:            private boolean firstShown = true;
2301:
2302:            /**
2303:             * Screens should automatically reset to the top of the when
2304:             * they are shown, except in cases where it is interrupted by
2305:             * a system menu or an off-screen editor - in which case it
2306:             * should be reshown exactly as it was.
2307:             */
2308:            boolean resetToTop = true;
2309:
2310:            /**
2311:             * Viewport height in the native resource
2312:             */
2313:            private int viewportHeight; // = 0;
2314:
2315:            /** 
2316:             * Overall dimensions of the view. It is an array so it could be passed 
2317:             * as a reference to <code>LayoutManager</code>.
2318:             */
2319:            int viewable[] = new int[4];
2320:
2321:            /**
2322:             * Left to right layout is default.
2323:             * Used by isImplicitLineBreak.
2324:             */
2325:            final static boolean ltr = true;
2326:
2327:        } // class FormLFImpl
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.