KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > retouche > editor > fold > GsfFoldManager


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 package org.netbeans.modules.retouche.editor.fold;
20
21 import java.io.IOException JavaDoc;
22 import java.lang.ref.Reference JavaDoc;
23 import java.lang.ref.WeakReference JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.TreeMap JavaDoc;
29 import java.util.WeakHashMap JavaDoc;
30 import javax.swing.SwingUtilities JavaDoc;
31 import javax.swing.event.DocumentEvent JavaDoc;
32 import javax.swing.text.BadLocationException JavaDoc;
33 import javax.swing.text.Document JavaDoc;
34 import javax.swing.text.Position JavaDoc;
35 import org.netbeans.api.editor.fold.Fold;
36 import org.netbeans.api.editor.fold.FoldType;
37 import org.netbeans.api.gsf.OffsetRange;
38 import org.netbeans.api.gsf.PositionManager;
39 import org.netbeans.api.gsf.StructureScanner;
40 import org.netbeans.api.retouche.source.CompilationInfo;
41 //import org.netbeans.api.timers.TimesCollector;
42
import org.netbeans.editor.BaseDocument;
43 import org.netbeans.modules.retouche.editor.semantic.ScanningCancellableTask;
44 import org.netbeans.spi.editor.fold.FoldHierarchyTransaction;
45 import org.netbeans.spi.editor.fold.FoldManager;
46 import org.netbeans.spi.editor.fold.FoldOperation;
47 import org.openide.ErrorManager;
48 import org.openide.filesystems.FileObject;
49 import org.openide.loaders.DataObject;
50
51 /**
52  * This file is originally from Retouche, the Java Support
53  * infrastructure in NetBeans. I have modified the file as little
54  * as possible to make merging Retouche fixes back as simple as
55  * possible.
56  *
57  * @author Jan Lahoda
58  */

