1 19 package org.netbeans.modules.retouche.editor.fold; 20 21 import java.io.IOException ; 22 import java.lang.ref.Reference ; 23 import java.lang.ref.WeakReference ; 24 import java.util.ArrayList ; 25 import java.util.HashMap ; 26 import java.util.List ; 27 import java.util.Map ; 28 import java.util.TreeMap ; 29 import java.util.WeakHashMap ; 30 import javax.swing.SwingUtilities ; 31 import javax.swing.event.DocumentEvent ; 32 import javax.swing.text.BadLocationException ; 33 import javax.swing.text.Document ; 34 import javax.swing.text.Position ; 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.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 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 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 { 80 public void run() { 81 synchronized (GsfFoldManager.this) { 82 if (released) 83 return ; 84 } 85 86 Document doc = operation.getHierarchy().getComponent().getDocument(); 87 DataObject od = (DataObject) doc.getProperty(Document.StreamDescriptionProperty); 88 89 if (od != null) { 90 currentFolds = new HashMap <FoldInfo, Fold>(); 91 task = JavaElementFoldTask.getTask(od.getPrimaryFile()); 92 task.setGsfFoldManager(GsfFoldManager.this); 93 } 94 } 95 } 96 97 public void insertUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) { 98 } 99 100 public void removeUpdate(DocumentEvent evt, FoldHierarchyTransaction transaction) { 101 } 102 103 public void changedUpdate(DocumentEvent 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 private static Map <FileObject, JavaElementFoldTask> file2Task = new WeakHashMap (); 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 <GsfFoldManager> manager; 143 144 synchronized void setGsfFoldManager(GsfFoldManager manager) { 145 this.manager = new WeakReference (manager); 146 } 147 148 public void run(final CompilationInfo info) { 149 GsfFoldManager manager; 150 151 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 166 List <FoldInfo> folds = new ArrayList (); 167 168 BaseDocument doc = null; 169 try { 170 doc = (BaseDocument)info.getDocument(); 171 } catch (IOException 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 } 190 191 private void scan(CompilationInfo info, List <FoldInfo> folds, BaseDocument doc) { 192 addTree(folds, info, doc); 193 } 194 195 private void addTree(List <FoldInfo> result, CompilationInfo info, 196 BaseDocument doc) { 197 StructureScanner scanner = info.getLanguage().getStructure(); 198 if (scanner != null) { 199 List <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 <FoldInfo> folds, BaseDocument doc) { 210 if (range != OffsetRange.NONE) { 211 int start = range.getStart(); 212 try { 213 start = org.netbeans.editor.Utilities.getRowEnd(doc, start); 215 } catch (BadLocationException 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 ble) { 223 org.openide.ErrorManager.getDefault().notify(ble); 224 } 225 } 226 } 227 } 228 229 private class CommitFolds implements Runnable { 230 231 private boolean insideRender; 232 private List <FoldInfo> infos; 233 private long startTime; 234 235 public CommitFolds(List <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 <FoldInfo, Fold> added = new TreeMap (); 258 List <FoldInfo> removed = new ArrayList <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 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 } 293 } 294 295 private static final FoldType TYPE_METHOD = new FoldType("java-element-method"); 296 300 private Map <FoldInfo, Fold> currentFolds; 301 302 protected static final class FoldInfo implements Comparable { 303 304 private FoldType type; 305 private Position start; 306 private Position end; 307 308 public FoldInfo(FoldType type, Document doc, int start, int end) throws BadLocationException { 309 this.type = type; 310 311 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 o) { 332 if (!(o instanceof FoldInfo)) 333 return false; 334 335 return compareTo(o) == 0; 336 } 337 338 public int compareTo(Object 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 |