Source Code Cross Referenced for HTMLCompletionQuery.java in  » IDE-Netbeans » html » org » netbeans » editor » ext » html » 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 » html » org.netbeans.editor.ext.html 
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-2006 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.editor.ext.html;
0043:
0044:        import java.util.logging.Level;
0045:        import java.util.logging.Logger;
0046:        import org.netbeans.editor.ext.html.SyntaxElement;
0047:        import java.awt.Component;
0048:        import java.awt.Font;
0049:        import java.awt.Graphics;
0050:        import java.io.IOException;
0051:        import java.net.URL;
0052:        import java.util.*;
0053:        import java.awt.Color;
0054:        import java.awt.event.KeyEvent;
0055:        import javax.swing.Action;
0056:        import javax.swing.text.JTextComponent;
0057:        import javax.swing.text.BadLocationException;
0058:        import javax.swing.text.Caret;
0059:        import javax.swing.text.Document;
0060:        import org.netbeans.editor.*;
0061:        import org.netbeans.editor.SettingsUtil;
0062:        import org.netbeans.editor.Utilities;
0063:        import org.netbeans.editor.ext.*;
0064:        import org.netbeans.editor.ext.html.dtd.*;
0065:        import org.netbeans.editor.ext.html.javadoc.HelpManager;
0066:        import org.netbeans.api.editor.completion.Completion;
0067:        import org.netbeans.api.html.lexer.HTMLTokenId;
0068:        import org.netbeans.api.lexer.Token;
0069:        import org.netbeans.api.lexer.TokenHierarchy;
0070:        import org.netbeans.api.lexer.TokenId;
0071:        import org.netbeans.api.lexer.TokenSequence;
0072:        import org.netbeans.modules.editor.indent.api.Reformat;
0073:        import org.netbeans.spi.editor.completion.CompletionDocumentation;
0074:        import org.netbeans.spi.editor.completion.CompletionItem;
0075:        import org.netbeans.spi.editor.completion.CompletionResultSet;
0076:        import org.netbeans.spi.editor.completion.CompletionTask;
0077:        import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery;
0078:        import org.netbeans.spi.editor.completion.support.AsyncCompletionTask;
0079:        import org.openide.ErrorManager;
0080:
0081:        /**
0082:         * HTML completion results finder
0083:         *
0084:         * @author Petr Nejedly
0085:         * @author Marek Fukala
0086:         * @version 1.10
0087:         */
0088:        public class HTMLCompletionQuery {
0089:
0090:            private static final String SCRIPT_TAG_NAME = "SCRIPT"; //NOI18N
0091:            private static final String STYLE_TAG_NAME = "STYLE"; //NOI18N
0092:
0093:            private static boolean lowerCase;
0094:
0095:            private static final HTMLCompletionQuery DEFAULT = new HTMLCompletionQuery();
0096:
0097:            public static HTMLCompletionQuery getDefault() {
0098:                return DEFAULT;
0099:            }
0100:
0101:            /** Perform the query on the given component. The query usually
0102:             * gets the component's document, the caret position and searches back
0103:             * to examine surrounding context. Then it returns the result.
0104:             * @param component the component to use in this query.
0105:             * @param offset position in the component's document to which the query will
0106:             *   be performed. Usually it's a caret position.
0107:             * @param support syntax-support that will be used during resolving of the query.
0108:             * @return result of the query or null if there's no result.
0109:             */
0110:            public List<CompletionItem> query(JTextComponent component,
0111:                    int offset) {
0112:                Class kitClass = Utilities.getKitClass(component);
0113:                BaseDocument doc = (BaseDocument) component.getDocument();
0114:
0115:                if (kitClass != null) {
0116:                    lowerCase = SettingsUtil.getBoolean(kitClass,
0117:                            HTMLSettingsNames.COMPLETION_LOWER_CASE,
0118:                            HTMLSettingsDefaults.defaultCompletionLowerCase);
0119:                }
0120:
0121:                if (doc.getLength() == 0)
0122:                    return null; // nothing to examine
0123:                HTMLSyntaxSupport sup = HTMLSyntaxSupport.get(doc);
0124:
0125:                if (sup == null)
0126:                    return null;// No SyntaxSupport for us, no hint for user
0127:
0128:                DTD dtd = sup.getDTD();
0129:                if (dtd == null)
0130:                    return null; // We have no knowledge about the structure!
0131:
0132:                doc.readLock();
0133:                try {
0134:                    TokenHierarchy hi = TokenHierarchy.get(doc);
0135:                    TokenSequence ts = hi.tokenSequence(HTMLTokenId.language());
0136:                    if (ts == null) {
0137:                        //HTML language is not top level one
0138:                        ts = hi.tokenSequence();
0139:                        ts.move(offset);
0140:                        if (ts.moveNext() || ts.movePrevious()) {
0141:                            ts = ts.embedded(HTMLTokenId.language());
0142:                        } else { // no tokens
0143:                            return null;
0144:                        }
0145:                    }
0146:
0147:                    if (ts == null) {
0148:                        //no HTML token on the offset
0149:                        return null;
0150:                    }
0151:
0152:                    ts.move(offset);
0153:                    if (!ts.moveNext() && !ts.movePrevious()) {
0154:                        return null; //no token found
0155:                    }
0156:
0157:                    Token item = ts.token();
0158:
0159:                    // are we inside token or between tokens
0160:                    boolean inside = ts.offset() < offset;
0161:
0162:                    if (!inside) { //use the previous token
0163:                        if (ts.movePrevious()) {
0164:                            item = ts.token();
0165:                        } else {
0166:                            return null; //no previous token - shouldn't happen
0167:                        }
0168:                    }
0169:
0170:                    Token tok = item;
0171:                    //scan the token chain before the
0172:                    while (!(tok.id() == HTMLTokenId.TAG_OPEN || tok.id() == HTMLTokenId.TAG_CLOSE)
0173:                            && ts.movePrevious()) {
0174:                        tok = ts.token();
0175:                    }
0176:
0177:                    //we found an open or close tag or encountered beginning of the file
0178:                    if (ts.index() > 0) {
0179:                        //found the tag
0180:                        String tagName = tok.text().toString();
0181:                        for (int i = 0; i < tagName.length(); i++) {
0182:                            char ch = tagName.charAt(i);
0183:                            if (Character.isLetter(ch)) {
0184:                                lowerCase = !Character.isUpperCase(tagName
0185:                                        .charAt(i));
0186:                                break;
0187:                            }
0188:                        }
0189:                    } //else use the setting value
0190:
0191:                    //rewind token sequence back
0192:                    ts.move(item.offset(hi));
0193:
0194:                    //get text before cursor
0195:                    int itemOffset = item.offset(hi);
0196:                    int diff = offset - itemOffset;
0197:                    String preText = item.text().toString();
0198:
0199:                    if (diff < preText.length()) {
0200:                        preText = preText.substring(0, offset - itemOffset);
0201:                    }
0202:                    TokenId id = item.id();
0203:
0204:                    List<CompletionItem> result = null;
0205:                    int len = 1;
0206:
0207:                    /* Character reference finder */
0208:                    if ((id == HTMLTokenId.TEXT || id == HTMLTokenId.VALUE)
0209:                            && preText.endsWith("&")) { // NOI18N
0210:                        result = translateCharRefs(offset - len, len, dtd
0211:                                .getCharRefList(""));
0212:                    } else if (id == HTMLTokenId.CHARACTER) {
0213:                        if (inside || !preText.endsWith(";")) { // NOI18N
0214:                            len = offset - itemOffset;
0215:                            result = translateCharRefs(offset - len, len, dtd
0216:                                    .getCharRefList(preText.substring(1)));
0217:                        }
0218:                        /* Tag finder */
0219:                    } else if (id == HTMLTokenId.TAG_OPEN) { // NOI18N
0220:                        len = offset - itemOffset + 1; // minus the < char length
0221:                        result = translateTags(itemOffset - 1, len, dtd
0222:                                .getElementList(preText));
0223:
0224:                        //test whether there is only one item in the CC list
0225:                        if (result.size() == 1) {
0226:                            //test whether the CC is trying to complete an already COMPLETE token - the problematic situation
0227:                            TagItem ti = (TagItem) result.get(0); //there should only one item
0228:                            String itemText = ti.getItemText();
0229:                            //itemText = itemText.substring(1, itemText.length() - 1); //remove the < > from the tag name
0230:
0231:                            if (preText.equals(itemText)) {
0232:                                //now I have to look ahead to get know whether
0233:                                //there are some attributes or an end of the tag
0234:
0235:                                ts.move(offset);
0236:                                ts.moveNext();
0237:                                Token t = ts.token();
0238:
0239:                                //test if next token is a whitespace and the next a tag token or an attribute token
0240:                                if (t.id() == HTMLTokenId.WS) {
0241:                                    if (ts.moveNext()) {
0242:                                        t = ts.token();
0243:                                        if ((t.id() == HTMLTokenId.TAG_CLOSE || t
0244:                                                .id() == HTMLTokenId.ARGUMENT)) {
0245:                                            //do not put the item into CC - otherwise it will break the completed tag
0246:                                            result = null;
0247:                                        }
0248:                                    }
0249:                                }
0250:                            }
0251:                        }
0252:
0253:                    } else if (id != HTMLTokenId.BLOCK_COMMENT
0254:                            && preText.endsWith("<")) { // NOI18N
0255:                        // There will be lookup for possible StartTags, in SyntaxSupport
0256:                        //                l = translateTags( offset-len, len, sup.getPossibleStartTags ( offset-len, "" ) );
0257:                        result = translateTags(offset - len, len, dtd
0258:                                .getElementList(""));
0259:
0260:                        /* EndTag finder */
0261:                    } else if (id == HTMLTokenId.TEXT && preText.endsWith("</")) { // NOI18N
0262:                        len = 2;
0263:                        result = sup.getPossibleEndTags(offset, "");
0264:                    } else if (id == HTMLTokenId.TAG_OPEN_SYMBOL
0265:                            && preText.endsWith("</")) { // NOI18N
0266:                        len = 2;
0267:                        result = sup.getPossibleEndTags(offset, "");
0268:                    } else if (id == HTMLTokenId.TAG_CLOSE) { // NOI18N
0269:                        len = offset - itemOffset;
0270:                        result = sup.getPossibleEndTags(offset, preText);
0271:
0272:                        /*Argument finder */
0273:                        /* TBD: It is possible to have arg just next to quoted value of previous
0274:                         * arg, these rules doesn't match start of such arg this case because
0275:                         * of need for matching starting quote
0276:                         */
0277:                    } else if (id == HTMLTokenId.TAG_CLOSE_SYMBOL) {
0278:                        result = sup.getAutocompletedEndTag(offset);
0279:
0280:                    } else if (id == HTMLTokenId.WS
0281:                            || id == HTMLTokenId.ARGUMENT) {
0282:                        SyntaxElement elem = null;
0283:                        try {
0284:                            elem = sup.getElementChain(offset);
0285:                            // #BUGFIX 25261 At the end of document the element is
0286:                            // automatically null but that does not mean that the
0287:                            // completion should return null. Only if element is null
0288:                            // also for offset-1...
0289:                            // + bugfix of #52909 - the > is recognized as SyntaxElement.TAG so we need to
0290:                            // get a syntax element before, when cc is called before > in a tag e.g. <table w|>
0291:                            if (elem == null
0292:                                    || (elem.getType() == SyntaxElement.TYPE_TAG && ">"
0293:                                            .equals(elem.getText()))) { // NOI18N
0294:                                elem = sup.getElementChain(offset - 1);
0295:                            }
0296:
0297:                        } catch (BadLocationException e) {
0298:                            return null;
0299:                        }
0300:
0301:                        if (elem == null)
0302:                            return null;
0303:
0304:                        if (elem.getType() == SyntaxElement.TYPE_TAG) { // not endTags
0305:                            SyntaxElement.Tag tagElem = (SyntaxElement.Tag) elem;
0306:
0307:                            String tagName = tagElem.getName().toUpperCase();
0308:                            DTD.Element tag = dtd.getElement(tagName);
0309:
0310:                            if (tag == null)
0311:                                return null; // unknown tag
0312:
0313:                            String prefix = (id == HTMLTokenId.ARGUMENT) ? preText
0314:                                    : "";
0315:                            len = prefix.length();
0316:                            List possible = tag.getAttributeList(prefix); // All attribs of given tag
0317:                            Collection<SyntaxElement.TagAttribute> existing = tagElem
0318:                                    .getAttributes(); // Attribs already used
0319:                            Collection<String> existingAttrsNames = new ArrayList<String>(
0320:                                    existing.size());
0321:                            for (SyntaxElement.TagAttribute ta : existing) {
0322:                                existingAttrsNames.add(ta.getName());
0323:                            }
0324:
0325:                            String wordAtCursor = (item == null) ? null : item
0326:                                    .text().toString();
0327:                            // #BUGFIX 25261 because of being at the end of document the
0328:                            // wordAtCursor must be checked for null to prevent NPE
0329:                            // below
0330:                            if (wordAtCursor == null) {
0331:                                wordAtCursor = "";
0332:                            }
0333:
0334:                            List<DTD.Attribute> attribs = new ArrayList<DTD.Attribute>();
0335:                            for (Iterator i = possible.iterator(); i.hasNext();) {
0336:                                DTD.Attribute attr = (DTD.Attribute) i.next();
0337:                                String aName = attr.getName();
0338:                                if (aName.equals(prefix)
0339:                                        || (!existingAttrsNames.contains(aName
0340:                                                .toUpperCase()) && !existingAttrsNames
0341:                                                .contains(aName.toLowerCase()))
0342:                                        || (wordAtCursor.equals(aName) && prefix
0343:                                                .length() > 0)) {
0344:                                    attribs.add(attr);
0345:                                }
0346:                            }
0347:                            result = translateAttribs(offset - len, len,
0348:                                    attribs, tag);
0349:                        }
0350:
0351:                        /* Value finder */
0352:                        /* Suggestion - find special-meaning attributes ( IMG src, A href,
0353:                         * color,.... - may be better resolved by attr type, may be moved
0354:                         * to propertysheet
0355:                         */
0356:                    } else if (id == HTMLTokenId.VALUE
0357:                            || id == HTMLTokenId.OPERATOR
0358:                            || id == HTMLTokenId.WS) {
0359:
0360:                        if (id == HTMLTokenId.WS) {
0361:                            //is the token before an operator? '<div color= |red>'
0362:                            ts.move(item.offset(hi));
0363:                            ts.movePrevious();
0364:                            Token t = ts.token();
0365:                            if (t.id() != HTMLTokenId.OPERATOR) {
0366:                                return null;
0367:                            }
0368:                        }
0369:
0370:                        SyntaxElement elem = null;
0371:                        try {
0372:                            elem = sup.getElementChain(offset);
0373:                        } catch (BadLocationException e) {
0374:                            return null;
0375:                        }
0376:
0377:                        if (elem == null)
0378:                            return null;
0379:
0380:                        // between Tag and error - common state when entering OOTL, e.g. <BDO dir=>
0381:                        if (elem.getType() == SyntaxElement.TYPE_ERROR) {
0382:                            elem = elem.getPrevious();
0383:                            if (elem == null)
0384:                                return null;
0385:                        }
0386:                        if (elem.getType() == SyntaxElement.TYPE_TAG) {
0387:                            SyntaxElement.Tag tagElem = (SyntaxElement.Tag) elem;
0388:
0389:                            String tagName = tagElem.getName().toUpperCase();
0390:                            DTD.Element tag = dtd.getElement(tagName);
0391:                            if (tag == null)
0392:                                return null; // unknown tag
0393:
0394:                            ts.move(item.offset(hi));
0395:                            ts.moveNext();
0396:                            Token argItem = ts.token();
0397:                            while (argItem.id() != HTMLTokenId.ARGUMENT
0398:                                    && ts.movePrevious()) {
0399:                                argItem = ts.token();
0400:                            }
0401:
0402:                            if (argItem.id() != HTMLTokenId.ARGUMENT)
0403:                                return null; // no ArgItem
0404:
0405:                            String argName = argItem.text().toString()
0406:                                    .toLowerCase();
0407:
0408:                            DTD.Attribute arg = tag.getAttribute(argName);
0409:                            if (arg == null
0410:                                    || arg.getType() != DTD.Attribute.TYPE_SET)
0411:                                return null;
0412:
0413:                            if (id != HTMLTokenId.VALUE) {
0414:                                len = 0;
0415:                                result = translateValues(offset - len, len, arg
0416:                                        .getValueList(""));
0417:                            } else {
0418:                                len = offset - itemOffset;
0419:
0420:                                String quotationChar = null;
0421:                                if (preText != null && preText.length() > 0) {
0422:                                    if (preText.substring(0, 1).equals("'"))
0423:                                        quotationChar = "'"; // NOI18N
0424:                                    if (preText.substring(0, 1).equals("\""))
0425:                                        quotationChar = "\""; // NOI18N
0426:                                }
0427:
0428:                                result = translateValues(
0429:                                        offset - len,
0430:                                        len,
0431:                                        arg
0432:                                                .getValueList(quotationChar == null ? preText
0433:                                                        : preText.substring(1)),
0434:                                        quotationChar);
0435:                            }
0436:                        }
0437:                    } else if (id == HTMLTokenId.SCRIPT) {
0438:                        result = addEndTag(SCRIPT_TAG_NAME, preText, offset);
0439:                    } else if (id == HTMLTokenId.STYLE) {
0440:                        result = addEndTag(STYLE_TAG_NAME, preText, offset);
0441:                    }
0442:
0443:                    return result;
0444:
0445:                } catch (BadLocationException ble) {
0446:                    ErrorManager.getDefault().notify(ble);
0447:                } finally {
0448:                    doc.readUnlock();
0449:                }
0450:
0451:                return null;
0452:            }
0453:
0454:            private List<CompletionItem> addEndTag(String tagName,
0455:                    String preText, int offset) {
0456:                int commonLength = getLastCommonCharIndex("</" + tagName + ">",
0457:                        preText.toUpperCase().trim()); //NOI18N
0458:                if (commonLength == -1) {
0459:                    commonLength = 0;
0460:                }
0461:                if (commonLength == preText.trim().length()) {
0462:                    ArrayList<CompletionItem> items = new ArrayList<CompletionItem>(
0463:                            1);
0464:                    items.add(new EndTagItem(lowerCase ? tagName.toLowerCase()
0465:                            : tagName, offset - commonLength, commonLength));
0466:                    return items;
0467:                }
0468:                return null;
0469:            }
0470:
0471:            private int getLastCommonCharIndex(String base, String pattern) {
0472:                int i = 0;
0473:                for (; i < base.length() && i < pattern.length(); i++) {
0474:                    if (base.charAt(i) != pattern.charAt(i)) {
0475:                        i--;
0476:                        break;
0477:                    }
0478:                }
0479:                return i;
0480:            }
0481:
0482:            List<CompletionItem> translateCharRefs(int offset, int length,
0483:                    List refs) {
0484:                List result = new ArrayList(refs.size());
0485:                String name;
0486:                for (Iterator i = refs.iterator(); i.hasNext();) {
0487:                    name = ((DTD.CharRef) i.next()).getName();
0488:                    result.add(new CharRefItem(name, offset, length, name));
0489:                }
0490:                return result;
0491:            }
0492:
0493:            List<CompletionItem> translateTags(int offset, int length, List tags) {
0494:                List result = new ArrayList(tags.size());
0495:                String name;
0496:                for (Iterator i = tags.iterator(); i.hasNext();) {
0497:                    name = ((DTD.Element) i.next()).getName();
0498:                    result.add(new TagItem(name, offset, length, name));
0499:                }
0500:                return result;
0501:            }
0502:
0503:            List<CompletionItem> translateAttribs(int offset, int length,
0504:                    List<DTD.Attribute> attribs, DTD.Element tag) {
0505:                List<CompletionItem> result = new ArrayList<CompletionItem>(
0506:                        attribs.size());
0507:                String tagName = tag.getName() + "#"; // NOI18N
0508:                for (DTD.Attribute attrib : attribs) {
0509:                    String name = attrib.getName();
0510:                    switch (attrib.getType()) {
0511:                    case DTD.Attribute.TYPE_BOOLEAN:
0512:                        result.add(new BooleanAttribItem(name, offset, length,
0513:                                attrib.isRequired(), tagName + name));
0514:                        break;
0515:                    case DTD.Attribute.TYPE_SET:
0516:                        result.add(new SetAttribItem(name, offset, length,
0517:                                attrib.isRequired(), tagName + name));
0518:                        break;
0519:                    case DTD.Attribute.TYPE_BASE:
0520:                        result.add(new PlainAttribItem(name, offset, length,
0521:                                attrib.isRequired(), tagName + name));
0522:                        break;
0523:                    }
0524:                }
0525:                return result;
0526:            }
0527:
0528:            List<CompletionItem> translateValues(int offset, int length,
0529:                    List values) {
0530:                return translateValues(offset, length, values, null);
0531:            }
0532:
0533:            List<CompletionItem> translateValues(int offset, int length,
0534:                    List values, String quotationChar) {
0535:                if (values == null)
0536:                    return new ArrayList(0);
0537:                List result = new ArrayList(values.size());
0538:                for (Iterator i = values.iterator(); i.hasNext();) {
0539:                    result.add(new ValueItem(((DTD.Value) i.next()).getName(),
0540:                            offset, length, quotationChar));
0541:                }
0542:                return result;
0543:            }
0544:
0545:            // Implementation of ResultItems for completion
0546:            /** The simple result item operating over an instance of the string,
0547:             * it is lightweight in the mean it doesn't allocate any new instances
0548:             * of anything and every data creates lazily on request to avoid
0549:             * creation of lot of string instances per completion result.
0550:             */
0551:            public static abstract class HTMLResultItem implements 
0552:                    CompletionItem {
0553:
0554:                /** The String on which is this ResultItem defined */
0555:                String baseText;
0556:                /** the remove and insert point for this item */
0557:                int offset;
0558:                /** The length of the text to be removed */
0559:                int length;
0560:
0561:                String helpID;
0562:
0563:                boolean shift = false;
0564:
0565:                private HTMLCompletionResultItemPaintComponent component;
0566:
0567:                private static final int HTML_ITEMS_SORT_PRIORITY = 20;
0568:
0569:                public HTMLResultItem(String baseText, int offset, int length) {
0570:                    this .baseText = lowerCase ? baseText.toLowerCase()
0571:                            : baseText.toUpperCase();
0572:                    this .offset = offset;
0573:                    this .length = length;
0574:                    this .helpID = null;
0575:                }
0576:
0577:                public HTMLResultItem(String baseText, int offset, int length,
0578:                        String helpID) {
0579:                    this (baseText, offset, length);
0580:                    this .helpID = helpID;
0581:                }
0582:
0583:                //-------------
0584:                protected int selectionStartOffset = -1;
0585:                protected int selectionEndOffset = -1;
0586:
0587:                public int getSortPriority() {
0588:                    return HTML_ITEMS_SORT_PRIORITY;
0589:                }
0590:
0591:                public CharSequence getSortText() {
0592:                    return HTMLResultItem.this .getItemText();
0593:                }
0594:
0595:                public CharSequence getInsertPrefix() {
0596:                    return getItemText();
0597:                }
0598:
0599:                public Component getPaintComponent(boolean isSelected) {
0600:                    //TODO: the paint component should be caches somehow
0601:                    HTMLCompletionResultItemPaintComponent component = new HTMLCompletionResultItemPaintComponent.StringPaintComponent(
0602:                            getPaintColor());
0603:                    component.setSelected(isSelected);
0604:                    component.setString(getItemText());
0605:                    return component;
0606:                }
0607:
0608:                public int getPreferredWidth(Graphics g, Font defaultFont) {
0609:                    HTMLCompletionResultItemPaintComponent renderComponent = (HTMLCompletionResultItemPaintComponent) getPaintComponent(false);
0610:                    return renderComponent.getPreferredWidth(g, defaultFont);
0611:                }
0612:
0613:                public void render(Graphics g, Font defaultFont,
0614:                        Color defaultColor, Color backgroundColor, int width,
0615:                        int height, boolean selected) {
0616:                    Component renderComponent = getPaintComponent(selected);
0617:                    renderComponent.setFont(defaultFont);
0618:                    renderComponent.setForeground(defaultColor);
0619:                    renderComponent.setBackground(backgroundColor);
0620:                    renderComponent.setBounds(0, 0, width, height);
0621:                    ((HTMLCompletionResultItemPaintComponent) renderComponent)
0622:                            .paintComponent(g);
0623:                }
0624:
0625:                protected Object getAssociatedObject() {
0626:                    return getItemText();
0627:                }
0628:
0629:                public static final String COMPLETION_SUBSTITUTE_TEXT = "completion-substitute-text"; //NOI18N
0630:
0631:                static int substituteOffset = -1;
0632:
0633:                public int getSubstituteOffset() {
0634:                    return substituteOffset;
0635:                }
0636:
0637:                public boolean instantSubstitution(JTextComponent c) {
0638:                    defaultAction(c);
0639:                    return true;
0640:                }
0641:
0642:                public CompletionTask createDocumentationTask() {
0643:                    return new AsyncCompletionTask(new DocQuery(this ));
0644:                }
0645:
0646:                public CompletionTask createToolTipTask() {
0647:                    return null;
0648:                }
0649:
0650:                public int getImportance() {
0651:                    return 0;
0652:                }
0653:
0654:                public void processKeyEvent(KeyEvent e) {
0655:                    shift = (e.getKeyCode() == KeyEvent.VK_ENTER
0656:                            && e.getID() == KeyEvent.KEY_PRESSED && e
0657:                            .isShiftDown());
0658:                }
0659:
0660:                public void defaultAction(JTextComponent component) {
0661:                    int substOffset = getSubstituteOffset();
0662:                    if (substOffset == -1)
0663:                        substOffset = component.getCaretPosition();
0664:
0665:                    if (!shift)
0666:                        Completion.get().hideAll();
0667:                    substituteText(component, substOffset, component
0668:                            .getCaretPosition()
0669:                            - substOffset, shift);
0670:                }
0671:
0672:                boolean replaceText(JTextComponent component, String text) {
0673:                    BaseDocument doc = (BaseDocument) component.getDocument();
0674:                    doc.atomicLock();
0675:                    try {
0676:                        //test whether we are trying to insert sg. what is already present in the text
0677:                        String currentText = doc.getText(offset, (doc
0678:                                .getLength() - offset) < text.length() ? (doc
0679:                                .getLength() - offset) : text.length());
0680:                        if (!text.equals(currentText)) {
0681:                            //remove common part
0682:                            doc.remove(offset, length);
0683:                            doc.insertString(offset, text, null);
0684:                        } else {
0685:                            int newCaretPos = component.getCaret().getDot()
0686:                                    + text.length() - length;
0687:                            //#82242 workaround - the problem is that in some situations
0688:                            //1) result item is created and it remembers the remove length
0689:                            //2) document is changed
0690:                            //3) RI is substituted.
0691:                            //this situation shouldn't happen imho and is a problem of CC infrastructure
0692:                            component.setCaretPosition(newCaretPos < doc
0693:                                    .getLength() ? newCaretPos : doc
0694:                                    .getLength());
0695:                        }
0696:                    } catch (BadLocationException exc) {
0697:                        return false; //not sucessfull
0698:                    } finally {
0699:                        doc.atomicUnlock();
0700:                    }
0701:                    return true;
0702:                }
0703:
0704:                protected void reformat(JTextComponent component, String text) {
0705:                    //does nothing by default; is overriden in EndTag
0706:                }
0707:
0708:                public boolean substituteCommonText(JTextComponent c, int a,
0709:                        int b, int subLen) {
0710:                    String text = getItemText().substring(0, subLen);
0711:                    boolean replaced = replaceText(c, text);
0712:                    reformat(c, text);
0713:                    return replaced;
0714:                }
0715:
0716:                public boolean substituteText(JTextComponent c, int a, int b,
0717:                        boolean shift) {
0718:                    String text = getItemText();
0719:                    boolean replaced = replaceText(c, text);
0720:                    reformat(c, text);
0721:                    return replaced;
0722:                }
0723:
0724:                /** @return Properly colored JLabel with text gotten from <CODE>getPaintText()</CODE>. */
0725:                public Component getPaintComponent(javax.swing.JList list,
0726:                        boolean isSelected, boolean cellHasFocus) {
0727:                    Component ret = getPaintComponent(isSelected);
0728:                    if (ret == null)
0729:                        return null;
0730:                    if (isSelected) {
0731:                        ret.setBackground(list.getSelectionBackground());
0732:                        ret.setForeground(list.getSelectionForeground());
0733:                    } else {
0734:                        ret.setBackground(list.getBackground());
0735:                        ret.setForeground(list.getForeground());
0736:                    }
0737:                    ret.getAccessibleContext().setAccessibleName(getItemText());
0738:                    ret.getAccessibleContext().setAccessibleDescription(
0739:                            getItemText());
0740:                    return ret;
0741:                }
0742:
0743:                /** The string used in painting by <CODE>getPaintComponent()</CODE>.
0744:                 * It defaults to delegate to <CODE>getItemText()</CODE>.
0745:                 * @return The String to be painted in Completion View.
0746:                 */
0747:                String getPaintText() {
0748:                    return getItemText();
0749:                }
0750:
0751:                abstract Color getPaintColor();
0752:
0753:                /** @return The String used for looking up the common part of multiple
0754:                 * items and for default way of replacing the text */
0755:                public String getItemText() {
0756:                    return baseText;
0757:                }
0758:
0759:                public String getHelpID() {
0760:                    return helpID;
0761:                }
0762:
0763:                public String toString() {
0764:                    StringBuffer sb = new StringBuffer();
0765:                    String className = this .getClass().getName();
0766:                    className = className
0767:                            .substring(className.lastIndexOf('.') + 1); //cut off the package
0768:                    sb.append(className);
0769:                    sb.append('(');
0770:                    sb.append(getItemText());
0771:                    sb.append(';');
0772:                    sb.append(getSubstituteOffset());
0773:                    sb.append(';');
0774:                    sb.append(getHelpID());
0775:                    sb.append(')');
0776:
0777:                    return sb.toString();
0778:                }
0779:
0780:            }
0781:
0782:            public static class AutocompleteEndTagItem extends EndTagItem {
0783:                public AutocompleteEndTagItem(String baseText, int offset) {
0784:                    this (baseText, offset, true);
0785:                }
0786:
0787:                public AutocompleteEndTagItem(String baseText, int offset,
0788:                        boolean changeCase) {
0789:                    super (baseText, offset, 0);
0790:                    if (!changeCase) {
0791:                        this .baseText = baseText; //#87218 hotfix - set the original value
0792:                    }
0793:                }
0794:
0795:                @Override()
0796:                boolean replaceText(JTextComponent component, String text) {
0797:                    boolean replaced = super .replaceText(component, text);
0798:                    if (replaced) {
0799:                        component.setCaretPosition(offset);
0800:                    }
0801:                    return replaced;
0802:                }
0803:
0804:                @Override
0805:                protected void reformat(JTextComponent component, String text) {
0806:                    try {
0807:                        BaseDocument doc = (BaseDocument) component
0808:                                .getDocument();
0809:                        int dotPos = component.getCaretPosition();
0810:                        Reformat reformat = Reformat.get(doc);
0811:                        reformat.lock();
0812:
0813:                        try {
0814:                            doc.atomicLock();
0815:                            try {
0816:                                int startOffset = Utilities.getRowStart(doc,
0817:                                        dotPos);
0818:                                int endOffset = Utilities
0819:                                        .getRowEnd(doc, dotPos);
0820:                                reformat.reformat(startOffset, endOffset);
0821:                            } finally {
0822:                                doc.atomicUnlock();
0823:                            }
0824:                        } finally {
0825:                            reformat.unlock();
0826:                        }
0827:                    } catch (BadLocationException e) {
0828:                        //ignore
0829:                    }
0830:                }
0831:
0832:                @Override
0833:                public CharSequence getInsertPrefix() {
0834:                    //disable instant substitution
0835:                    return null;
0836:                }
0837:
0838:            }
0839:
0840:            static class EndTagItem extends HTMLResultItem {
0841:
0842:                private int order = 0;
0843:
0844:                public EndTagItem(String baseText, int offset, int length) {
0845:                    super (baseText, offset, length);
0846:                }
0847:
0848:                public EndTagItem(String baseText, int offset, int length,
0849:                        String helpID) {
0850:                    super (baseText, offset, length, helpID);
0851:                }
0852:
0853:                public EndTagItem(String baseText, int offset, int length,
0854:                        String helpID, int order) {
0855:                    this (baseText, offset, length, helpID);
0856:                    this .order = order;
0857:                }
0858:
0859:                public CharSequence getSortText() {
0860:                    return getSortText(this .order);
0861:                }
0862:
0863:                private String getSortText(int index) {
0864:                    int zeros = index > 100 ? 0 : index > 10 ? 1 : 2;
0865:                    StringBuffer sb = new StringBuffer();
0866:                    for (int i = 0; i < zeros; i++) {
0867:                        sb.append('0');
0868:                    }
0869:                    sb.append("" + index);
0870:                    return sb.toString();
0871:                }
0872:
0873:                Color getPaintColor() {
0874:                    return Color.blue;
0875:                }
0876:
0877:                public String getItemText() {
0878:                    return "</" + baseText + ">";
0879:                } // NOI18N
0880:
0881:                public boolean substituteText(JTextComponent c, int a, int b,
0882:                        boolean shift) {
0883:                    return super .substituteText(c, a, b, shift);
0884:                }
0885:
0886:                @Override
0887:                protected void reformat(JTextComponent component, String text) {
0888:                    try {
0889:                        BaseDocument doc = (BaseDocument) component
0890:                                .getDocument();
0891:                        int dotPos = component.getCaretPosition();
0892:                        Reformat reformat = Reformat.get(doc);
0893:                        reformat.lock();
0894:
0895:                        try {
0896:                            doc.atomicLock();
0897:                            try {
0898:                                int startOffset = Utilities.getRowStart(doc,
0899:                                        dotPos);
0900:                                int endOffset = Utilities
0901:                                        .getRowEnd(doc, dotPos);
0902:                                reformat.reformat(startOffset, endOffset);
0903:                            } finally {
0904:                                doc.atomicUnlock();
0905:                            }
0906:                        } finally {
0907:                            reformat.unlock();
0908:                        }
0909:                    } catch (BadLocationException e) {
0910:                        //ignore
0911:                    }
0912:                }
0913:
0914:            }
0915:
0916:            private static class CharRefItem extends HTMLResultItem {
0917:
0918:                public CharRefItem(String name, int offset, int length) {
0919:                    super (name, offset, length);
0920:                    this .baseText = name;
0921:                }
0922:
0923:                public CharRefItem(String name, int offset, int length,
0924:                        String helpID) {
0925:                    super (name, offset, length, helpID);
0926:                    this .baseText = name;
0927:                }
0928:
0929:                Color getPaintColor() {
0930:                    return Color.red.darker();
0931:                }
0932:
0933:                public CharSequence getSortText() {
0934:                    String itext = getItemText();
0935:                    return itext.endsWith(";") ? itext.substring(0, itext
0936:                            .length() - 1) : itext;
0937:                }
0938:
0939:                public String getItemText() {
0940:                    return "&" + baseText + ";";
0941:                } // NOI18N
0942:            }
0943:
0944:            private static class TagItem extends HTMLResultItem {
0945:
0946:                public TagItem(String name, int offset, int length) {
0947:                    super (name, offset, length);
0948:                }
0949:
0950:                public TagItem(String name, int offset, int length,
0951:                        String helpID) {
0952:                    super (name, offset, length, helpID);
0953:                }
0954:
0955:                public boolean substituteText(JTextComponent c, int a, int b,
0956:                        boolean shift) {
0957:                    replaceText(c, "<" + baseText + (shift ? " >" : ">")); // NOI18N
0958:                    if (shift) {
0959:                        Caret caret = c.getCaret();
0960:                        caret.setDot(caret.getDot() - 1);
0961:                    }
0962:                    Completion.get().showCompletion(); //show the completion to possibly offer an end tag (end tag autocompletion feature)
0963:                    return !shift; // flag == false;
0964:                }
0965:
0966:                Color getPaintColor() {
0967:                    return Color.blue;
0968:                }
0969:
0970:                public String getItemText() {
0971:                    return "<" + baseText + ">";
0972:                } // NOI18N
0973:            }
0974:
0975:            private static class SetAttribItem extends HTMLResultItem {
0976:                boolean required;
0977:
0978:                public SetAttribItem(String name, int offset, int length,
0979:                        boolean required) {
0980:                    super (name, offset, length);
0981:                    this .required = required;
0982:                }
0983:
0984:                public SetAttribItem(String name, int offset, int length,
0985:                        boolean required, String helpID) {
0986:                    super (name, offset, length, helpID);
0987:                    this .required = required;
0988:                }
0989:
0990:                Color getPaintColor() {
0991:                    return required ? Color.red : Color.green.darker();
0992:                }
0993:
0994:                String getPaintText() {
0995:                    return baseText;
0996:                }
0997:
0998:                public String getItemText() {
0999:                    return baseText;
1000:                } //NOI18N
1001:
1002:                public boolean substituteText(JTextComponent c, int a, int b,
1003:                        boolean shift) {
1004:                    replaceText(c, baseText + "=\"\""); //NOI18N
1005:                    Caret caret = c.getCaret();
1006:                    caret.setDot(caret.getDot() - 1);
1007:
1008:                    return false; // always refresh
1009:                }
1010:            }
1011:
1012:            private static class BooleanAttribItem extends HTMLResultItem {
1013:
1014:                boolean required;
1015:
1016:                public BooleanAttribItem(String name, int offset, int length,
1017:                        boolean required) {
1018:                    super (name, offset, length);
1019:                    this .required = required;
1020:                }
1021:
1022:                public BooleanAttribItem(String name, int offset, int length,
1023:                        boolean required, String helpID) {
1024:                    super (name, offset, length, helpID);
1025:                    this .required = required;
1026:                }
1027:
1028:                Color getPaintColor() {
1029:                    return required ? Color.red : Color.green.darker();
1030:                }
1031:
1032:                public boolean substituteText(JTextComponent c, int a, int b,
1033:                        boolean shift) {
1034:                    replaceText(c, shift ? baseText + " " : baseText); // NOI18N
1035:                    return false; // always refresh
1036:                }
1037:            }
1038:
1039:            private static class PlainAttribItem extends HTMLResultItem {
1040:
1041:                boolean required;
1042:
1043:                public PlainAttribItem(String name, int offset, int length,
1044:                        boolean required) {
1045:                    super (name, offset, length);
1046:                    this .required = required;
1047:                }
1048:
1049:                public PlainAttribItem(String name, int offset, int length,
1050:                        boolean required, String helpID) {
1051:                    super (name, offset, length, helpID);
1052:                    this .required = required;
1053:                }
1054:
1055:                Color getPaintColor() {
1056:                    return required ? Color.red : Color.green.darker();
1057:                }
1058:
1059:                public boolean substituteText(JTextComponent c, int a, int b,
1060:                        boolean shift) {
1061:                    replaceText(c, baseText + "=\"\""); //NOI18N
1062:                    Caret caret = c.getCaret();
1063:                    caret.setDot(caret.getDot() - 1);
1064:                    return false; // always refresh
1065:                }
1066:            }
1067:
1068:            private static class ValueItem extends HTMLResultItem {
1069:
1070:                private String quotationChar = null;
1071:
1072:                public ValueItem(String name, int offset, int length,
1073:                        String quotationChar) {
1074:                    this (name, offset, length);
1075:                    this .quotationChar = quotationChar;
1076:                }
1077:
1078:                public ValueItem(String name, int offset, int length) {
1079:                    super (name, offset, length);
1080:                }
1081:
1082:                public CharSequence getInsertPrefix() {
1083:                    if (quotationChar == null) {
1084:                        return super .getInsertPrefix();
1085:                    } else {
1086:                        return quotationChar + super .getInsertPrefix();
1087:                    }
1088:                }
1089:
1090:                Color getPaintColor() {
1091:                    return Color.magenta;
1092:                }
1093:
1094:                public boolean substituteText(JTextComponent c, int a, int b,
1095:                        boolean shift) {
1096:                    //check whether there is already a " char after the CC offset
1097:                    BaseDocument doc = (BaseDocument) c.getDocument();
1098:                    boolean hasQuote = false;
1099:                    try {
1100:                        String currentText = doc.getText(c.getCaretPosition(),
1101:                                1);
1102:                        hasQuote = "\"".equals(currentText);
1103:                    } catch (BadLocationException ble) {
1104:                        //do nothing
1105:                    }
1106:                    String quotedText = ((quotationChar == null) ? baseText
1107:                            : quotationChar + baseText
1108:                                    + (hasQuote ? "" : quotationChar));
1109:                    replaceText(c, quotedText);
1110:                    return !shift;
1111:                }
1112:            }
1113:
1114:            static class DocQuery extends AsyncCompletionQuery {
1115:
1116:                private HTMLResultItem item;
1117:
1118:                DocQuery(HTMLResultItem item) {
1119:                    this .item = item;
1120:                }
1121:
1122:                protected void query(CompletionResultSet resultSet,
1123:                        Document doc, int caretOffset) {
1124:                    if (item != null
1125:                            && item.getHelpID() != null
1126:                            && HelpManager.getDefault().findHelpItem(
1127:                                    item.getHelpID()) != null) {
1128:                        resultSet.setDocumentation(new DocItem(item));
1129:                    }
1130:                    resultSet.finish();
1131:                }
1132:
1133:            }
1134:
1135:            static class LinkDocItem implements  CompletionDocumentation {
1136:                private URL url;
1137:
1138:                public LinkDocItem(URL url) {
1139:                    this .url = url;
1140:                }
1141:
1142:                public String getText() {
1143:                    return null;
1144:                    /*
1145:                    String anchor = HelpManager.getDefault().getAnchorText(url);
1146:                    if(anchor != null)
1147:                        return HelpManager.getDefault().getHelpText(url, anchor);
1148:                    else
1149:                        return HelpManager.getDefault().getHelpText(url);
1150:                     */
1151:                }
1152:
1153:                public URL getURL() {
1154:                    return url;
1155:                }
1156:
1157:                public CompletionDocumentation resolveLink(String link) {
1158:                    return new LinkDocItem(HelpManager.getDefault()
1159:                            .getRelativeURL(url, link));
1160:                }
1161:
1162:                public Action getGotoSourceAction() {
1163:                    return null;
1164:                }
1165:
1166:            }
1167:
1168:            public static class DocItem implements  CompletionDocumentation {
1169:                private String name;
1170:
1171:                public DocItem(HTMLResultItem ri) {
1172:                    this (ri.getHelpID());
1173:                }
1174:
1175:                public DocItem(String name) {
1176:                    this .name = name;
1177:                }
1178:
1179:                public String getText() {
1180:                    String help = HelpManager.getDefault().getHelp(name);
1181:                    return help;
1182:                }
1183:
1184:                public URL getURL() {
1185:                    return HelpManager.getDefault().getHelpURL(name);
1186:                }
1187:
1188:                public CompletionDocumentation resolveLink(String link) {
1189:                    String currentLink = HelpManager.getDefault().findHelpItem(
1190:                            name).getFile();
1191:                    return new LinkDocItem(HelpManager.getDefault()
1192:                            .getRelativeURL(
1193:                                    HelpManager.getDefault().getHelpURL(name),
1194:                                    link));
1195:                }
1196:
1197:                public Action getGotoSourceAction() {
1198:                    return null;
1199:                }
1200:            }
1201:
1202:            public static class HTMLCompletionResult extends
1203:                    CompletionQuery.DefaultResult {
1204:                private int substituteOffset;
1205:
1206:                public HTMLCompletionResult(JTextComponent component,
1207:                        String title, List data, int offset, int len) {
1208:                    super (component, title, data, offset, len);
1209:                    substituteOffset = offset - len;
1210:                }
1211:
1212:                public int getSubstituteOffset() {
1213:                    return substituteOffset;
1214:                }
1215:            }
1216:
1217:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.