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-2007 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: package org.netbeans.modules.visualweb.insync;
042:
043: import java.beans.PropertyChangeEvent;
044: import java.beans.PropertyChangeListener;
045: import javax.swing.Icon;
046: import javax.swing.ImageIcon;
047:
048: import org.openide.util.Utilities;
049: import org.openide.filesystems.FileObject;
050: import org.openide.text.Annotatable;
051: import org.openide.text.Annotation;
052: import org.openide.text.Line;
053: import org.openide.text.Line.Set;
054:
055: /**
056: * A source error; annotation which can be attached to a particular line in a source document.
057: * <p>Based on some similar code in the java module.
058: */
059: public class ParserAnnotation extends Annotation implements
060: PropertyChangeListener {
061:
062: public static final ParserAnnotation[] EMPTY_ARRAY = {};
063:
064: private FileObject fobj;
065: private final String message;
066: private final int line;
067: private final int column;
068: private Line docline;
069: private ParserAnnotation chained;
070: private Icon icon;
071:
072: /**
073: * Creates a new annotation.
074: *
075: * @param message The error message produced by the compiler/parser
076: * @param dataObject The data object this error is associated with
077: * @param line The line number where the error occurred
078: * @param column The column number on the line where the error occurred
079: */
080: public ParserAnnotation(String message, FileObject fobj, int line,
081: int column) {
082: this .fobj = fobj;
083: this .message = message;
084: this .line = line;
085: this .column = column;
086: }
087:
088: /**
089: * Annotation type, which allows the editor to look up annotation type information (defined in
090: * the layer file) such as the icon and highlight type to use for this annotation. See
091: * parser_annotation.xml for the definition of this type.
092: */
093: public String getAnnotationType() {
094: return "source-error"; // NOI18N
095: }
096:
097: /**
098: * Tooltip shown for this annotation. If this annotation is chained, return a tooltip showing
099: * the descriptions for all the chained annotations.
100: *
101: * @return the parser error message
102: */
103: public String getShortDescription() {
104: // Localize this with NbBundle:
105: if (chained != null)
106: return message + "\n\n" + chained.getShortDescription();
107: return message;
108: }
109:
110: /**
111: * Return the data object whose source file this error is associated with
112: *
113: * @return the data object associated with this error
114: */
115: public FileObject getFileObject() {
116: return fobj;
117: }
118:
119: /**
120: * Return the line number where the error occurred
121: *
122: * @return the line number - 1-based.
123: */
124: public int getLine() {
125: return line;
126: }
127:
128: /**
129: * Return the column number where the error occurred.
130: *
131: * @return the column number, or 0 if none is known.
132: */
133: public int getColumn() {
134: return column;
135: }
136:
137: /**
138: * Return the error message reported by the compiler/parser
139: *
140: * @return the localized error message
141: */
142: public String getMessage() {
143: return message;
144: }
145:
146: /**
147: * Return a suitable icon for this error
148: *
149: * @return an icon
150: */
151: public Icon getIcon() {
152: if (icon == null) {
153: java.awt.Image image = Utilities
154: .loadImage("org/netbeans/modules/visualweb/insync/error-glyph.gif");
155: if (image != null)
156: icon = image instanceof Icon ? (Icon) image
157: : new ImageIcon(image);
158: }
159: return icon;
160: }
161:
162: /**
163: * Chaining allows multiple annotations to appear on the same line using a single annotation -
164: * with a combined tooltip. This is useful since especially with java, it's not unlikely to
165: * encounter many errors on the same line, and you don't want a separate glyph/underline for
166: * each one, instead we have a single one.
167: */
168: public void chain(ParserAnnotation anno) {
169: if (chained != null)
170: chained.chain(anno);
171: else
172: chained = anno;
173: }
174:
175: /**
176: * Whenever the annotation is attached to the editor, listen for line edits so we can detach the
177: * annotation.
178: */
179: protected void notifyAttached(final Annotatable toAnno) {
180: super .notifyAttached(toAnno);
181: docline.addPropertyChangeListener(this );
182: }
183:
184: /**
185: * Whenever the annotation is detached from the editor we can stop listening for line edits.
186: */
187: protected void notifyDetached(Annotatable fromAnno) {
188: super .notifyDetached(fromAnno);
189: docline.removePropertyChangeListener(this );
190: }
191:
192: /**
193: * Only underline the part of the line that has text on it.
194: */
195: public void attachToLineSet(Set lines) {
196: docline = lines.getCurrent(line - 1);
197: char[] string = docline.getText().toCharArray();
198: int start = 0;
199: int end = string.length - 1;
200: while (start <= end && string[start] <= ' ')
201: start++;
202: while (start <= end && string[end] <= ' ')
203: end--;
204:
205: // XXX shouldn't we use the column??? But if so, chaining
206: // gets trickier...
207: Line.Part part;
208: if (start <= end)
209: part = docline.createPart(start, end - start + 1);
210: else
211: part = docline.createPart(0, string.length);
212:
213: attach(part);
214: }
215:
216: /**
217: * When the line containing the annotation is edited, remove the annotation immediately.
218: */
219: public void propertyChange(PropertyChangeEvent ev) {
220: String type = ev.getPropertyName();
221: if (type == null || type == Annotatable.PROP_TEXT) {
222: // User edited the line, assume error should be cleared.
223: detach();
224: }
225: }
226:
227: public String toString() {
228: return "ParserAnnotation[" + fobj + "," + line + ":" + message
229: + "]";
230: }
231: }
|