alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.xml.text.syntax;

import java.lang.ref.*;
import java.util.*;
import java.io.*;

import javax.swing.text.*;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;

import org.netbeans.editor.*;
import org.netbeans.editor.ext.*;

import org.netbeans.modules.xml.text.syntax.dom.*;
import org.openide.ErrorManager;
import org.openide.util.WeakListeners;

/**
 * Creates higher level syntax elements (DOM nodes) above token chain.
 * 

* It also defines rules for auto code completion poping up (Editor architecture issue). * * @author Petr Nejedly - original HTML code * @author Sandeep S. Randhawa - XML port * @author Petr Kuzel - use before strategy, use tokens whenever possible * @version 0.8 */ public class XMLSyntaxSupport extends ExtSyntaxSupport implements XMLTokenIDs { private Reference reference = new SoftReference(null); // cached helper private String systemId = null; // cached refernce to DTD private String publicId = null; // cached refernce to DTD private volatile boolean requestedAutoCompletion = false; /** Holds last character user have typed. */ private char lastInsertedChar = 'X'; // NOI18N private final DocumentMonitor documentMonitor; /** Creates new XMLSyntaxSupport */ public XMLSyntaxSupport(BaseDocument doc) { super(doc); // listener has same lifetime as this class documentMonitor = new DocumentMonitor(); DocumentListener l = WeakListeners.document(documentMonitor, doc); doc.addDocumentListener(l); } /** * Get token at given offet or previous one if at token boundary. * It does not lock the document. * @param offset valid position in document * @return TokenItem or null at the document beginning. */ public TokenItem getPreviousToken( int offset) throws BadLocationException { if (offset == 0) return null; if (offset < 0) throw new BadLocationException("Offset " + offset + " cannot be less than 0.", offset); //NOI18N // find first token item at the offset TokenItem item = null; int step = 11; int len = getDocument().getLength(); //??? read lock if (offset > len) throw new BadLocationException("Offset " + offset + " cannot be higher that document length " + len + " .", offset ); //NOI18N int from = Math.min(len, offset); int to = Math.min(len, offset); // go ahead to document beginning while ( item == null) { from = Math.max( from - step, 0); if ( from == 0) { to = Math.min(to + step, len); } item = getTokenChain( from, to); if ( from == 0 && to == len && item == null) { throw new IllegalStateException("Token at " + offset + " cannot be located!\nInspected range:[" + from + ", " + to + "]."); //NOI18N } } // if we are are at token boundary or at the fist document tokem all is OK // otherwise the offset actually resides in some next token while (item.getOffset() + item.getImage().length() < offset) { // it must cross or touch it TokenItem next = item.getNext(); if (next == null) { if (item.getOffset() + item.getImage().length() >= len) { return item; // we are at boundary at the end of document } else { throw new IllegalStateException("Token at " + offset + " cannot be located!\nPrevious token: " + item); //NOI18N } } item = next; } return item; } /** * Returns SyntaxElement instance for block of tokens, which is either * surrounding given offset, or is just before the offset. * @param offset Offset in document where to search for SyntaxElement. * @return SyntaxElement Element surrounding or laying BEFORE the offset * or null at document begining. */ public SyntaxElement getElementChain( int offset ) throws BadLocationException { TokenItem item = getPreviousToken( offset); if (item == null) return null; // locate SyntaxElement start boundary by traversing previous tokens // then create element starting from that boundary TokenID id = item.getTokenID(); TokenItem first = item; // reference can be in attribute or in content if( id == CHARACTER ) { while( id == CHARACTER ) { item = item.getPrevious(); if (item == null) break; id = item.getTokenID(); first = item; } // now item is either XMLSyntax.VALUE or we're in text, or at BOF if( id != VALUE && id != TEXT && id != CDATA_SECTION ) { // #34453 it may start of element tag or end of start tag (skip attributtes) if( id == XMLDefaultTokenContext.TAG ) { if( item.getImage().startsWith( "<" ) ) { return createElement( item ); // TAGO/ETAGO } else { do { item = item.getPrevious(); id = item.getTokenID(); } while( id != XMLDefaultTokenContext.TAG ); return createElement( item ); // TAGC } } return createElement( first ); } // else ( for VALUE or TEXT ) fall through } // these are possible only in containers (tags or doctype) if ( id == XMLDefaultTokenContext.WS || id == XMLDefaultTokenContext.ARGUMENT || id == XMLDefaultTokenContext.OPERATOR || id == XMLDefaultTokenContext.VALUE) // or doctype { while (true) { item = item.getPrevious(); id = item.getTokenID(); if (id == XMLDefaultTokenContext.TAG) break; if (id == XMLDefaultTokenContext.DECLARATION && item.getImage().trim().length() > 0) break; if (isInPI(id, false)) break; }; } if( id == TEXT || id == CDATA_SECTION) { while( id == TEXT || id == CHARACTER || id == CDATA_SECTION) { first = item; item = item.getPrevious(); if (item == null) break; id = item.getTokenID(); } return createElement( first ); // from start of continuous text } // // it may start of element tag or end of start tag (skip attributtes) // if( id == XMLDefaultTokenContext.TAG ) { if( item.getImage().startsWith( "<" ) ) { return createElement( item ); // TAGO/ETAGO } else { do { item = item.getPrevious(); id = item.getTokenID(); } while( id != XMLDefaultTokenContext.TAG ); return createElement( item ); // TAGC } } if( id == XMLDefaultTokenContext.ERROR ) return new SyntaxElement.Error( this, item, getTokenEnd( item ) ); if( id == XMLDefaultTokenContext.BLOCK_COMMENT ) { while( id == XMLDefaultTokenContext.BLOCK_COMMENT && !item.getImage().startsWith( "