KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > tasklist > docscan > SourceTaskProvider


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.tasklist.docscan;
21
22 import java.beans.*;
23 import java.util.List JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.Collection JavaDoc;
27 import java.util.regex.*;
28 import java.io.IOException JavaDoc;
29
30 import org.openide.ErrorManager;
31 import org.openide.text.Line;
32 import org.openide.util.WeakSet;
33 import org.openide.loaders.DataObject;
34 import org.openide.loaders.DataObjectNotFoundException;
35
36 import org.netbeans.modules.tasklist.core.*;
37 import org.netbeans.modules.tasklist.client.Suggestion;
38 import org.netbeans.modules.tasklist.client.SuggestionManager;
39 import org.netbeans.modules.tasklist.client.SuggestionAgent;
40 import org.netbeans.modules.tasklist.providers.DocumentSuggestionProvider;
41 import org.netbeans.modules.tasklist.providers.SuggestionContext;
42
43 // I was tempted to use BaseDocument here, since it has various
44
// advantages such as utilities for computing line numbers, access
45
// to the contents as an array, etc.
46
// However, not all documents opened are BaseDocuments - in particular,
47
// when using the XEmacs integration or the Vim integration, we have
48
// Documents, not BaseDocuments (a subclass of Document), so I'll
49
// stick with direct Document manipulation here.
50
//import org.netbeans.editor.BaseDocument;
51

52
53 /**
54  * This class scans the given document for source tasks. It does
55  * not provide any fix action.
56  *
57  * @todo If you have multiple hits on the same line, don't create a new
58  * task!
59  *
60  * @author Tor Norbye
61  * @author Trond Norbye
62  */

