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:
042: package org.netbeans.api.java.source;
043:
044: import java.io.IOException;
045: import java.io.Reader;
046: import java.io.Writer;
047: import java.util.concurrent.CopyOnWriteArrayList;
048: import javax.swing.event.ChangeListener;
049: import javax.swing.event.DocumentEvent;
050: import javax.swing.event.DocumentListener;
051: import javax.swing.text.JTextComponent;
052: import org.netbeans.modules.java.preprocessorbridge.spi.JavaFileFilterImplementation;
053: import org.netbeans.modules.java.preprocessorbridge.spi.JavaSourceProvider;
054: import org.openide.filesystems.FileObject;
055:
056: /**Binding between virtual Java source and the real source.
057: * Please note that this class is needed only for clients that need to work
058: * in non-Java files (eg. JSP files) or in dialogs, like code completion.
059: * Most clients do not need to use this class.
060: *
061: * @author Dusan Balek
062: * @since 0.21
063: */
064: public final class PositionConverter {
065:
066: private FileObject fo;
067: private JavaFileFilterImplementation filter;
068: private int offset;
069: private int length;
070: private JTextComponent component;
071:
072: PositionConverter(final FileObject fo,
073: final JavaFileFilterImplementation filter) {
074: this .fo = fo;
075: this .filter = filter;
076: }
077:
078: PositionConverter(final FileObject fo, int offset, int length,
079: final JTextComponent component) {
080: this .fo = fo;
081: this .offset = offset;
082: this .length = length;
083: this .component = component;
084: this .filter = new Filter();
085: }
086:
087: // API of the class --------------------------------------------------------
088:
089: /**Compute position in the document for given position in the virtual
090: * Java source.
091: *
092: * @param javaSourcePosition position in the virtual Java Source
093: * @return position in the document
094: * @since 0.21
095: */
096: public int getOriginalPosition(int javaSourcePosition) {
097: if (filter instanceof JavaSourceProvider.PositionTranslatingJavaFileFilterImplementation) {
098: return ((JavaSourceProvider.PositionTranslatingJavaFileFilterImplementation) filter)
099: .getOriginalPosition(javaSourcePosition);
100: }
101: return javaSourcePosition;
102: }
103:
104: /**Compute position in the virtual Java source for given position
105: * in the document.
106: *
107: * @param originalPosition position in the document
108: * @return position in the virtual Java source
109: * @since 0.21
110: */
111: public int getJavaSourcePosition(int originalPosition) {
112: if (filter instanceof JavaSourceProvider.PositionTranslatingJavaFileFilterImplementation) {
113: return ((JavaSourceProvider.PositionTranslatingJavaFileFilterImplementation) filter)
114: .getJavaSourcePosition(originalPosition);
115: }
116: return originalPosition;
117: }
118:
119: // Package private methods -------------------------------------------------
120:
121: JavaFileFilterImplementation getFilter() {
122: return filter;
123: }
124:
125: FileObject getFileObject() {
126: return fo;
127: }
128:
129: // Nested classes ----------------------------------------------------------
130:
131: private class Filter
132: implements
133: JavaSourceProvider.PositionTranslatingJavaFileFilterImplementation,
134: DocumentListener {
135:
136: CopyOnWriteArrayList<ChangeListener> listeners = new CopyOnWriteArrayList<ChangeListener>();
137:
138: public Filter() {
139: component.getDocument().addDocumentListener(this );
140: }
141:
142: public Reader filterReader(final Reader r) {
143: return new Reader() {
144:
145: private int next = 0;
146: private String text = convert(component.getText());
147:
148: public int read(char[] cbuf, int off, int len)
149: throws IOException {
150: synchronized (lock) {
151: if (off < 0 || off > cbuf.length || len < 0
152: || (off + len) > cbuf.length) {
153: throw new IndexOutOfBoundsException();
154: } else if (len == 0) {
155: return 0;
156: }
157: if (text.length() == 0 && length == 0)
158: return r.read(cbuf, off, len);
159: if (next < offset) {
160: int n = r.read(cbuf, off, Math.min(offset
161: - next, len));
162: next += n;
163: return n;
164: }
165: if (next == offset)
166: r.skip(length);
167: if (next < offset + text.length()) {
168: int n = Math.min(offset + text.length()
169: - next, len);
170: text.getChars(next - offset, next - offset
171: + n, cbuf, off);
172: next += n;
173: return n;
174: }
175: return r.read(cbuf, off, len);
176: }
177: }
178:
179: public void close() throws IOException {
180: r.close();
181: }
182: };
183: }
184:
185: public CharSequence filterCharSequence(CharSequence charSequence) {
186: return charSequence.subSequence(0, offset)
187: + convert(component.getText())
188: + charSequence.subSequence(offset + length,
189: charSequence.length());
190: }
191:
192: public Writer filterWriter(Writer w) {
193: throw new UnsupportedOperationException(
194: "Not supported yet.");
195: }
196:
197: public void addChangeListener(ChangeListener listener) {
198: listeners.addIfAbsent(listener);
199: }
200:
201: public void removeChangeListener(ChangeListener listener) {
202: listeners.remove(listener);
203: }
204:
205: public int getOriginalPosition(int javaSourcePosition) {
206: if (javaSourcePosition < offset)
207: return -1;
208: int diff = javaSourcePosition - offset;
209: return diff <= convert(component.getText()).length() ? diff
210: : -1;
211: }
212:
213: public int getJavaSourcePosition(int originalPosition) {
214: return offset + originalPosition;
215: }
216:
217: public void insertUpdate(DocumentEvent event) {
218: this .changedUpdate(event);
219: }
220:
221: public void removeUpdate(DocumentEvent event) {
222: this .changedUpdate(event);
223: }
224:
225: public void changedUpdate(DocumentEvent event) {
226: for (ChangeListener changeListener : listeners)
227: changeListener.stateChanged(null);
228: }
229:
230: private String convert(String string) {
231: StringBuilder sb = new StringBuilder(string.length());
232: for (int i = 0; i < string.length(); i++) {
233: char c = string.charAt(i);
234: if (c == '\r') { //NOI18N
235: if (i + 1 >= string.length()
236: || string.charAt(i + 1) != '\n') { //NOI18N
237: sb.append('\n'); //NOI18N
238: }
239: } else {
240: sb.append(c);
241: }
242: }
243: return sb.toString();
244: }
245: }
246: }
|