Source Code Cross Referenced for ModelViewMapper.java in  » IDE-Netbeans » visualweb.api.designer » org » netbeans » modules » visualweb » css2 » 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 » IDE Netbeans » visualweb.api.designer » org.netbeans.modules.visualweb.css2 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.netbeans.modules.visualweb.css2;
0043:
0044:        import org.netbeans.modules.visualweb.api.designer.DomProvider.DomPosition;
0045:        import org.netbeans.modules.visualweb.api.designer.DomProvider.DomPosition.Bias;
0046:        import org.netbeans.modules.visualweb.api.designer.cssengine.CssProvider;
0047:        import org.netbeans.modules.visualweb.api.designer.cssengine.CssValue;
0048:        import org.netbeans.modules.visualweb.api.designer.cssengine.XhtmlCss;
0049:        import org.netbeans.modules.visualweb.api.designer.markup.MarkupService;
0050:        import org.netbeans.modules.visualweb.designer.CssUtilities;
0051:        import org.netbeans.modules.visualweb.designer.InlineEditor;
0052:        import java.awt.Point;
0053:        import java.awt.Rectangle;
0054:        import java.util.ArrayList;
0055:        import java.util.List;
0056:
0057:        import org.openide.ErrorManager;
0058:        import org.w3c.dom.Element;
0059:        import org.w3c.dom.Node;
0060:        import org.w3c.dom.NodeList;
0061:
0062:        import org.netbeans.modules.visualweb.designer.DesignerUtils;
0063:        import org.netbeans.modules.visualweb.designer.WebForm;
0064:        import org.netbeans.modules.visualweb.designer.html.HtmlTag;
0065:
0066:        /**
0067:         * Class responsible for mapping between the DOM (jsp document and
0068:         * rendered html fragments) and the view (boxes and pixel coordinates).
0069:         * It also handles caret motion. Note that methods which return positions
0070:         * never return null, they return Position.NONE in that case.
0071:         *
0072:         * @todo Handle motion in tables
0073:         * @todo Handle motion past iframes, fragment box includes, etc.
0074:         * @todo There are two getLastLineboxPosition methods; join them
0075:         * @todo Handle the "hidden" flag on boxes, and skip them in
0076:         *  visual traversal
0077:         *
0078:         * @author Tor Norbye
0079:         */
0080:        public final class ModelViewMapper {
0081:            //    private WebForm webform;
0082:
0083:            private ModelViewMapper(WebForm webform) {
0084:                //        this.webform = webform;
0085:            }
0086:
0087:            /**
0088:             * Given a caret position, return the caret position to its left. This
0089:             * may not actually be the left on the screen, e.g. if you press left at the
0090:             * beginning of a line you may end up on the right side of the previous
0091:             * line.
0092:             * @param pos The caret position in the DOM
0093:             * @return The next visual position to the "left" of pos, or Position.NONE if
0094:             * there is no such position in the document (e.g. when you're at the
0095:             * first visual position in the document.)
0096:             */
0097:            //    public static Position computeArrowLeft(WebForm webform, Position sourcePos) {
0098:            public static DomPosition computeArrowLeft(WebForm webform,
0099:                    DomPosition sourcePos) {
0100:
0101:                //        assert !sourcePos.isRendered();
0102:                //        if (MarkupService.isRenderedNode(sourcePos.getNode())) {
0103:                if (sourcePos.isRenderedPosition()) {
0104:                    ErrorManager.getDefault().notify(
0105:                            ErrorManager.INFORMATIONAL,
0106:                            new IllegalArgumentException(
0107:                                    "Node is expected to be not rendered, node="
0108:                                            + sourcePos.getNode())); // NOI18N
0109:                }
0110:
0111:                //        Position pos = sourcePos.getRenderedPosition();
0112:                DomPosition pos = sourcePos.getRenderedPosition();
0113:
0114:                // TODO: in a table, use special case such that we handle the
0115:                // first-cell-in-a-row scenario correctly
0116:                LineBox lb = findLineBox(webform.getPane().getPageBox(), pos);
0117:
0118:                if (lb == null) {
0119:                    // Caret positions should always be in a linebox unless we're inline editing;
0120:                    // in inline editing mode we can delete backwards until we have no caret position
0121:                    // XXX #104463 This doesn't seem to be correct here.
0122:                    //            assert webform.getManager().isInlineEditing() : pos;
0123:
0124:                    //            return Position.NONE;
0125:                    return DomPosition.NONE;
0126:                }
0127:
0128:                //        Position p = findPrevPosition(lb, pos, webform.getManager().getInlineEditor());
0129:                DomPosition p = findPrevPosition(lb, pos, webform.getManager()
0130:                        .getInlineEditor());
0131:
0132:                //        if (p != Position.NONE) {
0133:                if (p != DomPosition.NONE) {
0134:
0135:                    //            if (p.isRendered()) {
0136:                    //            if (MarkupService.isRenderedNode(p.getNode())) {
0137:                    if (p.isRenderedPosition()) {
0138:                        p = p.getSourcePosition();
0139:                    }
0140:                }
0141:
0142:                return p;
0143:            }
0144:
0145:            /**
0146:             * Given a caret position, return the caret position to its right. This
0147:             * may not actually be the right on the screen, e.g. if you press right at the
0148:             * end of a line you may end up on the left side of the next
0149:             * line.
0150:             * @param pos The caret position in the DOM
0151:             * @return The next visual position to the "right" of pos, or Position.NONE if
0152:             * there is no such position in the document (e.g. when you're at the
0153:             * last visual position in the document.)
0154:             */
0155:            //    public static Position computeArrowRight(WebForm webform, Position sourcePos) {
0156:            public static DomPosition computeArrowRight(WebForm webform,
0157:                    DomPosition sourcePos) {
0158:                //        assert !sourcePos.isRendered();
0159:                //        if (MarkupService.isRenderedNode(sourcePos.getNode())) {
0160:                if (sourcePos.isRenderedPosition()) {
0161:                    ErrorManager.getDefault().notify(
0162:                            ErrorManager.INFORMATIONAL,
0163:                            new IllegalArgumentException(
0164:                                    "Node is expected to be not rendered, node="
0165:                                            + sourcePos.getNode())); // NOI18N
0166:                }
0167:
0168:                //        Position pos = sourcePos.getRenderedPosition();
0169:                DomPosition pos = sourcePos.getRenderedPosition();
0170:
0171:                // TODO: in a table, use special case such that we handle the
0172:                // last-cell-in-a-row scenario correctly
0173:                LineBox lb = findLineBox(webform.getPane().getPageBox(), pos);
0174:
0175:                if (lb == null) {
0176:                    //            assert false : pos; // Caret positions should always be in a linebox!!
0177:
0178:                    //            return Position.NONE;
0179:                    return DomPosition.NONE;
0180:                }
0181:
0182:                //        Position p = findNextPosition(lb, pos, webform.getManager().getInlineEditor());
0183:                DomPosition p = findNextPosition(lb, pos, webform.getManager()
0184:                        .getInlineEditor());
0185:
0186:                //        if (p != Position.NONE) {
0187:                if (p != DomPosition.NONE) {
0188:
0189:                    //            if (p.isRendered()) {
0190:                    //            if (MarkupService.isRenderedNode(p.getNode())) {
0191:                    if (p.isRenderedPosition()) {
0192:                        p = p.getSourcePosition();
0193:                    }
0194:                }
0195:
0196:                return p;
0197:            }
0198:
0199:            /**
0200:             * Given a caret position, return the caret position to "above" it; e.g. the
0201:             * position we should move the caret to if the user presses the up arrow key.
0202:             * @param pos The caret position in the DOM
0203:             * @return The next visual position above the given pos, or Position.NONE if
0204:             * there is no such position in the document (e.g. when you're on the first line
0205:             *  in the document.)
0206:             */
0207:            //    public static Position computeArrowUp(WebForm webform, Position sourcePos) {
0208:            public static DomPosition computeArrowUp(WebForm webform,
0209:                    DomPosition sourcePos) {
0210:                // TODO: If in a table, figure out the current position (I could stash these right 
0211:                // on the cellboxes), subtract one, and if still within the table, look for the first
0212:                // cell root (e.g. skip spans) and use that. Otherwise (if we're outside of the table), 
0213:                // use the table itself as an origin, then do the normal linebox search.
0214:                //        assert !sourcePos.isRendered();
0215:                //        if (MarkupService.isRenderedNode(sourcePos.getNode())) {
0216:                if (sourcePos.isRenderedPosition()) {
0217:                    ErrorManager.getDefault().notify(
0218:                            ErrorManager.INFORMATIONAL,
0219:                            new IllegalStateException(
0220:                                    "Node is expected to be not rendered, node="
0221:                                            + sourcePos.getNode())); // NOI18N
0222:                }
0223:
0224:                //        Position pos = sourcePos.getRenderedPosition();
0225:                DomPosition pos = sourcePos.getRenderedPosition();
0226:
0227:                LineBox lb = findLineBox(webform.getPane().getPageBox(), pos);
0228:
0229:                if (lb == null) {
0230:                    //            assert false : pos; // Caret positions should always be in a linebox!!
0231:
0232:                    //            return Position.NONE;
0233:                    return DomPosition.NONE;
0234:                }
0235:
0236:                //        DesignerCaret caret = webform.getPane().getCaret();
0237:                //        assert caret != null;
0238:                if (!webform.getPane().hasCaret()) {
0239:                    ErrorManager.getDefault().notify(
0240:                            ErrorManager.INFORMATIONAL,
0241:                            new IllegalStateException(
0242:                                    "Pane doesn't have caret!"));
0243:                    return DomPosition.NONE;
0244:                }
0245:
0246:                //        Point magicPosition = caret.getMagicCaretPosition();
0247:                Point magicPosition = webform.getPane().getCaretMagicPosition();
0248:
0249:                LineBox prev = lb;
0250:
0251:                while (true) {
0252:                    prev = findPrevLineBox(prev);
0253:
0254:                    if (prev == null) {
0255:                        //                return Position.NONE;
0256:                        return DomPosition.NONE;
0257:                    }
0258:
0259:                    //            Position p = prev.computePosition(magicPosition.x - prev.getAbsoluteX());
0260:                    DomPosition p = prev.computePosition(magicPosition.x
0261:                            - prev.getAbsoluteX());
0262:
0263:                    //            if (DesignerUtils.checkPosition(p, false, /*webform*/webform.getManager().getInlineEditor()) != Position.NONE) {
0264:                    //            if (isValidPosition(p, false, /*webform*/webform.getManager().getInlineEditor())) {
0265:                    if (isValidPosition(webform, p, false, /*webform*/webform
0266:                            .getManager().getInlineEditor())) {
0267:                        //                if (p != Position.NONE) {
0268:                        if (p != DomPosition.NONE) {
0269:
0270:                            //                    if (p.isRendered()) {
0271:                            //                    if (MarkupService.isRenderedNode(p.getNode())) {
0272:                            if (p.isRenderedPosition()) {
0273:                                p = p.getSourcePosition();
0274:                            }
0275:                        }
0276:
0277:                        return p;
0278:                    }
0279:                }
0280:            }
0281:
0282:            /**
0283:             * Given a caret position, return the caret position to "below" it; e.g. the
0284:             * position we should move the caret to if the user presses the down arrow key.
0285:             * @param pos The caret position in the DOM
0286:             * @return The next visual position below the given pos, or Position.NONE if
0287:             * there is no such position in the document (e.g. when you're on the last line
0288:             *  in the document.)
0289:             */
0290:            //    public static Position computeArrowDown(WebForm webform, Position sourcePos) {
0291:            public static DomPosition computeArrowDown(WebForm webform,
0292:                    DomPosition sourcePos) {
0293:                // TODO: If in a table, figure out the current position (I could stash these right 
0294:                // on the cellboxes), add one, and if still within the table, look for the first
0295:                // cell root (e.g. skip spans) and use that. Otherwise (if we're outside of the table), 
0296:                // use the table itself as an origin, then do the normal linebox search.
0297:                //        assert !sourcePos.isRendered();
0298:                //        if (MarkupService.isRenderedNode(sourcePos.getNode())) {
0299:                if (sourcePos.isRenderedPosition()) {
0300:                    ErrorManager.getDefault().notify(
0301:                            ErrorManager.INFORMATIONAL,
0302:                            new IllegalStateException(
0303:                                    "Node is expected to be not rendered, node="
0304:                                            + sourcePos.getNode())); // NOI18N
0305:                }
0306:
0307:                //        Position pos = sourcePos.getRenderedPosition();
0308:                DomPosition pos = sourcePos.getRenderedPosition();
0309:
0310:                LineBox lb = findLineBox(webform.getPane().getPageBox(), pos);
0311:
0312:                if (lb == null) {
0313:                    //            assert false : pos; // Caret positions should always be in a linebox!!
0314:
0315:                    //            return Position.NONE;
0316:                    return DomPosition.NONE;
0317:                }
0318:
0319:                //        DesignerCaret caret = webform.getPane().getCaret();
0320:                //        assert caret != null;
0321:                if (!webform.getPane().hasCaret()) {
0322:                    ErrorManager.getDefault().notify(
0323:                            ErrorManager.INFORMATIONAL,
0324:                            new IllegalStateException(
0325:                                    "Pane doesn't have caret!"));
0326:                    return DomPosition.NONE;
0327:                }
0328:
0329:                //        Point magicPosition = caret.getMagicCaretPosition();
0330:                Point magicPosition = webform.getPane().getCaretMagicPosition();
0331:
0332:                LineBox next = lb;
0333:
0334:                while (true) {
0335:                    next = findNextLineBox(next);
0336:
0337:                    if (next == null) {
0338:                        //                return Position.NONE;
0339:                        return DomPosition.NONE;
0340:                    }
0341:
0342:                    //            Position p = next.computePosition(magicPosition.x - next.getAbsoluteX());
0343:                    DomPosition p = next.computePosition(magicPosition.x
0344:                            - next.getAbsoluteX());
0345:
0346:                    //            if (DesignerUtils.checkPosition(p, false, /*webform*/webform.getManager().getInlineEditor()) != Position.NONE) {
0347:                    //            if (isValidPosition(p, false, /*webform*/webform.getManager().getInlineEditor())) {
0348:                    if (isValidPosition(webform, p, false, /*webform*/webform
0349:                            .getManager().getInlineEditor())) {
0350:                        //                if (p != Position.NONE) {
0351:                        if (p != DomPosition.NONE) {
0352:
0353:                            //                    if (p.isRendered()) {
0354:                            //                    if (MarkupService.isRenderedNode(p.getNode())) {
0355:                            if (p.isRenderedPosition()) {
0356:                                p = p.getSourcePosition();
0357:                            }
0358:                        }
0359:
0360:                        return p;
0361:                    }
0362:                }
0363:            }
0364:
0365:            /**
0366:             * Given a LineBox and a position in that line box, find the FIRST acceptable caret position.
0367:             * Note that the position may be in a different line box (this happens if the
0368:             * position you passed in was the last caret position in the linebox).
0369:             */
0370:            //    private static Position findNextPosition(LineBox lb, Position pos, InlineEditor inlineEditor) {
0371:            private static DomPosition findNextPosition(LineBox lb,
0372:                    DomPosition pos, InlineEditor inlineEditor) {
0373:                //        assert pos.isRendered();
0374:                //        if (!MarkupService.isRenderedNode(pos.getNode())) {
0375:                if (pos.isSourcePosition()) {
0376:                    ErrorManager.getDefault().notify(
0377:                            ErrorManager.INFORMATIONAL,
0378:                            new IllegalArgumentException(
0379:                                    "Node is expected to be rendered, node="
0380:                                            + pos.getNode())); // NOI18N
0381:                }
0382:
0383:                Node node = pos.getNode();
0384:                int offset = pos.getOffset();
0385:
0386:                if (node.getNodeType() == Node.ELEMENT_NODE) {
0387:                    NodeList nl = node.getChildNodes();
0388:
0389:                    if ((offset >= nl.getLength())
0390:                            || ((pos.getBias() == Bias.BACKWARD) && (offset > 0))) {
0391:                        node = nl.item(offset - 1);
0392:                        offset = 1;
0393:                    } else {
0394:                        node = nl.item(offset);
0395:                        offset = 0;
0396:                    }
0397:                }
0398:
0399:                CssBox box = null;
0400:
0401:                // Iterate over the line box contents. When you find the box containing the 
0402:                // current position, see if it contains the next position, and if so, return it.
0403:                int i = 0;
0404:
0405:                // Iterate over the line box contents. When you find the box containing the 
0406:                // current position, see if it contains the next position, and if so, return it.
0407:                int n = lb.getBoxCount();
0408:
0409:                for (; i < n; i++) {
0410:                    box = lb.getBox(i);
0411:
0412:                    if (box.getBoxType() == BoxType.TEXT) {
0413:                        TextBox tb = (TextBox) box;
0414:
0415:                        if ((tb.getNode() == node) && (
0416:                        /* This doesn't work when the position is somewhere in the DOM I'm
0417:                           not displaying, like in a region of space characters. Since I search
0418:                           the dom forwards however, I don't need this extra check.
0419:                        tb.getDomStartOffset() <= offset && */
0420:                        offset <= tb.getDomEndOffset())) {
0421:                            //                    Position p = tb.getNext(pos);
0422:                            DomPosition p = tb.getNext(pos);
0423:
0424:                            //                    if (p != Position.NONE) {
0425:                            if (p != DomPosition.NONE) {
0426:                                return p;
0427:                            }
0428:
0429:                            break;
0430:                        }
0431:                    } else if (box.getBoxType() == BoxType.SPACE) {
0432:                        SpaceBox tb = (SpaceBox) box;
0433:
0434:                        if ((tb.getNode() == node) && (
0435:                        /* This doesn't work when the position is somewhere in the DOM I'm
0436:                           not displaying, like in a region of space characters. Since I search
0437:                           the dom forwards however, I don't need this extra check.
0438:                        tb.getDomStartOffset() <= offset && */
0439:                        offset <= tb.getDomEndOffset())) {
0440:                            //                    Position p = tb.getNext(pos);
0441:                            DomPosition p = tb.getNext(pos);
0442:
0443:                            //                    if (p != Position.NONE) {
0444:                            if (p != DomPosition.NONE) {
0445:                                return p;
0446:                            }
0447:
0448:                            break;
0449:                        }
0450:                    } else if (box.getBoxType() == BoxType.LINEBREAK) {
0451:                        break;
0452:                        //            } else if (getElement(box) == node) {
0453:                    } else if (getComponentRootElementParentForCssBox(box) == node) {
0454:                        if (offset == 0) {
0455:                            // We can resolve this one quickly! Just pick position after
0456:                            //                    return Position.create(getElement(box).getSource(), true);
0457:                            //                    return Position.create(MarkupService.getSourceElementForElement(getElement(box)), true);
0458:                            //                    return Position.create(MarkupService.getSourceElementForElement(
0459:                            //                            getComponentRootElementParentForCssBox(box)), true);
0460:                            return lb
0461:                                    .getWebForm()
0462:                                    .createDomPosition(
0463:                                            MarkupService
0464:                                                    .getSourceElementForElement(getComponentRootElementParentForCssBox(box)),
0465:                                            true);
0466:                        }
0467:
0468:                        if (i >= (n - 1)) {
0469:                            // We've walked out of the last textbox/spacebox etc in the line
0470:                            // so jump to the next line
0471:                            return getFirstPosNextLine(lb, inlineEditor);
0472:                        } else {
0473:                            return findFirstLineboxPosition(lb, i + 1,
0474:                                    inlineEditor);
0475:                        }
0476:
0477:                        /*
0478:                        } else if (pos.isInside(box.getSourceElement())) {
0479:                        break;
0480:                         */
0481:                    }
0482:                }
0483:
0484:                //        assert i != n; // LineBox should have contained box; if not input arg was invalid
0485:                if (i == n) {
0486:                    ErrorManager.getDefault().notify(
0487:                            ErrorManager.INFORMATIONAL,
0488:                            new IllegalStateException(
0489:                                    "Next position not found, lb=" + lb
0490:                                            + ", pos=" + pos)); // NOI18N
0491:                    //            return Position.NONE;
0492:                    return DomPosition.NONE;
0493:                }
0494:
0495:                while (true) { // May have to try repeatedly to skip JSF fragment linebox contents
0496:
0497:                    if (i == n) {
0498:                        return getFirstPosNextLine(lb, inlineEditor);
0499:                    }
0500:
0501:                    // If there is no next box, or if the next box is a linebreak box,
0502:                    // Jump to the Next Line lb.getBox(i)
0503:                    if ((i >= (n - 1)) || // if there is no next box
0504:                            (lb.getBox(i + 1).getBoxType() == BoxType.LINEBREAK)) {
0505:                        // Jump to the next line: Find Next Line Box and if not null,
0506:                        // Find First Position in it and return that.
0507:                        return getFirstPosNextLine(lb, inlineEditor);
0508:                    }
0509:
0510:                    // If the next box is a space box or a text box, ask it for the next position
0511:                    // (e.g. skipping its first position) and return it.
0512:                    CssBox next = lb.getBox(i + 1);
0513:
0514:                    if (next.getBoxType() == BoxType.TEXT) {
0515:                        // We know it SHOULD have one position since all text and space boxes
0516:                        // must have at least one character
0517:                        TextBox tb = (TextBox) next;
0518:                        //                Position p = tb.getNext(tb.getFirstPosition());
0519:                        DomPosition p = tb.getNext(tb.getFirstPosition());
0520:
0521:                        //                if (DesignerUtils.checkPosition(p, false, inlineEditor) != Position.NONE) {
0522:                        //                if (isValidPosition(p, false, inlineEditor)) {
0523:                        if (isValidPosition(lb.getWebForm(), p, false,
0524:                                inlineEditor)) {
0525:                            return p;
0526:                        } else {
0527:                            // else it's probably a JSF component
0528:                            i++;
0529:
0530:                            continue;
0531:                        }
0532:                    } else if (next.getBoxType() == BoxType.SPACE) {
0533:                        SpaceBox tb = (SpaceBox) next;
0534:                        //                Position p = tb.getNext(tb.getFirstPosition());
0535:                        DomPosition p = tb.getNext(tb.getFirstPosition());
0536:
0537:                        //                if (DesignerUtils.checkPosition(p, false, inlineEditor) != Position.NONE) {
0538:                        //                if (isValidPosition(p, false, inlineEditor)) {
0539:                        if (isValidPosition(lb.getWebForm(), p, false,
0540:                                inlineEditor)) {
0541:                            return p;
0542:                        } else {
0543:                            // else it's probably a JSF component
0544:                            i++;
0545:
0546:                            continue;
0547:                        }
0548:                    }
0549:
0550:                    // Otherwise the next box must be an inline box (like an image, or a
0551:                    // button), so skip it. If there are no more boxes in the LineBox after
0552:                    // this box, we should jump to the next line.
0553:                    i += 2;
0554:
0555:                    if (i >= n) {
0556:                        // We've walked out of the last textbox/spacebox etc in the line
0557:                        // so jump to the next line
0558:                        return getFirstPosNextLine(lb, inlineEditor);
0559:                    } else {
0560:                        return findFirstLineboxPosition(lb, i, inlineEditor);
0561:                    }
0562:                }
0563:            }
0564:
0565:            /**
0566:             * Given a LineBox, compute the NEXT linebox and return its first
0567:             * position. Used as part of getNextPosition for various cases.
0568:             */
0569:            //    private static Position getFirstPosNextLine(LineBox lb, InlineEditor inlineEditor) {
0570:            private static DomPosition getFirstPosNextLine(LineBox lb,
0571:                    InlineEditor inlineEditor) {
0572:                // Jump to the next line: Find Next Line Box and if not null,
0573:                // Find First Position in it and return that.
0574:                LineBox nextLine = findNextLineBox(lb);
0575:
0576:                if (nextLine != null) {
0577:                    return findFirstLineboxPosition(nextLine, 0, inlineEditor);
0578:                } else {
0579:                    //            return Position.NONE;
0580:                    return DomPosition.NONE;
0581:                }
0582:            }
0583:
0584:            /**
0585:             * Given a LineBox, compute the PREVIOUS linebox and return its last.
0586:             * position. Used as part of getPrevPosition for various cases.
0587:             * @param inlineEditor (XXX suspicious) InlineEditor which is active in the page (or <code>null</code>).
0588:             */
0589:            //    private static Position getLastPosPrevLine(LineBox lb, InlineEditor inlineEditor) {
0590:            private static DomPosition getLastPosPrevLine(LineBox lb,
0591:                    InlineEditor inlineEditor) {
0592:                // Jump to the previous line:
0593:                // Find Previous Line Box and if not null, Find Last Position in it
0594:                // and return that.
0595:                LineBox prevLine = findPrevLineBox(lb);
0596:
0597:                if (prevLine != null) {
0598:                    return findLastLineboxPosition(prevLine, inlineEditor);
0599:                } else {
0600:                    //            return Position.NONE;
0601:                    return DomPosition.NONE;
0602:                }
0603:            }
0604:
0605:            /**
0606:             * Analogous to Find Next Position but move in the opposite direction.
0607:             * Note that the position may be in a different line box (this happens if the position
0608:             * you passed in was the first caret position in the linebox).
0609:             * @param inlineEditor (XXX suspicious) InlineEditor which is active in the page (or <code>null</code>).
0610:             */
0611:            //    private static Position findPrevPosition(LineBox lb, Position pos, InlineEditor inlineEditor) {
0612:            private static DomPosition findPrevPosition(LineBox lb,
0613:                    DomPosition pos, InlineEditor inlineEditor) {
0614:                //        assert pos.isRendered();
0615:                //        if (!MarkupService.isRenderedNode(pos.getNode())) {
0616:                if (pos.isSourcePosition()) {
0617:                    ErrorManager.getDefault().notify(
0618:                            ErrorManager.INFORMATIONAL,
0619:                            new IllegalArgumentException(
0620:                                    "Node is expected to be rendered, node="
0621:                                            + pos.getNode())); // NOI18N
0622:                }
0623:
0624:                Node node = pos.getNode();
0625:                int offset = pos.getOffset();
0626:
0627:                if (node.getNodeType() == Node.ELEMENT_NODE) {
0628:                    NodeList nl = node.getChildNodes();
0629:
0630:                    if ((offset >= nl.getLength())
0631:                            || ((pos.getBias() == Bias.BACKWARD) && (offset > 0))) {
0632:                        node = nl.item(offset - 1);
0633:                        offset = 1;
0634:                    } else {
0635:                        node = nl.item(offset);
0636:                        offset = 0;
0637:                    }
0638:                }
0639:
0640:                CssBox box = null;
0641:
0642:                // Iterate over the line box contents. When you find the box containing the 
0643:                // current position, see if it contains the previous position, and if so, return it.
0644:                int i = 0;
0645:
0646:                // Iterate over the line box contents. When you find the box containing the 
0647:                // current position, see if it contains the previous position, and if so, return it.
0648:                int n = lb.getBoxCount();
0649:
0650:                for (; i < n; i++) {
0651:                    box = lb.getBox(i);
0652:
0653:                    if (box.getBoxType() == BoxType.TEXT) {
0654:                        TextBox tb = (TextBox) box;
0655:
0656:                        if ((tb.getNode() == node) && (
0657:                        /* This doesn't work when the position is somewhere in the DOM I'm
0658:                           not displaying, like in a region of space characters. Since I search
0659:                           the dom forwards however, I don't need this extra check.
0660:                        tb.getDomStartOffset() <= offset && */
0661:                        offset <= tb.getDomEndOffset())) {
0662:                            //                    Position p = tb.getPrev(pos);
0663:                            DomPosition p = tb.getPrev(pos);
0664:
0665:                            //                    if (p != Position.NONE) {
0666:                            if (p != DomPosition.NONE) {
0667:                                return p;
0668:                            }
0669:
0670:                            break;
0671:                        }
0672:                    } else if (box.getBoxType() == BoxType.SPACE) {
0673:                        SpaceBox tb = (SpaceBox) box;
0674:
0675:                        if ((tb.getNode() == node) && (
0676:                        /* This doesn't work when the position is somewhere in the DOM I'm
0677:                           not displaying, like in a region of space characters. Since I search
0678:                           the dom forwards however, I don't need this extra check.
0679:                        tb.getDomStartOffset() <= offset && */
0680:                        offset <= tb.getDomEndOffset())) {
0681:                            //                    Position p = tb.getPrev(pos);
0682:                            DomPosition p = tb.getPrev(pos);
0683:
0684:                            //                    if (p != Position.NONE) {
0685:                            if (p != DomPosition.NONE) {
0686:                                return p;
0687:                            }
0688:
0689:                            break;
0690:                        }
0691:                    } else if (box.getBoxType() == BoxType.LINEBREAK) {
0692:                        break;
0693:                        //            } else if (getElement(box) == node) {
0694:                    } else if (getComponentRootElementParentForCssBox(box) == node) {
0695:                        if (offset == 1) {
0696:                            // We can resolve this one quickly! Just pick position before
0697:                            //                    return Position.create(getElement(box).getSource(), false);
0698:                            //                    return Position.create(MarkupService.getSourceElementForElement(getElement(box)), false);
0699:                            //                    return Position.create(MarkupService.getSourceElementForElement(
0700:                            //                            getComponentRootElementParentForCssBox(box)), false);
0701:                            return lb
0702:                                    .getWebForm()
0703:                                    .createDomPosition(
0704:                                            MarkupService
0705:                                                    .getSourceElementForElement(getComponentRootElementParentForCssBox(box)),
0706:                                            false);
0707:                        }
0708:
0709:                        if (i == 0) {
0710:                            // We've walked out of the first textbox/spacebox etc in the line
0711:                            // so jump to the previous line
0712:                            return getLastPosPrevLine(lb, inlineEditor);
0713:                        } else {
0714:                            return findLastLineboxPosition(lb, i - 1,
0715:                                    inlineEditor);
0716:                        }
0717:
0718:                        /*
0719:                        } else if (pos.isInside(box.getSourceElement())) {
0720:                        break;
0721:                         */
0722:                    }
0723:                }
0724:
0725:                //        assert i != n; // LineBox should have contained box; if not input arg was invalid
0726:                if (i == n) {
0727:                    ErrorManager.getDefault().notify(
0728:                            ErrorManager.INFORMATIONAL,
0729:                            new IllegalStateException(
0730:                                    "Previous position not found, lb=" + lb
0731:                                            + ", pos=" + pos)); // NOI18N
0732:                    //            return Position.NONE;
0733:                    return DomPosition.NONE;
0734:                }
0735:
0736:                while (true) {
0737:                    // If there is no previous box, Jump to the Previous Line
0738:                    if (i == 0) {
0739:                        // Jump to the previous line:
0740:                        return getLastPosPrevLine(lb, inlineEditor);
0741:                    }
0742:
0743:                    // If the previous box is a space box or a text box, ask it for the previous position
0744:                    // (e.g. skipping its last position) and return it.
0745:                    CssBox prev = lb.getBox(i - 1);
0746:
0747:                    if (prev.getBoxType() == BoxType.TEXT) {
0748:                        // We know it SHOULD have one position since all text and space boxes
0749:                        // must have at least one character
0750:                        TextBox tb = (TextBox) prev;
0751:                        //                Position p = tb.getPrev(tb.getLastPosition());
0752:                        DomPosition p = tb.getPrev(tb.getLastPosition());
0753:
0754:                        //                if (DesignerUtils.checkPosition(p, false, inlineEditor) != Position.NONE) {
0755:                        //                if (isValidPosition(p, false, inlineEditor)) {
0756:                        if (isValidPosition(lb.getWebForm(), p, false,
0757:                                inlineEditor)) {
0758:                            return p;
0759:                        } else {
0760:                            // else it's probably a JSF component
0761:                            i--;
0762:
0763:                            continue;
0764:                        }
0765:                    } else if (prev.getBoxType() == BoxType.SPACE) {
0766:                        SpaceBox tb = (SpaceBox) prev;
0767:                        //                Position p = tb.getPrev(tb.getLastPosition());
0768:                        DomPosition p = tb.getPrev(tb.getLastPosition());
0769:
0770:                        //                if (DesignerUtils.checkPosition(p, false, inlineEditor) != Position.NONE) {
0771:                        //                if (isValidPosition(p, false, inlineEditor)) {
0772:                        if (isValidPosition(lb.getWebForm(), p, false,
0773:                                inlineEditor)) {
0774:                            return p;
0775:                        } else {
0776:                            // else it's probably a JSF component
0777:                            i--;
0778:
0779:                            continue;
0780:                        }
0781:                    }
0782:
0783:                    // Otherwise the previous box must be an inline box (like an image, or a
0784:                    // button), so skip it. If this was the first box in the linebox, we should
0785:                    // jump to the previous line. (can I combine these too?
0786:                    i--;
0787:
0788:                    if (i < 0) {
0789:                        // We've walked out of the first textbox/spacebox etc in the line
0790:                        // so jump to the previous line
0791:                        return getLastPosPrevLine(lb, inlineEditor);
0792:                    } else {
0793:                        return findLastLineboxPosition(lb, i, inlineEditor);
0794:                    }
0795:                }
0796:            }
0797:
0798:            /**
0799:             * Given a Line Box, return the first position in the line box
0800:             * starting at the given box offset. Pass in 0 to get the first
0801:             * position in the line box.
0802:             * @param lb The line box
0803:             * @return The first legal caret position in the line box
0804:             */
0805:            //    private static Position findFirstLineboxPosition(LineBox lb, int index, InlineEditor inlineEditor) {
0806:            private static DomPosition findFirstLineboxPosition(LineBox lb,
0807:                    int index, InlineEditor inlineEditor) {
0808:                if (lb.getBoxCount() <= index) {
0809:                    //            assert false : lb;
0810:
0811:                    //            return Position.NONE;
0812:                    return DomPosition.NONE;
0813:                }
0814:
0815:                while (true) {
0816:                    CssBox box = lb.getBox(index);
0817:
0818:                    if (box.getBoxType() == BoxType.TEXT) {
0819:                        TextBox tb = (TextBox) box;
0820:                        //                Position pos = tb.getFirstPosition();
0821:                        DomPosition pos = tb.getFirstPosition();
0822:
0823:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
0824:                        //                if (isValidPosition(pos, false, inlineEditor)) {
0825:                        if (isValidPosition(lb.getWebForm(), pos, false,
0826:                                inlineEditor)) {
0827:                            return pos;
0828:                        }
0829:                    } else if (box.getBoxType() == BoxType.SPACE) {
0830:                        SpaceBox tb = (SpaceBox) box;
0831:                        //                Position pos = tb.getFirstPosition();
0832:                        DomPosition pos = tb.getFirstPosition();
0833:
0834:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
0835:                        //                if (isValidPosition(pos, false, inlineEditor)) {
0836:                        if (isValidPosition(lb.getWebForm(), pos, false,
0837:                                inlineEditor)) {
0838:                            return pos;
0839:                        }
0840:                    } else {
0841:                        // assert that this is a simple inline, noncontainer box,
0842:                        // such as an image, a StringBox, an iframe, etc.
0843:                        //                Position pos = Position.create(box.getSourceElement(), false);
0844:                        DomPosition pos = lb.getWebForm().createDomPosition(
0845:                                box.getSourceElement(), false);
0846:
0847:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
0848:                        //                if (isValidPosition(pos, false, inlineEditor)) {
0849:                        if (isValidPosition(lb.getWebForm(), pos, false,
0850:                                inlineEditor)) {
0851:                            return pos;
0852:                        }
0853:                    }
0854:
0855:                    index++;
0856:
0857:                    if (index == lb.getBoxCount()) {
0858:                        while (true) {
0859:                            lb = findNextLineBox(lb);
0860:
0861:                            if (lb == null) {
0862:                                //                        return Position.NONE;
0863:                                return DomPosition.NONE;
0864:                            }
0865:
0866:                            index = 0;
0867:
0868:                            if (index < lb.getBoxCount()) {
0869:                                break;
0870:                            }
0871:                        }
0872:                    }
0873:                }
0874:            }
0875:
0876:            /**
0877:             * Given a Line Box, return the last position in the line box.
0878:             * @param lb The line box
0879:             * @param inlineEditor (XXX suspicious) InlineEditor which is active in the page (or <code>null</code>).
0880:             * @return The last legal caret position in the line box
0881:             */
0882:            //    private static Position findLastLineboxPosition(LineBox lb, int index, InlineEditor inlineEditor) {
0883:            private static DomPosition findLastLineboxPosition(LineBox lb,
0884:                    int index, InlineEditor inlineEditor) {
0885:                if (lb.getBoxCount() <= index) {
0886:                    assert false : lb;
0887:
0888:                    //            return Position.NONE;
0889:                    return DomPosition.NONE;
0890:                }
0891:
0892:                while (true) {
0893:                    CssBox box = lb.getBox(index);
0894:
0895:                    if (box.getBoxType() == BoxType.TEXT) {
0896:                        TextBox tb = (TextBox) box;
0897:                        //                Position pos = tb.getLastPosition();
0898:                        DomPosition pos = tb.getLastPosition();
0899:
0900:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
0901:                        //                if (isValidPosition(pos, false, inlineEditor)) {
0902:                        if (isValidPosition(lb.getWebForm(), pos, false,
0903:                                inlineEditor)) {
0904:                            return pos;
0905:                        }
0906:                    } else if (box.getBoxType() == BoxType.SPACE) {
0907:                        SpaceBox tb = (SpaceBox) box;
0908:                        //                Position pos = tb.getLastPosition();
0909:                        DomPosition pos = tb.getLastPosition();
0910:
0911:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
0912:                        //                if (isValidPosition(pos, false, inlineEditor)) {
0913:                        if (isValidPosition(lb.getWebForm(), pos, false,
0914:                                inlineEditor)) {
0915:                            return pos;
0916:                        }
0917:                    } else {
0918:                        // assert that this is a simple inline, noncontainer box,
0919:                        // such as an image, a StringBox, an iframe, etc.
0920:                        if (index > 0) {
0921:                            CssBox prev = lb.getBox(index - 1);
0922:
0923:                            if (prev.getBoxType() == BoxType.TEXT) {
0924:                                TextBox tb = (TextBox) prev;
0925:                                //                        Position pos = tb.getLastPosition();
0926:                                DomPosition pos = tb.getLastPosition();
0927:
0928:                                //                        if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
0929:                                //                        if (isValidPosition(pos, false, inlineEditor)) {
0930:                                if (isValidPosition(lb.getWebForm(), pos,
0931:                                        false, inlineEditor)) {
0932:                                    return pos;
0933:                                }
0934:                            } else if (prev.getBoxType() == BoxType.SPACE) {
0935:                                SpaceBox tb = (SpaceBox) prev;
0936:                                //                        Position pos = tb.getLastPosition();
0937:                                DomPosition pos = tb.getLastPosition();
0938:
0939:                                //                        if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
0940:                                //                        if (isValidPosition(pos, false, inlineEditor)) {
0941:                                if (isValidPosition(lb.getWebForm(), pos,
0942:                                        false, inlineEditor)) {
0943:                                    return pos;
0944:                                }
0945:                            }
0946:                        }
0947:
0948:                        //                Position pos = Position.create(box.getSourceElement(), false);
0949:                        DomPosition pos = lb.getWebForm().createDomPosition(
0950:                                box.getSourceElement(), false);
0951:
0952:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
0953:                        //                if (isValidPosition(pos, false, inlineEditor)) {
0954:                        if (isValidPosition(lb.getWebForm(), pos, false,
0955:                                inlineEditor)) {
0956:                            return pos;
0957:                        }
0958:                    }
0959:
0960:                    index--; // Probably a JSF component
0961:
0962:                    if (index < 0) {
0963:                        while (true) {
0964:                            lb = findPrevLineBox(lb);
0965:
0966:                            if (lb == null) {
0967:                                //                        return Position.NONE;
0968:                                return DomPosition.NONE;
0969:                            }
0970:
0971:                            index = lb.getBoxCount() - 1;
0972:
0973:                            if (index >= 0) {
0974:                                break;
0975:                            }
0976:                        }
0977:                    }
0978:                }
0979:            }
0980:
0981:            /**
0982:             * Given a Line Box, return the last position in the line box.
0983:             * @todo XXX This needs to be combined with findLastLineboxPosition(LineBox,int)!!!
0984:             * @param lb The line box
0985:             * @param inlineEditor (XXX suspicious) InlineEditor which is active in the page (or <code>null</code>).
0986:             * @return The last legal caret position in the line box
0987:             */
0988:            //    private static Position findLastLineboxPosition(LineBox lb, InlineEditor inlineEditor) {
0989:            private static DomPosition findLastLineboxPosition(LineBox lb,
0990:                    InlineEditor inlineEditor) {
0991:                if (lb.getBoxCount() == 0) {
0992:                    //            assert false : lb;
0993:
0994:                    //            return Position.NONE;
0995:                    return DomPosition.NONE;
0996:                }
0997:
0998:                int index = lb.getBoxCount() - 1;
0999:
1000:                while (true) {
1001:                    CssBox box = lb.getBox(index);
1002:
1003:                    if (box.getBoxType() == BoxType.LINEBREAK) {
1004:                        //                Position pos = Position.create(box.getSourceElement(), false);
1005:                        DomPosition pos = lb.getWebForm().createDomPosition(
1006:                                box.getSourceElement(), false);
1007:
1008:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
1009:                        //                if (isValidPosition(pos, false, inlineEditor)) {
1010:                        if (isValidPosition(lb.getWebForm(), pos, false,
1011:                                inlineEditor)) {
1012:                            return pos;
1013:                        }
1014:                    }
1015:
1016:                    if (box.getBoxType() == BoxType.TEXT) {
1017:                        TextBox tb = (TextBox) box;
1018:                        //                Position pos = tb.getLastPosition();
1019:                        DomPosition pos = tb.getLastPosition();
1020:
1021:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
1022:                        //                if (isValidPosition(pos, false, inlineEditor)) {
1023:                        if (isValidPosition(lb.getWebForm(), pos, false,
1024:                                inlineEditor)) {
1025:                            return pos;
1026:                        }
1027:                    } else if (box.getBoxType() == BoxType.SPACE) {
1028:                        SpaceBox tb = (SpaceBox) box;
1029:                        //                Position pos = tb.getLastPosition();
1030:                        DomPosition pos = tb.getLastPosition();
1031:
1032:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
1033:                        //                if (isValidPosition(pos, false, inlineEditor)) {
1034:                        if (isValidPosition(lb.getWebForm(), pos, false,
1035:                                inlineEditor)) {
1036:                            return pos;
1037:                        }
1038:                    } else {
1039:                        //                Position pos = Position.create(box.getSourceElement(), true);
1040:                        DomPosition pos = lb.getWebForm().createDomPosition(
1041:                                box.getSourceElement(), true);
1042:
1043:                        //                if (DesignerUtils.checkPosition(pos, false, inlineEditor) != Position.NONE) {
1044:                        //                if (isValidPosition(pos, false, inlineEditor)) {
1045:                        if (isValidPosition(lb.getWebForm(), pos, false,
1046:                                inlineEditor)) {
1047:                            return pos;
1048:                        }
1049:                    }
1050:
1051:                    // It was probably a JSF component
1052:                    index--;
1053:
1054:                    if (index < 0) {
1055:                        while (true) {
1056:                            lb = findPrevLineBox(lb);
1057:
1058:                            if (lb == null) {
1059:                                //                        return Position.NONE;
1060:                                return DomPosition.NONE;
1061:                            }
1062:
1063:                            index = lb.getBoxCount() - 1;
1064:
1065:                            if (index >= 0) {
1066:                                break;
1067:                            }
1068:                        }
1069:                    }
1070:                }
1071:            }
1072:
1073:            /**
1074:             * Given a box, find the next linebox in flow searching forwards.
1075:             * @param box The box to start the search from (which may be
1076:             *  inside a linebox. The containing linebox will not be returned
1077:             *  as the next linebox.
1078:             * @return The next linebox in flow.
1079:             */
1080:            private static LineBox findNextLineBox(CssBox box) {
1081:                if ((box != null) && (box.getBoxType() != BoxType.LINEBOX)
1082:                        && box.getParent() instanceof  LineBoxGroup) {
1083:                    // The box is already managed as part of a line box group
1084:                    // See which line box it's in.
1085:                    CssBox parent = box.getParent();
1086:
1087:                    for (int j = 0, n = parent.getBoxCount(); j < n; j++) {
1088:                        CssBox linebox = parent.getBox(j);
1089:
1090:                        if (linebox.getBoxType() != BoxType.LINEBOX) {
1091:                            continue;
1092:                        }
1093:
1094:                        for (int k = 0, m = linebox.getBoxCount(); k < m; k++) {
1095:                            CssBox child = linebox.getBox(k);
1096:
1097:                            if (child == box) {
1098:                                // Found it
1099:                                int lineno = j + 1;
1100:
1101:                                while (lineno < n) {
1102:                                    CssBox next = parent.getBox(lineno);
1103:
1104:                                    if (next.getBoxType() == BoxType.LINEBOX) {
1105:                                        return (LineBox) next;
1106:                                    }
1107:
1108:                                    lineno++;
1109:                                }
1110:
1111:                                break;
1112:                            }
1113:                        }
1114:                    }
1115:
1116:                    box = parent;
1117:                }
1118:
1119:                // We're not in a linebox group, or we were already in the first
1120:                // line of that line box group...
1121:                while (box != null) {
1122:                    CssBox next = box.getNextNormalBlockBox();
1123:
1124:                    while (next != null) {
1125:                        LineBox lb = findFirstLineBox(next);
1126:
1127:                        if (lb != null) {
1128:                            return lb;
1129:                        }
1130:
1131:                        next = next.getNextNormalBlockBox();
1132:                    }
1133:
1134:                    box = box.getParent();
1135:                }
1136:
1137:                return null;
1138:            }
1139:
1140:            /**
1141:             * Given a box, find the previous linebox in flow searching backwards.
1142:             * @param box The box to start the search from (which may be
1143:             *  inside a linebox. The containing linebox will not be returned
1144:             *  as the next linebox.
1145:             * @return The previous linebox in flow.
1146:             */
1147:            private static LineBox findPrevLineBox(CssBox box) {
1148:                if ((box != null) && (box.getBoxType() != BoxType.LINEBOX)
1149:                        && box.getParent() instanceof  LineBoxGroup) {
1150:                    // The box is already managed as part of a line box group
1151:                    // See which line box it's in.
1152:                    CssBox parent = box.getParent();
1153:
1154:                    for (int j = 0, n = parent.getBoxCount(); j < n; j++) {
1155:                        CssBox linebox = parent.getBox(j);
1156:
1157:                        if (linebox.getBoxType() != BoxType.LINEBOX) {
1158:                            continue;
1159:                        }
1160:
1161:                        for (int k = 0, m = linebox.getBoxCount(); k < m; k++) {
1162:                            CssBox child = linebox.getBox(k);
1163:
1164:                            if (child == box) {
1165:                                // Found it
1166:                                int lineno = j - 1;
1167:
1168:                                while (lineno >= 0) {
1169:                                    CssBox prev = parent.getBox(lineno);
1170:
1171:                                    if (prev.getBoxType() == BoxType.LINEBOX) {
1172:                                        return (LineBox) prev;
1173:                                    }
1174:
1175:                                    lineno--;
1176:                                }
1177:
1178:                                break;
1179:                            }
1180:                        }
1181:                    }
1182:
1183:                    box = parent;
1184:                }
1185:
1186:                while (box != null) {
1187:                    CssBox prev = box.getPrevNormalBlockBox();
1188:
1189:                    while (prev != null) {
1190:                        LineBox lb = findLastLineBox(prev);
1191:
1192:                        if (lb != null) {
1193:                            return lb;
1194:                        }
1195:
1196:                        prev = prev.getPrevNormalBlockBox();
1197:                    }
1198:
1199:                    box = box.getParent();
1200:                }
1201:
1202:                return null;
1203:            }
1204:
1205:            /**
1206:             * Return the first linebox found in a depth search of this box tree
1207:             * @param box The root box to check
1208:             * @return The first LineBox found under the box
1209:             */
1210:            private static LineBox findFirstLineBox(CssBox box) {
1211:                if ((box.getBoxType() == BoxType.LINEBOX)
1212:                        && box instanceof  LineBox) { // LineBoxGroup is also BoxType.LINEBOX
1213:
1214:                    return (LineBox) box;
1215:                }
1216:
1217:                for (int i = 0, n = box.getBoxCount(); i < n; i++) {
1218:                    CssBox child = box.getBox(i);
1219:
1220:                    if (child instanceof  ExternalDocumentBox) {
1221:                        continue;
1222:                    }
1223:
1224:                    LineBox match = findFirstLineBox(child);
1225:
1226:                    if (match != null) {
1227:                        return match;
1228:                    }
1229:                }
1230:
1231:                return null;
1232:            }
1233:
1234:            /**
1235:             * Return the last linebox found in a depth search of this box tree
1236:             * @param box The root box to check
1237:             * @return The last LineBox found under the box
1238:             */
1239:            private static LineBox findLastLineBox(CssBox box) {
1240:                if ((box.getBoxType() == BoxType.LINEBOX)
1241:                        && box instanceof  LineBox) { // LineBoxGroup is also BoxType.LINEBOX
1242:
1243:                    return (LineBox) box;
1244:                }
1245:
1246:                for (int i = box.getBoxCount() - 1; i >= 0; i--) {
1247:                    CssBox child = box.getBox(i);
1248:
1249:                    if (child instanceof  ExternalDocumentBox) {
1250:                        continue;
1251:                    }
1252:
1253:                    LineBox match = findLastLineBox(child);
1254:
1255:                    if (match != null) {
1256:                        return match;
1257:                    }
1258:                }
1259:
1260:                return null;
1261:            }
1262:
1263:            /** Find the LineBox corresponding to the given position */
1264:            //    private static LineBox findLineBox(PageBox pageBox, Position pos) {
1265:            private static LineBox findLineBox(PageBox pageBox, DomPosition pos) {
1266:                //        CssBox box = findBox(webform.getPane().getPageBox(), pos);
1267:                CssBox box = findBox(pageBox, pos);
1268:
1269:                if (box == null) {
1270:                    return null;
1271:                }
1272:
1273:                return findLineBox(box, pos.getBias() == Bias.FORWARD);
1274:            }
1275:
1276:            /**
1277:             * Find the LineBox corresponding to the given box.
1278:             * If the box has an element which spans multiple lines (like a <span> whose
1279:             * text doesn't all fit on a single line) the "first" parameter will be
1280:             * used to decide if we should return the first linebox matching or the last
1281:             * linebox matching this box.
1282:             */
1283:            private static LineBox findLineBox(CssBox box, boolean first) { // HACK ALERT
1284:
1285:                CssBox curr = box;
1286:
1287:                while ((curr != null) && /*isSpan() &&*/
1288:                !(curr instanceof  LineBoxGroup)) {
1289:                    curr = curr.getParent();
1290:                }
1291:
1292:                if (curr == null) {
1293:                    return null;
1294:                }
1295:
1296:                if (!(curr instanceof  LineBoxGroup)) {
1297:                    // I must have run into an block box or absolutely positioned
1298:                    // box of some sort;
1299:                    // Look downwards for the first normal flow child and
1300:                    // if it's a line box group, use that
1301:                    CssBox firstBox = curr.getFirstNormalBox();
1302:
1303:                    if (firstBox instanceof  LineBoxGroup) {
1304:                        // HACK - returning first linebox - should find closest instead!!
1305:                        // XXX is there any chance this could be a float???
1306:                        return (LineBox) firstBox.getBox(0);
1307:                    } else {
1308:                        return null;
1309:                    }
1310:                }
1311:
1312:                LineBoxGroup lbg = (LineBoxGroup) curr;
1313:
1314:                for (int i = 0, n = lbg.getBoxCount(); i < n; i++) {
1315:                    CssBox b = lbg.getBox(i);
1316:
1317:                    if (b instanceof  LineBox) {
1318:                        LineBox lb = (LineBox) b;
1319:
1320:                        for (int j = 0, m = lb.getBoxCount(); j < m; j++) {
1321:                            if (lb.getBox(j) == box) {
1322:                                return lb;
1323:                            }
1324:                        }
1325:                    } else {
1326:                        // Floats can appear in a line context.
1327:                        assert b.getBoxType() == BoxType.FLOAT;
1328:
1329:                        // Float contents aren't in line boxes
1330:                        // XXX not true! but won't fix that right now
1331:                        continue;
1332:                    }
1333:                }
1334:
1335:                // We were found in a LineBoxGroup but not in one of its LineBoxes.
1336:                // That means we're a managed box that does not render its own inline box,
1337:                // such as for example "<b>".
1338:                // At this point we could go and search the boxes children to see if any of
1339:                // -them- (or their children, e.g. in <b><i><u>Hello...) render to an inline
1340:                // box. However the point is we shouldn't have even gotten the caret into
1341:                // this position - it should always be associated with an inline position.
1342:                // So rather than hack this here (where could be in trouble - what if there
1343:                // is no inlinebox inside our cursor position, e.g. <b>^</b> - so nothing
1344:                // here is rendered in any linebox, in that case we're hosed. So we need
1345:                // to fix the root cause of this.
1346:                // Uh oh this is unavoidable.
1347:                // Let's say my source has this:   
1348:                //   <h:outputText value="foo"/><h:outputText value="bar"/>
1349:                // Clearly I should be able to put the caret in between these texts. But in
1350:                // The HTML dom I have this:   
1351:                //   <span>foo</span>^<span>bar</span>
1352:                // The only valid caret position here is between the spans (indicated by ^).
1353:                // In terms of the sosurce dom this means I can only put the caret in a position
1354:                // that is rendered into a managed box - which doesn't appear in the line box
1355:                // hierarchy (the <span>.)
1356:                // Thus, I need to go here and make sure I can find line boxes for these things
1357:                // too. Note that a <span> can span multiple lines. Thus the span may have more
1358:                // than one associated linebox. 
1359:                //        Node element = getElement(box);
1360:                Node element = getComponentRootElementParentForCssBox(box);
1361:                assert element != null;
1362:
1363:                if (first) {
1364:                    // Look for the FIRST box present in a linebox for the given managed box
1365:                    for (int i = 0, n = lbg.getBoxCount(); i < n; i++) {
1366:                        CssBox b = lbg.getBox(i);
1367:
1368:                        if (b instanceof  LineBox) {
1369:                            LineBox lb = (LineBox) b;
1370:
1371:                            for (int j = 0, m = lb.getBoxCount(); j < m; j++) {
1372:                                CssBox ilb = lb.getBox(j);
1373:                                //                        Node node = getElement(ilb);
1374:                                Node node = getComponentRootElementParentForCssBox(ilb);
1375:
1376:                                // Search up the DOM to see if this leaf box is inside the given
1377:                                // target box' element
1378:                                while (node != null) {
1379:                                    if (node == element) {
1380:                                        return lb;
1381:                                    }
1382:
1383:                                    node = node.getParentNode();
1384:                                }
1385:                            }
1386:                        } else {
1387:                            // Floats can appear in a line context.
1388:                            assert b.getBoxType() == BoxType.FLOAT;
1389:
1390:                            // Float contents aren't in line boxes
1391:                            // XXX not true! but won't fix that right now
1392:                            continue;
1393:                        }
1394:                    }
1395:                } else {
1396:                    // Look for the LAST box present in a linebox for the given managed box
1397:                    // Same as above, but we search backwards in the linebox list as
1398:                    // well as backwards in each linebox. This ensures that I find the
1399:                    // last matching box rather than the first.
1400:                    for (int n = lbg.getBoxCount(), i = n - 1; i >= 0; i--) {
1401:                        CssBox b = lbg.getBox(i);
1402:
1403:                        if (b instanceof  LineBox) {
1404:                            LineBox lb = (LineBox) b;
1405:
1406:                            for (int m = lb.getBoxCount(), j = m - 1; j >= 0; j--) {
1407:                                CssBox ilb = lb.getBox(j);
1408:                                //                        Node node = getElement(ilb);
1409:                                Node node = getComponentRootElementParentForCssBox(ilb);
1410:
1411:                                // Search up the DOM to see if this leaf box is inside the given
1412:                                // target box' element
1413:                                while (node != null) {
1414:                                    if (node == element) {
1415:                                        return lb;
1416:                                    }
1417:
1418:                                    node = node.getParentNode();
1419:                                }
1420:                            }
1421:                        } else {
1422:                            // Floats can appear in a line context.
1423:                            assert b.getBoxType() == BoxType.FLOAT;
1424:
1425:                            // Float contents aren't in line boxes
1426:                            // XXX not true! but won't fix that right now
1427:                            continue;
1428:                        }
1429:                    }
1430:                }
1431:
1432:                return null;
1433:            }
1434:
1435:            /** Find the box whose corresponding node matches the given node, starting
1436:             * at the given root box. The offset is only relevant when we're dealing with
1437:             * a text box, where the node is split into many boxes.
1438:             */
1439:            public static CssBox findBox(CssBox root, Node target, int offset) { // HACK ALERT
1440:
1441:                if (root.getBoxType() == BoxType.TEXT) {
1442:                    TextBox tb = (TextBox) root;
1443:
1444:                    if ((tb.getNode() == target) && (
1445:                    /* This doesn't work when the position is somewhere in the DOM I'm
1446:                       not displaying, like in a region of space characters. Since I search
1447:                       the dom forwards however, I don't need this extra check.
1448:                    tb.getDomStartOffset() <= offset && */
1449:                    offset <= tb.getDomEndOffset())) {
1450:                        return tb;
1451:                    }
1452:
1453:                    return null;
1454:                } else if (root.getBoxType() == BoxType.SPACE) {
1455:                    SpaceBox tb = (SpaceBox) root;
1456:
1457:                    if ((tb.getNode() == target) && (
1458:                    /* This doesn't work when the position is somewhere in the DOM I'm
1459:                       not displaying, like in a region of space characters. Since I search
1460:                       the dom forwards however, I don't need this extra check.
1461:                    tb.getDomStartOffset() <= offset && */
1462:                    offset <= tb.getDomEndOffset())) {
1463:                        return tb;
1464:                    }
1465:
1466:                    return null;
1467:                }
1468:
1469:                if ((root.getElement() == target)
1470:                        || (root.getSourceElement() == target)) {
1471:                    return root;
1472:                }
1473:
1474:                for (int i = 0, n = root.getBoxCount(); i < n; i++) {
1475:                    CssBox child = root.getBox(i);
1476:                    CssBox match = findBox(child, target, offset);
1477:
1478:                    if (match != null) {
1479:                        if ((match.getBoxType() == BoxType.SPACE)
1480:                                && (i < (n - 1))) {
1481:                            CssBox match2 = findBox(root.getBox(i + 1), target,
1482:                                    offset);
1483:
1484:                            if (match2 != null) {
1485:                                if ((match2.getBoxType() == BoxType.TEXT)
1486:                                        && (((TextBox) match2)
1487:                                                .getDomStartOffset() >= offset)) {
1488:                                    return match2;
1489:                                } else if (match2.getBoxType() != BoxType.SPACE) {
1490:                                    return match2;
1491:                                }
1492:                            }
1493:                        }
1494:
1495:                        return match;
1496:                    }
1497:                }
1498:
1499:                return null;
1500:            }
1501:
1502:            /** Find the CssBox corresponding to a given position */
1503:            //    private static CssBox findBox(PageBox root, Position pos) { // HACK ALERT
1504:            private static CssBox findBox(PageBox root, DomPosition pos) { // HACK ALERT
1505:
1506:                //        if (pos == Position.NONE) {
1507:                if (pos == DomPosition.NONE) {
1508:                    return null;
1509:                }
1510:
1511:                Node node = pos.getNode();
1512:                int offset = pos.getOffset();
1513:
1514:                if ((node.getNodeType() == Node.TEXT_NODE)
1515:                        || (node.getNodeType() == Node.CDATA_SECTION_NODE)) {
1516:                    // Text node: locate the corresponding line box
1517:                    // The offset may point to a collapsed space character
1518:                    // so watch out:)
1519:                    Node p = node.getParentNode();
1520:                    CssBox box = null;
1521:
1522:                    // Try to shortcut the search through the box hierarchy for
1523:                    // the node matching this position by looking up the parent box
1524:                    if ((p != null) && (p.getNodeType() == Node.ELEMENT_NODE)) {
1525:                        Element pe = (Element) p;
1526:                        //                CssBox pb = CssBox.getBox(pe);
1527:                        CssBox pb = root.getWebForm().findCssBoxForElement(pe);
1528:
1529:                        if (pb != null) {
1530:                            box = findBox(pb, node, offset);
1531:
1532:                            if ((box == null)
1533:                                    && (node.getNodeValue().length() == 0)
1534:                                    && (node.getNextSibling() != null)) {
1535:                                // When I'm doing inline editing, I may be deleting
1536:                                // text within a node, so I end up pointing to
1537:                                // an empty text. If so try to look for the position
1538:                                // next to it instead.
1539:                                box = findBox(pb, node.getNextSibling(), 0);
1540:                            }
1541:
1542:                            if ((box == null)
1543:                                    && DesignerUtils.onlyWhitespace(node
1544:                                            .getNodeValue())) {
1545:                                // Perhaps it's a space box we've pulled
1546:                                if (pos.getBias() == Bias.FORWARD) {
1547:                                    if (node.getNextSibling() != null) {
1548:                                        box = findBox(pb,
1549:                                                node.getNextSibling(), 0);
1550:                                    }
1551:                                } else { // Bias.BACKWARD
1552:
1553:                                    if (node.getPreviousSibling() != null) {
1554:                                        box = findBox(pb, node
1555:                                                .getPreviousSibling(), 0);
1556:                                    }
1557:                                }
1558:                            }
1559:                        }
1560:                    }
1561:
1562:                    if (box == null) {
1563:                        box = findBox(root, node, offset);
1564:                    }
1565:
1566:                    return box;
1567:                } else if (node.getNodeType() == Node.ELEMENT_NODE) {
1568:                    // Element node
1569:                    // offset 0 means before the element, offset 1 means after
1570:                    Element element = (Element) node;
1571:                    NodeList list = element.getChildNodes();
1572:                    int len = list.getLength();
1573:
1574:                    if ((len == 0) || (offset >= len)) {
1575:                        // We have a 0 index but no children, e.g. we're
1576:                        // inside an empty element.
1577:                        // XXX Can we do anything here? For now just use the parent
1578:                        // element
1579:                    } else if ((pos.getBias() == Bias.BACKWARD) && (offset > 0)
1580:                            && ((offset - 1) < len)) {
1581:                        Node child = list.item(offset - 1);
1582:
1583:                        if (child.getNodeType() == Node.ELEMENT_NODE) {
1584:                            element = (Element) child;
1585:                        } else if ((child.getNodeType() == Node.TEXT_NODE)
1586:                                || (child.getNodeType() == Node.CDATA_SECTION_NODE)) {
1587:                            //                    CssBox pb = CssBox.getBox(element);
1588:                            CssBox pb = root.getWebForm().findCssBoxForElement(
1589:                                    element);
1590:
1591:                            CssBox box = null;
1592:
1593:                            if (pb != null) {
1594:                                box = findBox(pb, child, offset);
1595:
1596:                                if ((box == null)
1597:                                        && (child.getNodeValue().length() == 0)
1598:                                        && (child.getNextSibling() != null)) {
1599:                                    // When I'm doing inline editing, I may be deleting
1600:                                    // text within a node, so I end up pointing to
1601:                                    // an empty text. If so try to look for the position
1602:                                    // next to it instead.
1603:                                    box = findBox(pb, child.getNextSibling(), 0);
1604:                                }
1605:                            }
1606:
1607:                            if (box == null) {
1608:                                box = findBox(root, child, offset);
1609:                            }
1610:
1611:                            return box;
1612:                        }
1613:                    } else if (offset < len) {
1614:                        Node child = list.item(offset);
1615:
1616:                        if (child.getNodeType() == Node.ELEMENT_NODE) {
1617:                            element = (Element) child;
1618:                        } // else use parent -- which we already have stored in element
1619:                    }
1620:
1621:                    //            CssBox box = CssBox.getBox(element);
1622:                    CssBox box = root.getWebForm()
1623:                            .findCssBoxForElement(element);
1624:
1625:                    // Todo: find the nearest linebox
1626:                    return box;
1627:                } else {
1628:                    // Not sure how to handle this one
1629:                    ErrorManager.getDefault().log(
1630:                            "Unexpected node type in findBox: " + node);
1631:
1632:                    return null;
1633:                }
1634:            }
1635:
1636:            /**
1637:             * For the given caret position, compute the visible caret rectangle
1638:             * on the screen.  Note that the position must fit certain criteria:
1639:             * it needs to point inside a LineBox (e.g. be a valid caret position).
1640:             * @param A position in the source dom (where carets live for example)
1641:             */
1642:            //    public static Rectangle modelToView(PageBox pageBox, Position sourcePos) {
1643:            public static Rectangle modelToView(PageBox pageBox,
1644:                    DomPosition sourcePos) {
1645:                if (pageBox == null) {
1646:                    // XXX #122515 NPE, which shouldn't happen (it seems there is a deeper issue).
1647:                    return null;
1648:                }
1649:                // assert that the position is a valid position here?
1650:                //        if (sourcePos == Position.NONE) {
1651:                if (sourcePos == DomPosition.NONE) {
1652:                    return null;
1653:                }
1654:
1655:                //        assert !sourcePos.isRendered();
1656:                //        if (MarkupService.isRenderedNode(sourcePos.getNode())) {
1657:                if (sourcePos.isRenderedPosition()) {
1658:                    ErrorManager.getDefault().notify(
1659:                            ErrorManager.INFORMATIONAL,
1660:                            new IllegalArgumentException(
1661:                                    "Node is expected to be not rendered, node="
1662:                                            + sourcePos.getNode())); // NOI18N
1663:                }
1664:
1665:                //        Position pos = sourcePos.getRenderedPosition();
1666:                DomPosition pos = sourcePos.getRenderedPosition();
1667:
1668:                //        if (pos == Position.NONE) {
1669:                if (pos == DomPosition.NONE) {
1670:                    return null; // not yet rendered
1671:                }
1672:
1673:                Node node = pos.getNode();
1674:                int offset = pos.getOffset();
1675:
1676:                if (node.getNodeType() == Node.ELEMENT_NODE) {
1677:                    // XXX this should not be necessary!
1678:                    //XhtmlElement xel = (XhtmlElement)node;
1679:                    //node = xel.getSourceElement();
1680:                    if (node.getChildNodes().getLength() == 0) {
1681:                        // Have no children
1682:                        // Try to use font height instead
1683:                        Element element = (Element) node;
1684:                        //                CssBox box = CssBox.getBox(element);
1685:                        CssBox box = pageBox.getWebForm().findCssBoxForElement(
1686:                                element);
1687:
1688:                        // Find the first actual item in a linebox since parents
1689:                        // in inline context don't get inserted. But what about floats??
1690:                        while ((box != null)
1691:                                && (box.getHeight() == CssBox.UNINITIALIZED)
1692:                                && (box.getBoxCount() > 0)) {
1693:                            box = box.getBox(0);
1694:                        }
1695:
1696:                        // Todo: find the nearest linebox
1697:                        if (box != null) {
1698:                            int height = box.getHeight();
1699:                            //                    Font font = CssLookup.getFont(element, DesignerSettings.getInstance().getDefaultFontSize());
1700:                            //                    Font font = CssProvider.getValueService().getFontForElement(element, DesignerSettings.getInstance().getDefaultFontSize(), Font.PLAIN);
1701:                            //                    if (font != null) {
1702:                            //                        FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
1703:                            //                        height = metrics.getHeight();
1704:                            //                    }
1705:                            // XXX Missing text.
1706:                            height = CssUtilities
1707:                                    .getDesignerFontMetricsForElement(
1708:                                            element,
1709:                                            null,
1710:                                            pageBox.getWebForm()
1711:                                                    .getDefaultFontSize())
1712:                                    .getHeight();
1713:
1714:                            Rectangle r = new Rectangle(box.getAbsoluteX(), box
1715:                                    .getAbsoluteY(), box.getWidth(), height);
1716:
1717:                            if (box.isInlineBox()) {
1718:                                r.y = (box.getAbsoluteY() + box.getHeight())
1719:                                        - height;
1720:                            }
1721:
1722:                            return r;
1723:                        }
1724:
1725:                        return null;
1726:                    } else if ((pos.getBias() == Bias.BACKWARD)
1727:                            && (offset > 0)
1728:                            && ((offset - 1) < node.getChildNodes().getLength())) {
1729:                        node = node.getChildNodes().item(offset - 1);
1730:                        offset = 1;
1731:                    } else if (offset < node.getChildNodes().getLength()) {
1732:                        node = node.getChildNodes().item(offset);
1733:                        offset = 0;
1734:                    } else if (offset > 0) {
1735:                        // XXX not a good idea for <br> !
1736:                        // XXX This is highly suspect!!! I should probably use node.getChildNodes().getLength()-1 here!!! not offset-1
1737:                        node = node.getChildNodes().item(offset - 1);
1738:
1739:                        if (node.getNodeType() == Node.TEXT_NODE) {
1740:                            offset = node.getNodeValue().length();
1741:                        } else {
1742:                            offset = 1; // XXX ?
1743:                        }
1744:                    }
1745:                } else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) {
1746:                    if (node.getChildNodes().getLength() == 0) {
1747:                        // Have no children
1748:                        return null; // this shouldn't happen!!
1749:                    } else if ((pos.getBias() == Bias.BACKWARD)
1750:                            && (offset > 0)
1751:                            && ((offset - 1) < node.getChildNodes().getLength())) {
1752:                        node = node.getChildNodes().item(offset - 1);
1753:                        offset = 1;
1754:                    } else if (offset < node.getChildNodes().getLength()) {
1755:                        node = node.getChildNodes().item(offset);
1756:                        offset = 0;
1757:                    } else if (offset > 0) {
1758:                        // XXX not a good idea for <br> !
1759:                        node = node.getChildNodes().item(offset - 1);
1760:
1761:                        if (node.getNodeType() == Node.TEXT_NODE) {
1762:                            offset = node.getNodeValue().length();
1763:                        } else if (node.getNodeType() == Node.ELEMENT_NODE) {
1764:                            return modelToView(pageBox,
1765:                            //                        new Position(node, node.getChildNodes().getLength(), Bias.FORWARD));
1766:                                    //                            Position.create(node, node.getChildNodes().getLength(), Bias.FORWARD));
1767:                                    pageBox.getWebForm().createDomPosition(
1768:                                            node,
1769:                                            node.getChildNodes().getLength(),
1770:                                            Bias.FORWARD));
1771:                        } else {
1772:                            offset = 1; // XXX ?
1773:                        }
1774:                    }
1775:                }
1776:
1777:                if ((node.getNodeType() == Node.TEXT_NODE)
1778:                        || (node.getNodeType() == Node.CDATA_SECTION_NODE)) {
1779:                    //            // XXX this should not be necessary!
1780:                    //            if (node instanceof XhtmlText) {
1781:                    //                XhtmlText xt = (XhtmlText)node;
1782:                    //                node = xt.getSourceNode();
1783:                    //            }
1784:                    // Text node: locate the corresponding line box
1785:                    // The offset may point to a collapsed space character
1786:                    // so watch out:)
1787:                    Node p = node.getParentNode();
1788:                    CssBox pb = null;
1789:                    CssBox box = null;
1790:
1791:                    // Try to shortcut the search through the box hierarchy for
1792:                    // the node matching this position by looking up the parent box
1793:                    if ((p != null) && (p.getNodeType() == Node.ELEMENT_NODE)) {
1794:                        Element pe = (Element) p;
1795:                        //                pb = CssBox.getBox(pe);
1796:                        pb = pageBox.getWebForm().findCssBoxForElement(pe);
1797:
1798:                        if (pb != null) {
1799:                            // XXX here we should use the SOURCE node!
1800:                            box = findBox(pb, node, offset);
1801:                        }
1802:
1803:                        //                if (box == null) {
1804:                        //                    LineBox lb = findLineBox(pb);
1805:                        //                    if (lb != null) {
1806:                        //                        box = findBox(lb, node, offset);                        
1807:                        //                    }
1808:                        //                }
1809:                    }
1810:
1811:                    if (box == null) {
1812:                        box = findBox(pageBox, node, offset);
1813:                    }
1814:
1815:                    if ((box == null)
1816:                            && ((node.getNodeType() == Node.TEXT_NODE) || (node
1817:                                    .getNodeType() == Node.CDATA_SECTION_NODE))
1818:                            && (node.getNextSibling() != null)
1819:                            && (node.getNextSibling().getNodeType() == Node.ELEMENT_NODE)
1820:                            && ((Element) node.getNextSibling()).getTagName()
1821:                                    .equals(HtmlTag.BR.name)) {
1822:                        box = findBox(pageBox, node.getNextSibling(), 0);
1823:                    }
1824:
1825:                    if (box != null) {
1826:                        int x = box.getAbsoluteX();
1827:
1828:                        if (box.getBoxType() == BoxType.TEXT) {
1829:                            //                    return ((TextBox)box).getBoundingBox(new Position(node, offset, Bias.FORWARD));
1830:                            //                    return ((TextBox)box).getBoundingBox(Position.create(node, offset, Bias.FORWARD));
1831:                            return ((TextBox) box).getBoundingBox(pageBox
1832:                                    .getWebForm().createDomPosition(node,
1833:                                            offset, Bias.FORWARD));
1834:                        } else if (box.getBoxType() == BoxType.SPACE) {
1835:                            return ((SpaceBox) box).getBoundingBox(pageBox
1836:                                    .getWebForm().createDomPosition(node,
1837:                                            offset, Bias.FORWARD));
1838:
1839:                            /*
1840:                            } else if (box instanceof FormComponentBox) {
1841:                            return ((FormComponentBox)box).getBoundingBox(new Position(node, offset));
1842:                             */
1843:                        }
1844:
1845:                        return new Rectangle(x, box.getAbsoluteY(), box
1846:                                .getWidth(), box.getHeight());
1847:                    }
1848:
1849:                    if ((offset > 0)
1850:                            && (node.getNodeValue().charAt(offset - 1) == ' ')) {
1851:                        // Special case: the caret is after a space at the end of a text node;
1852:                        // in this case, since we don't create boxes for spaces, there's no
1853:                        // corresponding box recording the location. So find the most recent
1854:                        // box instead.
1855:                        box = findBox(pageBox, node, offset - 1);
1856:
1857:                        if (box != null) {
1858:                            Rectangle r = null;
1859:
1860:                            if (box.getBoxType() == BoxType.TEXT) {
1861:                                //                        r = ((TextBox)box).getBoundingBox(new Position(node, offset, Bias.FORWARD));
1862:                                //                        r = ((TextBox)box).getBoundingBox(Position.create(node, offset, Bias.FORWARD));
1863:                                r = ((TextBox) box).getBoundingBox(pageBox
1864:                                        .getWebForm().createDomPosition(node,
1865:                                                offset, Bias.FORWARD));
1866:                                r.width += ((TextBox) box).getMetrics()
1867:                                        .charWidth(' ');
1868:
1869:                                return r;
1870:                            } else if (box.getBoxType() == BoxType.SPACE) {
1871:                                //                        r = ((SpaceBox)box).getBoundingBox(new Position(node, offset, Bias.FORWARD));
1872:                                //                        r = ((SpaceBox)box).getBoundingBox(Position.create(node, offset, Bias.FORWARD));
1873:                                r = ((SpaceBox) box).getBoundingBox(pageBox
1874:                                        .getWebForm().createDomPosition(node,
1875:                                                offset, Bias.FORWARD));
1876:                                r.width += ((SpaceBox) box).getMetrics()
1877:                                        .charWidth(' ');
1878:
1879:                                return r;
1880:                            }
1881:
1882:                            int SPACE = 5; // hack - gotta find true space width
1883:
1884:                            return new Rectangle(box.getAbsoluteX() + SPACE,
1885:                                    box.getAbsoluteY(), box.getWidth(), box
1886:                                            .getHeight());
1887:                        }
1888:                    }
1889:
1890:                    // XXX do I have the same issue with space in front of
1891:                    // boxes too?
1892:                    if (pb != null) {
1893:                        int height = pb.getHeight();
1894:                        //                Font font = CssLookup.getFont(pb.getElement(), DesignerSettings.getInstance().getDefaultFontSize());
1895:                        //                Font font = CssProvider.getValueService().getFontForElement(pb.getElement(), DesignerSettings.getInstance().getDefaultFontSize(), Font.PLAIN);
1896:                        //                if (font != null) {
1897:                        //                    FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
1898:                        //                    height = metrics.getHeight();
1899:                        //                }
1900:                        // XXX Missing text.
1901:                        height = CssUtilities.getDesignerFontMetricsForElement(
1902:                                pb.getElement(), null,
1903:                                pageBox.getWebForm().getDefaultFontSize())
1904:                                .getHeight();
1905:
1906:                        // Try to find a sibling box
1907:                        Node curr = node.getPreviousSibling();
1908:
1909:                        while (curr != null) {
1910:                            box = findBox(pb, curr, 0);
1911:
1912:                            if (box != null) {
1913:                                break;
1914:                            }
1915:
1916:                            curr = curr.getPreviousSibling();
1917:                        }
1918:
1919:                        if (box != null) {
1920:                            // THIS IS A HACK! Just trying to get closer to the real position of the cursor
1921:                            Rectangle r = new Rectangle(box.getAbsoluteX()
1922:                                    + box.getWidth(), box.getAbsoluteY(), box
1923:                                    .getWidth(), height);
1924:
1925:                            // XXX adjust to get to the bottom as well??? (if inline box) as done elsewhere...
1926:                            curr = curr.getNextSibling();
1927:
1928:                            while (curr != node) {
1929:                                if (curr instanceof  Element
1930:                                        && ((Element) curr).getTagName()
1931:                                                .equals("br")) {
1932:                                    // newline
1933:                                    r.y += height;
1934:                                    r.x = box.getAbsoluteX();
1935:                                }
1936:
1937:                                curr = curr.getNextSibling();
1938:                            }
1939:
1940:                            return r;
1941:                        }
1942:
1943:                        Rectangle r = new Rectangle(pb.getAbsoluteX(), pb
1944:                                .getAbsoluteY(), pb.getWidth(), height);
1945:
1946:                        return r;
1947:                    }
1948:
1949:                    return null;
1950:                } else if (node.getNodeType() == Node.ELEMENT_NODE) {
1951:                    // Element node
1952:                    // offset 0 means before the element, offset 1 means after
1953:                    Element element = (Element) node;
1954:                    //            CssBox box = CssBox.getBox(element);
1955:                    CssBox box = pageBox.getWebForm().findCssBoxForElement(
1956:                            element);
1957:
1958:                    // Find the first actual item in a linebox since parents
1959:                    // in inline context don't get inserted. But what about floats??
1960:                    while ((box != null)
1961:                            && (box.getHeight() == CssBox.UNINITIALIZED)
1962:                            && (box.getBoxCount() > 0)) {
1963:                        box = box.getBox(0);
1964:                    }
1965:
1966:                    if (box == null) {
1967:                        box = findBox(pageBox, node, offset);
1968:                    }
1969:
1970:                    //            if ((box != null) && (box.getDesignBean() == null)) {
1971:                    //            if ((box != null) && (CssBox.getMarkupDesignBeanForCssBox(box) == null)) {
1972:                    if ((box != null)
1973:                            && (CssBox.getElementForComponentRootCssBox(box) == null)) {
1974:                        // We have a generated box... go find the associated line box
1975:                        LineBox lb = findLineBox(box, offset == 0);
1976:
1977:                        if (lb != null) {
1978:                            //CssBox lastBox = findBeanBox(lb, box.getDesignBean(), offset == 0);
1979:                            CssBox lastBox = null;
1980:                            //                    DesignBean bean = getBean(box);
1981:                            Element parentComponentRootElement = getComponentRootElementParentForCssBox(box);
1982:                            boolean first = (offset == 0);
1983:
1984:                            CssBox beanBox = null;
1985:
1986:                            for (int i = 0, n = lb.getBoxCount(); i < n; i++) {
1987:                                CssBox ilb = lb.getBox(i);
1988:
1989:                                //                        if (getBean(ilb) == bean) {
1990:                                if (getComponentRootElementParentForCssBox(ilb) == parentComponentRootElement) {
1991:                                    beanBox = ilb;
1992:
1993:                                    if (first) {
1994:                                        break;
1995:                                    }
1996:                                }
1997:                            }
1998:
1999:                            lastBox = beanBox;
2000:
2001:                            if (lastBox != null) {
2002:                                box = lastBox;
2003:                            }
2004:                        }
2005:                    }
2006:
2007:                    // Todo: find the nearest linebox
2008:                    if (box != null) {
2009:                        int height = box.getHeight();
2010:
2011:                        // Try to use font height instead
2012:                        //                Font font = CssLookup.getFont(element, DesignerSettings.getInstance().getDefaultSize());
2013:                        //                Font font = CssProvider.getValueService().getFontForElement(element, DesignerSettings.getInstance().getDefaultFontSize(), Font.PLAIN);
2014:                        //                if (font != null) {
2015:                        //                    FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
2016:                        //                    height = metrics.getHeight();
2017:                        //                }
2018:                        // XXX Missing text.
2019:                        height = CssUtilities.getDesignerFontMetricsForElement(
2020:                                element, null,
2021:                                pageBox.getWebForm().getDefaultFontSize())
2022:                                .getHeight();
2023:
2024:                        Rectangle r = new Rectangle(box.getAbsoluteX(), box
2025:                                .getAbsoluteY(), box.getWidth(), height);
2026:
2027:                        if (offset == 1) {
2028:                            r.x += box.getWidth();
2029:                        }
2030:
2031:                        if (box.isInlineBox()) {
2032:                            r.y = (box.getAbsoluteY() + box.getHeight())
2033:                                    - height;
2034:                        }
2035:
2036:                        return r;
2037:                    }
2038:
2039:                    return null;
2040:                } else {
2041:                    // Not sure how to handle this one
2042:                    ErrorManager.getDefault().log(
2043:                            "Unexpected node type in modelToView: " + node);
2044:
2045:                    return null;
2046:                }
2047:            }
2048:
2049:            //    /** Find the DesignBean associated with a particular box. */
2050:            //    private static DesignBean getBean(CssBox box) {
2051:            ////        RaveElement element = getElement(box);
2052:            //        Element element = getElement(box);
2053:            //
2054:            ////        if (element != null) {
2055:            ////            return element.getDesignBean();
2056:            ////        }
2057:            ////
2058:            ////        return null;
2059:            ////        return InSyncService.getProvider().getMarkupDesignBeanForElement(element);
2060:            //        return WebForm.getDomProviderService().getMarkupDesignBeanForElement(element);
2061:            //    }
2062:            //
2063:            //    private static Element getElement(CssBox box) {
2064:            ////        RaveElement element = (RaveElement)box.getElement();
2065:            //        Element element = box.getElement();
2066:            //
2067:            //        while (true) {
2068:            //            //if (element.getDesignBean() != null) {
2069:            //            //    return element;
2070:            //            //}
2071:            ////            if (element.getSource() != null) {
2072:            //            if (MarkupService.getSourceElementForElement(element) != null) {
2073:            //                return element;
2074:            //            }
2075:            //
2076:            //            Node parent = element.getParentNode();
2077:            //
2078:            //            if (parent instanceof Element) {
2079:            //                element = (Element)parent;
2080:            //            } else {
2081:            //                return null;
2082:            //            }
2083:            //        }
2084:            //    }
2085:
2086:            private static Element getComponentRootElementParentForCssBox(
2087:                    CssBox cssBox) {
2088:                while (true) {
2089:                    Element componentRootElement = CssBox
2090:                            .getElementForComponentRootCssBox(cssBox);
2091:                    if (componentRootElement != null) {
2092:                        return componentRootElement;
2093:                    }
2094:
2095:                    cssBox = cssBox.getParent();
2096:                    if (cssBox == null) {
2097:                        return null;
2098:                    }
2099:                }
2100:            }
2101:
2102:            /**
2103:             * Provides a mapping from the view coordinate space to the logical
2104:             * coordinate space of the model.
2105:             * The returned position is always a position in the source DOM,
2106:             * not a position in the rendered DOM (unless it is Position.NONE
2107:             * which means the position does not correlate to a position in the document.)
2108:             *
2109:             *
2110:             * @todo Find a better home for this method
2111:             * @param x the X coordinate >= 0
2112:             * @param y the Y coordinate >= 0
2113:             * @return the location within the model that best represents the
2114:             *  given point in the view >= 0.
2115:             */
2116:            //    public static Position viewToModel(WebForm webform, int x, int y) {
2117:            public static DomPosition viewToModel(WebForm webform, int x, int y) {
2118:                try {
2119:                    //            Position pos = findClosestPosition(webform, x, y);
2120:                    DomPosition pos = findClosestPosition(webform, x, y);
2121:
2122:                    //            if ((pos != Position.NONE) && pos.isRendered()) {
2123:                    //            if ((pos != Position.NONE)
2124:                    if ((pos != DomPosition.NONE)
2125:                    //            && MarkupService.isRenderedNode(pos.getNode())) {
2126:                            && pos.isRenderedPosition()) {
2127:                        return pos.getSourcePosition();
2128:                    } else {
2129:                        return pos;
2130:                    }
2131:
2132:                    // Assert that the position computed is a valid caret position (e.g.
2133:                    // points inside a LineBox) here?
2134:                } catch (Throwable t) {
2135:                    ErrorManager.getDefault().notify(t);
2136:
2137:                    //            return Position.NONE;
2138:                    return DomPosition.NONE;
2139:                }
2140:            }
2141:
2142:            /** For the given box, locate the position closest to the given x position
2143:             */
2144:            //    private static Position findClosestPosition(WebForm webform, int x, int y) {
2145:            private static DomPosition findClosestPosition(WebForm webform,
2146:                    int x, int y) {
2147:                CssBox box = webform.getPane().getPageBox().findCssBox((int) x,
2148:                        (int) y);
2149:
2150:                if (box == null) {
2151:                    //            return Position.NONE;
2152:                    return DomPosition.NONE;
2153:                }
2154:
2155:                assert !box.isPlaceHolder();
2156:
2157:                if (box instanceof  LineBoxGroup) {
2158:                    // We have clicked on a line that is not covered by a LineBox but
2159:                    // is inside a group of line boxes - e.g. this line is shorter than
2160:                    // others. Find it.
2161:                    //            Position pos = findLineBoxClosestTo(box, y, webform.getManager().getInlineEditor());
2162:                    DomPosition pos = findLineBoxClosestTo(box, y, webform
2163:                            .getManager().getInlineEditor());
2164:
2165:                    //            if (pos != Position.NONE) {
2166:                    if (pos != DomPosition.NONE) {
2167:                        return pos;
2168:                    }
2169:                }
2170:
2171:                // If you hit a linebox, just use that
2172:                LineBox lb = findLineBox(box, true);
2173:
2174:                if (lb != null) {
2175:                    //            Position p = lb.computePosition(x - lb.getAbsoluteX());
2176:                    DomPosition p = lb.computePosition(x - lb.getAbsoluteX());
2177:
2178:                    //            if (DesignerUtils.checkPosition(p, false, webform.getManager().getInlineEditor()) != Position.NONE) {
2179:                    //            if (isValidPosition(p, false, webform.getManager().getInlineEditor())) {
2180:                    if (isValidPosition(webform, p, false, webform.getManager()
2181:                            .getInlineEditor())) {
2182:                        return p;
2183:                    }
2184:                }
2185:
2186:                //        Position pos = findLineBoxClosestTo(box, y, webform.getManager().getInlineEditor());
2187:                DomPosition pos = findLineBoxClosestTo(box, y, webform
2188:                        .getManager().getInlineEditor());
2189:
2190:                //        if (pos != Position.NONE) {
2191:                if (pos != DomPosition.NONE) {
2192:                    return pos;
2193:                }
2194:
2195:                // No linebox, so look both above and below for matches,
2196:                // and pick the closest location
2197:                LineBox prevLine = findPrevLineBox(box);
2198:
2199:                if (prevLine == null) {
2200:                    prevLine = findLastLineBox(box);
2201:                }
2202:
2203:                Rectangle prev = null;
2204:                //        Position prevPos = null;
2205:                DomPosition prevPos = null;
2206:
2207:                if (prevLine != null) {
2208:                    prevPos = findLastLineboxPosition(prevLine, webform
2209:                            .getManager().getInlineEditor());
2210:
2211:                    //            if (prevPos != Position.NONE) {
2212:                    if (prevPos != DomPosition.NONE) {
2213:                        //                if (prevPos.isRendered()) {
2214:                        //                if (MarkupService.isRenderedNode(prevPos.getNode())) {
2215:                        if (prevPos.isRenderedPosition()) {
2216:                            prevPos = prevPos.getSourcePosition();
2217:                        }
2218:
2219:                        prev = modelToView(webform.getPane().getPageBox(),
2220:                                prevPos);
2221:                    }
2222:                }
2223:
2224:                LineBox nextLine = findNextLineBox(box);
2225:
2226:                if (nextLine == null) {
2227:                    nextLine = findFirstLineBox(box);
2228:                }
2229:
2230:                Rectangle next = null;
2231:                //        Position nextPos = null;
2232:                DomPosition nextPos = null;
2233:
2234:                if (nextLine != null) {
2235:                    nextPos = findFirstLineboxPosition(nextLine, 0, webform
2236:                            .getManager().getInlineEditor());
2237:
2238:                    //            if (nextPos != Position.NONE) {
2239:                    if (nextPos != DomPosition.NONE) {
2240:                        //                if (nextPos.isRendered()) {
2241:                        //                if (MarkupService.isRenderedNode(nextPos.getNode())) {
2242:                        if (nextPos.isRenderedPosition()) {
2243:                            nextPos = nextPos.getSourcePosition();
2244:                        }
2245:
2246:                        next = modelToView(webform.getPane().getPageBox(),
2247:                                nextPos);
2248:                    }
2249:                }
2250:
2251:                if ((next != null) && (prev != null)) {
2252:                    if (prevLine == nextLine) {
2253:                        return prevPos;
2254:                    }
2255:
2256:                    // See if we're closer to the first or the last line box - pick whichever
2257:                    // one is closest. Note however that we only look at the y coordinate, not
2258:                    // the real distance (Math.sqrt(dx*dx+dy*dy))
2259:                    if (Math.abs(y - next.y) < Math.abs(y - prev.y)) {
2260:                        return nextPos;
2261:                    } else {
2262:                        return prevPos;
2263:                    }
2264:                } else if (next != null) {
2265:                    return nextPos;
2266:                } else if (prev != null) {
2267:                    return prevPos;
2268:                } else {
2269:                    /* XXX I can't do this because I'm called when the read lock for
2270:                     * view hierarchy is held, and calling into DesignBean creation
2271:                     * will require a write lock on the unit...
2272:                    if (!webform.isGridMode()) {
2273:                        // There are no caret positions in the document. We should create one.
2274:                        // Are we closer to the top or the end? Just use y position.
2275:                        if (y > pageBox.getHeight()/2) {
2276:                            return createEndPosition();
2277:                        } else {
2278:                            return createBeginPosition();
2279:                        }
2280:                    }
2281:                     */
2282:
2283:                    //assert prevPos == Position.NONE && nextPos == Position.NONE : prevPos + "," + nextPos;
2284:                    //            return Position.NONE;
2285:                    return DomPosition.NONE;
2286:                }
2287:            }
2288:
2289:            //    private static Position findLineBoxClosestTo(CssBox box, int y, InlineEditor inlineEditor) {
2290:            private static DomPosition findLineBoxClosestTo(CssBox box, int y,
2291:                    InlineEditor inlineEditor) {
2292:                if ((box.getBoxType() == BoxType.LINEBOX)
2293:                        && box instanceof  LineBox) {
2294:                    LineBox lb = (LineBox) box;
2295:                    int cy = lb.getAbsoluteY();
2296:
2297:                    if ((y == CssBox.AUTO)
2298:                            || ((y >= cy) && (y <= (cy + lb.getHeight())))) {
2299:                        return findLastLineboxPosition(lb, inlineEditor);
2300:                    }
2301:                }
2302:
2303:                if (!(box instanceof  ExternalDocumentBox)) {
2304:                    // We've clicked outside of any of the children; see
2305:                    // if we can find a closer one
2306:                    for (int i = 0, n = box.getBoxCount(); i < n; i++) {
2307:                        //                Position match = findLineBoxClosestTo(box.getBox(i), y, inlineEditor);
2308:                        DomPosition match = findLineBoxClosestTo(box.getBox(i),
2309:                                y, inlineEditor);
2310:
2311:                        if (match != null) {
2312:                            return match;
2313:                        }
2314:                    }
2315:                }
2316:
2317:                //        return Position.NONE;
2318:                return DomPosition.NONE;
2319:            }
2320:
2321:            /** Return the position at the beginning of the line containing the given position */
2322:            //    public static Position getLineBegin(WebForm webform, Position sourcePos) {
2323:            public static DomPosition getLineBegin(WebForm webform,
2324:                    DomPosition sourcePos) {
2325:                //        assert !sourcePos.isRendered();
2326:                //        if (MarkupService.isRenderedNode(sourcePos.getNode())) {
2327:                if (sourcePos.isRenderedPosition()) {
2328:                    ErrorManager.getDefault().notify(
2329:                            ErrorManager.INFORMATIONAL,
2330:                            new IllegalArgumentException(
2331:                                    "Node is expected to be not rendered, node="
2332:                                            + sourcePos.getNode())); // NOI18N
2333:                }
2334:
2335:                //        Position pos = sourcePos.getRenderedPosition();
2336:                DomPosition pos = sourcePos.getRenderedPosition();
2337:
2338:                LineBox lb = findLineBox(webform.getPane().getPageBox(), pos);
2339:
2340:                if (lb == null) {
2341:                    assert false : pos; // Caret positions should always be in a linebox!!
2342:
2343:                    //            return Position.NONE;
2344:                    return DomPosition.NONE;
2345:                }
2346:
2347:                //        Position p = findFirstLineboxPosition(lb, 0, webform.getManager().getInlineEditor());
2348:                DomPosition p = findFirstLineboxPosition(lb, 0, webform
2349:                        .getManager().getInlineEditor());
2350:
2351:                return p.getSourcePosition();
2352:            }
2353:
2354:            /** Return the position at the end of the line containing the given position */
2355:            //    public static Position getLineEnd(WebForm webform, Position sourcePos) {
2356:            public static DomPosition getLineEnd(WebForm webform,
2357:                    DomPosition sourcePos) {
2358:                //        assert !sourcePos.isRendered();
2359:                //        if (MarkupService.isRenderedNode(sourcePos.getNode())) {
2360:                if (sourcePos.isRenderedPosition()) {
2361:                    ErrorManager.getDefault().notify(
2362:                            ErrorManager.INFORMATIONAL,
2363:                            new IllegalArgumentException(
2364:                                    "Node is expected to be not rendered, node="
2365:                                            + sourcePos.getNode())); // NOI18N
2366:                }
2367:
2368:                //        Position pos = sourcePos.getRenderedPosition();
2369:                DomPosition pos = sourcePos.getRenderedPosition();
2370:
2371:                LineBox lb = findLineBox(webform.getPane().getPageBox(), pos);
2372:
2373:                if (lb == null) {
2374:                    //            assert false : pos; // Caret positions should always be in a linebox!!
2375:
2376:                    //            return Position.NONE;
2377:                    return DomPosition.NONE;
2378:                }
2379:
2380:                //        Position p = findLastLineboxPosition(lb, webform.getManager().getInlineEditor());
2381:                DomPosition p = findLastLineboxPosition(lb, webform
2382:                        .getManager().getInlineEditor());
2383:
2384:                return p.getSourcePosition();
2385:            }
2386:
2387:            /** Find the beginning of the word from the given position */
2388:            //    public static Position getWordStart(PageBox pageBox, Position sourcePos) {
2389:            public static DomPosition getWordStart(PageBox pageBox,
2390:                    DomPosition sourcePos) {
2391:                //        assert !sourcePos.isRendered();
2392:                //        if (MarkupService.isRenderedNode(sourcePos.getNode())) {
2393:                if (sourcePos.isRenderedPosition()) {
2394:                    ErrorManager.getDefault().notify(
2395:                            ErrorManager.INFORMATIONAL,
2396:                            new IllegalArgumentException(
2397:                                    "Node is expected to be not rendered, node="
2398:                                            + sourcePos.getNode()));
2399:                }
2400:
2401:                //        Position pos = sourcePos.getRenderedPosition();
2402:                DomPosition pos = sourcePos.getRenderedPosition();
2403:
2404:                //        PageBox pageBox = webform.getPane().getPageBox();
2405:                CssBox box = findBox(pageBox, pos);
2406:
2407:                // XXX #110083 Possible NPE.
2408:                if (box == null) {
2409:                    return DomPosition.NONE;
2410:                }
2411:
2412:                if (box.getBoxType() == BoxType.TEXT) {
2413:                    TextBox tb = (TextBox) box;
2414:                    //            Position p = new Position(tb.getNode(), tb.getDomStartOffset(), Bias.FORWARD);
2415:                    //            Position p = Position.create(tb.getNode(), tb.getDomStartOffset(), Bias.FORWARD);
2416:                    DomPosition p = pageBox.getWebForm().createDomPosition(
2417:                            tb.getNode(), tb.getDomStartOffset(), Bias.FORWARD);
2418:
2419:                    return p.getSourcePosition();
2420:                } else if (box.getBoxType() == BoxType.SPACE) {
2421:                    SpaceBox tb = (SpaceBox) box;
2422:                    //            Position p = new Position(tb.getNode(), tb.getDomStartOffset(), Bias.FORWARD);
2423:                    //            Position p = Position.create(tb.getNode(), tb.getDomStartOffset(), Bias.FORWARD);
2424:                    DomPosition p = pageBox.getWebForm().createDomPosition(
2425:                            tb.getNode(), tb.getDomStartOffset(), Bias.FORWARD);
2426:
2427:                    return p.getSourcePosition();
2428:                } else {
2429:                    //            return Position.NONE;
2430:                    return DomPosition.NONE;
2431:                }
2432:            }
2433:
2434:            /** Find the end of the word from the given position */
2435:            //    public static Position getWordEnd(PageBox pageBox, Position sourcePos) {
2436:            public static DomPosition getWordEnd(PageBox pageBox,
2437:                    DomPosition sourcePos) {
2438:                //        assert !sourcePos.isRendered();
2439:                //        if (MarkupService.isRenderedNode(sourcePos.getNode())) {
2440:                if (sourcePos.isRenderedPosition()) {
2441:                    ErrorManager.getDefault().notify(
2442:                            ErrorManager.INFORMATIONAL,
2443:                            new IllegalArgumentException(
2444:                                    "Node is expected to be not rendered, node="
2445:                                            + sourcePos.getNode()));
2446:                }
2447:
2448:                //        Position pos = sourcePos.getRenderedPosition();
2449:                DomPosition pos = sourcePos.getRenderedPosition();
2450:
2451:                //        PageBox pageBox = webform.getPane().getPageBox();
2452:                CssBox box = findBox(pageBox, pos);
2453:
2454:                // XXX #127014 Possible NPE.
2455:                if (box == null) {
2456:                    return DomPosition.NONE;
2457:                }
2458:
2459:                if (box.getBoxType() == BoxType.TEXT) {
2460:                    TextBox tb = (TextBox) box;
2461:                    //            Position p = new Position(tb.getNode(), tb.getDomEndOffset(), Bias.BACKWARD);
2462:                    //            Position p = Position.create(tb.getNode(), tb.getDomEndOffset(), Bias.BACKWARD);
2463:                    DomPosition p = pageBox.getWebForm().createDomPosition(
2464:                            tb.getNode(), tb.getDomEndOffset(), Bias.BACKWARD);
2465:
2466:                    return p.getSourcePosition();
2467:                } else if (box.getBoxType() == BoxType.SPACE) {
2468:                    SpaceBox tb = (SpaceBox) box;
2469:                    //            Position p = new Position(tb.getNode(), tb.getDomEndOffset(), Bias.BACKWARD);
2470:                    //            Position p = Position.create(tb.getNode(), tb.getDomEndOffset(), Bias.BACKWARD);
2471:                    DomPosition p = pageBox.getWebForm().createDomPosition(
2472:                            tb.getNode(), tb.getDomEndOffset(), Bias.BACKWARD);
2473:
2474:                    return p.getSourcePosition();
2475:                } else {
2476:                    //            return Position.NONE;
2477:                    return DomPosition.NONE;
2478:                }
2479:            }
2480:
2481:            /**
2482:             * Return the first caret position in the document. If create is true,
2483:             * create one if necessary.
2484:             */
2485:            //    public static Position getFirstDocumentPosition(WebForm webform, boolean create) {
2486:            public static DomPosition getFirstDocumentPosition(WebForm webform,
2487:                    boolean create) {
2488:                // XXX #128116 Possible NPE after closing component.
2489:                if (webform.getPane().getPageBox() == null) {
2490:                    return DomPosition.NONE;
2491:                }
2492:
2493:                // XXX Very suspicious assertion.
2494:                //        assert webform.getPane().getPageBox().getElement().getOwnerDocument() == webform.getJspDom();
2495:                if (webform.getPane().getPageBox().getElement()
2496:                        .getOwnerDocument() != webform.getHtmlDom()) {
2497:                    ErrorManager.getDefault().notify(
2498:                            ErrorManager.INFORMATIONAL,
2499:                            new IllegalStateException(
2500:                                    "Owner document is expected to be html dom="
2501:                                            + webform.getHtmlDom() // NOI18N
2502:                                            + ", but it is dom="
2503:                                            + webform.getPane().getPageBox()
2504:                                                    .getElement()
2505:                                                    .getOwnerDocument())); // NOI18N
2506:                }
2507:
2508:                // First try to put the caret inside the the default parent of the component.
2509:                // This will avoid bugs like 6252951 where we start out with a caret
2510:                // outside the form component, which is probably where users want components
2511:                // added.
2512:                //        FacesPageUnit unit = webform.getModel().getFacesUnit();
2513:                //
2514:                //        if (unit != null) {
2515:                //            MarkupBean mb = unit.getDefaultParent();
2516:                ////            RaveElement element = (RaveElement)mb.getElement();
2517:                //            Element element = mb.getElement();
2518:
2519:                //        Element element = webform.getDefaultParentMarkupBeanElement();
2520:                //        if (element != null) {
2521:
2522:                //            if (element.getDesignBean() != null) {
2523:                ////                CssBox box = findBox(element.getDesignBean());
2524:                //                CssBox box = findBox(webform.getPane().getPageBox(), element.getDesignBean());
2525:                //            MarkupDesignBean markupDesignBean = InSyncService.getProvider().getMarkupDesignBeanForElement(element);
2526:                //            MarkupDesignBean markupDesignBean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(element);
2527:                //            if (markupDesignBean != null) {
2528:                //                CssBox box = findBox(webform.getPane().getPageBox(), markupDesignBean);
2529:
2530:                // XXX This seems to be rendundant (and JSF specific) here.
2531:                ////            Element componentRootElement = MarkupService.getRenderedElementForElement(element);
2532:                //            Element componentRootElement = webform.getDefaultParentComponent();
2533:                //            if (componentRootElement != null) {
2534:                //                CssBox box = findBoxForComponentRootElement(webform.getPane().getPageBox(), componentRootElement);
2535:                //
2536:                //                if (box != null) {
2537:                //                    LineBox lb = findFirstLineBox(box);
2538:                //
2539:                //                    if (lb != null) {
2540:                ////                        Position pos = findFirstLineboxPosition(lb, 0, webform.getManager().getInlineEditor());
2541:                //                        DomPosition pos = findFirstLineboxPosition(lb, 0, webform.getManager().getInlineEditor());
2542:                //
2543:                ////                        if (pos != Position.NONE) {
2544:                //                        if (pos != DomPosition.NONE) {
2545:                ////                            if (pos.isRendered()) {
2546:                ////                            if (MarkupService.isRenderedNode(pos.getNode())) {
2547:                //                            if (pos.isRenderedPosition()) {
2548:                //                                return pos.getSourcePosition();
2549:                //                            } else {
2550:                //                                return pos;
2551:                //                            }
2552:                //                        }
2553:                //                    }
2554:                //                }
2555:                //            }
2556:                //        }
2557:
2558:                if (webform.getPane().getPageBox() != null) {
2559:                    LineBox lb = findFirstLineBox(webform.getPane()
2560:                            .getPageBox());
2561:
2562:                    if (lb != null) {
2563:                        //                Position pos = findFirstLineboxPosition(lb, 0, webform.getManager().getInlineEditor());
2564:                        DomPosition pos = findFirstLineboxPosition(lb, 0,
2565:                                webform.getManager().getInlineEditor());
2566:
2567:                        //                if (pos != Position.NONE) {
2568:                        if (pos != DomPosition.NONE) {
2569:                            //                    if (pos.isRendered()) {
2570:                            //                    if (MarkupService.isRenderedNode(pos.getNode())) {
2571:                            if (pos.isRenderedPosition()) {
2572:                                return pos.getSourcePosition();
2573:                            } else {
2574:                                return pos;
2575:                            }
2576:                        }
2577:                    }
2578:                }
2579:
2580:                // Try to pick a place to set the caret
2581:                // First, if we have a webform, set the caret inside the <h:form> if
2582:                // one exists (and has a <br>)
2583:                // TODO; this is tricky. We've gotta make sure we only use
2584:                // normal flow children, not absolutely positioned children etc.
2585:                //        assert false : "need layout tree to set caret";
2586:                //        return Position.NONE;
2587:                return DomPosition.NONE;
2588:
2589:                /*
2590:                Element body = webform.getMarkup().getBody();
2591:                NodeList children = body.getChildNodes();
2592:                Position pos;
2593:                if (children.getLength() > 0 &&
2594:                    children.item(0).getNodeType() == Node.ELEMENT_NODE &&
2595:                    ((Element)children.item(0)).getTagName().equals("p")) { // NOI18N
2596:                    pos = new Position(children.item(0), 0, Bias.FORWARD);
2597:                } else if (children.getLength() > 1 &&
2598:                           children.item(0).getNodeType() == Node.TEXT_NODE &&
2599:                           Utilities.onlyWhitespace(children.item(0).getNodeValue()) &&
2600:                           children.item(1).getNodeType() == Node.ELEMENT_NODE &&
2601:                           ((Element)children.item(1)).getTagName().equals("p")) { // NOI18N
2602:                    pos = new Position(children.item(1), 0, Bias.FORWARD);
2603:                } else {
2604:                    pos = new Position(webform.getDocument().getBody(), 0, Bias.FORWARD);
2605:                }
2606:
2607:                 */
2608:            }
2609:
2610:            /**
2611:             * Return the last caret position in the document. If create is true,
2612:             * create one if necessary.
2613:             */
2614:            //    public static Position getLastDocumentPosition(WebForm webform, boolean create) {
2615:            public static DomPosition getLastDocumentPosition(WebForm webform,
2616:                    boolean create) {
2617:
2618:                // XXX #128116 Possible NPE after closing component.
2619:                if (webform.getPane().getPageBox() == null) {
2620:                    return DomPosition.NONE;
2621:                }
2622:
2623:                // XXX Very suspicious assertion.
2624:                //        assert webform.getPane().getPageBox().getElement().getOwnerDocument() == webform.getJspDom();
2625:                if (webform.getPane().getPageBox().getElement()
2626:                        .getOwnerDocument() != webform.getHtmlDom()) {
2627:                    ErrorManager.getDefault().notify(
2628:                            ErrorManager.INFORMATIONAL,
2629:                            new IllegalStateException(
2630:                                    "Owner document is expected to be html dom="
2631:                                            + webform.getHtmlDom() // NOI18N
2632:                                            + ", but it is dom="
2633:                                            + webform.getPane().getPageBox()
2634:                                                    .getElement()
2635:                                                    .getOwnerDocument())); // NOI18N
2636:                }
2637:
2638:                if (webform.getPane().getPageBox() != null) {
2639:                    LineBox lb = findLastLineBox(webform.getPane().getPageBox());
2640:
2641:                    if (lb != null) {
2642:                        //                Position pos = findLastLineboxPosition(lb, lb.getBoxCount() - 1, webform.getManager().getInlineEditor());
2643:                        DomPosition pos = findLastLineboxPosition(lb, lb
2644:                                .getBoxCount() - 1, webform.getManager()
2645:                                .getInlineEditor());
2646:
2647:                        //                if (pos != Position.NONE) {
2648:                        if (pos != DomPosition.NONE) {
2649:                            //                    if (pos.isRendered()) {
2650:                            //                    if (MarkupService.isRenderedNode(pos.getNode())) {
2651:                            if (pos.isRenderedPosition()) {
2652:                                return pos.getSourcePosition();
2653:                            } else {
2654:                                return pos;
2655:                            }
2656:                        }
2657:                    }
2658:                }
2659:
2660:                // Try to pick a place to set the caret
2661:                // First, if we have a webform, set the caret inside the <h:form> if
2662:                // one exists (and has a <br>)
2663:                // TODO; this is tricky. We've gotta make sure we only use
2664:                // normal flow children, not absolutely positioned children etc.
2665:                //        assert false : "need layout tree to set caret";
2666:                //        return Position.NONE;
2667:                return DomPosition.NONE;
2668:
2669:                /*
2670:                Element body = webform.getMarkup().getBody();
2671:                NodeList children = body.getChildNodes();
2672:                Position pos;
2673:                if (children.getLength() > 0 &&
2674:                    children.item(0).getNodeType() == Node.ELEMENT_NODE &&
2675:                    ((Element)children.item(0)).getTagName().equals("p")) { // NOI18N
2676:                    pos = new Position(children.item(0), 0, Bias.FORWARD);
2677:                } else if (children.getLength() > 1 &&
2678:                           children.item(0).getNodeType() == Node.TEXT_NODE &&
2679:                           Utilities.onlyWhitespace(children.item(0).getNodeValue()) &&
2680:                           children.item(1).getNodeType() == Node.ELEMENT_NODE &&
2681:                           ((Element)children.item(1)).getTagName().equals("p")) { // NOI18N
2682:                    pos = new Position(children.item(1), 0, Bias.FORWARD);
2683:                } else {
2684:                    pos = new Position(webform.getDocument().getBody(), 0, Bias.FORWARD);
2685:                }
2686:
2687:                 */
2688:            }
2689:
2690:            //    public static boolean isValidPosition(Position pos, boolean adjust, InlineEditor inline) {
2691:            public static boolean isValidPosition(WebForm webForm,
2692:                    DomPosition pos, boolean adjust, InlineEditor inline) {
2693:                //        return findValidPosition(pos, adjust, inline) != Position.NONE;
2694:                return findValidPosition(webForm, pos, adjust, inline) != DomPosition.NONE;
2695:            }
2696:
2697:            // XXX Moved from DesignerUtils.
2698:            /**
2699:             * Given a position in the DOM, find the closest valid position.
2700:             * In particular, the position is not allowed to be inside any
2701:             * "renders children" nodes.  It also doesn't allow positions
2702:             * that are "adjacent" (before, after) an absolutely positioned
2703:             * element.
2704:             *
2705:             * @param pos Position to be checked
2706:             * @param adjust If true, adjust the position to the nearest (above)
2707:             *   position that is valid.
2708:             * @param inline inlineEditor which is in the game in the designer or null.
2709:             * @todo This method is mostly used to determine if a position is a valid
2710:             *   caret position now. Perhaps rename it to that (isValidCaretPosition).
2711:             * @param dom The JSPX document DOM
2712:             */
2713:            //    public static Position checkValidPosition(Position pos, boolean adjust, /*WebForm webform*/InlineEditor inline) {
2714:            //    public static Position findValidPosition(Position pos, boolean adjust, /*WebForm webform*/InlineEditor inline) {
2715:            public static DomPosition findValidPosition(WebForm webForm,
2716:                    DomPosition pos, boolean adjust, /*WebForm webform*/
2717:                    InlineEditor inline) {
2718:                //        if(DEBUG) {
2719:                //            debugLog(DesignerUtils.class.getName() + ".checkPosition(Position, boolean, WebForm)");
2720:                //        }
2721:                //        if(pos == null || webform == null) {
2722:                if (pos == null) {
2723:                    return null;
2724:                }
2725:                //        if (pos == Position.NONE) {
2726:                if (pos == DomPosition.NONE) {
2727:                    return pos;
2728:                }
2729:
2730:                Node node = pos.getNode();
2731:
2732:                if (!adjust) {
2733:                    //            InlineEditor inline = webform.getManager().getInlineEditor();
2734:
2735:                    if (inline != null) {
2736:                        if (inline.checkPosition(pos)) {
2737:                            return pos;
2738:                        } else {
2739:                            //                    return Position.NONE;
2740:                            return DomPosition.NONE;
2741:                        }
2742:                    }
2743:                }
2744:
2745:                // Don't accept positions adjacent to an absolutely or relatively positioned container
2746:                if (!adjust) {
2747:                    //            RaveElement target = pos.getTargetElement();
2748:                    //            if ((target != null) && target.isRendered()) {
2749:                    Element target = pos.getTargetElement();
2750:                    //            if (MarkupService.isRenderedNode(target)) {
2751:                    if (webForm.isRenderedNode(target)) {
2752:                        //                Value val = CssLookup.getValue(target, XhtmlCss.POSITION_INDEX);
2753:                        CssValue cssValue = CssProvider.getEngineService()
2754:                                .getComputedValueForElement(target,
2755:                                        XhtmlCss.POSITION_INDEX);
2756:
2757:                        //                if ((val == CssValueConstants.ABSOLUTE_VALUE) ||
2758:                        //                        (val == CssValueConstants.RELATIVE_VALUE) ||
2759:                        //                        (val == CssValueConstants.FIXED_VALUE)) {
2760:                        if (CssProvider.getValueService().isAbsoluteValue(
2761:                                cssValue)
2762:                                || CssProvider.getValueService()
2763:                                        .isRelativeValue(cssValue)
2764:                                || CssProvider.getValueService().isFixedValue(
2765:                                        cssValue)) {
2766:                            //                    return Position.NONE;
2767:                            return DomPosition.NONE;
2768:                        }
2769:                    }
2770:                }
2771:
2772:                while (node != null) {
2773:                    //            if (node instanceof RaveRenderNode) {
2774:                    //                RaveRenderNode rn = (RaveRenderNode)node;
2775:                    //                if (rn.isRendered() && (rn.getSourceNode() == null)) {
2776:                    //            if (MarkupService.isRenderedNode(node) && MarkupService.getSourceNodeForNode(node) == null) {
2777:                    if (webForm.isRenderedNode(node)
2778:                            && MarkupService.getSourceNodeForNode(node) == null) {
2779:                        if (adjust) {
2780:                            Node curr = node;
2781:
2782:                            while (curr != null) {
2783:                                if (curr.getNodeType() == Node.ELEMENT_NODE) {
2784:                                    //                                RaveElement e = (RaveElement)curr;
2785:                                    Element e = (Element) curr;
2786:
2787:                                    //                                if (e.getSource() != null) {
2788:                                    if (MarkupService
2789:                                            .getSourceElementForElement(e) != null) {
2790:                                        //                                    MarkupDesignBean bean = e.getDesignBean();
2791:                                        //                                    MarkupDesignBean bean = InSyncService.getProvider().getMarkupDesignBeanForElement(e);
2792:                                        //                                    MarkupDesignBean bean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(e);
2793:                                        //                                    
2794:                                        //                                    if (bean != null) {
2795:                                        //                                        bean = /*FacesSupport.*/findRendersChildren(bean);
2796:                                        ////                                        e = (RaveElement)bean.getElement();
2797:                                        //                                        e = bean.getElement();
2798:                                        //                                    }
2799:                                        Element se = webForm
2800:                                                .getDomProviderService()
2801:                                                .getSourceElementWhichRendersChildren(
2802:                                                        e);
2803:                                        if (se != null) {
2804:                                            e = se;
2805:                                        }
2806:
2807:                                        //                                    return Position.create(e, pos.getOffset() > 0);
2808:                                        return webForm.createDomPosition(e, pos
2809:                                                .getOffset() > 0);
2810:                                    }
2811:                                }
2812:
2813:                                curr = curr.getParentNode();
2814:
2815:                                if (curr == null) {
2816:                                    //                                return Position.NONE;
2817:                                    return DomPosition.NONE;
2818:                                }
2819:                            }
2820:                        } else {
2821:                            //                        return Position.NONE;
2822:                            return DomPosition.NONE;
2823:                        }
2824:                        //                }
2825:                    }
2826:
2827:                    //            if (node instanceof RaveElement) {
2828:                    //                RaveElement element = (RaveElement)node;
2829:                    if (node instanceof  Element) {
2830:                        Element element = (Element) node;
2831:
2832:                        //                if (element.getDesignBean() != null) {
2833:                        //                    MarkupDesignBean bean = element.getDesignBean();
2834:                        //                MarkupDesignBean bean = InSyncService.getProvider().getMarkupDesignBeanForElement(element);
2835:                        //                MarkupDesignBean bean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(element);
2836:                        //                
2837:                        //                if (bean != null) {
2838:                        //                    MarkupDesignBean parent = /*FacesSupport.*/findRendersChildren(bean);
2839:                        //                    
2840:                        //                    // XXX what if bean itself is a renders children?
2841:                        //                    if (parent != bean) {
2842:                        Element se = webForm.getDomProviderService()
2843:                                .getSourceElementWhichRendersChildren(element);
2844:                        if (se != null) {
2845:                            //                    if (se != element) {
2846:                            // XXX #112580 Needs to compare rendered with rendered or source with source element.
2847:                            if (se != MarkupService
2848:                                    .getSourceElementForElement(element)) {
2849:                                if (adjust) {
2850:                                    // There was a renders-children parent we
2851:                                    // should skip
2852:                                    //                            Element parentElement = parent.getElement();
2853:                                    Element parentElement = se;
2854:
2855:                                    //                            return Position.create(parentElement, pos.getOffset() > 0);
2856:                                    return webForm.createDomPosition(
2857:                                            parentElement, pos.getOffset() > 0);
2858:                                } else {
2859:                                    //                            return Position.NONE;
2860:                                    return DomPosition.NONE;
2861:                                }
2862:                            }
2863:
2864:                            break;
2865:                        }
2866:                    }
2867:
2868:                    node = node.getParentNode();
2869:                }
2870:
2871:                //        InlineEditor inline = webform.getManager().getInlineEditor();
2872:
2873:                //        if (((pos != Position.NONE) && ((inline != null) && inline.checkPosition(pos))) ||
2874:                if (((pos != DomPosition.NONE) && ((inline != null) && inline
2875:                        .checkPosition(pos)))
2876:                        ||
2877:                        //                !pos.isRendered()) {
2878:                        //        !MarkupService.isRenderedNode(pos.getNode())) {
2879:                        pos.isSourcePosition()) {
2880:                    return pos;
2881:                } else if (adjust) {
2882:                    // Try to find the corresponding source
2883:                    node = pos.getNode();
2884:
2885:                    while (node != null) {
2886:                        //                if (node instanceof RaveElement) {
2887:                        //                    RaveElement element = (RaveElement)node;
2888:                        if (node instanceof  Element) {
2889:                            Element element = (Element) node;
2890:
2891:                            //                    if (element.getDesignBean() != null) {
2892:                            //                        DesignBean bean = element.getDesignBean();
2893:                            //                    DesignBean bean = InSyncService.getProvider().getMarkupDesignBeanForElement(element);
2894:                            //                    DesignBean bean = WebForm.getDomProviderService().getMarkupDesignBeanForElement(element);
2895:                            //                    if (bean != null) {
2896:                            Element componentRootElement = webForm
2897:                                    .getDomProviderService()
2898:                                    .getComponentRootElementForElement(element);
2899:                            if (componentRootElement != null) {
2900:                                //                        Element el = FacesSupport.getElement(bean);
2901:                                //                        Element el = Util.getElement(bean);
2902:                                //                        Element el = WebForm.getDomProviderService().getElement(bean);
2903:                                Element sourceElement = MarkupService
2904:                                        .getSourceElementForElement(componentRootElement);
2905:                                //                        return Position.create(sourceElement, pos.getOffset() > 0);
2906:                                return webForm.createDomPosition(sourceElement,
2907:                                        pos.getOffset() > 0);
2908:                            }
2909:                        }
2910:
2911:                        node = node.getParentNode();
2912:                    }
2913:
2914:                    //            return Position.NONE;
2915:                    return DomPosition.NONE;
2916:                } else {
2917:                    //            // XXX shouldn't this be return pos; ? Try to click somewhere in BoxModelTest
2918:                    //            // layout-floats3.html
2919:                    //            return Position.NONE;
2920:                    //        }
2921:                    return pos;
2922:                }
2923:            }
2924:
2925:            //    // XXX Moved from FacesSupport.
2926:            //    /** Find outermost renders-children bean above the given bean, or
2927:            //     * the bean itself if there is no such parent.
2928:            //     */
2929:            //    private /*public*/ static MarkupDesignBean findRendersChildren(MarkupDesignBean bean) {
2930:            //        // Similar to FacesSupport.findHtmlContainer(bean), but
2931:            //        // we need to return the outermost html container itself, not
2932:            //        // the parent, since we're not looking for its container but
2933:            //        // the bean to be moved itself.
2934:            //        MarkupDesignBean curr = bean;
2935:            //
2936:            ////        for (; curr != null; curr = FacesSupport.getBeanParent(curr)) {
2937:            //        for (; curr != null; curr = getBeanParent(curr)) {
2938:            //            if (curr.getInstance() instanceof F_Verbatim) {
2939:            //                // If you have a verbatim, we're okay to add html comps below it
2940:            //                return bean;
2941:            //            }
2942:            //
2943:            //            if (curr.getInstance() instanceof UIComponent) {
2944:            //                // Need to set the Thread's context classloader to be the Project's ClassLoader.
2945:            //            	ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
2946:            //            	try {
2947:            ////                    Thread.currentThread().setContextClassLoader(InSyncService.getProvider().getContextClassLoader(curr));
2948:            //                    Thread.currentThread().setContextClassLoader(WebForm.getDomProviderService().getContextClassLoaderForDesignContext(curr.getDesignContext()));
2949:            //                    if (((UIComponent)curr.getInstance()).getRendersChildren()) {
2950:            //                    	bean = curr;
2951:            //                        // Can't break here - there could be an outer
2952:            //                        // renders-children parent
2953:            //                    }               
2954:            //            	} finally {
2955:            //                    Thread.currentThread().setContextClassLoader(oldContextClassLoader);
2956:            //            	}                
2957:            //            }
2958:            //        }
2959:            //
2960:            //        return bean;
2961:            //    }
2962:            //    
2963:            //    // XXX Moved from FacesSupport.
2964:            //    /**
2965:            //     * Return the parent of the given markup design bean, if the parent is
2966:            //     * a MarkupDesignBean.
2967:            //     */
2968:            //    private static MarkupDesignBean getBeanParent(MarkupDesignBean bean) {
2969:            //        DesignBean parent = bean.getBeanParent();
2970:            //
2971:            //        if (parent instanceof MarkupDesignBean) {
2972:            //            return (MarkupDesignBean)parent;
2973:            //        }
2974:            //
2975:            //        return null;
2976:            //    }
2977:
2978:            /** Try to find the box corresponding to the given element. */
2979:            public static CssBox findBox(PageBox pageBox, Element element) {
2980:                //        CssBox box = CssBox.getBox(element);
2981:                CssBox box = pageBox.getWebForm().findCssBoxForElement(element);
2982:
2983:                if (box != null) {
2984:                    return box;
2985:                }
2986:
2987:                //        Position pos = Position.create(element, false);
2988:                DomPosition pos = pageBox.getWebForm().createDomPosition(
2989:                        element, false);
2990:
2991:                //        if (!pos.isRendered()) {
2992:                //        if (!MarkupService.isRenderedNode(pos.getNode())) {
2993:                if (pos.isSourcePosition()) {
2994:                    pos = pos.getRenderedPosition();
2995:                }
2996:
2997:                //        if (pos == Position.NONE) {
2998:                if (pos == DomPosition.NONE) {
2999:                    return null;
3000:                }
3001:
3002:                //        box = findBox(webform.getPane().getPageBox(), pos);
3003:                box = findBox(pageBox, pos);
3004:
3005:                if (box != null) {
3006:                    return box;
3007:                }
3008:
3009:                return null;
3010:            }
3011:
3012:            //    /** Locate a component in the visible view given the x,y coordinates
3013:            //     * XXX Get rid of it, replace with #findElement. */
3014:            //    public static MarkupDesignBean findMarkupDesignBean(CssBox box) {
3015:            //        for (; box != null; box = box.getParent()) {
3016:            //            MarkupDesignBean boxMarkupDesignBean = CssBox.getMarkupDesignBeanForCssBox(box);
3017:            ////            if (box.getDesignBean() != null) {
3018:            ////                DesignBean lb = box.getDesignBean();
3019:            //            if (boxMarkupDesignBean != null) {
3020:            //                DesignBean lb = boxMarkupDesignBean;
3021:            //
3022:            ////                if (FacesSupport.isSpecialBean(/*webform, */lb)) {
3023:            ////                if (Util.isSpecialBean(lb)) {
3024:            //                if (lb instanceof MarkupDesignBean && WebForm.getDomProviderService().isSpecialComponent(
3025:            //                        WebForm.getDomProviderService().getComponentRootElementForMarkupDesignBean((MarkupDesignBean)lb))) {
3026:            //                    continue;
3027:            //                }
3028:            //
3029:            //                return boxMarkupDesignBean;
3030:            //            }
3031:            //        }
3032:            //
3033:            //        return null;
3034:            //    }
3035:
3036:            /** Locates element in the visible view given the box.
3037:             * @return <code>Element</code> or <code>null</code> if there is not such */
3038:            public static Element findElement(CssBox box) {
3039:                WebForm webForm = box == null ? null : box.getWebForm();
3040:                if (webForm == null) {
3041:                    return null;
3042:                }
3043:                for (; box != null; box = box.getParent()) {
3044:                    // #107084 Find the element, don't check for the root.
3045:                    //            Element componentRootElement = CssBox.getElementForComponentRootCssBox(box);
3046:                    Element element = box.getElement();
3047:                    if (element != null) {
3048:                        if (webForm.getDomProviderService().isSpecialComponent(
3049:                                element)) {
3050:                            continue;
3051:                        }
3052:
3053:                        return element;
3054:                    }
3055:                }
3056:
3057:                return null;
3058:            }
3059:
3060:            // XXX #106870 This is different from findElement.
3061:            /** Locates component root element in the visible view given the box.
3062:             * @return <code>Element</code> or <code>null</code> if there is not such */
3063:            public static Element findComponentRootElement(CssBox box) {
3064:                WebForm webForm = box == null ? null : box.getWebForm();
3065:                if (webForm == null) {
3066:                    return null;
3067:                }
3068:                for (; box != null; box = box.getParent()) {
3069:                    // #107084 Find the element, don't check for the root.
3070:                    //            Element componentRootElement = CssBox.getElementForComponentRootCssBox(box);
3071:                    //            Element element = box.getComponentRootElement();
3072:                    //            if (element != null) {
3073:                    // XXX #113773 Fixing selecting of some element whose parent box 
3074:                    // is excluded from the hierarchy (suspicous architecture).
3075:                    Element element = box.getElement();
3076:                    // XXX #118287 Also pass the parent box to determine the principal element
3077:                    // (the real one might be excluded from the tree)
3078:                    CssBox parentBox = box.getParent();
3079:                    Element parentElement = parentBox == null ? null
3080:                            : parentBox.getElement();
3081:                    if (webForm.getDomProviderService().isPrincipalElement(
3082:                            element, parentElement)) {
3083:                        if (webForm.getDomProviderService().isSpecialComponent(
3084:                                element)) {
3085:                            continue;
3086:                        }
3087:
3088:                        return element;
3089:                    }
3090:                }
3091:
3092:                return null;
3093:            }
3094:
3095:            public static CssBox findBox(PageBox pageBox, int x, int y) {
3096:                //        PageBox pageBox = webform.getPane().getPageBox();
3097:
3098:                // Locate closest box
3099:                return pageBox.findCssBox(x, y);
3100:            }
3101:
3102:            //    /** XXX Get rid of it, replace with #findElement. */
3103:            //    public static MarkupDesignBean findMarkupDesignBean(PageBox pageBox, int x, int y) {
3104:            ////        CssBox box = findBox(x, y);
3105:            //        CssBox box = findBox(pageBox, x, y);
3106:            //
3107:            //        return findMarkupDesignBean(box);
3108:            //    }
3109:
3110:            public static Element findElement(PageBox pageBox, int x, int y) {
3111:                //        CssBox box = findBox(x, y);
3112:                CssBox box = findBox(pageBox, x, y);
3113:
3114:                return findElement(box);
3115:            }
3116:
3117:            //    public static Rectangle findShape(PageBox pageBox, DesignBean lbean) {
3118:            public static Rectangle findShape(PageBox pageBox,
3119:                    Element componentRootElement) {
3120:                //        CssBox box = findBox(pageBox, lbean);
3121:                //        if (!(lbean instanceof MarkupDesignBean)) {
3122:                //            return null;
3123:                //        }
3124:                if (componentRootElement == null) {
3125:                    return null;
3126:                }
3127:                CssBox box = findBoxForComponentRootElement(pageBox,
3128:                        componentRootElement);
3129:
3130:                if (box == null) {
3131:                    ErrorManager.getDefault().notify(
3132:                            ErrorManager.INFORMATIONAL,
3133:                            //                new NullPointerException("Null box for bean=" + lbean)); // NOI18N
3134:                            new NullPointerException("Null box for element="
3135:                                    + componentRootElement)); // NOI18N
3136:
3137:                    return null;
3138:                }
3139:
3140:                return new Rectangle(box.getAbsoluteX(), box.getAbsoluteY(),
3141:                        box.getWidth(), box.getHeight());
3142:            }
3143:
3144:            //    // XXX Get rid of this. Replace with #findCssBoxForComponentRootElement.
3145:            //    public static CssBox findBox(PageBox pageBox, DesignBean lbean) {
3146:            ////        PageBox pageBox = webform.getPane().getPageBox();
3147:            ////        return pageBox.find(lbean);
3148:            //        return pageBox.findCssBox(lbean);
3149:            //    }
3150:
3151:            public static CssBox findBoxForComponentRootElement(
3152:                    PageBox pageBox, Element componentRootElement) {
3153:                //        PageBox pageBox = webform.getPane().getPageBox();
3154:                //        return pageBox.find(lbean);
3155:                return pageBox
3156:                        .findCssBoxForComponentRootElement(componentRootElement);
3157:            }
3158:
3159:            public static List<Rectangle> getComponentRectangles(
3160:                    PageBox pageBox, /*DesignBean lb*/
3161:                    Element componentRootElement) {
3162:                List<Rectangle> result = new ArrayList<Rectangle>();
3163:                //        PageBox pageBox = webform.getPane().getPageBox();
3164:                //        pageBox.computeRectangles(lb, result);
3165:                pageBox.computeRectangles(componentRootElement, result);
3166:
3167:                if (result.size() == 0) {
3168:                    // Didn't find any bounds for the component. That can happen
3169:                    // with some components, like TableRowGroups, which
3170:                    // correspond to elements that don't have direct
3171:                    // representatives as boxes, such as <tr> in tables
3172:                    // If so, just try to compute its bounds and return
3173:                    // it here
3174:                    //            Rectangle r = getComponentBounds(lb);
3175:                    //            Rectangle r = getComponentBounds(pageBox, lb);
3176:                    Rectangle r = getComponentBounds(pageBox,
3177:                            componentRootElement);
3178:
3179:                    if (r != null) {
3180:                        result.add(r);
3181:                    }
3182:                }
3183:
3184:                return result;
3185:            }
3186:
3187:            public static Rectangle getComponentBounds(PageBox pageBox, /*DesignBean lb*/
3188:                    Element componentRootElement) {
3189:                //        PageBox pageBox = webform.getPane().getPageBox();
3190:                //        if (!(lb instanceof MarkupDesignBean)) {
3191:                //            return null;
3192:                //        }
3193:                //        Element componentRootElement = SelectionManager.getComponentRootElementForMarkupDesignBean((MarkupDesignBean)lb);
3194:                if (componentRootElement == null) {
3195:                    return null;
3196:                }
3197:
3198:                //        Rectangle bounds = pageBox.computeBounds(lb, null);
3199:                Rectangle bounds = pageBox.computeBounds(componentRootElement,
3200:                        null);
3201:
3202:                // Some components render to a top level element which isn't represented
3203:                // directly in the box hierarchy, such as <tr> for example; TableBoxes
3204:                // don't have row boxes, they manage cells directly.
3205:                // In this case, look for the bounds of all the children of the component
3206:                // and assume that the parent is basically made up of the union of its children
3207:                if (bounds == null) {
3208:                    //            for (int i = 0, n = lb.getChildBeanCount(); i < n; i++) {
3209:                    //                DesignBean child = lb.getChildBean(i);
3210:                    //                bounds = pageBox.computeBounds(child, bounds);
3211:                    //            }
3212:                    WebForm webForm = pageBox.getWebForm();
3213:                    Element[] childComponentRootElements = webForm
3214:                            .getDomProviderService()
3215:                            .getChildComponentRootElements(componentRootElement);
3216:                    for (Element child : childComponentRootElements) {
3217:                        bounds = pageBox.computeBounds(child, bounds);
3218:                    }
3219:                }
3220:
3221:                return bounds;
3222:            }
3223:
3224:            //    public Rectangle getRegionBounds(MarkupMouseRegion region) {
3225:            //        return webform.getPane().getPageBox().computeRegionBounds(region, null);
3226:            //    }
3227:
3228:            /** Finds closes parent (including itself) component root element.  */
3229:            public static Element findClosestComponentRootElement(
3230:                    WebForm webForm, Node node) {
3231:                while (node != null) {
3232:                    if (node instanceof  Element
3233:                            && webForm.getDomProviderService()
3234:                                    .isPrincipalElement((Element) node, null)) {
3235:                        return (Element) node;
3236:                    }
3237:
3238:                    node = node.getParentNode();
3239:                }
3240:
3241:                return null;
3242:            }
3243:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.