1 19 20 package org.netbeans.modules.xml.text.completion; 21 22 import java.io.IOException ; 23 import java.util.ArrayList ; 24 import java.util.Enumeration ; 25 import java.util.List ; 26 import java.util.LinkedList ; 27 import java.util.Collections ; 28 29 import javax.swing.event.DocumentEvent ; 30 import javax.swing.event.DocumentListener ; 31 import javax.swing.text.BadLocationException ; 32 import javax.swing.text.Document ; 33 import javax.swing.text.Position ; 34 import org.netbeans.api.xml.parsers.DocumentInputSource; 35 import org.netbeans.modules.editor.NbEditorUtilities; 36 import org.netbeans.modules.xml.api.model.ExtendedGrammarQuery; 37 import org.netbeans.modules.xml.api.model.GrammarEnvironment; 38 import org.netbeans.modules.xml.api.model.GrammarQuery; 39 import org.netbeans.modules.xml.api.model.GrammarQueryManager; 40 import org.netbeans.modules.xml.text.syntax.SyntaxElement; 41 import org.netbeans.modules.xml.text.syntax.XMLSyntaxSupport; 42 import org.netbeans.modules.xml.text.syntax.dom.SyntaxNode; 43 import org.openide.filesystems.FileChangeAdapter; 44 import org.openide.filesystems.FileChangeListener; 45 import org.openide.filesystems.FileEvent; 46 import org.openide.filesystems.FileObject; 47 import org.openide.filesystems.FileSystem; 48 import org.openide.loaders.DataObject; 49 import org.openide.text.NbDocument; 50 import org.openide.util.WeakListeners; 51 import org.w3c.dom.Node ; 52 import org.xml.sax.InputSource ; 53 import org.openide.awt.StatusDisplayer; 54 55 61 class GrammarManager extends FileChangeAdapter implements DocumentListener { 62 63 private static final String FILE_PROTOCOL_URI_PREFIX = "file:/"; 65 private ArrayList <FileObject> externalDTDs = new ArrayList (); 66 67 private int state = INVALID; 69 70 static final int VALID = 1; 71 static final int INVALID = 3; 72 73 private GrammarQuery grammar; 75 76 private final XMLSyntaxSupport syntax; 78 private final Document doc; 79 80 private Position [] guarded; 82 83 private Position maxGuarded; 85 86 private int environmentElementsCount = -1; 87 88 91 public GrammarManager(Document doc, XMLSyntaxSupport syntax) { 92 this.doc = doc; 93 this.syntax = syntax; 94 } 95 96 100 public synchronized GrammarQuery getGrammar() { 101 102 switch (state) { 103 case VALID: 104 return grammar; 105 106 case INVALID: 107 loadGrammar(); 108 return grammar; 109 110 default: 111 throw new IllegalStateException (); 112 } 113 } 114 115 116 119 public synchronized void invalidateGrammar() { 120 121 if (state == VALID) { 123 String msg = Util.THIS.getString("MSG_loading_cancel"); 124 StatusDisplayer.getDefault().setStatusText(msg); 125 } 126 127 doc.removeDocumentListener(this); 128 129 for(FileObject fo : externalDTDs) { 131 fo.removeFileChangeListener(this); 133 } 134 externalDTDs.clear(); 135 136 guarded = new Position [0]; 137 state = INVALID; 138 } 139 140 public void fileChanged(FileEvent fe) { 141 invalidateGrammar(); 143 } 144 145 public void fileDeleted(FileEvent fe) { 146 invalidateGrammar(); 147 } 148 149 public void insertUpdate(DocumentEvent e) { 150 checkDocumentEnvironment(e); 153 154 if (isGuarded(e.getOffset(), e.getLength())) { 155 invalidateGrammar(); 156 } 157 } 158 159 public void removeUpdate(DocumentEvent e) { 160 checkDocumentEnvironment(e); 163 164 if (isGuarded(e.getOffset(), e.getLength())) { 165 invalidateGrammar(); 166 } 167 } 168 169 private void checkDocumentEnvironment(DocumentEvent e) { 170 long current = System.currentTimeMillis(); 171 172 try { 173 LinkedList ll = getEnvironmentElements(); 174 if(ll.size() != environmentElementsCount) { 175 invalidateGrammar(); 176 environmentElementsCount = ll.size(); 177 } 178 }catch(BadLocationException ble) {} 179 180 } 181 182 public void changedUpdate(DocumentEvent e) { 183 } 185 186 private boolean isGuarded(int offset, int length) { 187 188 if ((maxGuarded != null) && (offset > maxGuarded.getOffset())) { 190 return false; 191 } 192 193 for (int i = 0; i<guarded.length; i+=2) { 195 int start = guarded[i].getOffset(); 196 int end = guarded[i+1].getOffset(); 197 if (start < offset && offset < end) { 198 return true; 199 } 200 int changeEnd = offset + length; 201 if (offset < start && start < changeEnd) { 202 return true; 203 } 204 } 205 206 return false; 207 } 208 209 210 214 private synchronized void grammarLoaded(GrammarQuery grammar) { 215 216 String status = (grammar != null) ? Util.THIS.getString("MSG_loading_done") 217 : Util.THIS.getString("MSG_loading_failed"); 218 219 this.grammar = grammar == null ? EmptyQuery.INSTANCE : grammar; 220 state = VALID; 221 222 StatusDisplayer.getDefault().setStatusText(status); 223 } 224 225 226 229 private void loadGrammar() { 230 231 232 GrammarQuery loaded = null; 233 try { 234 235 String status = Util.THIS.getString("MSG_loading"); 236 StatusDisplayer.getDefault().setStatusText(status); 237 238 240 try { 241 242 LinkedList ctx = getEnvironmentElements(); 243 InputSource inputSource = new DocumentInputSource(doc); 244 FileObject fileObject = null; 245 Object obj = doc.getProperty(Document.StreamDescriptionProperty); 246 if (obj instanceof DataObject) { 247 DataObject dobj = (DataObject) obj; 248 fileObject = dobj.getPrimaryFile(); 249 } 250 GrammarEnvironment env = new GrammarEnvironment(Collections.enumeration(ctx), inputSource, fileObject); 251 252 254 GrammarQueryManager g = GrammarQueryManager.getDefault(); 255 Enumeration en = g.enabled(env); 256 if (en == null) return; 257 258 260 List positions = new ArrayList (10); 261 int max = 0; 262 263 while (en.hasMoreElements()) { 264 Node next = (Node) en.nextElement(); 265 if (next instanceof SyntaxNode) { 266 SyntaxNode node = (SyntaxNode) next; 267 int start = node.getElementOffset(); 268 int end = start + node.getElementLength(); 269 if (end > max) max = end; 270 Position startPosition = 271 NbDocument.createPosition(doc, start, Position.Bias.Forward); 272 positions.add(startPosition); 273 Position endPosition = 274 NbDocument.createPosition(doc, end, Position.Bias.Backward); 275 positions.add(endPosition); 276 } 277 } 278 279 guarded = (Position []) positions.toArray(new Position [positions.size()]); 280 maxGuarded = NbDocument.createPosition(doc, max, Position.Bias.Backward); 281 282 283 285 loaded = g.getGrammar(env); 286 287 if(loaded instanceof ExtendedGrammarQuery) { 288 for(String resolvedEntity : (List <String >)((ExtendedGrammarQuery)loaded).getResolvedEntities()) { 290 if(!resolvedEntity.startsWith(FILE_PROTOCOL_URI_PREFIX)) continue; 292 293 DataObject docDo = NbEditorUtilities.getDataObject(doc); 294 if(docDo != null) { 295 FileObject docFo = docDo.getPrimaryFile(); 296 if(docFo != null) { 297 try { 298 FileSystem fs = docFo.getFileSystem(); 299 FileObject fo = fs.findResource(resolvedEntity.substring(FILE_PROTOCOL_URI_PREFIX.length())); if(fo != null) { 301 externalDTDs.add(fo); 302 fo.addFileChangeListener((FileChangeListener)WeakListeners.create(FileChangeListener.class, this, doc)); 304 } 306 }catch(IOException e) { 307 e.printStackTrace(); 308 } 309 } 310 } 311 } 312 } 313 314 } catch (BadLocationException ex) { 315 loaded = null; 316 } 317 318 } finally { 319 320 doc.addDocumentListener(GrammarManager.this); 321 322 grammarLoaded(loaded); 323 } 324 } 325 326 private LinkedList getEnvironmentElements() throws BadLocationException { 327 LinkedList ctx = new LinkedList (); 328 SyntaxElement first = syntax.getElementChain(1); 329 while (true) { 330 if (first == null) break; 331 if (first instanceof SyntaxNode) { 332 SyntaxNode node = (SyntaxNode) first; 333 ctx.add(node); 334 if (node.ELEMENT_NODE == node.getNodeType()) { 335 break; 336 } 337 } 338 first = first.getNext(); 339 } 340 return ctx; 341 } 342 } 343 344 | Popular Tags |