001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.web.core.syntax.spi;
043:
044: import java.beans.PropertyChangeSupport;
045: import java.util.Map;
046: import java.util.Iterator;
047:
048: import javax.servlet.jsp.tagext.TagLibraryInfo;
049:
050: /** Holds data relevant to the JSP coloring for one JSP page. The main purposes
051: * of this class are
052: * to report which prefixes are tag library prefixes in the page, and allows
053: * listening on the change of the prefixes, at which point the page needs to be
054: * recolored.
055: *
056: * @author Petr Jiricka
057: */
058: public final class JSPColoringData extends PropertyChangeSupport {
059:
060: /** An property whose change is fired every time the tag library
061: * information changes in such a way that recoloring of the document is required.
062: */
063: public static final String PROP_COLORING_CHANGE = "coloringChange"; // NOI18N
064: public static final String PROP_PARSING_SUCCESSFUL = "parsingSuccessful"; //NOI18N
065: public static final String PROP_PARSING_IN_PROGRESS = "parsingInProgress"; //NOI18N
066:
067: /** Taglib id -> TagLibraryInfo */
068: private Map taglibs;
069:
070: /** Prefix -> Taglib id */
071: private Map prefixMapper;
072:
073: private boolean elIgnored = false;
074:
075: private boolean xmlSyntax = false;
076:
077: /** Creates a new instance of JSPColoringData. */
078: public JSPColoringData(Object sourceBean) {
079: super (sourceBean);
080: }
081:
082: public Map getPrefixMapper() {
083: return prefixMapper;
084: }
085:
086: public String toString() {
087: return "JSPColoringData, taglibMap:\n"
088: + (prefixMapper == null ? "null" : mapToString(
089: prefixMapper, " "));
090: }
091:
092: private static String mapToString(Map m, String indent) {
093: StringBuffer sb = new StringBuffer();
094: Iterator it = m.keySet().iterator();
095: while (it.hasNext()) {
096: Object key = it.next();
097: sb.append(indent).append(key).append(" -> ").append(
098: m.get(key)).append("\n");
099: }
100: return sb.toString();
101: }
102:
103: /** Returns true if the given tag library prefix is known in this page.
104: */
105: public boolean isTagLibRegistered(String prefix) {
106: if ((taglibs == null) || (prefixMapper == null)) {
107: return false;
108: }
109: return prefixMapper.containsKey(prefix);
110: }
111:
112: /** Returns true if the EL is ignored in this page.
113: */
114: public boolean isELIgnored() {
115: return elIgnored;
116: }
117:
118: /** Returns true if the page is in xml syntax (JSP Documnet).
119: * If the page is in standard syntax, returns false.
120: */
121: public boolean isXMLSyntax() {
122: return xmlSyntax;
123: }
124:
125: /*public boolean isBodyIntepretedByTag(String prefix, String tagName) {
126: }*/
127:
128: public void parsingStarted() {
129: firePropertyChange(PROP_PARSING_IN_PROGRESS, null, new Boolean(
130: true));
131: }
132:
133: /** Incorporates new parse data from the parser, possibly firing a change about coloring.
134: * @param newTaglibs the new map of (uri -> TagLibraryInfo)
135: * @param newPrefixMapper the new map of (prefix, uri)
136: * @param parseSuccessful wherher parsing was successful. If false, then the new information is partial only
137: */
138: public void applyParsedData(Map newTaglibs, Map newPrefixMapper,
139: boolean newELIgnored, boolean newXMLSyntax,
140: boolean parseSuccessful) {
141: // check whether coloring has not changed
142: boolean coloringSame = equalsColoringInformation(taglibs,
143: prefixMapper, newTaglibs, newPrefixMapper);
144:
145: firePropertyChange(PROP_PARSING_SUCCESSFUL, null, new Boolean(
146: parseSuccessful));
147:
148: // check and apply EL data
149: if (parseSuccessful) {
150: coloringSame = coloringSame && (elIgnored == newELIgnored);
151: elIgnored = newELIgnored;
152: }
153:
154: //An additional check for the coloring change ->
155: //if the elIgnored and xmlSyntax have default values and the taglibs and prefixes are empty,
156: //there is no need to repaint the editor (fire the property change).
157: //Test if this is a first call of this method - after opening of the editor
158: if ((taglibs == null) && (prefixMapper == null)) {
159: coloringSame = ((newELIgnored == elIgnored)
160: && (newXMLSyntax == xmlSyntax)
161: && newTaglibs.isEmpty() && newPrefixMapper
162: .isEmpty());
163: }
164:
165: if (newXMLSyntax != xmlSyntax) {
166: xmlSyntax = newXMLSyntax;
167: coloringSame = false;
168: }
169:
170: // appy taglib data
171: if (parseSuccessful || (taglibs == null)
172: || (prefixMapper == null)) {
173: // overwrite
174: taglibs = newTaglibs;
175: prefixMapper = newPrefixMapper;
176: } else {
177: // merge
178: Iterator it = newPrefixMapper.keySet().iterator();
179: while (it.hasNext()) {
180: Object prefix = it.next();
181: Object uri = newPrefixMapper.get(prefix);
182: Object uriOld = prefixMapper.get(prefix);
183: if ((uriOld == null) || !uri.equals(uriOld)) {
184: Object newTaglib = newTaglibs.get(uri);
185: if (newTaglib != null) {
186: // change - merge it
187: prefixMapper.put(prefix, uri);
188: taglibs.put(uri, newTaglib);
189: }
190: }
191: }
192: }
193: // possibly fire the change
194: if (!coloringSame) {
195: firePropertyChange(PROP_COLORING_CHANGE, null, null);
196: }
197: }
198:
199: private static boolean equalsColoringInformation(Map taglibs1,
200: Map prefixMapper1, Map taglibs2, Map prefixMapper2) {
201: if ((taglibs1 == null) != (taglibs2 == null)) {
202: return false;
203: }
204: if ((prefixMapper1 == null) != (prefixMapper2 == null)) {
205: return false;
206: }
207: if (prefixMapper1.size() != prefixMapper2.size()) {
208: return false;
209: } else {
210: Iterator it = prefixMapper1.keySet().iterator();
211: while (it.hasNext()) {
212: Object prefix = it.next();
213: Object key1 = prefixMapper1.get(prefix);
214: Object key2 = prefixMapper2.get(prefix);
215: if ((key1 == null) || (key2 == null)) {
216: return false;
217: }
218: TagLibraryInfo tli1 = (TagLibraryInfo) taglibs1
219: .get(key1);
220: TagLibraryInfo tli2 = (TagLibraryInfo) taglibs2
221: .get(key2);
222: if ((tli1 == null) || (tli2 == null)) {
223: return false;
224: }
225: if (!equalsColoringInformation(tli1, tli2)) {
226: return false;
227: }
228: }
229: return true;
230: }
231: }
232:
233: private static boolean equalsColoringInformation(
234: TagLibraryInfo tli1, TagLibraryInfo tli2) {
235: /** PENDING
236: * should be going through all tags and checking whether the value
237: * returned by tagInfo.getBodyContent() has not changed.
238: */
239: return true;
240: }
241:
242: }
|