59 public class GsfFoldManager implements FoldManager {
60     
61     private FoldOperation operation;
62     private FileObject file;
63     private JavaElementFoldTask task;
64     private boolean released = true;
65     
66     /** Creates a new instance of GsfFoldManager */
67     public GsfFoldManager() {
68     }
69
70     public void init(FoldOperation operation) {
71         this.operation = operation;
72     }
73
74     public synchronized void initFolds(FoldHierarchyTransaction transaction) {
75         released = false;
76         new Init().run();
77     }
78     
79     private final class Init implements Runnable JavaDoc {
80         public void run() {
81             synchronized (GsfFoldManager.this) {
82                 if (released)
83                     return ;
84             }
85             
86             Document JavaDoc doc = operation.getHierarchy().getComponent().getDocument();
87             DataObject od = (DataObject) doc.getProperty(Document.StreamDescriptionProperty);
88             
89             if (od != null) {
90                 currentFolds = new HashMap JavaDoc<FoldInfo, Fold>();
91                 task = JavaElementFoldTask.getTask(od.getPrimaryFile());
92                 task.setGsfFoldManager(GsfFoldManager.this);
93             }
94         }
95     }
96
97     public void insertUpdate(DocumentEvent JavaDoc evt, FoldHierarchyTransaction transaction) {
98     }
99
100     public void removeUpdate(DocumentEvent JavaDoc evt, FoldHierarchyTransaction transaction) {
101     }
102
103     public void changedUpdate(DocumentEvent JavaDoc evt, FoldHierarchyTransaction transaction) {
104     }
105
106     public void removeEmptyNotify(Fold emptyFold) {
107         currentFolds.remove(operation.getExtraInfo(emptyFold));
108     }
109
110     public void removeDamagedNotify(Fold damagedFold) {
111         currentFolds.remove(operation.getExtraInfo(damagedFold));
112     }
113
114     public void expandNotify(Fold expandedFold) {
115     }
116
117     public synchronized void release() {
118         released = true;
119         if (task != null)
120             task.setGsfFoldManager(null);
121         
122         task = null;
123         file = null;
124         currentFolds = null;
125     }
126     
127     static final class JavaElementFoldTask extends ScanningCancellableTask<CompilationInfo> {
128         
129         //XXX: this will hold JavaElementFoldTask as long as the FileObject exists:
130
private static Map JavaDoc<FileObject, JavaElementFoldTask> file2Task = new WeakHashMap JavaDoc();
131         
132         static JavaElementFoldTask getTask(FileObject file) {
133             JavaElementFoldTask task = file2Task.get(file);
134             
135             if (task == null) {
136                 file2Task.put(file, task = new JavaElementFoldTask());
137             }
138             
139             return task;
140         }
141         
142         private Reference JavaDoc<GsfFoldManager> manager;
143         
144         synchronized void setGsfFoldManager(GsfFoldManager manager) {
145             this.manager = new WeakReference JavaDoc(manager);
146         }
147         
148         public void run(final CompilationInfo info) {
149             GsfFoldManager manager;
150             
151             //the synchronized section should be as limited as possible here
152
//in particular, "scan" should not be called in the synchronized section
153
//or a deadlock could appear: sy(this)+document read lock against
154
//document write lock and this.cancel/sy(this)
155
synchronized (this) {
156                 manager = this.manager != null ? this.manager.get() : null;
157             }
158             
159             if (manager == null)
160                 return ;
161             
162             long startTime = System.currentTimeMillis();
163
164             //final CompilationUnitTree cu = info.getCompilationUnit();
165

166             List JavaDoc<FoldInfo> folds = new ArrayList JavaDoc();
167             
168             BaseDocument doc = null;
169             try {
170                 doc = (BaseDocument)info.getDocument();
171             } catch (IOException JavaDoc ioe) {
172                 org.openide.ErrorManager.getDefault().notify(ioe);
173             }
174             if (doc == null) {
175                 return;
176             }
177             if (info.getParserResult() != null && info.getParserResult().getRoot() != null) {
178                scan(info, folds, doc);
179             }
180
181             if (isCancelled()) {
182                 return;
183             }
184             SwingUtilities.invokeLater(manager.new CommitFolds(folds));
185             
186             long endTime = System.currentTimeMillis();
187             
188             //TimesCollector.getDefault().reportTime(info.getFileObject(), "com-folds-1", "Folds - 1", endTime - startTime);
189
}
190
191         private void scan(CompilationInfo info, List JavaDoc<FoldInfo> folds, BaseDocument doc) {
192             addTree(folds, info, doc);
193         }
194
195         private void addTree(List JavaDoc<FoldInfo> result, CompilationInfo info,
196            BaseDocument doc) {
197             StructureScanner scanner = info.getLanguage().getStructure();
198             if (scanner != null) {
199                 List JavaDoc<OffsetRange> folds = scanner.folds(info);
200                 if (isCancelled()) {
201                     return;
202                 }
203                 for (OffsetRange range : folds) {
204                     addFold(range, result, doc);
205                 }
206             }
207         }
208
209         private void addFold(OffsetRange range, List JavaDoc<FoldInfo> folds, BaseDocument doc) {
210             if (range != OffsetRange.NONE) {
211                 int start = range.getStart();
212                 try {
213                     // Start the fold at the END of the line
214
start = org.netbeans.editor.Utilities.getRowEnd(doc, start);
215                 } catch (BadLocationException JavaDoc ex) {
216                     ErrorManager.getDefault().notify(ex);
217                     start = range.getStart();
218                 }
219                 int end = range.getEnd();
220                 try {
221                     folds.add(new FoldInfo(TYPE_METHOD, doc, start, end));
222                 } catch (BadLocationException JavaDoc ble) {
223                     org.openide.ErrorManager.getDefault().notify(ble);
224                 }
225             }
226         }
227     }
228     
229     private class CommitFolds implements Runnable JavaDoc {
230         
231         private boolean insideRender;
232         private List JavaDoc<FoldInfo> infos;
233         private long startTime;
234         
235         public CommitFolds(List JavaDoc<FoldInfo> infos) {
236             this.infos = infos;
237         }
238         
239         public void run() {
240             if (!insideRender) {
241                 startTime = System.currentTimeMillis();
242                 insideRender = true;
243                 operation.getHierarchy().getComponent().getDocument().render(this);
244                 
245                 return;
246             }
247             
248             operation.getHierarchy().lock();
249             
250             try {
251                 FoldHierarchyTransaction tr = operation.openTransaction();
252                 
253                 try {
254                     if (currentFolds == null)
255                         return ;
256                     
257                     Map JavaDoc<FoldInfo, Fold> added = new TreeMap JavaDoc();
258                     List JavaDoc<FoldInfo> removed = new ArrayList JavaDoc<FoldInfo>(currentFolds.keySet());
259                     
260                     for (FoldInfo i : infos) {
261                         if (removed.remove(i)) {
262                             continue ;
263                         }
264                         
265                         int start = i.start.getOffset();
266                         int end = i.end.getOffset();
267                         
268                         if (end > start) {
269                             Fold f = operation.addToHierarchy(i.type, "{...}", false, start, end, 0, 0, i, tr);
270                             
271                             added.put(i, f);
272                         }
273                     }
274                     
275                     for (FoldInfo i : removed) {
276                         operation.removeFromHierarchy(currentFolds.remove(i), tr);
277                     }
278                     
279                     currentFolds.putAll(added);
280                 } catch (BadLocationException JavaDoc e) {
281                     ErrorManager.getDefault().notify(e);
282                 } finally {
283                     tr.commit();
284                 }
285             } finally {
286                 operation.getHierarchy().unlock();
287             }
288             
289             long endTime = System.currentTimeMillis();
290             
291             //TimesCollector.getDefault().reportTime(file, "java-folds-2", "Folds - 2", endTime - startTime);
292
}
293     }
294     
295     private static final FoldType TYPE_METHOD = new FoldType("java-element-method");
296     //private static final FoldType TYPE_CLASS = new FoldType("java-element-class");
297
//private static final FoldType TYPE_JAVADOC = new FoldType("java-element-javadoc");
298
//private static final FoldType TYPE_INITIAL = new FoldType("java-element-initial");
299

300     private Map JavaDoc<FoldInfo, Fold> currentFolds;
301     
302     protected static final class FoldInfo implements Comparable JavaDoc {
303         
304         private FoldType type;
305         private Position JavaDoc start;
306         private Position JavaDoc end;
307         
308         public FoldInfo(FoldType type, Document JavaDoc doc, int start, int end) throws BadLocationException JavaDoc {
309             this.type = type;
310             
311             // If you invoke code completion while indexing is in progress, the
312
// completion job (which stores the caret offset) will be delayed until
313
// indexing is complete - potentially minutes later. When the job
314
// is finally run we need to make sure the caret position is still valid. (93017)
315
int length = doc.getLength();
316             if (start > length) {
317                 start = length;
318             }
319             if (end > length) {
320                 end = length;
321             }
322             
323             this.start = doc.createPosition(start);
324             this.end = doc.createPosition(end);
325         }
326         
327         public int hashCode() {
328             return 1;
329         }
330         
331         public boolean equals(Object JavaDoc o) {
332             if (!(o instanceof FoldInfo))
333                 return false;
334             
335             return compareTo(o) == 0;
336         }
337         
338         public int compareTo(Object JavaDoc o) {
339             FoldInfo remote = (FoldInfo) o;
340             
341             if (start.getOffset() < remote.start.getOffset()) {
342                 return -1;
343             }
344             
345             if (start.getOffset() > remote.start.getOffset()) {
346                 return 1;
347             }
348             
349             if (end.getOffset() < remote.end.getOffset()) {
350                 return -1;
351             }
352             
353             if (end.getOffset() > remote.end.getOffset()) {
354                 return 1;
355             }
356             
357             return 0;
358         }
359         
360     }
361 }
362
Popular Tags