1 19 20 package org.netbeans.modules.languages; 21 22 import java.io.IOException ; 23 import org.netbeans.modules.languages.features.ActionCreator; 24 import org.netbeans.api.languages.LanguagesManager; 25 import org.netbeans.api.languages.ParseException; 26 import java.beans.PropertyChangeEvent ; 27 import java.beans.PropertyChangeListener ; 28 import java.io.OutputStream ; 29 import java.util.HashSet ; 30 import org.netbeans.modules.languages.parser.LanguageDefinitionNotFoundException; 31 import org.netbeans.api.languages.ParseException; 32 import org.openide.ErrorManager; 33 import org.openide.filesystems.FileAttributeEvent; 34 import org.openide.filesystems.FileChangeListener; 35 import org.openide.filesystems.FileEvent; 36 import org.openide.filesystems.FileObject; 37 import org.openide.filesystems.FileRenameEvent; 38 import org.openide.filesystems.FileSystem; 39 import org.openide.filesystems.FileSystem.AtomicAction; 40 import org.openide.filesystems.FileUtil; 41 import org.openide.filesystems.Repository; 42 import java.io.IOException ; 43 import java.io.InputStream ; 44 import java.util.Collections ; 45 import java.util.Enumeration ; 46 import java.util.HashMap ; 47 import java.util.Iterator ; 48 import java.util.List ; 49 import java.util.Map ; 50 import java.util.Set ; 51 import java.util.Vector ; 52 import org.netbeans.modules.languages.features.ColorsManager; 53 import org.openide.modules.ModuleInfo; 54 import org.openide.util.Lookup; 55 import org.openide.util.LookupEvent; 56 import org.openide.util.LookupListener; 57 58 59 63 public class LanguagesManagerImpl extends LanguagesManager { 64 65 66 public static LanguagesManagerImpl get () { 67 return (LanguagesManagerImpl) LanguagesManager.getDefault (); 68 } 69 70 71 private Lookup.Result<ModuleInfo> result; 72 private LookupListener lookupListener; 73 private PropertyChangeListener moduleInfoListener; 74 private Set <ModuleInfo> moduleInfos; 75 76 77 public LanguagesManagerImpl () { 78 result = Lookup.getDefault ().<ModuleInfo>lookupResult (ModuleInfo.class); 79 lookupListener = new LookupListener () { 80 public void resultChanged (LookupEvent ev) { 81 Set <ModuleInfo> newModules = new HashSet <ModuleInfo> (result.allInstances ()); 82 newModules.removeAll (moduleInfos); 83 Iterator <ModuleInfo> it = newModules.iterator (); 84 while (it.hasNext ()) 85 it.next ().addPropertyChangeListener (moduleInfoListener); 86 Set <ModuleInfo> oldModules = new HashSet <ModuleInfo> (moduleInfos); 87 oldModules.removeAll (result.allInstances ()); 88 it = oldModules.iterator (); 89 while (it.hasNext ()) 90 it.next ().removePropertyChangeListener (moduleInfoListener); 91 moduleInfos = new HashSet <ModuleInfo> (result.allInstances ()); 92 refreshSupportedMimeTypes (); 93 } 94 }; 95 result.addLookupListener (lookupListener); 96 moduleInfoListener = new PropertyChangeListener () { 97 public void propertyChange (PropertyChangeEvent a) { 98 refreshSupportedMimeTypes (); 99 } 100 }; 101 moduleInfos = new HashSet <ModuleInfo> (result.allInstances ()); 102 Iterator <ModuleInfo> it = moduleInfos.iterator (); 103 while (it.hasNext ()) { 104 ModuleInfo info = it.next (); 105 info.addPropertyChangeListener (moduleInfoListener); 106 } 107 } 108 109 private Set <String > mimeTypes = null; 110 111 public Set <String > getSupportedMimeTypes () { 112 if (mimeTypes == null) 113 mimeTypes = loadMimeTypes (); 114 return Collections.<String >unmodifiableSet (mimeTypes); 115 } 116 117 136 private Map <String ,Object > mimeTypeToLanguage = new HashMap <String ,Object > (); 137 138 public synchronized Language getLanguage (String mimeType) 139 throws ParseException { 140 if (!mimeTypeToLanguage.containsKey (mimeType)) { 141 mimeTypeToLanguage.put (mimeType, new ParseException ("Already parisng " + mimeType)); 142 try { 143 FileSystem fs = Repository.getDefault ().getDefaultFileSystem (); 144 FileObject fo = fs.findResource ("Editors/" + mimeType + "/language.nbs"); 145 if (fo == null) 146 throw new LanguageDefinitionNotFoundException 147 ("Language definition for " + mimeType + " not found."); 148 addListener (fo); 149 Language l = NBSLanguageReader.readLanguage (fo, mimeType); 150 initLanguage (l); 151 mimeTypeToLanguage.put (mimeType, l); 153 } catch (ParseException ex) { 154 mimeTypeToLanguage.put (mimeType, ex); 155 throw ex; 156 } catch (Exception ex) { 157 ParseException pe = new ParseException (ex); 158 mimeTypeToLanguage.put (mimeType, pe); 159 throw pe; 160 } 161 } 162 if (mimeTypeToLanguage.get (mimeType) instanceof ParseException) 163 throw (ParseException) mimeTypeToLanguage.get (mimeType); 164 return (Language) mimeTypeToLanguage.get (mimeType); 165 } 166 167 private Vector <LanguagesManagerListener> listeners = new Vector <LanguagesManagerListener> (); 168 169 public void addLanguagesManagerListener (LanguagesManagerListener l) { 170 listeners.add (l); 171 } 172 173 public void removeLanguagesManagerListener (LanguagesManagerListener l) { 174 listeners.remove (l); 175 } 176 177 178 180 private void refreshSupportedMimeTypes () { 181 Set <String > mimeTypes = loadMimeTypes (); 182 if (mimeTypes.equals (this.mimeTypes)) 183 return; 184 Set <String > added = new HashSet <String > (mimeTypes); 185 added.removeAll (this.mimeTypes); 186 Set <String > removed = new HashSet <String > (this.mimeTypes); 187 removed.removeAll (mimeTypes); 188 Iterator <String > it = removed.iterator (); 189 while (it.hasNext ()) { 190 String mimeType = it.next (); 191 this.mimeTypes.remove (mimeType); 192 fireLanguageRemoved (mimeType); 193 } 194 it = added.iterator (); 195 while (it.hasNext ()) { 196 String mimeType = it.next (); 197 this.mimeTypes.add (mimeType); 198 fireLanguageAdded (mimeType); 199 } 200 } 201 202 private void languageChanged (String mimeType) { 203 mimeTypeToLanguage.remove (mimeType); 204 Vector <LanguagesManagerListener> v = (Vector <LanguagesManagerListener>) listeners.clone (); 205 Iterator <LanguagesManagerListener> it = v.iterator (); 206 while (it.hasNext ()) { 207 LanguagesManagerListener l = it.next (); 208 l.languageChanged (mimeType); 209 } 210 } 211 212 private void fireLanguageAdded (String mimeType) { 213 Vector <LanguagesManagerListener> v = (Vector <LanguagesManagerListener>) listeners.clone (); 214 Iterator <LanguagesManagerListener> it = v.iterator (); 215 while (it.hasNext ()) { 216 LanguagesManagerListener l = it.next (); 217 l.languageAdded (mimeType); 218 } 219 } 220 221 private void fireLanguageRemoved (String mimeType) { 222 Vector <LanguagesManagerListener> v = (Vector <LanguagesManagerListener>) listeners.clone (); 223 Iterator <LanguagesManagerListener> it = v.iterator (); 224 while (it.hasNext ()) { 225 LanguagesManagerListener l = it.next (); 226 l.languageRemoved (mimeType); 227 } 228 } 229 230 private Set <FileObject> listeningOn = new HashSet <FileObject> (); 231 private Listener listener; 232 233 private void addListener (FileObject fo) { 234 if (!listeningOn.contains (fo)) { 235 if (listener == null) 236 listener = new Listener (); 237 fo.addFileChangeListener (listener); 238 listeningOn.add (fo); 239 } 240 } 241 242 private void initLanguage (Language l) { 243 try { 244 245 FileSystem fs = Repository.getDefault ().getDefaultFileSystem (); 246 final FileObject root = fs.findResource ("Editors/" + l.getMimeType ()); 247 248 if (root.getFileObject ("Settings.settings") == null) 250 fs.runAtomicAction (new AtomicAction () { 251 public void run () { 252 try { 253 InputStream is = getClass().getClassLoader().getResourceAsStream("org/netbeans/modules/languages/resources/LanguagesOptions.settings"); 254 try { 255 FileObject fo = root.createData("Settings.settings"); 256 OutputStream os = fo.getOutputStream(); 257 try { 258 FileUtil.copy(is, os); 259 } finally { 261 os.close(); 262 } 263 } finally { 264 is.close(); 265 } 266 } catch (IOException ex) { 267 ErrorManager.getDefault ().notify (ex); 268 } 269 } 270 }); 271 272 if (root.getFileObject ("SideBar/org-netbeans-modules-languages-features-CodeFoldingSideBarFactory.instance") == null 274 ) { 276 FileUtil.createData (root, "FoldManager/org-netbeans-modules-languages-features-LanguagesFoldManager$Factory.instance"); 277 FileUtil.createData (root, "SideBar/org-netbeans-modules-languages-features-CodeFoldingSideBarFactory.instance"); 278 FileObject fo = root.getFileObject ("SideBar"); 279 fo.setAttribute ("org-netbeans-editor-GlyphGutter.instance/org-netbeans-modules-languages-features-CodeFoldingSideBarFactory.instance", Boolean.TRUE); 280 } 281 282 if (root.getFileObject ("UpToDateStatusProvider/org-netbeans-modules-languages-features-UpToDateStatusProviderFactoryImpl.instance") == null 284 ) 286 FileUtil.createData (root, "UpToDateStatusProvider/org-netbeans-modules-languages-features-UpToDateStatusProviderFactoryImpl.instance"); 287 288 289 initPopupMenu (root, l); 290 291 if (l.getFeatures ("NAVIGATOR") != null) { 293 String foldFileName = "Navigator/Panels/" + l.getMimeType () + 294 "/org-netbeans-modules-languages-features-LanguagesNavigator.instance"; 295 if (fs.findResource (foldFileName) == null) 296 FileUtil.createData (fs.getRoot (), foldFileName); 297 } 298 299 if (l.getFeatures ("TOOLTIP") != null) 301 FileUtil.createData (root, "ToolTips/org-netbeans-modules-languages-features-ToolTipAnnotation.instance"); 302 303 } catch (IOException ex) { 304 ErrorManager.getDefault ().notify (ex); 305 } 306 307 ColorsManager.initColorings (l); 309 } 310 311 private static void initPopupMenu (FileObject root, Language l) throws IOException { 312 FileObject popup = FileUtil.createFolder (root, "Popup"); 313 createSeparator (popup, "SeparatorAfterSelectInPopupAction", "org-netbeans-modules-editor-NbSelectInPopupAction.instance", null); 314 List <Feature> actions = l.getFeatures ("ACTION"); 315 String lastAction = "SeparatorAfterSelectInPopupAction.instance"; 316 Iterator <Feature> it = actions.iterator (); 317 while (it.hasNext ()) { 318 Feature action = it.next (); 319 if (action.getBoolean ("explorer", false)) 320 continue; 321 String name = action.getSelector ().getAsString (); 322 String displayName= (String ) action.getValue ("name"); 323 String performer = action.getMethodName ("performer"); 324 String enabler = action.getMethodName ("enabled"); 325 String installAfter = (String ) action.getValue ("install_after"); 326 String installBefore = (String ) action.getValue ("install_before"); 327 boolean separatorBefore = action.getBoolean ("separator_before", false); 328 boolean separatorAfter = action.getBoolean ("separator_after", false); 329 FileObject fobj = FileUtil.createData (popup, name + ".instance"); fobj.setAttribute("instanceCreate", new ActionCreator (new Object [] {displayName, performer, enabler})); fobj.setAttribute("instanceClass", "org.netbeans.modules.languages.features.GenericAction"); if (separatorBefore) { 333 createSeparator (popup, name + "_separator_before", installBefore, name + ".instance"); 334 popup.setAttribute (name + "_separator_before/" + name + ".instance", Boolean.TRUE); 335 } else 336 if (installBefore != null) 337 popup.setAttribute (installBefore + "/" + name + ".instance", Boolean.TRUE); 338 else 339 popup.setAttribute (lastAction + "/" + name + ".instance", Boolean.TRUE); 340 if (separatorAfter) { 341 createSeparator (popup, name + "_separator_after", installAfter, name + ".instance"); 342 popup.setAttribute (name + "_separator_after/" + name + ".instance", Boolean.TRUE); 343 } else 344 if (installAfter != null) 345 popup.setAttribute (installAfter + "/" + name + ".instance", Boolean.TRUE); 346 if (installAfter == null && installBefore == null) 347 lastAction = name + ".instance"; 348 } 349 popup.setAttribute (lastAction + "/org-netbeans-modules-languages-features-FormatAction.instance", Boolean.TRUE); 350 FileUtil.createData (popup, "org-netbeans-modules-languages-features-FormatAction.instance"); 351 createSeparator (popup, "SeparatorBeforeCut", "org-netbeans-modules-languages-features-FormatAction.instance", "org-openide-actions-CutAction.instance"); 352 createSeparator (popup, "SeparatorAfterPaste", "org-openide-actions-PasteAction.instance", "generate-fold-popup"); 353 FileUtil.createData (popup, "generate-fold-popup"); 354 } 356 357 private String spacesToDashes(String text) { 358 StringBuffer buf = new StringBuffer (); 359 int length = text.length(); 360 for (int x = 0; x < length; x++) { 361 char c = text.charAt(x); 362 buf.append(Character.isWhitespace(c) ? '_' : c); 363 } 364 return buf.toString(); 365 } 366 367 static Set <String > loadMimeTypes () { 368 Set <String > result = new HashSet <String > (); 369 FileSystem fs = Repository.getDefault ().getDefaultFileSystem (); 370 FileObject root = fs.findResource ("Editors"); 371 Enumeration e1 = root.getChildren (false); 372 while (e1.hasMoreElements ()) { 373 FileObject f1 = (FileObject) e1.nextElement (); 374 if (f1.isData ()) continue; 375 Enumeration e2 = f1.getChildren (false); 376 while (e2.hasMoreElements ()) { 377 FileObject f2 = (FileObject) e2.nextElement (); 378 if (f2.isData ()) continue; 379 FileObject fo = f2.getFileObject ("language.nbs"); 380 if (fo == null) continue; 381 result.add (f1.getName () + '/' + f2.getName ()); 382 } 383 } 384 return result; 385 } 386 387 private static void createSeparator ( 388 FileObject folder, 389 String name, 390 String after, 391 String before 392 ) throws IOException { 393 name += ".instance"; 394 FileObject separator = FileUtil.createData (folder, name); 395 separator.setAttribute ("instanceClass", "javax.swing.JSeparator"); 396 if (after != null) 397 folder.setAttribute (after + "/" + name, Boolean.TRUE); 398 if (before != null) 399 folder.setAttribute (name + "/" + before, Boolean.TRUE); 400 } 401 402 403 405 public static interface LanguagesManagerListener { 406 407 public void languageAdded (String mimeType); 408 public void languageRemoved (String mimeType); 409 public void languageChanged (String mimeType); 410 } 411 412 private class Listener implements FileChangeListener { 413 414 public void fileAttributeChanged (FileAttributeEvent fe) { 415 } 416 public void fileChanged (FileEvent fe) { 417 FileObject fo = fe.getFile (); 418 String mimeType = fo.getParent ().getParent ().getName () + 419 '/' + fo.getParent ().getName (); 420 languageChanged (mimeType); 421 } 422 public void fileDataCreated (FileEvent fe) { 423 } 424 public void fileDeleted (FileEvent fe) { 425 FileObject fo = fe.getFile (); 426 String mimeType = fo.getParent ().getName (); 427 languageChanged (mimeType); 428 } 429 public void fileFolderCreated (FileEvent fe) { 430 } 431 public void fileRenamed (FileRenameEvent fe) { 432 } 433 } 434 } 435 436 437 438 | Popular Tags |