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.javadoc.search;
043:
044: import java.util.StringTokenizer;
045: import java.io.Reader;
046: import java.io.InputStreamReader;
047: import java.io.BufferedReader;
048: import java.net.URL;
049:
050: import javax.swing.text.html.parser.ParserDelegator;
051: import javax.swing.text.html.HTMLEditorKit;
052: import javax.swing.text.html.HTML;
053: import javax.swing.text.MutableAttributeSet;
054:
055: import org.openide.ErrorManager;
056: import org.openide.util.NbBundle;
057: import org.openide.filesystems.FileObject;
058:
059: /** This class implements the index search through documenation
060: * generated by Jdk 1.2 standard doclet
061: */
062:
063: class SearchThreadJdk12 extends IndexSearchThread {
064:
065: private Reader in;
066: private URL contextURL;
067:
068: private boolean stopSearch = false;
069:
070: private boolean splitedIndex = false;
071: private int currentIndexNumber;
072: private FileObject folder = null;
073: private final Object LOCK = new Object();
074:
075: public SearchThreadJdk12(String toFind, FileObject fo,
076: IndexSearchThread.DocIndexItemConsumer diiConsumer,
077: boolean caseSensitive) {
078:
079: super (toFind, fo, diiConsumer, caseSensitive);
080: //this.caseSensitive = caseSensitive;
081:
082: if (fo.isFolder()) {
083: // Documentation uses splited index - resolve the right file
084:
085: // This is just a try in most cases the fileNumber should be
086: // the right one but when some index files are missing we have
087: // to find the right one
088: folder = fo;
089: currentIndexNumber = (int) (Character.toUpperCase(lastField
090: .charAt(0))) - 'A' + 1;//toFind.charAt(0) )) - 'A' + 1;
091:
092: if (currentIndexNumber < 1) {
093: currentIndexNumber = 1;
094: } else if (currentIndexNumber > 26) {
095: currentIndexNumber = 27;
096: }
097:
098: /*
099: if ( currentIndexNumber < 1 || currentIndexNumber > 26 ) {
100: currentIndexNumber = 27;
101: }
102: */
103: findFileObject(0);
104:
105: splitedIndex = true;
106: } else {
107: try {
108: contextURL = this .indexRoot.getURL();
109: //contextURL = this.fo.getParent().getURL();
110: } catch (org.openide.filesystems.FileStateInvalidException e) {
111: throw new InternalError(
112: "Can't create documentation folder URL - file state invalid"); // NOI18N
113: }
114:
115: splitedIndex = false;
116: }
117: }
118:
119: public void stopSearch() {
120: Reader br;
121: synchronized (LOCK) {
122: stopSearch = true;
123: br = in;
124: }
125:
126: try {
127: if (br != null)
128: br.close();
129: } catch (java.io.IOException e) {
130: ErrorManager.getDefault().notify(e);
131: }
132: }
133:
134: public void run() {
135:
136: ParserDelegator pd = new ParserDelegator();
137:
138: if (indexRoot == null || lastField == null
139: || lastField.length() == 0) {
140: taskFinished();
141: return;
142: }
143:
144: SearchCallbackJdk12 sc = null;
145:
146: int theDirection = 0;
147:
148: do {
149: if (sc != null) {
150:
151: if (sc.badFile != theDirection) {
152: break;
153: }
154:
155: findFileObject(sc.badFile);
156: if (indexRoot == null) {
157: // No other file to search
158: break;
159: }
160: }
161:
162: try {
163: synchronized (LOCK) {
164: if (stopSearch) {
165: break;
166: }
167: in = new BufferedReader(new InputStreamReader(
168: indexRoot.getInputStream()));
169: }
170: pd.parse(in, sc = new SearchCallbackJdk12(splitedIndex,
171: caseSensitive), true);
172: } catch (java.io.IOException e) {
173: // Do nothing
174: }
175:
176: if (sc.badFile != 0 && theDirection == 0) {
177: theDirection = sc.badFile;
178: }
179: } while (sc.badFile != 0);
180:
181: try {
182: if (in != null) {
183: in.close();
184: }
185: } catch (java.io.IOException e) {
186: // Do nothing
187: }
188: //is.searchEnded();
189: taskFinished();
190: }
191:
192: void findFileObject(int direction) {
193:
194: if (direction < 0) {
195: currentIndexNumber--;
196: } else if (direction > 0) {
197: currentIndexNumber++;
198: }
199:
200: do {
201:
202: // Assure the only one direction of looking for Files
203:
204: if (currentIndexNumber < 0 || currentIndexNumber > 27) {
205: indexRoot = null;
206: return;
207: }
208:
209: String fileName = "index-" + currentIndexNumber; // NOI18N
210:
211: if (folder == null) {
212: indexRoot = null;
213: return;
214: }
215:
216: indexRoot = folder.getFileObject(fileName, "html"); // NOI18N
217:
218: if (indexRoot != null) {
219: try {
220: contextURL = this .indexRoot.getURL();
221: } catch (org.openide.filesystems.FileStateInvalidException e) {
222: throw new InternalError(
223: "Can't create documentation folder URL - file state invalid"); // NOI18N
224: }
225: } else {
226:
227: currentIndexNumber += direction > 0 ? 1 : -1;
228: }
229: } while (indexRoot == null);
230:
231: }
232:
233: // Inner classes ------------------------------------------------------------------------------------
234:
235: /* These are constants for the inner class */
236:
237: static private final String STR_CLASS = NbBundle.getMessage(
238: SearchThreadJdk12.class, "JDK12_CLASS"); //NOI18N
239: static private final String STR_INTERFACE = NbBundle.getMessage(
240: SearchThreadJdk12.class, "JDK12_INTERFACE"); //NOI18N
241: static private final String STR_EXCEPTION = NbBundle.getMessage(
242: SearchThreadJdk12.class, "JDK12_EXCEPTION"); //NOI18N
243: static private final String STR_CONSTRUCTOR = NbBundle.getMessage(
244: SearchThreadJdk12.class, "JDK12_CONSTRUCTOR"); //NOI18N
245: static private final String STR_METHOD = NbBundle.getMessage(
246: SearchThreadJdk12.class, "JDK12_METHOD"); //NOI18N
247: static private final String STR_ERROR = NbBundle.getMessage(
248: SearchThreadJdk12.class, "JDK12_ERROR"); //NOI18N
249: static private final String STR_VARIABLE = NbBundle.getMessage(
250: SearchThreadJdk12.class, "JDK12_VARIABLE"); //NOI18N
251: static private final String STR_STATIC = NbBundle.getMessage(
252: SearchThreadJdk12.class, "JDK12_STATIC"); //NOI18N
253: static private final String STR_DASH = NbBundle.getMessage(
254: SearchThreadJdk12.class, "JDK12_DASH"); //NOI18N
255: static private final String STR_PACKAGE = NbBundle.getMessage(
256: SearchThreadJdk12.class, "JDK12_PACKAGE"); //NOI18N
257: private static final String STR_ENUM = NbBundle.getMessage(
258: SearchThreadJdk12.class, "JDK15_ENUM"); //NOI18N
259: private static final String STR_ANNTYPE = NbBundle.getMessage(
260: SearchThreadJdk12.class, "JDK15_ANNOTATION_TYPE"); //NOI18N
261:
262: static private final int IN_BALAST = 0;
263: static private final int IN_DT = 1;
264: static private final int IN_AREF = 2;
265: // static private final int IN_B = 3;
266: static private final int IN_DESCRIPTION = 4;
267: static private final int IN_DESCRIPTION_SUFFIX = 5;
268:
269: /** This inner class parses the JDK 1.2 Documentation index and returns
270: * found indexItems.
271: */
272:
273: private class SearchCallbackJdk12 extends
274: HTMLEditorKit.ParserCallback {
275:
276: private String hrefVal;
277: private DocIndexItem currentDii = null;
278: private int where = IN_BALAST;
279:
280: private boolean splited;
281: private boolean stopOnNext = false;
282:
283: private int badFile = 0;
284:
285: int printText = 0;
286:
287: SearchCallbackJdk12(boolean splited, boolean caseSensitive) {
288: super ();
289: this .splited = splited;
290: }
291:
292: public void handleStartTag(HTML.Tag t, MutableAttributeSet a,
293: int pos) {
294:
295: if (t == HTML.Tag.DT) {
296: where = IN_DT;
297: currentDii = null;
298: } else if (t == HTML.Tag.A && where == IN_DT) {
299: where = IN_AREF;
300: Object val = a.getAttribute(HTML.Attribute.HREF);
301: if (val != null) {
302: hrefVal = (String) val.toString();
303: currentDii = new DocIndexItem(null, null,
304: contextURL, hrefVal);
305: }
306: } else if (t == HTML.Tag.A
307: && (where == IN_DESCRIPTION_SUFFIX || where == IN_DESCRIPTION)) {
308: ; // Just ignore
309: } else if (t == HTML.Tag.B && where == IN_AREF) {
310: where = IN_AREF;
311: } else {
312: where = IN_BALAST;
313: }
314: }
315:
316: public void handleEndTag(HTML.Tag t, int pos) {
317: if (t == HTML.Tag.DT && where != IN_BALAST) {
318: where = IN_BALAST;
319: }
320: }
321:
322: public void handleText(char[] data, int pos) {
323:
324: if (where == IN_AREF) {
325:
326: if (stopOnNext) {
327: try {
328: in.close();
329: where = IN_BALAST;
330: return;
331: } catch (java.io.IOException e) {
332: ErrorManager.getDefault().notify(e);
333: }
334: }
335:
336: String text = new String(data);
337:
338: if (splited) {
339: // it is possible that we search wrong file
340: char first = Character.toUpperCase(lastField
341: .charAt(0));//toFind.charAt( 0 ) );
342: char curr = Character.toUpperCase(data[0]);
343: if (first != curr) {
344:
345: badFile = first < curr ? -1 : 1;
346: try {
347: in.close();
348: where = IN_BALAST;
349: return;
350: } catch (java.io.IOException e) {
351: ErrorManager.getDefault().notify(e);
352: }
353: }
354:
355: }
356: currentDii.setField(text.trim());
357: where = IN_DESCRIPTION;
358: } else if (where == IN_DESCRIPTION) {
359: String text = new String(data);
360:
361: /*
362: // Stop suffering if we are behind the searched words
363: if ( text.substring( 0, Math.min(toFind.length(), text.length()) ).compareTo( toFind ) > 0 ) {
364: try {
365: System.out.println("Stoping suffering");
366: in.close();
367: }
368: catch ( java.io.IOException e ) {
369: ErrorManager.getDefault().notify(e);
370: }
371: }
372: */
373:
374: //text = text.toUpperCase();
375: int dashIdx = text.indexOf(STR_DASH);
376: if (dashIdx < 0) {
377: return;
378: }
379: text = text.substring(dashIdx - 1);
380: currentDii.setRemark(text);
381:
382: StringTokenizer st = new StringTokenizer(text);
383: String token = st.nextToken();
384: if (token.equals(STR_DASH))
385: token = st.nextToken();
386:
387: boolean isStatic = false;
388:
389: if (token.equalsIgnoreCase(STR_STATIC)) {
390: isStatic = true;
391: token = st.nextToken();
392: }
393:
394: if (token.equalsIgnoreCase(STR_CLASS))
395: currentDii.setIconIndex(DocSearchIcons.ICON_CLASS);
396: else if (token.equalsIgnoreCase(STR_INTERFACE))
397: currentDii
398: .setIconIndex(DocSearchIcons.ICON_INTERFACE);
399: else if (token.equalsIgnoreCase(STR_ENUM))
400: currentDii.setIconIndex(DocSearchIcons.ICON_ENUM);
401: else if (token.equalsIgnoreCase(STR_ANNTYPE))
402: currentDii
403: .setIconIndex(DocSearchIcons.ICON_ANNTYPE);
404: else if (token.equalsIgnoreCase(STR_EXCEPTION))
405: currentDii
406: .setIconIndex(DocSearchIcons.ICON_EXCEPTION);
407: else if (token.equalsIgnoreCase(STR_ERROR))
408: currentDii.setIconIndex(DocSearchIcons.ICON_ERROR);
409: else if (token.equalsIgnoreCase(STR_PACKAGE))
410: currentDii
411: .setIconIndex(DocSearchIcons.ICON_PACKAGE);
412: else if (token.equalsIgnoreCase(STR_CONSTRUCTOR))
413: currentDii
414: .setIconIndex(DocSearchIcons.ICON_CONSTRUCTOR);
415: else if (token.equalsIgnoreCase(STR_METHOD))
416: currentDii
417: .setIconIndex(isStatic ? DocSearchIcons.ICON_METHOD_ST
418: : DocSearchIcons.ICON_METHOD);
419: else if (token.equalsIgnoreCase(STR_VARIABLE))
420: currentDii
421: .setIconIndex(isStatic ? DocSearchIcons.ICON_VARIABLE_ST
422: : DocSearchIcons.ICON_VARIABLE);
423:
424: // Add the item when all information is available
425: //insertDocIndexItem( currentDii );
426:
427: if (currentDii.getPackage() != null) {
428: where = IN_DESCRIPTION_SUFFIX;
429: } else if (text.endsWith(".")) { // NOI18N
430: where = IN_DESCRIPTION_SUFFIX;
431: currentDii.setPackage(text.substring(
432: text.lastIndexOf(' ')).trim());
433: } else
434: where = IN_BALAST;
435: } else if (where == IN_DESCRIPTION_SUFFIX) {
436: String remark = String.valueOf(data);
437: currentDii.setRemark(currentDii.getRemark() + remark);
438: String declaringClass = remark.trim();
439: if (!(".".equals(declaringClass))) { //NOI18N
440: currentDii.setDeclaringClass(declaringClass);
441: insertDocIndexItem(currentDii);
442: }
443: } else
444: where = IN_BALAST;
445:
446: }
447: /*
448: private boolean getContainsText(String text){//, boolean caseSensitive){
449: if( lastField.length() != 0 && text.indexOf( lastField ) != -1 )
450: return true;
451: else if ( middleField.length() != 0 && text.indexOf( middleField ) != -1 )
452: return true;
453: else if ( reminder.length() != 0 && text.indexOf( reminder ) != -1 )
454: return true;
455: else
456: return false;
457: }
458: */
459: }
460: }
|