63 public final class SourceTaskProvider extends DocumentSuggestionProvider
64     implements PropertyChangeListener {
65
66     final static String JavaDoc TYPE = "nb-tasklist-scannedtask"; // NOI18N
67

68     /** The Set<SuggetionAgent> of recent task agents. Agent is identified by line. */
69     private WeakSet agents = new WeakSet();
70
71     // context being scanned for recent request
72
private SuggestionContext env;
73
74     private Settings settings;
75
76     /**
77      * Return the typenames of the suggestions that this provider
78      * will create.
79      * @return An array of string names. Should never be null. Most
80      * providers will create Suggestions of a single type, so it will
81      * be an array with one element.
82      */

83     public String JavaDoc getType() {
84         return TYPE;
85     }
86
87     public void notifyFinish() {
88         Cache.store();
89         settings = null;
90     }
91
92     public void notifyPrepare() {
93         // Cache.load(); too slow call it here
94
settings = Settings.getDefault();
95     }
96
97     public void notifyRun() {
98         // TODO propagate to consumers ()
99
}
100
101     public void notifyStop() {
102         // TODO propagate to consumers ()
103
}
104
105     public void propertyChange(PropertyChangeEvent ev) {
106         // is comes asynchronously from settings
107
// if everything goes well it rescan suggestions
108
// for recently opened document
109
if (Settings.PROP_SCAN_TAGS.equals(ev.getPropertyName())
110         || Settings.PROP_SCAN_SKIP.equals(ev.getPropertyName())) {
111             if (env == null) return;
112             // TODO propagate to consumers ()
113
}
114     }
115
116     // Q: why it this one requestless?
117
// A; because it synchronously returns results
118
public List JavaDoc scan(final SuggestionContext env) {
119
120         SuggestionManager manager = SuggestionManager.getDefault();
121         if (!manager.isEnabled(TYPE)) {
122             return null;
123         }
124
125         // Would it be better to move caching one level higher
126
// to suggestions framework? Such simple cache may be,
127
// more advanced caching probably not.
128
try {
129             if (DataObject.find(env.getFileObject()).isModified() == false) {
130                 List JavaDoc cached = Cache.get(env);
131                 if (cached != null) return cached;
132             }
133         } catch (DataObjectNotFoundException e) {
134             // ignore cache
135
}
136
137         boolean skipCode = settings().getSkipComments();
138         List JavaDoc tasks;
139     
140         if (skipCode) {
141             tasks = scanCommentsOnly(env);
142         } else {
143             tasks = scanAll(env);
144         }
145         Cache.put(env, tasks);
146
147         return tasks;
148     }
149     
150     
151     /**
152      * Given the contents of a buffer, scan it for todo items. Ignore
153      * all items found outside comment sections...
154      * @param doc The document to scan
155      * @param dobj The data object whose primary file should be scanned
156      */

157     private List JavaDoc scanCommentsOnly(SuggestionContext env) {
158         ArrayList JavaDoc newTasks = new ArrayList JavaDoc();
159         SourceCodeCommentParser sccp;
160         String JavaDoc suffix = env.getFileObject().getExt();
161             
162         // @todo These parameters should be configured somewhere.
163
// Since I don't know how I am going to store the data, I
164
// support only a set of hardcoded rules... After all,
165
// I promised only to support a given set of filetypes ;)
166
if (suffix.equalsIgnoreCase("java") || // NOI18N
167
suffix.equalsIgnoreCase("c") || // NOI18N
168
suffix.equalsIgnoreCase("cpp")) { // NOI18N
169
// I know that '//' require the C-99 standard, but I think
170
// the compiler should sort that out....
171
sccp = new SourceCodeCommentParser("//", "/*", "*/");
172         } else if (suffix.equalsIgnoreCase("html") || // NOI18N
173
suffix.equalsIgnoreCase("htm") || // NOI18N
174
suffix.equalsIgnoreCase("xml")) { // NOI18N
175
sccp = new SourceCodeCommentParser("<!--", "-->");
176         } else if (suffix.equalsIgnoreCase("jsp")) { // NOI18N
177
sccp = new SourceCodeCommentParser("<%--", "--%>");
178         } else if (suffix.equalsIgnoreCase("sh")) { // NOI18N
179
sccp = new SourceCodeCommentParser("#"); // NOI18N
180
} else {
181             sccp = new SourceCodeCommentParser();
182         }
183
184         CharSequence JavaDoc text = env.getCharSequence();
185         sccp.setDocument(env);
186
187         SourceCodeCommentParser.CommentRegion reg =
188             new SourceCodeCommentParser.CommentRegion();
189         
190         TaskTag matchTag = null;
191
192         try {
193             Matcher matcher = settings.getTaskTags().getScanRegexp().matcher(text);
194             int len = text.length();
195             int lineno = 1;
196             int index = 0;
197         int idx = 0;
198
199             // find the first comment region
200
if (!sccp.nextRegion(reg)) {
201                 // Done searching the document... bail out..
202
return newTasks;
203             }
204
205             while (index < len && matcher.find(index)) {
206                 int begin = matcher.start();
207                 int end = matcher.end();
208                 boolean toosoon = false;
209                 boolean goahead;
210
211                 do {
212                     goahead = true;
213
214                     // A match within the source comment?
215
if (begin < reg.start) {
216                         toosoon = true;
217                         // too soon.. get next match
218
} else if (begin > reg.stop) {
219                         goahead = false;
220                         if (!sccp.nextRegion(reg)) {
221                             // Done searching the document... bail out..
222
return newTasks;
223                         }
224                     }
225                 } while (!goahead);
226
227                 if (toosoon) {
228                     // find next match!
229
index = end;
230                     continue;
231                 }
232
233                 matchTag = getTag(text, begin, end);
234
235                 // begin should be the beginning of this line (but avoid
236
// clash if I have two tokens on the same line...
237
char c = 'a'; // NOI18N
238
int nonwhite = begin;
239                 while (begin >= index && (c = text.charAt(begin)) != '\n') { // NOI18N
240
if (c != ' ' && c != '\t') { // NOI18N
241
nonwhite = begin;
242                     }
243                     --begin;
244                 }
245                 
246                 begin = nonwhite;
247                 
248                 // end should be the last "nonwhite" character on this line...
249
nonwhite = end;
250                 while (end < len) {
251                     c = text.charAt(end);
252                     if (c == '\n' || c == '\r') {// NOI18N
253
break;
254                     } else if (c != ' ' && c != '\t') {// NOI18N
255
nonwhite = end;
256                     }
257                     ++end;
258                 }
259
260                 // calculate current line number
261
while (idx <= begin) {
262                     if (text.charAt(idx) == '\n') {// NOI18N
263
++lineno;
264                     }
265                     ++idx;
266                 }
267                 
268                 index = end;
269                 
270                 String JavaDoc description = text.subSequence(begin, nonwhite+1).toString();
271
272                 DataObject dataObject = DataObject.find(env.getFileObject());
273                 Line line = TLUtils.getLineByNumber(dataObject, lineno);
274
275                 Suggestion task = prepareSuggestion(matchTag, description, line);
276                 newTasks.add(task);
277             }
278         } catch (Exception JavaDoc e) {
279             ErrorManager.getDefault().notify(e);
280         }
281         return newTasks;
282     }
283
284     /**
285      * Given the contents of a buffer, scan it for todo items.
286      */

287     private List JavaDoc scanAll(SuggestionContext env) {
288         ArrayList JavaDoc newTasks = new ArrayList JavaDoc();
289  
290         CharSequence JavaDoc text = env.getCharSequence();
291
292         TaskTag matchTag = null;
293         try {
294             int index = 0;
295             int lineno = 1;
296             int len = text.length();
297
298             Matcher matcher = settings().getTaskTags().getScanRegexp().matcher(text);
299             while (index < len && matcher.find(index)) {
300                 int begin = matcher.start();
301                 int end = matcher.end();
302                 matchTag = getTag(text, begin, end);
303
304                 // begin should be the beginning of this line (but avoid
305
// clash if I have two tokens on the same line...
306
char c = 'a'; // NOI18N
307
int nonwhite = begin;
308                 while (begin >= index && (c = text.charAt(begin)) != '\n') { // NOI18N
309
if (c != ' ' && c != '\t') { // NOI18N
310
nonwhite = begin;
311                     }
312                     --begin;
313                 }
314                 
315                 begin = nonwhite;
316                 
317                 // end should be the last "nonwhite" character on this line...
318
nonwhite = end;
319                 while (end < len) {
320                     c = text.charAt(end);
321                     if (c == '\n' || c == '\r') {// NOI18N
322
break;
323                     } else if (c != ' ' && c != '\t') {// NOI18N
324
nonwhite = end;
325                     }
326                     ++end;
327                 }
328
329                 // calculate current line number
330
int idx = index;
331                 while (idx <= begin) {
332                     if (text.charAt(idx) == '\n') {// NOI18N
333
++lineno;
334                     }
335                     ++idx;
336                 }
337                 
338                 index = end;
339                 
340                 String JavaDoc description = text.subSequence(begin, nonwhite+1).toString();
341
342                 DataObject dataObject = DataObject.find(env.getFileObject());
343                 Line line = TLUtils.getLineByNumber(dataObject, lineno);
344
345                 Suggestion task = prepareSuggestion(matchTag, description, line);
346                 newTasks.add(task);
347
348             }
349         } catch (Exception JavaDoc e) {
350             e.printStackTrace();
351         }
352         return newTasks;
353     }
354
355     /** Merges found sugegstions with known ones if one exists. */
356     private Suggestion prepareSuggestion(TaskTag matchTag, String JavaDoc description, Line line) {
357         Suggestion suggestion = null;
358         if (line != null) {
359             SuggestionAgent agent = getAgent(line);
360             if (agent != null) {
361                 suggestion = agent.getSuggestion();
362                 agent.setSummary(description);
363                 if (matchTag != null) {
364                     agent.setPriority(matchTag.getPriority());
365                 }
366             }
367         }
368         
369         if (suggestion == null) {
370             SuggestionManager manager = SuggestionManager.getDefault();
371             SuggestionAgent agent = manager.createSuggestion(null,
372                 SourceTaskProvider.TYPE, description, null, this);
373
374             agent.setLine(line);
375             if (matchTag != null) {
376                 agent.setPriority(matchTag.getPriority());
377             }
378             agents.add(agent);
379             suggestion = agent.getSuggestion();
380         }
381
382         return suggestion;
383     }
384
385     private TaskTag getTag(CharSequence JavaDoc text, int start, int end) {
386         TaskTag tag = settings().getTaskTags().getTag(text, start+1, (end - start)-1);
387         return tag;
388     }
389
390     private Settings settings() {
391         if (settings == null) {
392             // FIXME manifests missing prepare event
393
settings = Settings.getDefault();
394         }
395         return settings;
396     }
397
398     private SuggestionAgent getAgent(Line l) {
399         Iterator JavaDoc it = agents.iterator();
400         while (it.hasNext()) {
401             SuggestionAgent next = (SuggestionAgent) it.next();
402             if (next == null) continue;
403             if (l.equals(next.getSuggestion().getLine())) return next;
404         }
405         return null;
406     }
407 }
408
409
410
Popular Tags