KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > web > core > syntax > folding > JspFoldManager


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.web.core.syntax.folding;
21
22 import java.lang.reflect.InvocationTargetException JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Stack JavaDoc;
30 import java.util.Timer JavaDoc;
31 import java.util.TimerTask JavaDoc;
32 import javax.swing.SwingUtilities JavaDoc;
33 import javax.swing.event.DocumentEvent JavaDoc;
34 import javax.swing.text.BadLocationException JavaDoc;
35 import javax.swing.text.Document JavaDoc;
36 import javax.swing.text.JTextComponent JavaDoc;
37 import org.netbeans.api.editor.fold.Fold;
38 import org.netbeans.api.editor.fold.FoldHierarchy;
39 import org.netbeans.api.editor.fold.FoldType;
40 import org.netbeans.api.editor.fold.FoldUtilities;
41 import org.netbeans.editor.BaseDocument;
42 import org.netbeans.editor.Settings;
43 import org.netbeans.editor.SettingsChangeEvent;
44 import org.netbeans.editor.SettingsChangeListener;
45 import org.netbeans.editor.SettingsUtil;
46 import org.netbeans.editor.Utilities;
47 import org.netbeans.editor.ext.html.HTMLSyntaxSupport;
48 import org.netbeans.modules.web.core.syntax.settings.JspSettings;
49 import org.netbeans.modules.web.core.syntax.JspSyntaxSupport;
50 import org.netbeans.modules.web.core.syntax.SyntaxElement;
51 import org.netbeans.spi.editor.fold.FoldHierarchyTransaction;
52 import org.netbeans.spi.editor.fold.FoldManager;
53 import org.netbeans.spi.editor.fold.FoldOperation;
54 import org.openide.ErrorManager;
55
56 /**
57  * This class is an implementation of @see org.netbeans.spi.editor.fold.FoldManager
58  * responsible for creating, deleting and updating code folds.
59  *
60  * @author Marek.Fukala@Sun.COM
61  */

