0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.netbeans.modules.gsf;
0042:
0043: import java.beans.PropertyChangeListener;
0044: import java.io.IOException;
0045: import java.io.InputStream;
0046: import java.io.OutputStream;
0047: import java.net.MalformedURLException;
0048: import java.net.URL;
0049: import java.util.ArrayList;
0050: import java.util.Collection;
0051: import java.util.Collections;
0052: import java.util.HashMap;
0053: import java.util.Iterator;
0054: import java.util.List;
0055: import java.util.Map;
0056: import java.util.RandomAccess;
0057: import org.netbeans.api.lexer.Token;
0058: import org.netbeans.api.lexer.TokenId;
0059: import org.netbeans.modules.gsf.api.EmbeddingModel;
0060: import org.netbeans.modules.gsf.api.GsfLanguage;
0061: import org.netbeans.modules.gsf.api.annotations.CheckForNull;
0062: import org.netbeans.modules.gsf.api.annotations.NonNull;
0063: import org.netbeans.api.lexer.TokenHierarchy;
0064: import org.netbeans.api.lexer.TokenSequence;
0065: import org.netbeans.editor.BaseDocument;
0066: import org.netbeans.modules.gsfpath.api.classpath.ClassPath;
0067: import org.netbeans.modules.gsfret.source.usages.ClassIndexManager;
0068: import org.netbeans.modules.gsfpath.spi.classpath.ClassPathFactory;
0069: import org.netbeans.modules.gsfpath.spi.classpath.ClassPathImplementation;
0070: import org.netbeans.modules.gsfpath.spi.classpath.PathResourceImplementation;
0071: import org.openide.filesystems.FileObject;
0072: import org.openide.filesystems.FileSystem;
0073: import org.openide.filesystems.FileSystem.AtomicAction;
0074: import org.openide.filesystems.FileUtil;
0075: import org.openide.filesystems.Repository;
0076: import org.openide.util.Exceptions;
0077: import org.openide.util.Lookup;
0078:
0079: /**
0080: * Registry which locates and provides information about languages supported
0081: * by various plugins.
0082: *
0083: * @author Tor Norbye
0084: */
0085: public class LanguageRegistry implements Iterable<Language> {
0086:
0087: private static LanguageRegistry instance;
0088: private static final String DISPLAY_NAME = "displayName";
0089: private static final String ICON_BASE = "iconBase";
0090: private static final String EXTENSIONS = "extensions";
0091: private static final String LANGUAGE = "language.instance";
0092: private static final String PARSER = "parser.instance";
0093: private static final String COMPLETION = "completion.instance";
0094: private static final String RENAMER = "renamer.instance";
0095: private static final String FORMATTER = "formatter.instance";
0096: private static final String BRACKET_COMPLETION = "bracket.instance";
0097: private static final String DECLARATION_FINDER = "declarationfinder.instance";
0098: private static final String INDEXER = "indexer.instance";
0099: private static final String PALETTE = "palette.instance";
0100: private static final String STRUCTURE = "structure.instance";
0101: private static final String HINTS = "hints.instance";
0102: private static final String SEMANTIC = "semantic.instance";
0103: private static final String OCCURRENCES = "occurrences.instance";
0104:
0105: /** Location in the system file system where languages are registered */
0106: private static final String FOLDER = "GsfPlugins";
0107: private List<Language> languages;
0108: private boolean languagesInitialized;
0109: private Collection<? extends EmbeddingModel> embeddingModels;
0110:
0111: /**
0112: * Creates a new instance of LanguageRegistry
0113: */
0114: public LanguageRegistry() {
0115: initialize();
0116: }
0117:
0118: /** For testing only! */
0119: public void addLanguages(List<Language> newLanguages) {
0120: if (languages != null && languages.size() > 0) {
0121: throw new RuntimeException(
0122: "This is for testing purposes only!!!");
0123: }
0124:
0125: this .languages = newLanguages;
0126: }
0127:
0128: public static synchronized LanguageRegistry getInstance() {
0129: if (instance == null) {
0130: instance = new LanguageRegistry();
0131: }
0132:
0133: return instance;
0134: }
0135:
0136: /**
0137: * Return a language implementation that corresponds to the given file extension,
0138: * or null if no such language is supported
0139: */
0140: public Language getLanguageByExtension(@NonNull
0141: String extension) {
0142: extension = extension.toLowerCase();
0143:
0144: // TODO - create a map if this is slow
0145: for (Language language : this ) {
0146: String[] extensions = language.getExtensions();
0147:
0148: for (int i = 0; i < extensions.length; i++) {
0149: if (extension.equals(extensions[i])) {
0150: return language;
0151: }
0152: }
0153: }
0154:
0155: return null;
0156: }
0157:
0158: /**
0159: * Return a language implementation that corresponds to the given mimeType,
0160: * or null if no such language is supported
0161: */
0162: public Language getLanguageByMimeType(@NonNull
0163: String mimeType) {
0164: if (languages == null) {
0165: return null;
0166: }
0167:
0168: assert mimeType.equals(mimeType.toLowerCase()) : mimeType;
0169: assert languages instanceof RandomAccess;
0170:
0171: for (int i = 0, n = languages.size(); i < n; i++) {
0172: Language language = languages.get(i);
0173: if (language.getMimeType().equals(mimeType)) {
0174: return language;
0175: }
0176: }
0177:
0178: return null;
0179: }
0180:
0181: @CheckForNull
0182: public EmbeddingModel getEmbedding(@NonNull
0183: String targetMimeType, @NonNull
0184: String sourceMimeType) {
0185: Collection<? extends EmbeddingModel> models = getEmbeddingModels();
0186:
0187: for (EmbeddingModel model : models) {
0188: if (model.getTargetMimeType().equals(targetMimeType)
0189: && model.getSourceMimeTypes().contains(
0190: sourceMimeType)) {
0191: return model;
0192: }
0193: }
0194:
0195: return null;
0196: }
0197:
0198: private Collection<? extends EmbeddingModel> getEmbeddingModels() {
0199: if (embeddingModels == null) {
0200: embeddingModels = Lookup.getDefault().lookupAll(
0201: EmbeddingModel.class);
0202: }
0203:
0204: return embeddingModels;
0205: }
0206:
0207: private Map<String, Map<String, Boolean>> relevantMimes = new HashMap<String, Map<String, Boolean>>();
0208:
0209: /** Return true iff the given file object is relevant for the given mimeType.
0210: * This is true when the file is of a mime type that we're looking for, or if there
0211: * is an embedding model mapping available for the given file's mime type targeting
0212: * the requested mime type.
0213: */
0214: public boolean isRelevantFor(FileObject fo, String targetMimeType) {
0215: final String fileMimeType = fo.getMIMEType();
0216: if (targetMimeType.equals(fileMimeType)) {
0217: return true;
0218: }
0219:
0220: Map<String, Boolean> mimeMap = relevantMimes
0221: .get(targetMimeType);
0222: if (mimeMap == null) {
0223: mimeMap = new HashMap<String, Boolean>();
0224: relevantMimes.put(targetMimeType, mimeMap);
0225: }
0226:
0227: Boolean result = mimeMap.get(fileMimeType);
0228: if (result == null) {
0229: // Check to see if the file is relevant
0230: result = Boolean.FALSE;
0231:
0232: Collection<? extends EmbeddingModel> models = getEmbeddingModels();
0233: for (EmbeddingModel model : models) {
0234: if (model.getTargetMimeType().equals(targetMimeType)
0235: && model.getSourceMimeTypes().contains(
0236: fileMimeType)) {
0237: result = Boolean.TRUE;
0238: break;
0239: }
0240: }
0241:
0242: mimeMap.put(fileMimeType, result);
0243: }
0244:
0245: return result.booleanValue();
0246: }
0247:
0248: @NonNull
0249: public List<Language> getApplicableLanguages(String mimeType) {
0250: // TODO - cache the answer since this is called a lot (for example during
0251: // task list scanning)
0252: Collection<? extends EmbeddingModel> models = getEmbeddingModels();
0253:
0254: List<Language> result = new ArrayList<Language>(5);
0255:
0256: final Language origLanguage = getLanguageByMimeType(mimeType);
0257: if (origLanguage != null) {
0258: result.add(origLanguage);
0259: }
0260:
0261: for (EmbeddingModel model : models) {
0262: if (model.getSourceMimeTypes().contains(mimeType)) {
0263: Language language = getLanguageByMimeType(model
0264: .getTargetMimeType());
0265: if (language != null && !result.contains(language)) {
0266: result.add(language);
0267: }
0268: }
0269: }
0270:
0271: return result;
0272: }
0273:
0274: private ClassPath libraryPath;
0275: private List<URL> urls;
0276:
0277: public List<URL> getLibraryUrls() {
0278: if (urls == null) {
0279: urls = new ArrayList<URL>();
0280: for (Language language : this ) {
0281: GsfLanguage gsfLanguage = language.getGsfLanguage();
0282: if (gsfLanguage != null) {
0283: for (FileObject fo : gsfLanguage.getCoreLibraries()) {
0284: try {
0285: URL url = FileUtil.toFile(fo).toURI()
0286: .toURL();
0287: urls.add(url);
0288: ClassIndexManager.get(language)
0289: .addBootRoot(url);
0290: } catch (MalformedURLException ex) {
0291: Exceptions.printStackTrace(ex);
0292: }
0293: }
0294: }
0295: }
0296: }
0297:
0298: return urls;
0299: }
0300:
0301: public List<FileObject> getLibraryFos() {
0302: List<FileObject> fos = new ArrayList<FileObject>();
0303: for (Language language : this ) {
0304: GsfLanguage gsfLanguage = language.getGsfLanguage();
0305: if (gsfLanguage != null) {
0306: for (FileObject fo : gsfLanguage.getCoreLibraries()) {
0307: fos.add(fo);
0308: }
0309: }
0310: }
0311:
0312: return fos;
0313: }
0314:
0315: public ClassPath getLibraryPaths() {
0316: if (libraryPath == null) {
0317: List<URL> urlList = getLibraryUrls();
0318: final URL[] urlArray = urlList.toArray(new URL[urlList
0319: .size()]);
0320:
0321: libraryPath = ClassPathFactory
0322: .createClassPath(new ClassPathImplementation() {
0323:
0324: public List<? extends PathResourceImplementation> getResources() {
0325: return Collections
0326: .<PathResourceImplementation> singletonList(new PathResourceImplementation() {
0327: public URL[] getRoots() {
0328: return urlArray;
0329: }
0330:
0331: public ClassPathImplementation getContent() {
0332: return null;
0333: }
0334:
0335: public void addPropertyChangeListener(
0336: PropertyChangeListener listener) {
0337: }
0338:
0339: public void removePropertyChangeListener(
0340: PropertyChangeListener listener) {
0341: }
0342: });
0343: }
0344:
0345: public void addPropertyChangeListener(
0346: PropertyChangeListener listener) {
0347: }
0348:
0349: public void removePropertyChangeListener(
0350: PropertyChangeListener listener) {
0351: }
0352:
0353: });
0354: }
0355:
0356: return libraryPath;
0357: }
0358:
0359: private void addLanguages(List<Language> result, TokenSequence ts,
0360: int offset) {
0361: ts.move(offset);
0362: if (ts.moveNext() || ts.movePrevious()) {
0363: TokenSequence ets = ts.embedded();
0364: if (ets != null) {
0365: addLanguages(result, ets, offset); // Recurse
0366: }
0367: String mimeType = ts.language().mimeType();
0368: Language language = getLanguageByMimeType(mimeType);
0369:
0370: if (language != null) {
0371: result.add(language);
0372: }
0373: }
0374: }
0375:
0376: public List<Language> getEmbeddedLanguages(BaseDocument doc,
0377: int offset) {
0378: List<Language> result = new ArrayList<Language>();
0379:
0380: doc.readLock(); // Read-lock due to Token hierarchy use
0381: try {
0382: TokenSequence ts = TokenHierarchy.get(doc).tokenSequence();
0383: if (ts != null) {
0384: addLanguages(result, ts, offset);
0385: }
0386: } finally {
0387: doc.readUnlock();
0388: }
0389:
0390: String mimeType = (String) doc.getProperty("mimeType"); // NOI18N
0391: if (mimeType != null) {
0392: Language language = LanguageRegistry.getInstance()
0393: .getLanguageByMimeType(mimeType);
0394: if (language != null) {
0395: result.add(language);
0396: }
0397: }
0398:
0399: return result;
0400: }
0401:
0402: /**
0403: * Return true iff the given mimeType is supported by a registered language plugin
0404: * @return True iff the given mimeType is supported
0405: */
0406: public boolean isSupported(@NonNull
0407: String mimeType) {
0408: if (mimeType == null) {
0409: return false;
0410: }
0411: for (Language language : this ) {
0412: if (mimeType.equals(language.getMimeType())) {
0413: return true;
0414: }
0415: }
0416:
0417: return false;
0418: }
0419:
0420: public String getLanguagesDisplayName() {
0421: StringBuilder sb = new StringBuilder();
0422: for (Language language : this ) {
0423: if (sb.length() > 0) {
0424: sb.append(", ");
0425: }
0426: sb.append(language.getDisplayName());
0427: }
0428:
0429: return sb.toString();
0430: }
0431:
0432: public Iterator<Language> iterator() {
0433: if (languages == null) {
0434: return new Iterator<Language>() {
0435:
0436: public boolean hasNext() {
0437: return false;
0438: }
0439:
0440: public Language next() {
0441: return null;
0442: }
0443:
0444: public void remove() {
0445: }
0446: };
0447: } else {
0448: return languages.iterator();
0449: }
0450: }
0451:
0452: private synchronized void initialize() {
0453: if (languages == null) {
0454: readSfs();
0455:
0456: initializeLanguages();
0457: }
0458: }
0459:
0460: synchronized void initializeLanguages() {
0461: if (languagesInitialized) {
0462: return;
0463: }
0464:
0465: languagesInitialized = true;
0466:
0467: if (languages == null) {
0468: // No registered languages
0469: return;
0470: }
0471:
0472: Iterator it = languages.iterator();
0473:
0474: while (it.hasNext()) {
0475: final Language language = (Language) it.next();
0476:
0477: initializeLanguage(language);
0478:
0479: // I had hoped to lazily initialize editors
0480: // but the Options panel is eagerly (at startup) caching the
0481: // set of mime folders that provide NetBeans/Defaults/coloring.xml
0482: // in the system file system, and only those are listed in the
0483: // Languages list for syntax editing.
0484: // One thing I can do here, is ONLY populate the coloring in advance
0485: // and leave the other portions for later - but coloring is probably
0486: // the most expensive file to compute anyway. Luckily, this should
0487: // only have to be done once - it will not be updated on subsequent
0488: // IDE starts until the user dir is removed.
0489: // Actually, this causes some real serious problems. DataLoader registration
0490: // doesn't happen in just one go - and here, the call to initializeLanguageForEditor will
0491: // be called before all loaders have been registered (I was seeing it with RhtmlDataLoader)
0492: // but the list will be fixed (because DataLoaderPool calls down to the LoaderPoolNode
0493: // and copies it list before it's done, and doesn't know to refresh itself).
0494: //
0495: // Perhaps I can work around this by adding some specific MIME folder registrations
0496: // early, but not do full initialization? I specifically need to avoid any calls into
0497: // the DataObject area - which initializeLanguageForEditor will do when instantiating the
0498: // registered scanners etc.
0499: // SwingUtilities.invokeLater(new Runnable() {
0500: // // Gotta invoke later because if it's done as part of DataLoader initialization,
0501: // // loader registration fails and our files are not recognized
0502: // public void run() {
0503: // initializeLanguageForEditor(language);
0504: // }
0505: // });
0506: }
0507: }
0508:
0509: private void readSfs() {
0510: FileSystem sfs = Repository.getDefault().getDefaultFileSystem();
0511: FileObject f = sfs.findResource(FOLDER);
0512:
0513: if (f == null) {
0514: return;
0515: }
0516:
0517: // Read languages
0518: FileObject[] children = f.getChildren();
0519: languages = new ArrayList<Language>();
0520:
0521: for (int i = 0; i < children.length; i++) {
0522: FileObject mimePrefixFile = children[i];
0523:
0524: // Read languages
0525: FileObject[] innerChildren = mimePrefixFile.getChildren();
0526:
0527: for (int j = 0; j < innerChildren.length; j++) {
0528: FileObject mimeFile = innerChildren[j];
0529:
0530: String mime = mimePrefixFile.getName() + "/"
0531: + mimeFile.getName();
0532: DefaultLanguage language = new DefaultLanguage(mime);
0533: languages.add(language);
0534:
0535: String displayName = (String) mimeFile
0536: .getAttribute(DISPLAY_NAME);
0537:
0538: /*
0539: public String getLanguageName (String mimeType) {
0540: if (!mimeTypeToName.containsKey (mimeType)) {
0541: FileSystem fs = Repository.getDefault ().getDefaultFileSystem ();
0542: FileObject fo = fs.findResource ("Editors/" + mimeType);
0543: if (fo == null) return "???";
0544: String bundleName = (String) fo.getAttribute ("SystemFileSystem.localizingBundle");
0545: String name = mimeType;
0546: if (bundleName != null)
0547: try {
0548: name = NbBundle.getBundle (bundleName).getString (mimeType);
0549: } catch (MissingResourceException ex) {}
0550: mimeTypeToName.put (mimeType, name);
0551: }
0552: return (String) mimeTypeToName.get (mimeType);
0553: }
0554: */
0555: if ((displayName != null) && (displayName.length() > 0)) {
0556: language.setDisplayName(displayName);
0557: }
0558:
0559: Boolean useCustomEditorKit = (Boolean) mimeFile
0560: .getAttribute("useCustomEditorKit"); // NOI18N
0561: if (useCustomEditorKit != null
0562: && useCustomEditorKit.booleanValue()) {
0563: language.setUseCustomEditorKit(true);
0564: }
0565:
0566: // Try to obtain icon from (new) IDE location for icons per mime type:
0567: FileObject loaderMimeFile = sfs.findResource("Loaders/"
0568: + mime);
0569:
0570: if (loaderMimeFile != null) {
0571: String iconBase = (String) loaderMimeFile
0572: .getAttribute(ICON_BASE);
0573:
0574: if ((iconBase != null) && (iconBase.length() > 0)) {
0575: language.setIconBase(iconBase);
0576: }
0577: }
0578:
0579: //Local icon registration in the Languages/ folder
0580: //String iconBase = (String)mimeFile.getAttribute(ICON_BASE);
0581: //
0582: //if ((iconBase != null) && (iconBase.length() > 0)) {
0583: // language.setIconBase(iconBase);
0584: //}
0585: // Look for extensions, scanners, parsers, etc.
0586: FileObject extensionsDir = mimeFile.getFileObject(
0587: EXTENSIONS, null);
0588:
0589: if ((extensionsDir != null) && extensionsDir.isFolder()) {
0590: FileObject[] extensionFiles = extensionsDir
0591: .getChildren();
0592:
0593: for (int k = 0; k < extensionFiles.length; k++) {
0594: String extension = extensionFiles[k].getName();
0595: language.addExtension(extension);
0596: }
0597: }
0598:
0599: FileObject languageFile = mimeFile.getFileObject(
0600: LANGUAGE, null);
0601:
0602: if (languageFile != null) {
0603: language.setGsfLanguageFile(languageFile);
0604: }
0605:
0606: FileObject parserFile = mimeFile.getFileObject(PARSER,
0607: null);
0608:
0609: if (parserFile != null) {
0610: language.setParserFile(parserFile);
0611: }
0612:
0613: FileObject completionFile = mimeFile.getFileObject(
0614: COMPLETION, null);
0615:
0616: if (completionFile != null) {
0617: language.setCompletionProviderFile(completionFile);
0618: }
0619:
0620: FileObject renamerFile = mimeFile.getFileObject(
0621: RENAMER, null);
0622:
0623: if (renamerFile != null) {
0624: language.setInstantRenamerFile(renamerFile);
0625: }
0626:
0627: FileObject formatterFile = mimeFile.getFileObject(
0628: FORMATTER, null);
0629:
0630: if (formatterFile != null) {
0631: language.setFormatterFile(formatterFile);
0632: }
0633:
0634: FileObject finderFile = mimeFile.getFileObject(
0635: DECLARATION_FINDER, null);
0636:
0637: if (finderFile != null) {
0638: language.setDeclarationFinderFile(finderFile);
0639: }
0640:
0641: FileObject bracketFile = mimeFile.getFileObject(
0642: BRACKET_COMPLETION, null);
0643:
0644: if (bracketFile != null) {
0645: language.setBracketCompletionFile(bracketFile);
0646: }
0647:
0648: FileObject indexerFile = mimeFile.getFileObject(
0649: INDEXER, null);
0650:
0651: if (indexerFile != null) {
0652: language.setIndexerFile(indexerFile);
0653: }
0654:
0655: FileObject structureFile = mimeFile.getFileObject(
0656: STRUCTURE, null);
0657:
0658: if (structureFile != null) {
0659: language.setStructureFile(structureFile);
0660: }
0661:
0662: FileObject hintsFile = mimeFile.getFileObject(HINTS,
0663: null);
0664:
0665: if (hintsFile != null) {
0666: language.setHintsProviderFile(hintsFile);
0667: }
0668:
0669: FileObject paletteFile = mimeFile.getFileObject(
0670: PALETTE, null);
0671:
0672: if (paletteFile != null) {
0673: language.setPaletteFile(paletteFile);
0674: }
0675:
0676: FileObject semanticFile = mimeFile.getFileObject(
0677: SEMANTIC, null);
0678:
0679: if (semanticFile != null) {
0680: language.setSemanticAnalyzer(semanticFile);
0681: }
0682:
0683: FileObject occurrencesFile = mimeFile.getFileObject(
0684: OCCURRENCES, null);
0685:
0686: if (occurrencesFile != null) {
0687: language.setOccurrencesFinderFile(occurrencesFile);
0688: }
0689: }
0690: }
0691: }
0692:
0693: /**
0694: * Based on code from Schliemann
0695: *
0696: * @author Jan Jancura
0697: */
0698: private void initializeLanguage(Language language) {
0699: FileSystem fs = Repository.getDefault().getDefaultFileSystem();
0700:
0701: // I can't call language.getStructure() here - it causes initialization
0702: // of the language objects too early (before registry is populated),
0703: // so just check if we potentially have a structure scanner
0704: if (((DefaultLanguage) language).hasStructureScanner()) {
0705: String navFileName = "Navigator/Panels/"
0706: + language.getMimeType()
0707: + "/org-netbeans-modules-gsfret-navigation-ClassMemberPanel.instance";
0708:
0709: FileObject fo = fs.findResource(navFileName);
0710:
0711: if (fo == null) {
0712: try {
0713: FileUtil.createData(fs.getRoot(), navFileName);
0714: } catch (IOException ex) {
0715: Exceptions.printStackTrace(ex);
0716: }
0717: }
0718: } else {
0719: // Remove obsolete panel file
0720: String navFileName = "Navigator/Panels/"
0721: + language.getMimeType()
0722: + "/org-netbeans-modules-gsfret-navigation-ClassMemberPanel.instance";
0723:
0724: FileObject old = fs.findResource(navFileName);
0725:
0726: if (old != null) {
0727: try {
0728: old.delete();
0729: } catch (IOException ex) {
0730: Exceptions.printStackTrace(ex);
0731: }
0732: }
0733: }
0734:
0735: String oldNavFileName = "Navigator/Panels/"
0736: + language.getMimeType()
0737: + "/org-netbeans-modules-retouche-navigation-ClassMemberPanel.instance";
0738: // Delete the old navigator description - I have moved the class name
0739: FileObject old = fs.findResource(oldNavFileName);
0740:
0741: if (old != null) {
0742: try {
0743: old.delete();
0744: } catch (IOException ex) {
0745: Exceptions.printStackTrace(ex);
0746: }
0747: }
0748: }
0749:
0750: /**
0751: * Delayed initialization of editor settings for a language, until the editor
0752: * requests the info via mime lookup.
0753: *
0754: * @todo Ensure that the Options dialog also uses Mime lookup such that this
0755: * is initialized in time.
0756: *
0757: * Based on code from Schliemann
0758: *
0759: * @author Jan Jancura
0760: */
0761: void initializeLanguageForEditor(Language l) {
0762: FileSystem fs = Repository.getDefault().getDefaultFileSystem();
0763: final FileObject root = fs.findResource("Editors/"
0764: + l.getMimeType()); // NOI18N
0765: if (root.getFileObject("Settings.settings") == null) {
0766: // NOI18N
0767: try {
0768: fs.runAtomicAction(new AtomicAction() {
0769:
0770: public void run() {
0771: try {
0772: InputStream is = getClass()
0773: .getClassLoader()
0774: .getResourceAsStream(
0775: "org/netbeans/modules/gsf/GsfOptions.settings"); // NOI18N
0776: try {
0777: FileObject fo = root
0778: .createData("Settings.settings"); // NOI18N
0779: OutputStream os = fo.getOutputStream();
0780:
0781: try {
0782: FileUtil.copy(is, os);
0783: } finally {
0784: os.close();
0785: }
0786: } finally {
0787: is.close();
0788: }
0789: } catch (IOException ex) {
0790: Exceptions.printStackTrace(ex);
0791: }
0792: }
0793: });
0794: } catch (IOException ex) {
0795: Exceptions.printStackTrace(ex);
0796: }
0797: }
0798:
0799: // init code folding bar
0800: if ((root
0801: .getFileObject("SideBar/org-netbeans-modules-editor-gsfret-GsfCodeFoldingSideBarFactory.instance") == null)
0802: && (l.getParser() != null)) {
0803: // XXX Don't construct a new parser just to see this!
0804: try {
0805: //FileUtil.createData (root, "FoldManager/org-netbeans-editor-CustomFoldManager$Factory.instance");
0806: FileUtil
0807: .createData(
0808: root,
0809: "FoldManager/org-netbeans-modules-gsfret-editor-fold-GsfFoldManagerFactory.instance");
0810: FileUtil
0811: .createData(
0812: root,
0813: "SideBar/org-netbeans-modules-editor-gsfret-GsfCodeFoldingSideBarFactory.instance")
0814: .setAttribute("position", 1200);
0815: } catch (IOException ex) {
0816: Exceptions.printStackTrace(ex);
0817: }
0818: }
0819:
0820: boolean checkUserdirUpgrade = false;
0821: // Delete old names present up to and including beta2
0822: FileObject oldSidebar = root
0823: .getFileObject("SideBar/org-netbeans-modules-editor-retouche-GsfCodeFoldingSideBarFactory.instance");
0824:
0825: if (oldSidebar != null) {
0826: checkUserdirUpgrade = true;
0827: try {
0828: oldSidebar.delete();
0829: oldSidebar = root
0830: .getFileObject("FoldManager/org-netbeans-modules-retouche-editor-fold-GsfFoldManagerFactory.instance");
0831: if (oldSidebar != null) {
0832: oldSidebar.delete();
0833: }
0834: } catch (IOException ex) {
0835: Exceptions.printStackTrace(ex);
0836: }
0837: }
0838:
0839: // init hyperlink provider
0840: FileObject hyperlinkProvider = root
0841: .getFileObject("HyperlinkProviders/GsfHyperlinkProvider.instance");
0842: if (hyperlinkProvider == null) {
0843: try {
0844: hyperlinkProvider = FileUtil
0845: .createData(root,
0846: "HyperlinkProviders/GsfHyperlinkProvider.instance");
0847: hyperlinkProvider
0848: .setAttribute("instanceClass",
0849: "org.netbeans.modules.gsfret.editor.hyperlink.GsfHyperlinkProvider");
0850: hyperlinkProvider
0851: .setAttribute("instanceOf",
0852: "org.netbeans.lib.editor.hyperlink.spi.HyperlinkProviderExt");
0853: } catch (IOException ex) {
0854: Exceptions.printStackTrace(ex);
0855: }
0856: } else {
0857: if (checkUserdirUpgrade
0858: && "org.netbeans.modules.retouche.editor.hyperlink.GsfHyperlinkProvider"
0859: .equals(hyperlinkProvider
0860: .getAttribute("instanceClass"))) {
0861: // Userdir upgrade
0862: try {
0863: hyperlinkProvider
0864: .setAttribute("instanceClass",
0865: "org.netbeans.modules.gsfret.editor.hyperlink.GsfHyperlinkProvider");
0866: } catch (IOException ex) {
0867: Exceptions.printStackTrace(ex);
0868: }
0869: }
0870: if ("org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider"
0871: .equals(hyperlinkProvider
0872: .getAttribute("instanceOf"))) {
0873: // Userdir upgrade
0874: try {
0875: hyperlinkProvider
0876: .setAttribute("instanceOf",
0877: "org.netbeans.lib.editor.hyperlink.spi.HyperlinkProviderExt");
0878: } catch (IOException ex) {
0879: Exceptions.printStackTrace(ex);
0880: }
0881: }
0882: }
0883:
0884: // Context menu
0885: FileObject popup = root.getFileObject("Popup");
0886: if (popup == null) {
0887: try {
0888: popup = root.createFolder("Popup");
0889: } catch (Exception ex) {
0890: Exceptions.printStackTrace(ex);
0891: }
0892: }
0893:
0894: // I can't just do popup!=null to see if I need to dynamically add gsf
0895: // menu items because modules may have registered additional Popup
0896: // items, so the layer will contain Popup already
0897: FileObject ref = popup.getFileObject("in-place-refactoring");
0898:
0899: if (ref == null) {
0900: try {
0901: popup.createData("in-place-refactoring").setAttribute(
0902: "position", 680);
0903: FileObject gotoF = popup.getFileObject("goto");
0904: if (gotoF == null) {
0905: gotoF = popup.createFolder("goto");
0906: gotoF.setAttribute("position", 500);
0907: }
0908: gotoF.setAttribute("SystemFileSystem.localizingBundle",
0909: "org.netbeans.modules.gsf.Bundle");
0910: gotoF.createData("goto-declaration").setAttribute(
0911: "position", 500);
0912: gotoF.createData("goto").setAttribute("position", 600); // Goto by linenumber
0913: // What about goto-source etc?
0914: // TODO: Goto Type (integrate with Java's GotoType)
0915: // Temporary - userdir upgrade
0916: if (popup.getFileObject("SeparatorBeforeCut.instance") == null) {
0917: FileObject sep = popup
0918: .createData("SeparatorBeforeCut.instance");
0919: sep.setAttribute("instanceClass",
0920: "javax.swing.JSeparator");
0921: // Should be before org-netbeans-modules-editor-NbSelectInPopupAction.instance & org-openide-actions-CutAction.instance:
0922: sep.setAttribute("position", 1200);
0923: }
0924: if (popup.getFileObject("format") == null) {
0925: popup.createData("format").setAttribute("position",
0926: 750);
0927: }
0928: FileObject sep2 = popup
0929: .createData("SeparatorAfterFormat.instance");
0930: sep2.setAttribute("instanceClass",
0931: "javax.swing.JSeparator");
0932: // Should be between org-openide-actions-PasteAction.instance and format
0933: sep2.setAttribute("position", 780);
0934: // Temporary - userdir upgrade
0935: // Obsolete - nuke
0936: if (checkUserdirUpgrade
0937: && popup.getFileObject("pretty-print") != null) {
0938: popup.getFileObject("pretty-print").delete();
0939: }
0940: } catch (IOException ex) {
0941: Exceptions.printStackTrace(ex);
0942: }
0943: } else {
0944: if (checkUserdirUpgrade
0945: && popup.getFileObject("generate-goto-popup") != null) {
0946: FileObject f = popup
0947: .getFileObject("generate-goto-popup");
0948:
0949: try {
0950: f.delete();
0951: } catch (IOException ioe) {
0952: Exceptions.printStackTrace(ioe);
0953: }
0954: }
0955:
0956: // Temporary userdir upgrade
0957: if (checkUserdirUpgrade
0958: && root.getFileObject("Popup/format") == null) {
0959: try {
0960: popup.createData("format");
0961: } catch (IOException ex) {
0962: Exceptions.printStackTrace(ex);
0963: }
0964: }
0965:
0966: // Obsolete - nuke
0967: if (checkUserdirUpgrade
0968: && root.getFileObject("Popup/pretty-print") != null) {
0969: try {
0970: FileObject d = root
0971: .getFileObject("Popup/pretty-print");
0972: d.delete();
0973: } catch (IOException ex) {
0974: Exceptions.printStackTrace(ex);
0975: }
0976: }
0977: }
0978:
0979: // Service to show if file is compileable or not
0980: if (root
0981: .getFileObject("UpToDateStatusProvider/org-netbeans-modules-gsfret-hints-GsfUpToDateStateProviderFactory.instance") == null) {
0982: try {
0983: FileUtil
0984: .createData(
0985: root,
0986: "UpToDateStatusProvider/org-netbeans-modules-gsfret-hints-GsfUpToDateStateProviderFactory.instance");
0987: } catch (IOException ex) {
0988: Exceptions.printStackTrace(ex);
0989: }
0990: }
0991: if (checkUserdirUpgrade) {
0992: // Delete old name present up to and including beta2
0993: FileObject old = root
0994: .getFileObject("UpToDateStatusProvider/org-netbeans-modules-retouche-hints-GsfUpToDateStateProviderFactory.instance");
0995: if (old != null) {
0996: try {
0997: old.delete();
0998: } catch (IOException ex) {
0999: Exceptions.printStackTrace(ex);
1000: }
1001: }
1002: }
1003:
1004: // I'm not sure what this is used for - perhaps to turn orange when there are unused imports etc.
1005: if (root
1006: .getFileObject("UpToDateStatusProvider/org-netbeans-modules-gsfret-editor-semantic-OccurrencesMarkProviderCreator.instance") == null) {
1007: try {
1008: FileUtil
1009: .createData(
1010: root,
1011: "UpToDateStatusProvider/org-netbeans-modules-gsfret-editor-semantic-OccurrencesMarkProviderCreator.instance");
1012: } catch (IOException ex) {
1013: Exceptions.printStackTrace(ex);
1014: }
1015: }
1016: if (checkUserdirUpgrade) {
1017: // Delete old name present up to and including beta2
1018: FileObject old = root
1019: .getFileObject("UpToDateStatusProvider/org-netbeans-modules-retouche-editor-semantic-OccurrencesMarkProviderCreator.instance");
1020: if (old != null) {
1021: try {
1022: old.delete();
1023: } catch (IOException ex) {
1024: Exceptions.printStackTrace(ex);
1025: }
1026: }
1027: }
1028:
1029: /* XXX breaks ValidateLayerConsistencyTest.testInstantiateAllInstances: Editors/text/x-ruby/org-netbeans-modules-gsfret-hints-GsfHintsProvider.instance thrown exception java.lang.ClassNotFoundException: Cannot instantiate org.netbeans.modules.gsfret.hints.GsfHintsProvider
1030: // Editor hints -- this may not be necessary - might already be done from the java source tasks factory...
1031: String hintsFilename =
1032: "Editors/" + l.getMimeType() +
1033: "/org-netbeans-modules-gsfret-hints-GsfHintsProvider.instance";
1034: if (fs.findResource(hintsFilename) == null) {
1035: try {
1036: FileObject fo = FileUtil.createData(fs.getRoot(), hintsFilename);
1037: fo.setAttribute("instanceOf", "org.netbeans.modules.editor.hints.spi.HintsProvider");
1038: } catch (IOException ex) {
1039: Exceptions.printStackTrace(ex);
1040: }
1041: }
1042: */
1043:
1044: // Code completion
1045: String completionProviders = "CompletionProviders";
1046: FileObject completion = root.getFileObject(completionProviders);
1047:
1048: if (completion == null) {
1049: try {
1050: completion = root.createFolder(completionProviders);
1051: } catch (IOException ex) {
1052: Exceptions.printStackTrace(ex);
1053: }
1054: }
1055: if (completion != null) {
1056: String templates = "org-netbeans-lib-editor-codetemplates-CodeTemplateCompletionProvider.instance";
1057: FileObject templeteProvider = root
1058: .getFileObject(completionProviders + "/"
1059: + templates);
1060: if (templeteProvider == null) {
1061: try {
1062: completion.createData(templates);
1063: } catch (IOException ex) {
1064: Exceptions.printStackTrace(ex);
1065: }
1066: }
1067: String provider = "org-netbeans-modules-gsfret-editor-completion-GsfCompletionProvider.instance";
1068: FileObject completionProvider = root
1069: .getFileObject(completionProviders + "/" + provider);
1070: if (completionProvider == null) {
1071: try {
1072: completion.createData(provider);
1073: } catch (IOException ex) {
1074: Exceptions.printStackTrace(ex);
1075: }
1076:
1077: }
1078: if (checkUserdirUpgrade) {
1079: // Delete old name present up to and including beta2
1080: FileObject old = completion
1081: .getFileObject("org-netbeans-modules-retouche-editor-completion-GsfCompletionProvider.instance");
1082: if (old != null) {
1083: try {
1084: old.delete();
1085: } catch (IOException ex) {
1086: Exceptions.printStackTrace(ex);
1087: }
1088: }
1089: }
1090: }
1091:
1092: // Editor toolbar: commenting and uncommenting actions
1093: if (root.getFileObject("Toolbars/Default/comment") == null) {
1094: if (!((l.getGsfLanguage() == null) || (l.getGsfLanguage()
1095: .getLineCommentPrefix() == null))) {
1096: try {
1097: FileObject sep = FileUtil
1098: .createData(root,
1099: "Toolbars/Default/Separator-before-comment.instance");
1100: sep.setAttribute("instanceClass",
1101: "javax.swing.JSeparator");
1102: sep.setAttribute("position", 30000);
1103:
1104: FileUtil.createData(root,
1105: "Toolbars/Default/comment").setAttribute(
1106: "position", 30100);
1107: FileUtil.createData(root,
1108: "Toolbars/Default/uncomment").setAttribute(
1109: "position", 30200);
1110: } catch (IOException ex) {
1111: Exceptions.printStackTrace(ex);
1112: }
1113: }
1114: }
1115:
1116: // init code templates
1117: if (root
1118: .getFileObject("CodeTemplateProcessorFactories/org-netbeans-modules-gsfret-editor-codetemplates-GsfCodeTemplateProcessor$Factory.instance") == null) {
1119: try {
1120: FileObject fo = FileUtil
1121: .createData(
1122: root,
1123: "CodeTemplateProcessorFactories/org-netbeans-modules-gsfret-editor-codetemplates-GsfCodeTemplateProcessor$Factory.instance");
1124: } catch (IOException ex) {
1125: Exceptions.printStackTrace(ex);
1126: }
1127: }
1128: if (checkUserdirUpgrade) {
1129: // Delete old name present up to and including beta2
1130: FileObject old = root
1131: .getFileObject("CodeTemplateProcessorFactories/org-netbeans-modules-retouche-editor-codetemplates-GsfCodeTemplateProcessor$Factory.instance");
1132: if (old != null) {
1133: try {
1134: old.delete();
1135: } catch (IOException ex) {
1136: Exceptions.printStackTrace(ex);
1137: }
1138: }
1139: }
1140:
1141: // init code templates filters
1142: if (root
1143: .getFileObject("CodeTemplateFilterFactories/org-netbeans-modules-gsfret-editor-codetemplates-GsfCodeTemplateFilter$Factory.instance") == null) {
1144: try {
1145: FileObject fo = FileUtil
1146: .createData(
1147: root,
1148: "CodeTemplateFilterFactories/org-netbeans-modules-gsfret-editor-codetemplates-GsfCodeTemplateFilter$Factory.instance");
1149: } catch (IOException ex) {
1150: Exceptions.printStackTrace(ex);
1151: }
1152: }
1153: if (checkUserdirUpgrade) {
1154: // Delete old name present up to and including beta2
1155: FileObject old = root
1156: .getFileObject("CodeTemplateFilterFactories/org-netbeans-modules-retouche-editor-codetemplates-GsfCodeTemplateFilter$Factory.instance");
1157: if (old != null) {
1158: try {
1159: old.delete();
1160: } catch (IOException ex) {
1161: Exceptions.printStackTrace(ex);
1162: }
1163: }
1164: }
1165:
1166: // Temporarily disabled; each language does it instead
1167: //initializeColoring(l);
1168: }
1169:
1170: // void initializeColoring(Language l) {
1171: // FileSystem fs = Repository.getDefault().getDefaultFileSystem();
1172: // final FileObject root = fs.findResource("Editors/" + l.getMimeType());
1173: //
1174: // // Initialize Coloring
1175: // if (l.getGsfLanguage() != null) {
1176: // List<?extends TokenId> types = l.getGsfLanguage().getRelevantTokenTypes();
1177: //
1178: // if ((types != null) && (types.size() > 0)) {
1179: // //String prefix = "gls-";
1180: // String prefix = "";
1181: //
1182: // // Default categories
1183: // Collection defaults =
1184: // EditorSettings.getDefault().getDefaultFontColorDefaults("NetBeans");
1185: // Map defaultsMap = new HashMap();
1186: // Iterator it = defaults.iterator(); // check if IDE Defaults module is installed
1187: //
1188: // while (it.hasNext()) {
1189: // AttributeSet as = (AttributeSet)it.next();
1190: // defaultsMap.put(as.getAttribute(StyleConstants.NameAttribute), as);
1191: // }
1192: //
1193: // // current colors
1194: // FontColorSettingsFactory fcsf =
1195: // EditorSettings.getDefault()
1196: // .getFontColorSettings(new String[] { l.getMimeType() });
1197: // Collection colors = fcsf.getAllFontColors("NetBeans"); // NOI18N
1198: // Map colorsMap = new HashMap();
1199: // it = colors.iterator();
1200: //
1201: // while (it.hasNext()) {
1202: // AttributeSet as = (AttributeSet)it.next();
1203: // colorsMap.put(as.getAttribute(StyleConstants.NameAttribute), as);
1204: // }
1205: //
1206: // for (TokenId id : types) {
1207: // TokenType type = l.getGsfLanguage().getTokenType(id);
1208: //
1209: // if (type == null) {
1210: // type = DefaultTokenType.getTokenType(id);
1211: // }
1212: //
1213: // if (type == null) {
1214: // continue;
1215: // }
1216: //
1217: // //String colorName = type.getName();
1218: // String colorName = id.name();
1219: // String category = type.getCategory();
1220: // SimpleAttributeSet as = new SimpleAttributeSet();
1221: // as.addAttribute(StyleConstants.NameAttribute, colorName);
1222: //
1223: // if (colorName != null) {
1224: // addColor(colorName, category, as, l, colorsMap, defaultsMap, prefix,
1225: // type.getDisplayName(), type.getColor(), type.getBackgroundColor(),
1226: // type.getFontType());
1227: // } else {
1228: // System.err.println("skipping null colorName for " + type);
1229: // }
1230: // }
1231: //
1232: // fcsf.setAllFontColorsDefaults("NetBeans", colorsMap.values());
1233: // fcsf.setAllFontColors("NetBeans", colorsMap.values());
1234: // }
1235: // }
1236: // }
1237: //
1238: // /**
1239: // * Based on code from Schliemann
1240: // *
1241: // * @author Jan Jancura
1242: // * @author Tor Norbye
1243: // */
1244: // private void addColor(String colorName, String category, SimpleAttributeSet sas, Language l,
1245: // Map colorsMap, Map defaultsMap, String prefix, String displayName, Color fg, Color bg,
1246: // int fontMode) {
1247: // String color = colorName;
1248: //
1249: // String pcolor = prefix + color;
1250: //
1251: // if (sas == null) {
1252: // sas = new SimpleAttributeSet();
1253: // }
1254: //
1255: // sas.addAttribute(StyleConstants.NameAttribute, pcolor);
1256: // sas.addAttribute(EditorStyleConstants.DisplayName, displayName);
1257: //
1258: // if (defaultsMap.containsKey(category)) {
1259: // sas.addAttribute(EditorStyleConstants.Default, category);
1260: // } else {
1261: // if (fg != null) {
1262: // sas.addAttribute(StyleConstants.Foreground, fg);
1263: // }
1264: //
1265: // if (bg != null) {
1266: // sas.addAttribute(StyleConstants.Background, bg);
1267: // }
1268: //
1269: // if ((fontMode & Font.BOLD) != 0) {
1270: // sas.addAttribute(StyleConstants.Bold, Boolean.TRUE);
1271: // }
1272: //
1273: // if ((fontMode & Font.ITALIC) != 0) {
1274: // sas.addAttribute(StyleConstants.Italic, Boolean.TRUE);
1275: // }
1276: // }
1277: //
1278: // colorsMap.put(pcolor, sas);
1279: // }
1280: }
|