62 public class JspFoldManager implements FoldManager, SettingsChangeListener {
63     
64     private static final boolean SHOW_TIMES = Boolean.getBoolean("org.netbeans.modules.web.core.folding.measure");
65     
66     private FoldOperation operation;
67     private JspSyntaxSupport sup;
68     
69     //timer performing periodicall folds update
70
private Timer JavaDoc timer;
71     private TimerTask JavaDoc timerTask;
72     private int foldsUpdateInterval = -1;
73     
74     private long foldsGenerationTime = -1;
75     
76     private boolean documentDirty = true;
77     
78     private BaseDocument doc = null;
79     
80     protected FoldOperation getOperation() {
81         return operation;
82     }
83     
84     public void init(FoldOperation operation) {
85         this.operation = operation;
86         Settings.addSettingsChangeListener(this);
87         foldsUpdateInterval = getSetting(JspSettings.CODE_FOLDING_UPDATE_TIMEOUT);
88     }
89     
90     public void initFolds(FoldHierarchyTransaction transaction) {
91         //filter first initFolds call when the EditorPane has PlainDocument content
92
Document JavaDoc doc = getOperation().getHierarchy().getComponent().getDocument();
93         if(doc instanceof BaseDocument) {
94             this.doc = (BaseDocument)doc;
95             
96             sup = new JspSyntaxSupport(getDocument());
97             
98             //start folds updater timer
99
//put off the initial fold search due to the processor overhead during page opening
100
timer = new Timer JavaDoc();
101             restartTimer();
102         }
103     }
104     
105     private void restartTimer() {
106         documentDirty = true;
107         //test whether the FoldManager.release() was called.
108
//if so, then do not try to update folds anymore
109
if(timer == null) return ;
110         
111         if(timerTask != null) timerTask.cancel();
112         timerTask = createTimerTask();
113         timer.schedule(timerTask, foldsUpdateInterval);
114     }
115     
116     private TimerTask JavaDoc createTimerTask() {
117         return new TimerTask JavaDoc() {
118             public void run() {
119                 //set the update thread priority
120
Thread JavaDoc thr = new Thread JavaDoc(new Runnable JavaDoc() {
121                     public void run() {
122                         try {
123                             documentDirty = false;
124                             updateFolds();
125                         }catch(ParsingCancelledException pce) {
126                             if(debug) System.out.println("parsing cancelled");
127                         }
128                     }
129                 });
130                 thr.setPriority(Thread.MIN_PRIORITY + 1);
131                 thr.start();
132                 //wait for the thread to die
133
try {
134                     thr.join();
135                 }catch(InterruptedException JavaDoc e) {
136                     //ignore
137
}
138             }
139         };
140     }
141     
142     public void release() {
143         Settings.removeSettingsChangeListener(this);
144         if(timer != null) {
145             timer.cancel();
146             timer = null;
147         }
148     }
149     
150     public void insertUpdate(DocumentEvent JavaDoc evt, FoldHierarchyTransaction transaction) {
151         restartTimer();
152     }
153     
154     public void removeUpdate(DocumentEvent JavaDoc evt, FoldHierarchyTransaction transaction) {
155         restartTimer();
156     }
157     
158     public void changedUpdate(DocumentEvent JavaDoc evt, FoldHierarchyTransaction transaction) {
159         //do nothing - the updates are catched in insertUpdate and removeUpdate methods
160
}
161     
162     public void removeEmptyNotify(Fold epmtyFold) {
163     }
164     
165     public void removeDamagedNotify(Fold damagedFold) {
166     }
167     
168     public void expandNotify(Fold expandedFold) {
169     }
170     
171     public void settingsChange(SettingsChangeEvent evt) {
172         // Get folding presets
173
if(evt.getSettingName() == JspSettings.CODE_FOLDING_UPDATE_TIMEOUT) {
174             foldsUpdateInterval = getSetting(JspSettings.CODE_FOLDING_UPDATE_TIMEOUT);
175             restartTimer();
176         }
177     }
178     
179     private List JavaDoc generateFolds() throws BadLocationException JavaDoc, ParsingCancelledException {
180         BaseDocument bdoc = (BaseDocument)getDocument();
181         JspSyntaxSupport jspsup = (JspSyntaxSupport)bdoc.getSyntaxSupport().get(JspSyntaxSupport.class);
182         HTMLSyntaxSupport htmlsup = (HTMLSyntaxSupport)bdoc.getSyntaxSupport().get(HTMLSyntaxSupport.class);
183         
184         int htmlSEEnd = -1;
185         ArrayList JavaDoc found = new ArrayList JavaDoc(getDocument().getLength() / 100); // ~an element per 100 chars ???
186
SyntaxElement sel = jspsup.getElementChain(1);
187         Stack JavaDoc stack = new Stack JavaDoc();
188         org.netbeans.editor.ext.html.parser.SyntaxElement htmlCommentStartElement = null;
189         int prevSelOffset = sel != null ? sel.getElementOffset() : 0;
190         while(sel != null) {
191             //check if the parsing should be cancelled (when there is a change in the parsed document)
192
if(documentDirty) throw new ParsingCancelledException();
193             
194             if(debug) System.out.println(sel);
195             if(sel.getCompletionContext() == JspSyntaxSupport.COMMENT_COMPLETION_CONTEXT)
196                 found.add(new FoldInfo(sel.getElementOffset(), sel.getElementOffset() + sel.getElementLength(), JspFoldTypes.COMMENT, JspFoldTypes.COMMENT_DESCRIPTION));
197             else if(sel.getCompletionContext() == JspSyntaxSupport.SCRIPTINGL_COMPLETION_CONTEXT)
198                 found.add(new FoldInfo(sel.getElementOffset(), sel.getElementOffset() + sel.getElementLength(), JspFoldTypes.SCRIPTLET, JspFoldTypes.SCRIPTLET_DESCRIPTION));
199             else if(sel.getCompletionContext() == JspSyntaxSupport.CONTENTL_COMPLETION_CONTEXT) {
200                 //fixme: the HTML folds needs to be obtained from the brand new unexisting editor infrastrucure
201
// //html
202
// org.netbeans.editor.ext.html.parser.SyntaxElement htmlsel = htmlsup.getElementChain(sel.getElementOffset());
203
// while(htmlsel != null) {
204
// //check if the parsing should be cancelled (when there is a change in the parsed document)
205
// if(documentDirty) throw new ParsingCancelledException();
206
// //test if the html element starts right at or after the sel element
207
// //this is necessary due to problems caused by Expression Language-s pieces in an html tag.
208
// if(htmlsel.getElementOffset() >= sel.getElementOffset()) {
209
// if(debug) System.out.println(htmlsel);
210
// if(htmlsel.getType() == org.netbeans.editor.ext.html.parser.SyntaxElement.TYPE_COMMENT) {
211
// if(htmlCommentStartElement == null && htmlsel.getText().startsWith("<!--")) {//NOI18N
212
// if(htmlsel.getText().endsWith("-->"))
213
// found.add(new FoldInfo(htmlsel.getElementOffset(), htmlsel.getElementOffset() + htmlsel.getElementLength(), JspFoldTypes.HTML_COMMENT, JspFoldTypes.HTML_COMMENT_DESCRIPTION));
214
// else
215
// htmlCommentStartElement = htmlsel;
216
// } else if(htmlCommentStartElement != null && htmlsel.getText().endsWith("-->")) { //NOI18N
217
// found.add(new FoldInfo(htmlCommentStartElement.getElementOffset(), htmlsel.getElementOffset() + htmlsel.getElementLength(), JspFoldTypes.HTML_COMMENT, JspFoldTypes.HTML_COMMENT_DESCRIPTION));
218
// htmlCommentStartElement = null;
219
// }
220
// } else if(htmlsel.getType() == org.netbeans.editor.ext.html.parser.SyntaxElement.TYPE_TAG && !htmlsel.getText().startsWith("<")) {
221
// //open html tag
222
// TagSE tse = new TagSE(htmlsel);
223
// handleOpenTagElement(tse, found, stack);
224
// } else if(htmlsel.getType() == org.netbeans.editor.ext.html.parser.SyntaxElement.TYPE_ENDTAG && !htmlsel.getText().startsWith("</")) {
225
// //end html tag
226
// TagSE tse = new TagSE(htmlsel);
227
// handleEndTagElement(tse, found, stack);
228
// }
229
// }
230
// htmlSEEnd = htmlsel.getElementOffset() + htmlsel.getElementLength();
231
// htmlsel = htmlsel.getNext();
232
// //loops detection
233
// if(htmlsel != null) {
234
// if(prevSelOffset>=htmlsel.getElementOffset()) {
235
// notifyLoop(bdoc, prevSelOffset);
236
// return Collections.EMPTY_LIST;
237
// } else {
238
// prevSelOffset = htmlsel.getElementOffset();
239
// }
240
// }
241
// }
242
} else if(sel.getCompletionContext() == JspSyntaxSupport.TAG_COMPLETION_CONTEXT) {
243                 //jsp open tag
244
TagSE tse = new TagSE(sel);
245                 handleOpenTagElement(tse, found, stack);
246             } else if(sel.getCompletionContext() == JspSyntaxSupport.ENDTAG_COMPLETION_CONTEXT ) {
247                 //found jsp end tag
248
TagSE tse = new TagSE(sel);
249                 handleEndTagElement(tse, found, stack);
250             }
251             //start scanning for syntax elements after the offset where HTML scanning stopped
252
//this is necessary since JSP syntax element's are divided by expression language
253
//and the JSP aren't
254
sel = sel.getNext();
255             
256             if(htmlSEEnd != -1 && sel != null) {
257                 int psoffs = sel.getElementOffset();
258                 while(sel != null && (sel.getElementOffset() + sel.getElementLength()) <= htmlSEEnd) {
259                     sel = sel.getNext();
260                     //loops detection
261
if(sel != null) {
262                         if(psoffs>=sel.getElementOffset()) {
263                             notifyLoop(bdoc, psoffs);
264                             return Collections.EMPTY_LIST;
265                         } else {
266                             psoffs = sel.getElementOffset();
267                         }
268                     }
269                 }
270                 htmlSEEnd = -1;
271             }
272             
273             //loops detection
274
if(sel != null) {
275                 if(prevSelOffset>=sel.getElementOffset()) {
276                     notifyLoop(bdoc, prevSelOffset);
277                     return Collections.EMPTY_LIST;
278                 } else {
279                     prevSelOffset = sel.getElementOffset();
280                 }
281             }
282             
283         }
284         
285         return found;
286     }
287     
288     private void notifyLoop(Document JavaDoc doc, int offset) throws BadLocationException JavaDoc {
289         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
290         sb.append("A loop in SyntaxElement-s detected around offset " + offset + " when scanning the document. Please report this and attach the dumped document content:\n");
291         sb.append(">>>>>\n");
292         sb.append(doc.getText(0, doc.getLength()));
293         sb.append("\n<<<<<\n");
294         
295         ErrorManager.getDefault().log(ErrorManager.WARNING, sb.toString());//NOI18N
296
}
297     
298     private void handleOpenTagElement(TagSE tse, List JavaDoc found, Stack JavaDoc stack) {
299         if(tse.isSingletonTag()) {
300             //create element - do not put into stack
301
found.add(new FoldInfo(tse.getElementOffset(), tse.getElementOffset() + tse.getElementLength(), JspFoldTypes.TAG, getSingletonTagFoldName(tse.getTagName())));
302         } else {
303             stack.push(tse);
304         }
305     }
306     
307     private void handleEndTagElement(TagSE tse, List JavaDoc found, Stack JavaDoc stack) {
308         if(!stack.isEmpty()) {
309             TagSE top = (TagSE)stack.peek();
310             assert top.isOpenTag();
311             if(tse.getTagName().equalsIgnoreCase(top.getTagName())) {
312                 //we found corresponding open jsp tag
313
found.add(new FoldInfo(top.getElementOffset(), tse.getElementOffset() + tse.getElementLength(), JspFoldTypes.TAG, getTagFoldName(top.getTagName())));
314                 stack.pop();
315             } else {
316                 //I need to save the pop-ed elements for the case that there isn't
317
//any matching start tag found
318
ArrayList JavaDoc savedElements = new ArrayList JavaDoc();
319                 //this semaphore is used behind the loop to detect whether a
320
//matching start has been found
321
boolean foundStartTag = false;
322                 
323                 while(!stack.isEmpty()) {
324                     TagSE start = (TagSE)stack.pop();
325                     savedElements.add(start);
326                     assert start.isOpenTag();
327                     if(start.getTagName().equalsIgnoreCase(tse.getTagName())) {
328                         //found a matching start tag
329
found.add(new FoldInfo(start.getElementOffset(),
330                                 tse.getElementOffset() + tse.getElementLength(),
331                                 JspFoldTypes.TAG, getTagFoldName(start.getTagName())));
332                         
333                         foundStartTag = true;
334                         break; //break the while loop
335
}
336                 }
337                 if(!foundStartTag) {
338                     //we didn't find any matching start tag =>
339
//return all elements back to the stack
340
for(int i = savedElements.size() - 1; i >= 0; i--) {
341                         stack.push(savedElements.get(i));
342                     }
343                 }
344             }
345         }
346     }
347     
348     private String JavaDoc getSingletonTagFoldName(String JavaDoc tagName) {
349         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
350         sb.append('<');
351         sb.append(tagName);
352         sb.append('/');
353         sb.append('>');
354         return sb.toString();
355     }
356     
357     private String JavaDoc getTagFoldName(String JavaDoc tagName) {
358         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
359         sb.append('<');
360         sb.append(tagName);
361         sb.append(">...</");
362         sb.append(tagName);
363         sb.append('>');
364         return sb.toString();
365     }
366     
367     private synchronized void updateFolds() throws ParsingCancelledException {
368         FoldHierarchy fh = getOperation().getHierarchy();
369         
370         //measure folds generation time
371
long startTime = System.currentTimeMillis();
372         
373         try {
374             //parse document and create a list of FoldInfo-s
375
List JavaDoc generated = generateFolds();
376             
377             if(SHOW_TIMES) System.out.println("[jsp folding] parsing of text of " + getDocument().getProperty(Document.TitleProperty) + " done in " + (System.currentTimeMillis() - startTime) + " millis.");
378             
379 // //the timer is set to null when release() is called on this FoldManager => document is about to be closed
380
// if(timer == null) {
381
// if (debug) System.out.println("release() called -> cancelling folds update"); // NOI18N
382
// return ;
383
// }
384
//filter out one-line folds
385
Iterator JavaDoc itr = generated.iterator();
386             HashSet JavaDoc olfs = new HashSet JavaDoc();
387             while (itr.hasNext()) {
388                 FoldInfo elem = (FoldInfo) itr.next();
389                 if(isOneLineElement(elem)) olfs.add(elem);
390             }
391             generated.removeAll(olfs);
392             
393             
394             //get existing folds
395
List JavaDoc existingFolds = FoldUtilities.findRecursive(fh.getRootFold());
396             assert existingFolds != null : "Existing folds is null!"; // NOI18N
397

398             //...and generate a list of new folds and a list of folds to be removed
399
final HashSet JavaDoc/*<FoldInfo>*/ newborns = new HashSet JavaDoc(generated.size() / 2);
400             final HashSet JavaDoc/*<Fold>*/ zombies = new HashSet JavaDoc(generated.size() / 2);
401             
402             //go through all the parsed elements and compare it with the list of existing folds
403
Iterator JavaDoc genItr = generated.iterator();
404             Hashtable JavaDoc newbornsLinesCache = new Hashtable JavaDoc();
405             HashSet JavaDoc duplicateNewborns = new HashSet JavaDoc();
406             while(genItr.hasNext()) {
407                 FoldInfo fi = (FoldInfo)genItr.next();
408                 if(debug) System.out.println("NEWBORN " + fi);
409                 //do not add more newborns with the same lineoffset
410
int fiLineOffset = Utilities.getLineOffset((BaseDocument)getDocument(), fi.startOffset);
411                 FoldInfo found = (FoldInfo)newbornsLinesCache.get(Integer.valueOf(fiLineOffset));
412                 if(found != null) {
413                     //figure out whether the new element is a descendant of the already added one
414
if(found.endOffset < fi.endOffset) {
415                         //remove the descendant and add the current
416
duplicateNewborns.add(found);
417                     }
418                 }
419                 newbornsLinesCache.put(Integer.valueOf(fiLineOffset), fi); //add line mapping of the current element
420

421                 //try to find a fold for the fold info
422
Fold fs = FoldUtilities.findNearestFold(fh, fi.startOffset);
423                 if(fs != null
424                         && fs.getStartOffset() == fi.startOffset
425                         && fs.getEndOffset() == fi.endOffset) {
426                     //there is a fold with the same boundaries as the FoldInfo
427
if(fi.foldType != fs.getType() || !(fi.description.equals(fs.getDescription()))) {
428                         //the fold has different type or/and description => recreate
429
zombies.add(fs);
430                         newborns.add(fi);
431                     }
432                 } else {
433                     //create a new fold
434
newborns.add(fi);
435                 }
436             }
437             newborns.removeAll(duplicateNewborns);
438             existingFolds.removeAll(zombies);
439             
440             Hashtable JavaDoc linesToFoldsCache = new Hashtable JavaDoc(); //needed by ***
441

442             //remove not existing folds
443
Iterator JavaDoc extItr = existingFolds.iterator();
444             while(extItr.hasNext()) {
445                 Fold f = (Fold)extItr.next();
446 // if(!zombies.contains(f)) { //check if not alread scheduled to remove
447
Iterator JavaDoc genItr2 = generated.iterator();
448                 boolean found = false;
449                 while(genItr2.hasNext()) {
450                     FoldInfo fi = (FoldInfo)genItr2.next();
451                     if(f.getStartOffset() == fi.startOffset
452                             && f.getEndOffset() == fi.endOffset) {
453                         found = true;
454                         break;
455                     }
456                 }
457                 if(!found) {
458                     zombies.add(f);
459                 } else {
460                     //store the fold lineoffset 2 fold mapping
461
int lineoffset = Utilities.getLineOffset((BaseDocument)getDocument(), f.getStartOffset());
462                     linesToFoldsCache.put(Integer.valueOf(lineoffset), f);
463                 }
464 // }
465
}
466             
467             //*** check for all newborns if there isn't any existing fold
468
//starting on the same line which is a descendant of this new fold
469
//if so remove it.
470
Iterator JavaDoc newbornsItr = newborns.iterator();
471             HashSet JavaDoc newbornsToRemove = new HashSet JavaDoc();
472             while(newbornsItr.hasNext()) {
473                 FoldInfo fi = (FoldInfo)newbornsItr.next();
474                 Fold existing = (Fold)linesToFoldsCache.get(Integer.valueOf(Utilities.getLineOffset((BaseDocument)getDocument(), fi.startOffset)));
475                 if(existing != null) {
476                     //test if the fold is my descendant
477
if(existing.getEndOffset() < fi.endOffset) {
478                         //descendant - remove it
479
zombies.add(existing);
480                     } else {
481                         //remove the newborn
482
newbornsToRemove.add(fi);
483                     }
484                 }
485             }
486             newborns.removeAll(newbornsToRemove);
487             
488             if(SHOW_TIMES) System.out.println("[jsp folding] parsing and mangles with elements for " + getDocument().getProperty(Document.TitleProperty) + " done in " + (System.currentTimeMillis() - startTime) + " millis.");
489             
490             //run folds update in event dispatching thread
491
SwingUtilities.invokeAndWait(new Runnable JavaDoc() {
492                 public void run() {
493                     if(debug) System.out.println("updating folds --> locking document!"); // NOI18N
494
//lock the document for changes
495
(getDocument()).readLock();
496                     try {
497                         //lock the hierarchy
498
FoldHierarchy fh = getOperation().getHierarchy();
499                         fh.lock();
500                         try {
501                             //open new transaction
502
FoldHierarchyTransaction fhTran = getOperation().openTransaction();
503                             try {
504                                 //remove outdated folds
505
Iterator JavaDoc i = zombies.iterator();
506                                 while(i.hasNext()) {
507                                     Fold f = (Fold)i.next();
508                                     //test whether the size of the document is greater than zero,
509
//if it is then this means that the document has been closed in editor.
510
if(getDocument().getLength() == 0) break;
511                                     
512                                     if(debug) System.out.println("- removing fold " + f);
513                                     getOperation().removeFromHierarchy(f, fhTran);
514                                 }
515                                 
516                                 //add new folds
517
Iterator JavaDoc newFolds = newborns.iterator();
518                                 while(newFolds.hasNext()) {
519                                     FoldInfo f = (FoldInfo)newFolds.next();
520                                     //test whether the size of the document is greater than zero,
521
//if it is then this means that the document has been closed in editor.
522
if(getDocument().getLength() == 0) break;
523                                     
524                                     if(debug) System.out.println("+ adding fold " + f);
525                                     if(f.startOffset >= 0
526                                             && f.endOffset >= 0
527                                             && f.startOffset < f.endOffset
528                                             && f.endOffset <= getDocument().getLength()) {
529                                         getOperation().addToHierarchy(f.foldType, f.description, false, f.startOffset , f.endOffset , 0, 0, null, fhTran);
530                                     }
531                                 }
532                             }catch(BadLocationException JavaDoc ble) {
533                                 //when the document is closing the hierarchy returns different empty document, grrrr
534
Document JavaDoc fhDoc = getOperation().getHierarchy().getComponent().getDocument();
535                                 if(fhDoc.getLength() > 0) ErrorManager.getDefault().notify(ble);
536                             }finally {
537                                 fhTran.commit();
538                             }
539                         } finally {
540                             fh.unlock();
541                         }
542                     } finally {
543                         (getDocument()).readUnlock();
544                     }
545                     if(debug) System.out.println("document unlocked!"); // NOI18N
546
}
547             });
548             
549             
550         }catch(BadLocationException JavaDoc e) {
551             //in case that the document is about to be closed
552
//the BLE can be throws from some editor utility classes
553
//so we can swallow it in this case
554
Document JavaDoc fhDoc = getOperation().getHierarchy().getComponent().getDocument();
555             if(fhDoc.getLength() > 0) ErrorManager.getDefault().notify(e);
556         }catch(InterruptedException JavaDoc ie) {
557             //do nothing
558
}catch(InvocationTargetException JavaDoc ite) {
559             ErrorManager.getDefault().notify(ite);
560         }catch(ParsingCancelledException pce) {
561             throw new ParsingCancelledException();
562         }catch(Exception JavaDoc e) {
563             //do not let exceptions like NPEs to fall through to the timer's task run method.
564
//if this happens the timer is cancelled and cannot be used anymore
565
ErrorManager.getDefault().notify(e);
566         } finally {
567             if(debug) JspFoldUtils.printFolds(getOperation()); //DEBUG - print folds structure into console
568
}
569         
570         //measure folds generation time
571
foldsGenerationTime = System.currentTimeMillis() - startTime;
572         if(SHOW_TIMES) System.out.println("jsp folding] folds for " + getDocument().getProperty(Document.TitleProperty) + " generated in " + foldsGenerationTime + " millis.");
573         
574     }
575     
576     private boolean isOneLineElement(FoldInfo fi) throws BadLocationException JavaDoc {
577         return Utilities.getLineOffset((BaseDocument)getDocument(), fi.startOffset) == Utilities.getLineOffset((BaseDocument)getDocument(), fi.endOffset);
578     }
579     
580     private boolean foldsBoundariesEquals(Fold f1, Fold f2) {
581         return (f1.getStartOffset() == f2.getStartOffset()
582         && f1.getEndOffset() == f2.getEndOffset());
583     }
584     
585     private int getSetting(String JavaDoc settingName){
586         JTextComponent JavaDoc tc = getOperation().getHierarchy().getComponent();
587         return SettingsUtil.getInteger(org.netbeans.editor.Utilities.getKitClass(tc), settingName, JspSettings.defaultCodeFoldingUpdateInterval);
588     }
589     
590     private BaseDocument getDocument() {
591         return this.doc;
592     }
593     
594     /** Returns a time in milliseconds for how long code folds were generated.
595      * This time doesn't involve running of any code from fold hirarchy.
596      */

597     public long getLastFoldsGenerationTime() {
598         return foldsGenerationTime;
599     }
600     
601     private static class FoldInfo {
602         public int startOffset, endOffset;
603         public FoldType foldType = null;
604         public String JavaDoc description = null;
605         
606         public FoldInfo(int startOffset, int endOffset, FoldType foldType, String JavaDoc description) {
607             this.startOffset = startOffset;
608             this.endOffset = endOffset;
609             this.foldType = foldType;
610             this.description = description;
611         }
612         
613         public String JavaDoc toString() {
614             return "FoldInfo[start=" + startOffset + ", end=" + endOffset + ", descr=" + description + ", type=" + foldType + "]";
615         }
616     }
617     
618     //pretty hacky thing - a replacement of a common ancestor of html and jsp SyntaxElement-s.
619
private static class TagSE {
620         private final org.netbeans.editor.ext.html.parser.SyntaxElement.Named htmlse;
621         private final org.netbeans.modules.web.core.syntax.SyntaxElement.TagLikeElement jspse;
622         
623         public TagSE(Object JavaDoc se) {
624             if(se instanceof org.netbeans.editor.ext.html.parser.SyntaxElement.Named) {
625                 htmlse = (org.netbeans.editor.ext.html.parser.SyntaxElement.Named)se;
626                 jspse = null;
627             } else if(se instanceof org.netbeans.modules.web.core.syntax.SyntaxElement.TagLikeElement) {
628                 htmlse = null;
629                 jspse = (org.netbeans.modules.web.core.syntax.SyntaxElement.TagLikeElement)se;
630             } else {
631                 throw new IllegalArgumentException JavaDoc("Object " + se + " is not a Tag SyntaxElement!");
632             }
633         }
634         
635         
636         public boolean wrapsHTML() {
637             return htmlse != null;
638         }
639         public boolean wrapsJSP() {
640             return !wrapsHTML(); // :-)
641
}
642         
643         public int getElementOffset() {
644             //the HTML syntax has shifted start offset comparing to jsp syntax element
645
return wrapsHTML() ? htmlse.getElementOffset() - 1 : jspse.getElementOffset();
646         }
647         
648         public int getElementLength() {
649             //the HTML syntax has shifted start offset comparing to jsp syntax element
650
return wrapsHTML() ? htmlse.getElementLength() + 1 : jspse.getElementLength();
651         }
652         
653         public int getType() {
654             return wrapsHTML() ? htmlse.getType() : jspse.getCompletionContext();
655         }
656         
657         public boolean isOpenTag() {
658             return wrapsHTML() ? htmlse.getType() == htmlse.TYPE_TAG : jspse.getCompletionContext() == JspSyntaxSupport.TAG_COMPLETION_CONTEXT;
659         }
660         
661         public String JavaDoc getTagName() {
662             return wrapsHTML() ? htmlse.getName() : jspse.getName();
663         }
664         
665         public boolean isSingletonTag() {
666             if(!isOpenTag()) return false;
667             return wrapsHTML() ? ((org.netbeans.editor.ext.html.parser.SyntaxElement.Tag)htmlse).isEmpty() : ((org.netbeans.modules.web.core.syntax.SyntaxElement.Tag)jspse).isClosed();
668         }
669         
670     }
671     
672     private static class ParsingCancelledException extends Exception JavaDoc {
673         public ParsingCancelledException() {
674             super();
675         }
676     }
677     
678     //enable/disable debugging messages for this class
679
private static final boolean debug = false;
680     private static final boolean lightDebug = debug || false;
681 }
682
Popular Tags