Index: editor/settings/storage/manifest.mf =================================================================== RCS file: /cvs/editor/settings/storage/manifest.mf,v retrieving revision 1.10 retrieving revision 1.8.4.2 diff -u -r1.10 -r1.8.4.2 --- editor/settings/storage/manifest.mf 5 Feb 2007 09:43:30 -0000 1.10 +++ editor/settings/storage/manifest.mf 19 Mar 2007 02:44:45 -0000 1.8.4.2 @@ -2,5 +2,5 @@ OpenIDE-Module: org.netbeans.modules.editor.settings.storage/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/editor/settings/storage/Bundle.properties OpenIDE-Module-Provides: org.netbeans.api.editor.settings.implementation -OpenIDE-Module-Specification-Version: 1.9 +OpenIDE-Module-Specification-Version: 1.10 OpenIDE-Module-Layer: org/netbeans/modules/editor/settings/storage/layer.xml Index: editor/settings/storage/arch/apichanges.xml =================================================================== RCS file: /cvs/editor/settings/storage/arch/apichanges.xml,v retrieving revision 1.3 retrieving revision 1.1.6.2 diff -u -r1.3 -r1.1.6.2 --- editor/settings/storage/arch/apichanges.xml 5 Feb 2007 09:43:32 -0000 1.3 +++ editor/settings/storage/arch/apichanges.xml 19 Mar 2007 02:44:45 -0000 1.1.6.2 @@ -82,6 +82,28 @@ + #90403 - phase 1 + + + + + +

+ The phase 1 of the editor settings enhancements, please see + issue 90403 + for details. Briefly, the changes involve introducing a special + folder for each setting type, profiles are always stored in their + own folder, modules are allowed to register multiple settings files, + platform specific settings, the use of 'text/base' for all-editors + settings has been deprecated in favor of the hierarchy root (ie. 'Editors' folder), etc. +

+

+ The changes are documented in the Architecture Description document + and marked with the module version. +

+
+
+ Adding EditorSettings.getAllMimeTypes() Index: editor/settings/storage/arch/arch-editor-settings-storage.xml =================================================================== RCS file: /cvs/editor/settings/storage/arch/arch-editor-settings-storage.xml,v retrieving revision 1.9 retrieving revision 1.9.4.1 diff -u -r1.9 -r1.9.4.1 --- editor/settings/storage/arch/arch-editor-settings-storage.xml 23 Nov 2006 03:07:26 -0000 1.9 +++ editor/settings/storage/arch/arch-editor-settings-storage.xml 19 Mar 2007 02:44:46 -0000 1.9.4.1 @@ -134,10 +134,53 @@

Font & color files

+ +

Since version 1.10 the storage module does not require coloring files to be +called any special name. The coloring profiles and files are expected to be +registered by modules under a special folder called FontsColors. The +structure below shows an example of registering several different coloring files +for all editors and the text/x-java mime type. +

+ +
+    Editors
+     |- FontsColors
+     |   |- NetBeans
+     |       |- Defaults
+     |           |- foo.xml
+     |           |- bar.xml
+     |- text
+         |- x-java
+             |- FontsColors
+                 |- NetBeans
+                     |- Defaults
+                         |- xyz.xml
+                         |- abc.xml
+
+

-There are three different types of files containing information about fonts and colors -that should be used in editor. All of them have the same structure, but different -purpose. +In order to distinguish files containing token-related colorings from those +with highlight-related colorings the storage module recognizes a special file +attribute called nbeditor-settings-ColoringType, which value can +either be token or highlight. If a coloring file does +not specify this attribute it is automatically expected to contain token-related +colorings. +

+ +

+Generally, the files with default values are stored in Defaults +subfolders while the files with user changes are stored directly in the +profile's folder. +

+ +

+The default profile for font & colors is called 'NetBeans'. +

+ +

Prior to version 1.10 the storage module expected colorings in the +three different types of files. They are still recognized to support +backwards compatibility, but modules are suggusted to use the new registration +scheme. All of those three files had the same structure, but different purpose.

    @@ -160,37 +203,119 @@
+ +

Key bindings files

-Generally, files for both the default values and user changes have the same name. -The files with default values are stored in Defaults subfolders while -the files with user changes are stored directly in the profile's folder. +Since version 1.10 modules can provide their keybindings in multiple files +placed under the special folder called Keybindings and its profiles' +subfolders. Similarily as for colorings the files with default key bindings are stored in Defaults +subfolder and user changes are stored in files directly in the profile's folder. +The example below shows registration of several keybinding files for all editors +and the text/x-java mime type.

+
+    Editors
+     |- Keybindings
+     |   |- NetBeans
+     |       |- Defaults
+     |           |- foo.xml
+     |           |- bar.xml
+     |- text
+         |- x-java
+             |- Keybindings
+                 |- NetBeans
+                     |- Defaults
+                         |- xyz.xml
+                         |- abc.xml
+
+

-The default profile for font & colors is called 'NetBeans'. +Prior to version 1.10 the default profile for key bindings, called NetBeans, +had not been stored in its own folder. Therefore the default key bindings for +the NetBeans profile used to be stored directly in +Editors/<mime-type>/Defaults/keybindings.xml and similarily +user changes used to be stored in Editors/<mime-type>/keybindings.xml. +This has been deprecated, but is still supported for backwards compatibility reasons.

+

+Also the special mime type called text/base, has been deprecated +and should not be used anymore. It is however still supported to preserve +backwards compatibility. +

+ +

Platform specific settings

-

Key bindings files

-The key bindings information is stored in keybindings.xml files. The -files with default key bindings are stored in Defaults subfolder and -user changes are stored in files directly in the profile's folder. +Since 1.10 it is possible to mark setting files as applicable only on a certain +platform (a.k.a. operating system). This was mainly introduced for keybindings, +which are generally platform sensitive settings, but can be used for any other +setting type supported by the storage module. +

+ +

+Some platforms (eg. Mac) define their own special rules for the use of some +combinations of keystrokes (eg. ctrl+Q closes the app) that applications on that +platform have to obey. NetBeans mitigates this problem by introducing a special +module ide/applemenu, which is only loaded on Mac and which overrides +keybindings.xml files provided by some Netbeans modules (eg. editor and java). +This approach works albeit some severe limitations. However with introducing +multiple setting files this would no longer be practical, which is why platform +specific settings have been introduced.

-Althought the default profile for key bindings is called NetBeans, but there is no -special folder used for this profile. It means that the default key bindings for -the NetBeans profile should be stored in Editors/<mime-type>/Defaults/keybindings.xml. -Similarily user changes will be stored in Editors/<mime-type>/keybindings.xml. +The storage module recognizes a special file attribute for marking +platform specific setting files called nbeditor-settings-targetOS. +The rules for its use follow.

+
    +
  • + Any file that does not define nbeditor-settings-targetOS is loaded + on all platforms. All such files will be loaded exactly in the same order as + they appear on the system filesystem. +
  • +
  • + If a file defines nbeditor-settings-targetOS attribute, but its + value does not correspond to the current Operating System, the file is ignored. +
  • +
  • + If a file defines nbeditor-settings-targetOS attribute and its + value designates the current Operating System, the file will be loaded. + Furthermore, any such a file will be loaded after other files in the + same folder that do not define this attribute and therefore its settings will + override settings from those other files. +
  • +
  • + If there is more files that define nbeditor-settings-targetOS + attribute and are eligible for loading on the current Operating System, + they will be loaded in the same order as they appear on the system filesystem. +
  • +
+

-Additionally to normal mime types there is a special mime type called -text/base, which can be used for providing default key bindings that -will be added to all mime type specific key bindings. +The available values that can be used for the nbeditor-settings-targetOS +attribute are the string names of the OS_* constants in org.openide.util.Utilities +class. So, for example the following file will only be loaded on MacOS and its settings +will override settings from all other files that do not specify the target OS attribute.

+
+<folder name="Editors">
+  <folder name="Keybindings">
+    <folder name="NetBeans">
+      <folder name="Defaults">
+        <file name="keybindings-for-mac.xml" url="...">
+          <attr name="nbeditor-settings-targetOS" stringvalue="OS_MAC"/>
+        </file>
+      </folder>
+    </folder>
+  </folder>
+</folder>
+
+ @@ -730,7 +855,7 @@ --> -Yes. module creates a new MimeLookupInitializer and plug it into the MimeLookup. Also EditorSettings +Yes. module creates a new MimeDataProvider and plug it into the MimeLookup. Also EditorSettings implementation is registered into default lookup. @@ -746,7 +871,7 @@ --> -Yes. The implementation of MimeLookupInitializer is +Yes. The implementation of MimeDataProvider is registered via META-INF/services. @@ -939,7 +1064,8 @@ --> -Yes. The layer is used for registering DTDs in the Netbeans catalog. +Yes. The layer is used for registering DTDs in the Netbeans catalog and MIME type +resolvers for editor settings files. Index: editor/settings/storage/nbproject/project.xml =================================================================== RCS file: /cvs/editor/settings/storage/nbproject/project.xml,v retrieving revision 1.10 retrieving revision 1.9.2.2 diff -u -r1.10 -r1.9.2.2 --- editor/settings/storage/nbproject/project.xml 26 Jan 2007 04:58:50 -0000 1.10 +++ editor/settings/storage/nbproject/project.xml 10 Mar 2007 00:54:59 -0000 1.9.2.2 @@ -87,6 +87,9 @@ org.netbeans.core.startup + + org.openide.modules + Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/Bundle.properties =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/Bundle.properties,v retrieving revision 1.3 retrieving revision 1.3.12.1 diff -u -r1.3 -r1.3.12.1 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/Bundle.properties 30 Jun 2006 19:18:23 -0000 1.3 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/Bundle.properties 10 Mar 2007 00:55:03 -0000 1.3.12.1 @@ -20,3 +20,5 @@ OpenIDE-Module-Short-Description=Contains support for editor settings storage OpenIDE-Module-Long-Description=Editor Settings Storage module. +# MIMEResolver +Services/MIMEResolver/org-netbeans-modules-editor-settings-storage-mime-resolver.xml=Netbeans Editor Settings Files Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/ColoringStorage.java =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/ColoringStorage.java,v retrieving revision 1.25 retrieving revision 1.19.2.4 diff -u -r1.25 -r1.19.2.4 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/ColoringStorage.java 26 Jan 2007 04:58:51 -0000 1.25 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/ColoringStorage.java 15 Mar 2007 21:46:29 -0000 1.19.2.4 @@ -20,10 +20,12 @@ package org.netbeans.modules.editor.settings.storage; import java.awt.Color; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Level; @@ -32,10 +34,10 @@ import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import org.netbeans.api.editor.mimelookup.MimePath; -import org.netbeans.api.editor.settings.AttributesUtilities; import org.netbeans.api.editor.settings.EditorStyleConstants; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileSystem; +import org.openide.filesystems.FileUtil; import org.openide.filesystems.Repository; import org.openide.xml.XMLUtil; import org.w3c.dom.Document; @@ -52,19 +54,11 @@ * * @author Jan Jancura */ -final class ColoringStorage { +public final class ColoringStorage { private static final Logger LOG = Logger.getLogger(ColoringStorage.class.getName()); - // XXX: These constants are package private only for EditorSettingsImpl.init*() method. - // Once we get rid of filenames these will be removed. - - /* package */ static final String ALL_LANGUAGES_FILE_NAME = "defaultColoring.xml"; // NOI18N - /* package */ static final String COLORING_FILE_NAME = "coloring.xml"; // NOI18N - /* package */ static final String HIGHLIGHTING_FILE_NAME = "editorColoring.xml"; // NOI18N - - /** The name of the folder within a profile's folder containing module installed defaults. */ - /* package */ static final String DEFAULTS_FOLDER = "Defaults"; //NOI18N + private static final String HIGHLIGHTING_FILE_NAME = "editorColoring.xml"; // NOI18N private static final String E_ROOT = "fontscolors"; //NOI18N private static final String E_FONTCOLOR = "fontcolor"; //NOI18N @@ -85,6 +79,10 @@ private static final String PUBLIC_ID = "-//NetBeans//DTD Editor Fonts and Colors settings 1.1//EN"; //NOI18N private static final String SYSTEM_ID = "http://www.netbeans.org/dtds/EditorFontsColors-1_1.dtd"; //NOI18N + + private static final String FA_TYPE = "nbeditor-settings-ColoringType"; //NOI18N + private static final String FAV_TOKEN = "token"; //NOI18N + private static final String FAV_HIGHLIGHT = "highlight"; //NOI18N private ColoringStorage() { } @@ -97,49 +95,102 @@ boolean colorings, // true for colorings, false for highlightings boolean defaults // read default values only ) { - String fileName = determineFileName(mimePath, colorings); + assert mimePath != null : "The parameter mimePath must not be null"; //NOI18N + assert profile != null : "The parameter profile must not be null"; //NOI18N - // 1) load colorings - FileSystem fs = Repository.getDefault().getDefaultFileSystem(); - FileObject fo = null; - - if (!defaults) { - fo = fs.findResource(Utils.getFileName(mimePath, profile, fileName)); + FileObject baseFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors"); //NOI18N + Map> files = new HashMap>(); + SettingsType.FONTSCOLORS.getLocator().scan(baseFolder, mimePath.getPath(), profile, true, true, !defaults, files); + + assert files.size() <= 1 : "Too many results in the scan"; //NOI18N + + List profileInfos = files.get(profile); + if (profileInfos == null) { + return Collections.emptyMap(); } - if (fo == null) { - fo = fs.findResource(Utils.getFileName( - mimePath, profile, DEFAULTS_FOLDER + "/" + fileName)); //NOI18N + List filesForLocalization; + if (!profile.equals(EditorSettingsImpl.DEFAULT_PROFILE)) { + // If non-default profile load the default profile supplied by modules + // to find the localizing bundles. + Map> defaultProfileModulesFiles = new HashMap>(); + SettingsType.FONTSCOLORS.getLocator().scan(baseFolder, mimePath.getPath(), EditorSettingsImpl.DEFAULT_PROFILE, true, true, false, defaultProfileModulesFiles); + filesForLocalization = defaultProfileModulesFiles.get(EditorSettingsImpl.DEFAULT_PROFILE); + + // if there is no default profile (eg. in tests) + if (filesForLocalization == null) { + filesForLocalization = Collections.emptyList(); + } + } else { + filesForLocalization = profileInfos; } - if (fo == null) { - return null; - } else { - List l = (List) XMLStorage.load(fo, new ColoringsReader()); + Map fontsColorsMap = new HashMap(); + for(Object [] info : profileInfos) { + FileObject profileHome = (FileObject) info[0]; + FileObject settingFile = (FileObject) info[1]; + boolean modulesFile = ((Boolean) info[2]).booleanValue(); + + // Skip files with wrong type of colorings + boolean isTokenColoringFile = isTokenColoringFile(settingFile); + if (isTokenColoringFile != colorings) { + continue; + } - // 2) translate names of categories - FileObject basicName = fs.findResource( - Utils.getFileName(mimePath, EditorSettingsImpl.DEFAULT_PROFILE, DEFAULTS_FOLDER + "/" + fileName) //NOI18N - ); + // Load colorings from the settingFile + @SuppressWarnings("unchecked") + List sets = (List) XMLStorage.load(settingFile, new ColoringsReader()); - Map m = new HashMap(); - Iterator it = l.iterator(); - while (it.hasNext()) { - SimpleAttributeSet as = (SimpleAttributeSet) it.next(); + // Process loaded colorings + for(SimpleAttributeSet as : sets) { String name = (String) as.getAttribute(StyleConstants.NameAttribute); - String displayName = Utils.getLocalizedName(basicName, name, name); + SimpleAttributeSet previous = fontsColorsMap.get(name); + if (previous == null) { + // Find display name + // Try the settingFile first + String displayName = Utils.getLocalizedName(settingFile, name, null, true); + // Then try all module files from the default profile + if (displayName == null) { + for(Object [] locFileInfo : filesForLocalization) { + FileObject locFile = (FileObject) locFileInfo[1]; + displayName = Utils.getLocalizedName(settingFile, name, null, true); + if (displayName != null) { + break; + } + } + } + + if (displayName == null) { + displayName = name; + } + as.addAttribute(EditorStyleConstants.DisplayName, displayName); - m.put(name, AttributesUtilities.createImmutable(as)); + fontsColorsMap.put(name, as); + } else { + mergeAttributeSets(previous, as); + } } + } - return m; + return Utils.immutize(fontsColorsMap); + } + + private static void mergeAttributeSets(SimpleAttributeSet original, AttributeSet toMerge) { + for(Enumeration names = toMerge.getAttributeNames(); names.hasMoreElements(); ) { + Object key = names.nextElement(); + Object value = toMerge.getAttribute(key); + original.addAttribute(key, value); } - } + } private static class ColoringsReader extends XMLStorage.Handler { + private List colorings = new ArrayList(); + public ColoringsReader() { + } + public Object getResult () { return colorings; } @@ -157,9 +208,9 @@ } else if (name.equals(E_FONTCOLOR)) { SimpleAttributeSet a = new SimpleAttributeSet(); String value; - + a.addAttribute(StyleConstants.NameAttribute, attributes.getValue(A_NAME)); - + value = attributes.getValue(A_BACKGROUND); if (value != null) { a.addAttribute(StyleConstants.Background, Utils.stringToColor(value)); @@ -239,15 +290,45 @@ public static void deleteColorings( MimePath mimePath, String profile, - boolean colorings, // true for colorings, false for highlightings + final boolean colorings, // true for colorings, false for highlightings boolean defaults // delete default values ) { - String fileName = determineFileName(mimePath, colorings); - if (defaults) { - fileName = DEFAULTS_FOLDER + "/" + fileName; - } + assert mimePath != null : "The parameter mimePath must not be null"; //NOI18N + assert profile != null : "The parameter profile must not be null"; //NOI18N + + FileSystem sfs = Repository.getDefault().getDefaultFileSystem(); + FileObject baseFolder = sfs.findResource("Editors"); //NOI18N + Map> files = new HashMap>(); + SettingsType.FONTSCOLORS.getLocator().scan(baseFolder, mimePath.getPath(), profile, true, defaults, !defaults, files); + + assert files.size() <= 1 : "Too many results in the scan"; //NOI18N - Utils.deleteFileObject(mimePath, profile, fileName); + final List profileInfos = files.get(profile); + if (profileInfos != null) { + try { + sfs.runAtomicAction(new FileSystem.AtomicAction() { + public void run() { + for(Object [] info : profileInfos) { + FileObject settingFile = (FileObject) info[1]; + + // Skip files with wrong type of colorings + boolean isTokenColoringFile = isTokenColoringFile(settingFile); + if (isTokenColoringFile != colorings) { + continue; + } + + try { + settingFile.delete(); + } catch (IOException ioe) { + LOG.log(Level.WARNING, "Can't delete editor settings file " + settingFile.getPath(), ioe); //NOI18N + } + } + } + }); + } catch (IOException ioe) { + LOG.log(Level.WARNING, "Can't delete editor colorings for " + mimePath.getPath() + ", " + profile, ioe); //NOI18N + } + } } // save .......................................................... @@ -255,17 +336,28 @@ public static void saveColorings( MimePath mimePath, String profile, - boolean colorings, // true for colorings, false for highlightings + final boolean colorings, // true for colorings, false for highlightings boolean defaults, // save default values - Collection fontColors + final Collection fontColors ) { - String fileName = determineFileName(mimePath, colorings); - if (defaults) { - fileName = DEFAULTS_FOLDER + "/" + fileName; - } + assert mimePath != null : "The parameter mimePath must not be null"; //NOI18N + assert profile != null : "The parameter profile must not be null"; //NOI18N - FileObject fo = Utils.createFileObject(mimePath, profile, fileName); - saveColorings(fo, fontColors); + final FileSystem sfs = Repository.getDefault().getDefaultFileSystem(); + final String settingFileName = SettingsType.FONTSCOLORS.getLocator().getWritableFileName(mimePath.getPath(), profile, defaults); + + try { + sfs.runAtomicAction(new FileSystem.AtomicAction() { + public void run() throws IOException { + FileObject baseFolder = sfs.findResource("Editors"); //NOI18N + FileObject f = FileUtil.createData(baseFolder, settingFileName); + f.setAttribute(FA_TYPE, colorings ? FAV_TOKEN : FAV_HIGHLIGHT); + saveColorings(f, fontColors); + } + }); + } catch (IOException ioe) { + LOG.log(Level.WARNING, "Can't save editor colorings for " + mimePath.getPath() + ", " + profile, ioe); //NOI18N + } } private static void saveColorings(FileObject fo, Collection colorings) { @@ -357,19 +449,12 @@ XMLStorage.save(fo, doc); } - private static String determineFileName(MimePath mimePath, boolean colorings) { - String fileName; - - if (colorings) { - if (mimePath.size() == 0) { - fileName = ALL_LANGUAGES_FILE_NAME; - } else { - fileName = COLORING_FILE_NAME; - } + private static boolean isTokenColoringFile(FileObject f) { + Object typeValue = f.getAttribute(FA_TYPE); + if (typeValue instanceof String) { + return typeValue.equals(FAV_TOKEN); } else { - fileName = HIGHLIGHTING_FILE_NAME; + return !f.getNameExt().equals(HIGHLIGHTING_FILE_NAME); } - - return fileName; } } Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/CompositeFCS.java =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/CompositeFCS.java,v retrieving revision 1.3 retrieving revision 1.3.4.1 diff -u -r1.3 -r1.3.4.1 Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/EditorKeyBindings-1_1.dtd =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/EditorKeyBindings-1_1.dtd,v retrieving revision 1.2 retrieving revision 1.2.6.1 diff -u -r1.2 -r1.2.6.1 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/EditorKeyBindings-1_1.dtd 9 Nov 2006 02:03:40 -0000 1.2 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/EditorKeyBindings-1_1.dtd 16 Mar 2007 02:54:24 -0000 1.2.6.1 @@ -31,10 +31,12 @@ - + Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/EditorSettingsImpl.java =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/EditorSettingsImpl.java,v retrieving revision 1.36 retrieving revision 1.29.2.4 diff -u -r1.36 -r1.29.2.4 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/EditorSettingsImpl.java 5 Feb 2007 09:26:18 -0000 1.36 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/EditorSettingsImpl.java 15 Mar 2007 08:54:05 -0000 1.29.2.4 @@ -24,15 +24,15 @@ import java.io.IOException; import java.util.Collection; import java.util.Collections; -import java.util.Enumeration; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.text.AttributeSet; import org.netbeans.api.editor.mimelookup.MimePath; +import org.netbeans.api.editor.settings.FontColorSettings; +import org.netbeans.api.editor.settings.KeyBindingSettings; import org.netbeans.modules.editor.settings.storage.api.EditorSettings; import org.netbeans.modules.editor.settings.storage.api.FontColorSettingsFactory; import org.netbeans.modules.editor.settings.storage.api.KeyBindingSettingsFactory; @@ -71,6 +71,9 @@ /** Storage folder for the current keybindings profile attribute. */ private static final String KEYMAPS_FOLDER = "Keymaps"; // NOI18N + public static final String TEXT_BASE_MIME_TYPE = "text/base"; //NOI18N + private static final String [] EMPTY = new String[0]; + private static EditorSettingsImpl instance = null; public static synchronized EditorSettingsImpl getInstance() { @@ -80,29 +83,29 @@ return instance; } - public Set getAllMimeTypes () { - FileObject editorsFo = Repository.getDefault().getDefaultFileSystem().findResource(EDITORS_FOLDER); - HashSet mimeTypes = new HashSet(); - - if (editorsFo != null) { - for(FileObject f : editorsFo.getChildren()) { - if (!f.isFolder()) { - continue; - } + // ------------------------------------------------------ + // Mime types + // ------------------------------------------------------ - String firstPart = f.getNameExt(); - for(FileObject ff : f.getChildren()) { - if (!ff.isFolder()) { - continue; - } + private final MimeTypesTracker topLevelMimeTypes = new MimeTypesTracker(EDITORS_FOLDER, null); + private final HashMap settingMimeTypes = new HashMap(); + + public Set getAllMimeTypes () { + return topLevelMimeTypes.getMimeTypes(); + } - String mimeType = firstPart + "/" + ff.getNameExt(); //NOI18N - mimeTypes.add(mimeType); - } + private MimeTypesTracker getMimeTypesTracker(Class settingApiClass) { + SettingsType type = SettingsType.get(settingApiClass); + assert type != null : "Invalid editor settings API class: " + settingApiClass; //NOI18N + + synchronized (settingMimeTypes) { + MimeTypesTracker tracker = settingMimeTypes.get(type); + if (tracker == null) { + tracker = new MimeTypesTracker(EDITORS_FOLDER, type); + settingMimeTypes.put(type, tracker); } + return tracker; } - - return mimeTypes; } /** @@ -110,11 +113,9 @@ * * @return set of mimetypes */ - public Set getMimeTypes () { - if (mimeTypesWithColoring == null) { - init (); - } - return mimeTypesWithColoring; + // XXX: the API should actually use Collection + public Set getMimeTypes() { + return getMimeTypesTracker(FontColorSettings.class).getMimeTypes(); } /** @@ -123,12 +124,48 @@ * @return name of language for given mime type */ public String getLanguageName (String mimeType) { - FileObject fo = Repository.getDefault().getDefaultFileSystem().findResource("Editors/" + mimeType); //NOI18N - return fo == null ? mimeType : Utils.getLocalizedName(fo, mimeType, mimeType); + return topLevelMimeTypes.getMimeTypeDisplayName(mimeType); } + // ------------------------------------------------------ + // Profiles + // ------------------------------------------------------ + + private final HashMap settingProfiles = new HashMap(); + private ProfilesTracker getProfilesTracker(Class settingApiClass) { + SettingsType type = SettingsType.get(settingApiClass); + assert type != null : "Invalid editor settings API class: " + settingApiClass; //NOI18N + + synchronized (settingProfiles) { + ProfilesTracker tracker = settingProfiles.get(type); + if (tracker == null) { + tracker = new ProfilesTracker(type, topLevelMimeTypes); + settingProfiles.put(type, tracker); + } + return tracker; + } + } - // FontColors .............................................................. + /** + * Translates profile's display name to its Id. If the profile's display name + * can't be translated this method will simply return the profile's display name + * without translation. + */ + String getInternalFontColorProfile(String profile) { + ProfilesTracker tracker = getProfilesTracker(FontColorSettings.class); + ProfilesTracker.ProfileDescription pd = tracker.getProfileByDisplayName(profile); + return pd == null ? profile : pd.getId(); + } + + String getInternalKeymapProfile (String profile) { + ProfilesTracker tracker = getProfilesTracker(KeyBindingSettings.class); + ProfilesTracker.ProfileDescription pd = tracker.getProfileByDisplayName(profile); + return pd == null ? profile : pd.getId(); + } + + // ------------------------------------------------------ + // Font Colors + // ------------------------------------------------------ /* package */ void notifyTokenFontColorChange(MimePath mimePath, String profile) { // XXX: this is hack, we should not abuse the event values like that @@ -141,22 +178,9 @@ * @return set of font & colors profiles */ public Set getFontColorProfiles () { - if (fontColorProfiles == null) { - init (); - } - - Set result = new HashSet(); - for(String profile : fontColorProfiles.keySet()) { - if (!profile.startsWith ("test")) { - result.add(profile); - } - } - - return result; + return getProfilesTracker(FontColorSettings.class).getProfilesDisplayNames(); } - private Set systemFontColorProfiles; - /** * Returns true for user defined profile. * @@ -164,13 +188,12 @@ * @return true for user defined profile */ public boolean isCustomFontColorProfile(String profile) { - if (systemFontColorProfiles == null) { - init (); - } - - return !systemFontColorProfiles.contains(profile); + ProfilesTracker tracker = getProfilesTracker(FontColorSettings.class); + ProfilesTracker.ProfileDescription pd = tracker.getProfileByDisplayName(profile); + return pd != null && !pd.isRollbackAllowed(); } - + + // XXX: Rewrite this using NbPreferences private String currentFontColorProfile; /** @@ -347,7 +370,6 @@ ColoringStorage.deleteColorings (MimePath.EMPTY, internalProfile, false, false); highlightings.remove (internalProfile); - init (); } else { if (fontColors.equals (highlightings.get (internalProfile))) return; @@ -365,8 +387,6 @@ false, fontColors.values () ); - if (fontColorProfiles.get (profile) == null) - fontColorProfiles.put (profile, profile); } } @@ -374,20 +394,20 @@ } - // KeyMaps ................................................................. + // ------------------------------------------------------ + // Keybindings + // ------------------------------------------------------ /** * Returns set of keymap profiles. * * @return set of font & colors profiles */ + // XXX: the API should actually use Collection public Set getKeyMapProfiles () { - if (keyMapProfiles == null) init (); - return Collections.unmodifiableSet (keyMapProfiles.keySet ()); + return getProfilesTracker(KeyBindingSettings.class).getProfilesDisplayNames(); } - private Set systemKeymapProfiles; - /** * Returns true for user defined profile. * @@ -395,11 +415,9 @@ * @return true for user defined profile */ public boolean isCustomKeymapProfile (String profile) { - if (systemKeymapProfiles == null) { - init(); - } - - return !systemKeymapProfiles.contains (profile); + ProfilesTracker tracker = getProfilesTracker(KeyBindingSettings.class); + ProfilesTracker.ProfileDescription pd = tracker.getProfileByDisplayName(profile); + return pd == null || !pd.isRollbackAllowed(); } private String currentKeyMapProfile; @@ -497,135 +515,11 @@ // support methods ......................................................... - - private Map fontColorProfiles; - private Map keyMapProfiles; - private Set mimeTypesWithColoring; private EditorSettingsImpl() { } - private void init () { - fontColorProfiles = new HashMap(); - keyMapProfiles = new HashMap(); - keyMapProfiles.put (DEFAULT_PROFILE, DEFAULT_PROFILE); - mimeTypesWithColoring = new HashSet(); - systemFontColorProfiles = new HashSet(); - systemKeymapProfiles = new HashSet(); - FileSystem fs = Repository.getDefault ().getDefaultFileSystem (); - FileObject fo = fs.findResource (EDITORS_FOLDER); - if (fo != null) { - Enumeration e = fo.getFolders (false); - while (e.hasMoreElements()) { - init1 ((FileObject) e.nextElement ()); - } - } - - mimeTypesWithColoring = Collections.unmodifiableSet(mimeTypesWithColoring); - } - - private void init1 (FileObject fo) { - Enumeration e = fo.getChildren (false); - while (e.hasMoreElements ()) - init2 ((FileObject) e.nextElement ()); - } - - private void init2 (FileObject fo) { - if (fo.getNameExt ().equals (ColoringStorage.DEFAULTS_FOLDER) && fo.isFolder () && - fo.getFileObject (ColoringStorage.HIGHLIGHTING_FILE_NAME) != null - ) - addFontColorsProfile (fo, true); // Editors/ProfileName/Defaults/editorColoring.xml - else - if (fo.getNameExt ().equals (ColoringStorage.HIGHLIGHTING_FILE_NAME)) - addFontColorsProfile (fo, false); // Editors/ProfileName/editorColoring.xml - else - if (fo.getFileObject (DEFAULT_PROFILE + "/" + ColoringStorage.DEFAULTS_FOLDER + "/" + ColoringStorage.COLORING_FILE_NAME) != null) //NOI18N - addMimeType (fo); // Editors/XXX/YYY/NetBeans/Defaults/coloring.xml - else - if (fo.getPath ().endsWith ("text/base") && fo.isFolder ()) { //NOI18N - if (fo.getFileObject (KeyMapsStorage.DEFAULTS_FOLDER + "/" + KeyMapsStorage.KEYBINDING_FILE_NAME) != null) //NOI18N - addKeyMapProfile (fo, true); // Editors/text/base/Defaults/keybindings.xml - else - if (fo.getFileObject (KeyMapsStorage.KEYBINDING_FILE_NAME) != null) - addKeyMapProfile (fo, false); // Editors/text/base/keybindings.xml - Enumeration e = fo.getChildren (false); - while (e.hasMoreElements ()) { - FileObject ff = (FileObject) e.nextElement (); - if (!ff.getNameExt().equals(KeyMapsStorage.DEFAULTS_FOLDER)) { - init3 (ff); - } - } - } - } - - private void init3 (FileObject fo) { - if (fo.getFileObject (KeyMapsStorage.DEFAULTS_FOLDER + "/" + KeyMapsStorage.KEYBINDING_FILE_NAME) != null) //NOI18N - addKeyMapProfile (fo, true); // Editors/text/base/ProfileName/Defaults/keybindings.xml - else - if (fo.getFileObject (KeyMapsStorage.KEYBINDING_FILE_NAME) != null) - addKeyMapProfile (fo, false); // Editors/text/base/ProfileName/keybindings.xml - } - - private void addMimeType(FileObject fo) { - String mimeType = fo.getPath().substring(8); - mimeTypesWithColoring.add(mimeType); - } - - private void addFontColorsProfile(FileObject fo, boolean systemProfile) { - String profile = fo.getParent().getNameExt(); - String displayName = Utils.getLocalizedName(fo.getParent(), profile, profile); - - if (systemProfile) { - systemFontColorProfiles.add(displayName); - } - - fontColorProfiles.put(displayName, profile); - } - - private void addKeyMapProfile(FileObject fo, boolean systemProfile) { - String profile = fo.getNameExt(); - if (profile.equals("base")) { //NOI18N - profile = DEFAULT_PROFILE; - } - - String displayName = Utils.getLocalizedName(fo, profile, profile); - - if (systemProfile) { - systemKeymapProfiles.add(displayName); - } - - keyMapProfiles.put(displayName, profile); - } - - /** - * Translates profile's display name to its Id. If the profile's display name - * can't be translated this method will simply return the profile's display name - * without translation. - */ - String getInternalFontColorProfile(String profile) { - if (fontColorProfiles == null) { - init (); - } - - String result = fontColorProfiles.get(profile); - return result != null ? result : profile; - } - - String getInternalKeymapProfile (String profile) { - if (keyMapProfiles == null) { - init(); - } - - String result = keyMapProfiles.get (profile); - if (result != null) { - return result; - } else { - keyMapProfiles.put(profile, profile); - return profile; - } - } - public KeyBindingSettingsFactory getKeyBindingSettings (String[] mimeTypes) { mimeTypes = filter(mimeTypes); return KeyBindingSettingsImpl.get(Utils.mimeTypes2mimePath(mimeTypes)); @@ -637,12 +531,28 @@ } private String [] filter(String [] mimeTypes) { - if (mimeTypes.length > 0 && mimeTypes[0].startsWith("test")) { //NOI18N - String [] filtered = new String [mimeTypes.length]; - System.arraycopy(mimeTypes, 0, filtered, 0, mimeTypes.length); - filtered[0] = mimeTypes[0].substring(mimeTypes[0].indexOf('_') + 1); //NOI18N + if (mimeTypes.length > 0) { + String [] filtered = mimeTypes; - LOG.log(Level.INFO, "Don't use 'test' mime type to access settings through the editor/settings/storage API!", new Throwable("Stacktrace")); + if (mimeTypes[0].contains(TEXT_BASE_MIME_TYPE)) { + if (mimeTypes.length == 1) { + filtered = EMPTY; + } else { + filtered = new String [mimeTypes.length - 1]; + System.arraycopy(mimeTypes, 1, filtered, 0, mimeTypes.length - 1); + } + + if (LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, TEXT_BASE_MIME_TYPE + "has been deprecated, use MimePath.EMPTY instead."); //, new Throwable("Stacktrace") //NOI18N + } + + } else if (mimeTypes[0].startsWith("test")) { + filtered = new String [mimeTypes.length]; + System.arraycopy(mimeTypes, 0, filtered, 0, mimeTypes.length); + filtered[0] = mimeTypes[0].substring(mimeTypes[0].indexOf('_') + 1); //NOI18N + + LOG.log(Level.INFO, "Don't use 'test' mime type to access settings through the editor/settings/storage API!", new Throwable("Stacktrace")); + } return filtered; } else { Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/FontColorSettingsImpl.java =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/FontColorSettingsImpl.java,v retrieving revision 1.41 retrieving revision 1.37.2.2 diff -u -r1.41 -r1.37.2.2 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/FontColorSettingsImpl.java 4 Jan 2007 01:07:33 -0000 1.41 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/FontColorSettingsImpl.java 15 Mar 2007 08:54:02 -0000 1.37.2.2 @@ -27,7 +27,6 @@ import java.util.WeakHashMap; import java.util.logging.Logger; import javax.swing.text.AttributeSet; -import javax.swing.text.StyleConstants; import org.netbeans.api.editor.mimelookup.MimePath; import org.netbeans.modules.editor.settings.storage.api.FontColorSettingsFactory; Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/KeyBindingSettingsImpl.java =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/KeyBindingSettingsImpl.java,v retrieving revision 1.34 retrieving revision 1.29.2.3 diff -u -r1.34 -r1.29.2.3 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/KeyBindingSettingsImpl.java 11 Jan 2007 03:01:27 -0000 1.34 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/KeyBindingSettingsImpl.java 19 Mar 2007 04:28:56 -0000 1.29.2.3 @@ -41,11 +41,6 @@ import org.netbeans.api.editor.settings.MultiKeyBinding; import org.netbeans.modules.editor.settings.storage.api.EditorSettings; import org.netbeans.modules.editor.settings.storage.api.KeyBindingSettingsFactory; -import org.openide.filesystems.FileAttributeEvent; -import org.openide.filesystems.FileChangeListener; -import org.openide.filesystems.FileEvent; -import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileRenameEvent; import org.openide.util.Utilities; /** @@ -109,8 +104,8 @@ private void init () { if (init) return; init = true; - if (mimePath.size() != 1 || !mimePath.getMimeType(0).equals("text/base")) { //NOI18N - baseKBS = EditorSettingsImpl.getInstance().getKeyBindingSettings(new String[] {"text/base"}); //NOI18N + if (mimePath.size() > 0) { + baseKBS = get(MimePath.EMPTY); } listener = new Listener(this, baseKBS); } @@ -138,26 +133,8 @@ List result = new ArrayList(); if (!keyMaps.containsKey (profile)) { synchronized (this) { - - // 2) load original profile for this mimeType - // Map (List (KeyStroke) > MultiKeyBinding) - Map, MultiKeyBinding> defaults = - new HashMap, MultiKeyBinding>(getDefaults(profile)); - - // 3) load & apply modifications to defaults - Object[] ret = KeyMapsStorage.loadKeyMaps(mimePath, profile, false); - - @SuppressWarnings("unchecked") - Map, MultiKeyBinding> shortcuts = (Map, MultiKeyBinding>) ret[0]; - @SuppressWarnings("unchecked") - Set> removedShortcuts = (Set>) ret[1]; - - for(Collection s : removedShortcuts) { - defaults.remove(s); - } - defaults.putAll(shortcuts); - - List localShortcuts = new ArrayList(defaults.values()); + Map, MultiKeyBinding> shortcuts = KeyMapsStorage.loadKeyMaps(mimePath, profile, false); + List localShortcuts = new ArrayList(shortcuts.values()); keyMaps.put(profile, localShortcuts); result.addAll(localShortcuts); } @@ -279,11 +256,7 @@ */ private Map, MultiKeyBinding> getDefaults(String profile) { if (!defaults.containsKey (profile)) { - Object [] ret = KeyMapsStorage.loadKeyMaps(mimePath, profile, true); - @SuppressWarnings("unchecked") - Map, MultiKeyBinding> keyMap = - (Map, MultiKeyBinding>) ret[0]; - + Map, MultiKeyBinding> keyMap = KeyMapsStorage.loadKeyMaps(mimePath, profile, true); defaults.put(profile, keyMap); } @@ -334,10 +307,7 @@ private static class Listener extends WeakReference - implements FileChangeListener, PropertyChangeListener, Runnable { - - /** /Editor/mimetype/currentProfile/ folder*/ - private FileObject fo; + implements PropertyChangeListener, Runnable { private KeyBindingSettingsFactory baseKBS; Listener ( @@ -363,11 +333,9 @@ ); if (baseKBS != null) baseKBS.addPropertyChangeListener (this); - setFolderListener (); } private void removeListeners () { - fo.removeFileChangeListener (this); if (baseKBS != null) baseKBS.removePropertyChangeListener (this); EditorSettingsImpl.getInstance().removePropertyChangeListener( @@ -379,56 +347,12 @@ public void propertyChange (PropertyChangeEvent evt) { KeyBindingSettingsImpl r = getSettings (); if (r == null) return; - if (EditorSettings.PROP_CURRENT_KEY_MAP_PROFILE.equals ( - evt.getPropertyName () - )) - setFolderListener (); r.log ("refresh2", Collections.EMPTY_SET); r.pcs.firePropertyChange (null, null, null); } public void run() { removeListeners(); - } - - public void fileDataCreated (FileEvent fe) { - } - - public void fileChanged (FileEvent fe) { - KeyBindingSettingsImpl r = getSettings (); - if (r == null) return; - if (fe.getFile().getNameExt().equals(KeyMapsStorage.KEYBINDING_FILE_NAME)) { - r.refresh(); - } - } - - public void fileDeleted (FileEvent fe) { - KeyBindingSettingsImpl r = getSettings (); - if (r == null) return; - if (fe.getFile().getNameExt().equals(KeyMapsStorage.KEYBINDING_FILE_NAME)) { - r.refresh(); - } - } - - public void fileFolderCreated(FileEvent fe) { - } - - public void fileRenamed(FileRenameEvent fe) { - } - - public void fileAttributeChanged(FileAttributeEvent fe) { - } - - private void setFolderListener() { - if (fo != null) fo.removeFileChangeListener (this); - String profile = EditorSettingsImpl.getInstance().getCurrentKeyMapProfile(); - if (profile.equals(EditorSettingsImpl.DEFAULT_PROFILE)) profile = null; - - KeyBindingSettingsImpl kbsi = getSettings(); - if (kbsi != null) { - fo = Utils.createFileObject(kbsi.mimePath, profile, null); - fo.addFileChangeListener (this); - } } } Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/KeyMapsStorage.java =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/KeyMapsStorage.java,v retrieving revision 1.19 retrieving revision 1.14.2.3 diff -u -r1.19 -r1.14.2.3 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/KeyMapsStorage.java 11 Jan 2007 14:48:09 -0000 1.19 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/KeyMapsStorage.java 16 Mar 2007 02:54:24 -0000 1.14.2.3 @@ -19,11 +19,13 @@ package org.netbeans.modules.editor.settings.storage; +import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; @@ -31,8 +33,10 @@ import javax.swing.KeyStroke; import org.netbeans.api.editor.mimelookup.MimePath; import org.netbeans.api.editor.settings.MultiKeyBinding; - import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileSystem; +import org.openide.filesystems.FileUtil; +import org.openide.filesystems.Repository; import org.openide.util.Utilities; import org.openide.xml.XMLUtil; import org.w3c.dom.Document; @@ -53,13 +57,6 @@ private static final Logger LOG = Logger.getLogger(KeyMapsStorage.class.getName()); - // XXX: These constants are package private only for EditorSettingsImpl.init*() method. - // Once we get rid of filenames these will be removed. - /* package */ static final String KEYBINDING_FILE_NAME = "keybindings.xml"; // NOI18N - - /** The name of the folder within a profile's folder containing module installed defaults. */ - /* package */ static final String DEFAULTS_FOLDER = "Defaults"; //NOI18N - private static final String ROOT = "bindings"; //NOI18N private static final String E_BIND = "bind"; //NOI18N private static final String A_ACTION_NAME = "actionName"; //NOI18N @@ -75,34 +72,58 @@ // load .................................................................... - /** - * Object [Map (List (KeyStroke) > MultiKeyBinding), - * Set (List (KeyStroke))] - * [modified, removed] - */ - public static Object[] loadKeyMaps ( + public static Map, MultiKeyBinding> loadKeyMaps ( MimePath mimePath, String profile, boolean defaults ) { - // 1) load colorings - if (profile.equals(EditorSettingsImpl.DEFAULT_PROFILE)) profile = null; + assert mimePath != null : "The parameter mimePath must not be null"; //NOI18N + assert profile != null : "The parameter profile must not be null"; //NOI18N + + FileObject baseFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors"); //NOI18N + Map> files = new HashMap>(); + SettingsType.KEYBINDINGS.getLocator().scan(baseFolder, mimePath.getPath(), profile, true, true, !defaults, files); + + assert files.size() <= 1 : "Too many results in the scan"; //NOI18N - String fileName = defaults ? DEFAULTS_FOLDER + "/" + KEYBINDING_FILE_NAME : KEYBINDING_FILE_NAME; - FileObject fo = Utils.getFileObject(mimePath, profile, fileName); - if (fo == null) { - return new Object[] { - Collections., MultiKeyBinding>emptyMap(), - Collections.>emptySet() - }; - } else { - return (Object[]) XMLStorage.load(fo, new KeyMapsReader()); + List profileInfos = files.get(profile); + if (profileInfos == null) { + return Collections., MultiKeyBinding>emptyMap(); } + + Map, MultiKeyBinding> keybindingsMap = new HashMap, MultiKeyBinding>(); + for(Object [] info : profileInfos) { + FileObject profileHome = (FileObject) info[0]; + FileObject settingFile = (FileObject) info[1]; + boolean modulesFile = ((Boolean) info[2]).booleanValue(); + + // Load colorings from the settingFile + @SuppressWarnings("unchecked") + Object [] loadedData = (Object []) XMLStorage.load(settingFile, new KeyMapsReader()); + @SuppressWarnings("unchecked") + Map, MultiKeyBinding> addedBindings = (Map, MultiKeyBinding>) loadedData[0]; + @SuppressWarnings("unchecked") + Collection> removedBindings = (Collection>) loadedData[1]; + +// System.out.println("settingsFile : " + settingFile.getPath()); +// System.out.println("addedBindings : " + addedBindings); +// System.out.println("removedBindings : " + removedBindings); + + // First add all new bindings + keybindingsMap.putAll(addedBindings); + + // Remove all keybindings marked as removed + for(Collection binding : removedBindings) { + keybindingsMap.remove(binding); + } + } + + return Collections.unmodifiableMap(keybindingsMap); } private static class KeyMapsReader extends XMLStorage.Handler { private Map, MultiKeyBinding> keyMap = new HashMap, MultiKeyBinding>(); - private Set> removedShortcuts = new HashSet>(); + private Collection> removedShortcuts = new HashSet>(); public Object getResult() { return new Object[] {keyMap, removedShortcuts}; @@ -119,7 +140,6 @@ // We don't read anything from the root element } else if (name.equals(E_BIND)) { - String actionName = attributes.getValue(A_ACTION_NAME); String key = attributes.getValue(A_KEY); if (!Utilities.isMac() && @@ -129,8 +149,8 @@ // these characters do not work on MAC, Alt should be coded as 'O' // and Ctrl as 'D' int idx = key.indexOf('-'); - if (idx != -1 && (key.charAt(0) == 'A' || key.charAt(0) == 'C')) { - LOG.warning("The keybinding '" + key + "' for action '" + actionName + //NOI18N + if (idx != -1 && (key.charAt(0) == 'A' || key.charAt(0) == 'C')) { //NOI18N + LOG.warning("The keybinding '" + key + //NOI18N "' in " + getProcessedFile().getPath() + " may not work correctly on Mac. " + //NOI18N "Keybindings starting with Alt or Ctrl should " + //NOI18N "be coded with latin capital letters 'O' " + //NOI18N @@ -144,8 +164,14 @@ if (Boolean.valueOf(remove)) { removedShortcuts.add(Arrays.asList(shortcut)); } else { - MultiKeyBinding mkb = new MultiKeyBinding(shortcut, actionName); - keyMap.put(Arrays.asList(shortcut), mkb); + String actionName = attributes.getValue(A_ACTION_NAME); + if (actionName != null) { + MultiKeyBinding mkb = new MultiKeyBinding(shortcut, actionName); + keyMap.put(Arrays.asList(shortcut), mkb); +// System.out.println("!!! adding: '" + key + "' -> '" + actionName + "'"); + } else { + LOG.warning("Ignoring keybinding '" + key + "' with no action name."); //NOI18N + } } } } catch (Exception ex) { @@ -168,12 +194,35 @@ String profile, boolean defaults ) { - if (profile.equals(EditorSettingsImpl.DEFAULT_PROFILE)) { - profile = null; - } + assert mimePath != null : "The parameter mimePath must not be null"; //NOI18N + assert profile != null : "The parameter profile must not be null"; //NOI18N + + FileSystem sfs = Repository.getDefault().getDefaultFileSystem(); + FileObject baseFolder = sfs.findResource("Editors"); //NOI18N + Map> files = new HashMap>(); + SettingsType.KEYBINDINGS.getLocator().scan(baseFolder, mimePath.getPath(), profile, true, defaults, !defaults, files); + + assert files.size() <= 1 : "Too many results in the scan"; //NOI18N - String fileName = defaults ? DEFAULTS_FOLDER + "/" + KEYBINDING_FILE_NAME : KEYBINDING_FILE_NAME; - Utils.deleteFileObject(mimePath, profile, fileName); + final List profileInfos = files.get(profile); + if (profileInfos != null) { + try { + sfs.runAtomicAction(new FileSystem.AtomicAction() { + public void run() { + for(Object [] info : profileInfos) { + FileObject settingFile = (FileObject) info[1]; + try { + settingFile.delete(); + } catch (IOException ioe) { + LOG.log(Level.WARNING, "Can't delete editor settings file " + settingFile.getPath(), ioe); //NOI18N + } + } + } + }); + } catch (IOException ioe) { + LOG.log(Level.WARNING, "Can't delete editor keybindings for " + mimePath.getPath() + ", " + profile, ioe); //NOI18N + } + } } // save .......................................................... @@ -182,19 +231,29 @@ MimePath mimePath, String profile, boolean defaults, - Collection keyMap, // modified shortcuts - Set> removed // shortcuts + final Collection keybindings, // modified shortcuts + final Set> removedKeybindings // shortcuts ) { - if (profile.equals(EditorSettingsImpl.DEFAULT_PROFILE)) { - profile = null; - } + assert mimePath != null : "The parameter mimePath must not be null"; //NOI18N + assert profile != null : "The parameter profile must not be null"; //NOI18N - String fileName = defaults ? DEFAULTS_FOLDER + "/" + KEYBINDING_FILE_NAME : KEYBINDING_FILE_NAME; - FileObject fo = Utils.createFileObject(mimePath, profile, fileName); - saveKeyMaps (fo, keyMap, removed); + final FileSystem sfs = Repository.getDefault().getDefaultFileSystem(); + final String settingFileName = SettingsType.KEYBINDINGS.getLocator().getWritableFileName(mimePath.getPath(), profile, defaults); + + try { + sfs.runAtomicAction(new FileSystem.AtomicAction() { + public void run() throws IOException { + FileObject baseFolder = sfs.findResource("Editors"); //NOI18N + FileObject f = FileUtil.createData(baseFolder, settingFileName); + saveKeybindings(f, keybindings, removedKeybindings); + } + }); + } catch (IOException ioe) { + LOG.log(Level.WARNING, "Can't save editor keybindings for " + mimePath.getPath() + ", " + profile, ioe); //NOI18N + } } - private static void saveKeyMaps( + private static void saveKeybindings( FileObject fo, Collection keyMap, Set> removed Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/MimeTypesTracker.java =================================================================== RCS file: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/MimeTypesTracker.java diff -N editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/MimeTypesTracker.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/MimeTypesTracker.java 12 Mar 2007 10:24:12 -0000 1.1.2.2 @@ -0,0 +1,328 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.editor.settings.storage; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.openide.filesystems.FileChangeAdapter; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileRenameEvent; +import org.openide.filesystems.FileSystem; +import org.openide.filesystems.Repository; +import org.openide.util.WeakListeners; + +/** + * The tracker of mime types registered as folders under a common root. This class + * will listen on a hierarchical structure of folders under a baseFolder + * and will interpret its subfolders as mime type definitions. For example the + * following structure of folders will be interpreted as two mime types 'text/x-java' + * and 'application/pdf'. + * + *
+ *   <baseFolder>/text/x-java
+ *   <baseFolder>/application/pdf
+ * 
+ * + * @author Vita Stejskal + */ +public final class MimeTypesTracker { + + private static final Logger LOG = Logger.getLogger(MimeTypesTracker.class.getName()); + + private static final Pattern REG_NAME_PATTERN = Pattern.compile("^[[\\p{Alnum}][!#$&.+\\-^_]]{1,127}$"); //NOI18N + + private static final Set WELL_KNOWN_TYPES = new HashSet(Arrays.asList( + "application", //NOI18N + "audio", //NOI18N + "image", //NOI18N + "message", //NOI18N + "model", //NOI18N + "multipart", //NOI18N + "text", //NOI18N + "video" //NOI18N + )); + + private static final String ATTR_MIME_TYPE_FOLDER_MARKER = "org-netbeans-editor-MimeTypeDefinition"; //NOI18N + + /** The property for notifying changes in mime types tracked by this tracker. */ + public static final String PROP_MIME_TYPES = "mime-types"; //NOI18N + + /** + * Create a new tracker for tracking mime types under the basePath + * folder. + * + * @param basePath The path on the system FileSystem where the + * mime types should be tracked. + * @param settingsType The type of settings to track mime types for. If not + * null the tracker will only list mime types that declare + * settings of this type. + */ + public MimeTypesTracker(String basePath, SettingsType settingsType) { + this.basePath = basePath; + this.basePathElements = basePath.split("/"); //NOI18N + this.locator = settingsType == null ? null : settingsType.getLocator(); + + rebuild(); + + // Start listening + this.listener = new Listener(); + FileSystem sfs = Repository.getDefault().getDefaultFileSystem(); + sfs.addFileChangeListener(WeakListeners.create(FileChangeListener.class,listener, sfs)); + } + + /** + * Gets the root of the mime types hierarchy watched by this tracker. + * + * @return The basePath passed to the constructor. + */ + public String getBasePath() { + return basePath; + } + + /** + * Gets the list of mime types (Strings) located under this + * tracker's basePath. + * + * @return The list of mime types. + */ + public Set getMimeTypes() { + synchronized (LOCK) { + return mimeTypes.keySet(); + } + } + + /** + * Gets a display name for a mime type. The display name is read from the + * localizing bundle associated to the mime type's folder (FileObject). + * The value of the mimeType parameter will be used as bundle + * key to read the display name. + * + * @param mimeType The mime type to get the display name for. + * @return The display (localized) name of the mime type or the mimeType + * if the display name can't be found. + */ + public String getMimeTypeDisplayName(String mimeType) { + String displayName = mimeTypes.get(mimeType); + return displayName == null ? mimeType : displayName; + } + + /** + * Adds a listener that will be receiving PROP_MIME_TYPES notifcations. + * + * @param l The listener to add. + */ + public void addPropertyChangeListener(PropertyChangeListener l) { + pcs.addPropertyChangeListener(l); + } + + /** + * Removes a previously added listener. + * + * @param l The listener to remove. + */ + public void removePropertyChangeListener(PropertyChangeListener l) { + pcs.removePropertyChangeListener(l); + } + + // ------------------------------------------------------------------ + // private implementation + // ------------------------------------------------------------------ + + private final String LOCK = new String("MimeTypesTracker.LOCK"); //NOI18N + + private final String basePath; + private final String [] basePathElements; + private final SettingsType.Locator locator; + + private FileObject folder; + private boolean isBaseFolder; + + private Map mimeTypes = Collections.emptyMap(); + + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private final FileChangeListener listener; + + private void rebuild() { + PropertyChangeEvent event = null; + + synchronized (LOCK) { + Object [] ret = findTarget(basePathElements); + FileObject f = (FileObject) ret[0]; + boolean isBase = ((Boolean) ret[1]).booleanValue(); + + // The base folder or some folder up in the hierarchy has been created/deleted + if (f != folder) { + // Set the current folder and its is-target-flag + folder = f; + isBaseFolder = isBase; + + LOG.finest("folder = '" + folder.getPath() + "'"); //NOI18N + LOG.finest("isBaseFolder = '" + isBaseFolder + "'"); //NOI18N + } + + if (isBaseFolder) { + // Clear the cache + Map newMimeTypes = new HashMap(); + + // Go through mime type types + FileObject [] types = folder.getChildren(); + for(int i = 0; i < types.length; i++) { + if (!isValidType(types[i])) { + continue; + } + + // Go through mime type subtypes + FileObject [] subTypes = types[i].getChildren(); + for(int j = 0; j < subTypes.length; j++) { + if (!isValidSubtype(subTypes[j])) { + continue; + } + + String mimeType = types[i].getNameExt() + "/" + subTypes[j].getNameExt(); //NOI18N + + boolean add; + if (locator != null) { + Map> scan = new HashMap>(); + locator.scan(folder, mimeType, null, false, true, true, scan); + add = !scan.isEmpty(); + } else { + add = true; + } + + if (add) { + // First try the standard way for filesystem annotations + String displayName = Utils.getLocalizedName(subTypes[j], null); + + // Then try the crap way introduced with Tools-Options + if (displayName == null) { + displayName = Utils.getLocalizedName(subTypes[j], mimeType, mimeType); + } + newMimeTypes.put(mimeType, displayName); + } + } + } + + newMimeTypes = Collections.unmodifiableMap(newMimeTypes); + if (!mimeTypes.equals(newMimeTypes)) { + event = new PropertyChangeEvent(this, PROP_MIME_TYPES, mimeTypes, newMimeTypes); + mimeTypes = newMimeTypes; + } + } + } + + if (event != null) { + pcs.firePropertyChange(event); + } + } + + private static boolean isValidType(FileObject typeFile) { + if (!typeFile.isFolder()) { + return false; + } + + String typeName = typeFile.getNameExt(); + + if (!isValidRegName(typeName)) { + return false; + } + + if (WELL_KNOWN_TYPES.contains(typeName)) { + return true; + } + + // XXX: undocumented backdoor + Object marker = typeFile.getAttribute(ATTR_MIME_TYPE_FOLDER_MARKER); + if ((marker instanceof Boolean) && ((Boolean) marker).booleanValue()) { + return true; + } + + return false; + } + + private static boolean isValidSubtype(FileObject subtypeFile) { + if (!subtypeFile.isFolder()) { + return false; + } + + String typeName = subtypeFile.getNameExt(); + return isValidRegName(typeName) && !typeName.equals("base"); //NOI18N + } + + private static boolean isValidRegName(String name) { + Matcher m = REG_NAME_PATTERN.matcher(name); + return m.matches(); + } + + private static Object [] findTarget(String [] path) { + FileObject target = Repository.getDefault().getDefaultFileSystem().getRoot(); + boolean isTarget = 0 == path.length; + + for (int i = 0; i < path.length; i++) { + FileObject f = target.getFileObject(path[i]); + + if (f == null || !f.isFolder() || !f.isValid() || f.isVirtual()) { + break; + } else { + target = f; + isTarget = i + 1 == path.length; + } + } + + return new Object [] { target, Boolean.valueOf(isTarget) }; + } + + private final class Listener extends FileChangeAdapter { + + public Listener() { + } + + public void fileFolderCreated(FileEvent fe) { + notifyRebuild(fe.getFile()); + } + + public void fileDeleted(FileEvent fe) { + notifyRebuild(fe.getFile()); + } + + public void fileRenamed(FileRenameEvent fe) { + notifyRebuild(fe.getFile()); + } + + private void notifyRebuild(FileObject f) { + String path = f.getPath(); + if (path.startsWith(basePath)) { + rebuild(); + } + } + } // End of Listener class +} Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/ProfilesTracker.java =================================================================== RCS file: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/ProfilesTracker.java diff -N editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/ProfilesTracker.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/ProfilesTracker.java 12 Mar 2007 10:24:12 -0000 1.1.2.4 @@ -0,0 +1,284 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.editor.settings.storage; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; +import org.openide.filesystems.FileChangeAdapter; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileRenameEvent; +import org.openide.filesystems.FileSystem; +import org.openide.filesystems.Repository; +import org.openide.util.WeakListeners; + +/** + * + * @author Vita Stejskal + */ +public final class ProfilesTracker { + + /** + * The property name for notifying changes in the tracked profiles. + */ + public static final String PROP_PROFILES = "profiles"; //NOI18N + + /** + * Creates a new instance of ProfilesTracker. + * + * @param type + * @param mimeTypes + * @param strict + */ + public ProfilesTracker(SettingsType type, MimeTypesTracker mimeTypes) { + assert type != null : "The parameter type must not be null"; //NOI18N + assert type.isUsingProfiles() : "No need to track profiles for settings that do not use profiles."; //NOI18N + + this.locator = type == null ? null : type.getLocator(); + this.mimeTypes = mimeTypes; + + rebuild(); + + // Start listening + this.listener = new Listener(); + this.sfs = Repository.getDefault().getDefaultFileSystem(); + this.sfs.addFileChangeListener(WeakListeners.create(FileChangeListener.class, listener, this.sfs)); + this.mimeTypes.addPropertyChangeListener(listener); + } + + /** + * Gets the list of profiles for the tracked setting type. + * + * @return Profiles as a map of profile name -> profile display name. + */ + public Set getProfilesDisplayNames() { + synchronized (LOCK) { + return profilesByDisplayName.keySet(); + } + } + + /** + * Gets description for a profile by its name. + * + * @param displayName The display name of the profile to get the description for. + * @retutn The profile's description or null if there is no + * profile with the display name. + */ + public ProfileDescription getProfileByDisplayName(String displayName) { + synchronized (LOCK) { + return profilesByDisplayName.get(displayName); + } + } + + /** + * Adds a listener that will be receiving PROP_PROFILES notifcations. + * + * @param l The listener to add. + */ + public void addPropertyChangeListener(PropertyChangeListener l) { + pcs.addPropertyChangeListener(l); + } + + /** + * Removes a previously added listener. + * + * @param l The listener to remove. + */ + public void removePropertyChangeListener(PropertyChangeListener l) { + pcs.removePropertyChangeListener(l); + } + + public static final class ProfileDescription { + private final String id; + private final String displayName; + private final boolean isRollbackAllowed; + + private ProfileDescription(String id, String displayName, boolean isRollbackAllowed) { + this.id = id; + this.displayName = displayName; + this.isRollbackAllowed = isRollbackAllowed; + } + + public boolean isRollbackAllowed() { + return isRollbackAllowed; + } + + public String getDisplayName() { + return displayName; + } + + public String getId() { + return id; + } + + } // End of ProfileDescription class + + // ------------------------------------------------------------------ + // private implementation + // ------------------------------------------------------------------ + + private static final Logger LOG = Logger.getLogger(ProfilesTracker.class.getName()); + + private final SettingsType.Locator locator; + private final MimeTypesTracker mimeTypes; + + private final FileSystem sfs; + private final Listener listener; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + private final String LOCK = new String("ProfilesTracker.LOCK"); //NOI18N + private Map profiles = Collections.emptyMap(); + private Map profilesByDisplayName = Collections.emptyMap(); + + private void rebuild() { + PropertyChangeEvent event = null; + + synchronized (LOCK) { + FileSystem sfs = Repository.getDefault().getDefaultFileSystem(); + Map> scan = new HashMap>(); + + FileObject baseFolder = sfs.findResource(mimeTypes.getBasePath()); + if (baseFolder != null && baseFolder.isFolder()) { + // Scan base folder + locator.scan(baseFolder, null, null, false, true, true, scan); + + // Scan mime type folders + Collection mimes = mimeTypes.getMimeTypes(); + for(String mime : mimes) { + locator.scan(baseFolder, mime, null, false, true, true, scan); + } + } + + HashMap newProfiles = new HashMap(); + HashMap newProfilesByDisplayName = new HashMap(); + for(String id : scan.keySet()) { + List profileInfos = scan.get(id); + + // Determine profile's display name and if it can roll back user changes + String displayName = null; + boolean canRollback = false; + for(Object [] info : profileInfos) { + FileObject profileHome = (FileObject) info[0]; + FileObject settingFile = (FileObject) info[1]; + boolean modulesFile = ((Boolean) info[2]); + + if (displayName == null && profileHome != null) { + // First try the standard way for filesystem annotations + displayName = Utils.getLocalizedName(profileHome, null); + + // Then try the crap way introduced with Tools-Options + if (displayName == null) { + displayName = Utils.getLocalizedName(profileHome, id, null); + } + } + + if (!canRollback) { + canRollback = modulesFile; + } + + if (displayName != null && canRollback) { + break; + } + } + displayName = displayName == null ? id : displayName; + + // Check for duplicate display names + ProfileDescription maybeDupl = newProfilesByDisplayName.get(displayName); + if (maybeDupl != null) { + LOG.warning("Ignoring profile '" + id + "', it's got the same display name as '" + maybeDupl.getId()); //NOI18N + continue; + } + + ProfileDescription desc = reuseOrCreate(id, displayName, canRollback); + newProfiles.put(id, desc); + newProfilesByDisplayName.put(displayName, desc); + } + + // Just a sanity check + assert newProfilesByDisplayName.size() == newProfiles.size() : "Inconsistent profile maps"; //NOI18N + + if (!profiles.equals(newProfiles)) { + event = new PropertyChangeEvent(this, PROP_PROFILES, profiles, newProfiles); + profiles = newProfiles; + profilesByDisplayName = newProfilesByDisplayName; + } + } + + if (event != null) { + pcs.firePropertyChange(event); + } + } + + private ProfileDescription reuseOrCreate(String id, String displayName, boolean rollback) { + ProfileDescription desc = profiles.get(id); + if (desc != null) { + if (desc.getDisplayName().equals(displayName) && desc.isRollbackAllowed() == rollback) { + return desc; + } + } + return new ProfileDescription(id, displayName, rollback); + } + + private final class Listener extends FileChangeAdapter implements PropertyChangeListener { + + public Listener() { + } + + public void propertyChange(PropertyChangeEvent evt) { + rebuild(); + } + + @Override + public void fileDataCreated(FileEvent fe) { + notifyRebuild(fe.getFile()); + } + + @Override + public void fileFolderCreated(FileEvent fe) { + notifyRebuild(fe.getFile()); + } + + @Override + public void fileDeleted(FileEvent fe) { + notifyRebuild(fe.getFile()); + } + + @Override + public void fileRenamed(FileRenameEvent fe) { + notifyRebuild(fe.getFile()); + } + + private void notifyRebuild(FileObject file) { + String path = file.getPath(); + if (path.startsWith(mimeTypes.getBasePath())) { + rebuild(); + } + } + } // End of Listener class +} Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/SettingsProvider.java =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/SettingsProvider.java,v retrieving revision 1.6 retrieving revision 1.3.4.2 diff -u -r1.6 -r1.3.4.2 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/SettingsProvider.java 4 Jan 2007 01:07:31 -0000 1.6 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/SettingsProvider.java 15 Mar 2007 08:54:05 -0000 1.3.4.2 @@ -63,6 +63,14 @@ * @return Lookup or null, if there are no lookup-able objects for mime or global level. */ public Lookup getLookup(MimePath mimePath) { + if (mimePath.size() > 0 && mimePath.getMimeType(0).contains(EditorSettingsImpl.TEXT_BASE_MIME_TYPE)) { + if (LOG.isLoggable(Level.INFO)) { + LOG.log(Level.INFO, "Won't provide any settings for " + EditorSettingsImpl.TEXT_BASE_MIME_TYPE + //NOI18N + "It's been deprecated, use MimePath.EMPTY instead."); //, new Throwable("Stacktrace") //NOI18N + } + return null; + } + synchronized (cache) { WeakReference ref = cache.get(mimePath); Lookup lookup = ref == null ? null : ref.get(); Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/SettingsType.java =================================================================== RCS file: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/SettingsType.java diff -N editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/SettingsType.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/SettingsType.java 16 Mar 2007 01:18:53 -0000 1.1.2.5 @@ -0,0 +1,559 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.editor.settings.storage; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.netbeans.api.editor.settings.FontColorSettings; +import org.netbeans.api.editor.settings.KeyBindingSettings; +import org.openide.filesystems.FileObject; +import org.openide.util.TopologicalSortException; +import org.openide.util.Utilities; + +/** + * + * @author Vita Stejskal + */ +public enum SettingsType { + + FONTSCOLORS( + "FontsColors", //NOI18N + true, + FontColorSettings.class, + "text/x-nbeditor-fontcolorsettings" //NOI18N + ), + KEYBINDINGS( + "Keybindings", //NOI18N + true, + KeyBindingSettings.class, + "text/x-nbeditor-keybindingsettings" //NOI18N + ); + + public static SettingsType get(Class apiClass) { + assert apiClass != null : "The parameter apiClass can't be null"; //NOI18N + + for (SettingsType type : SettingsType.values()) { + if (type.apiClass.equals(apiClass)) { + return type; + } + } + return null; + } + + public static interface Locator { + public void scan(FileObject baseFolder, String mimeType, String profileId, boolean fullScan, boolean scanModules, boolean scanUsers, Map> results); + public String getWritableFileName(String mimeType, String profileId, boolean modulesFile); + } + + // ------------------------------------------------------------------ + // private implementation + // ------------------------------------------------------------------ + + private static final Logger LOG = Logger.getLogger(SettingsType.class.getName()); + + private final String settingsTypeId; + private final boolean usesProfiles; + private final Class apiClass; + private final String mimeType; + private Locator locator; + + private SettingsType(String settingsTypeId, boolean usesProfiles, Class apiClass, String mimeType) { + this.settingsTypeId = settingsTypeId; + this.usesProfiles = usesProfiles; + this.apiClass = apiClass; + this.mimeType = mimeType; + } + + public String getId() { + return settingsTypeId; + } + + public boolean isUsingProfiles() { + return usesProfiles; + } + + public String getMimeType() { + return mimeType; + } + + public Locator getLocator() { + if (locator == null) { + switch (this) { + case FONTSCOLORS: locator = new FontsColorsLocator(); break; + case KEYBINDINGS: locator = new KeybindingsLocator(); break; + default: locator = new DefaultLocator(this); + } + } + return locator; + } + + private static class DefaultLocator implements Locator { + + protected static final String MODULE_FILES_FOLDER = "Defaults"; //NOI18N + protected static final String DEFAULT_PROFILE_NAME = EditorSettingsImpl.DEFAULT_PROFILE; + + private static final String WRITABLE_FILE_PREFIX = "org-netbeans-modules-editor-settings-Custom"; //NOI18N + private static final String WRITABLE_FILE_SUFFIX = ".xml"; //NOI18N + private static final String FA_TARGET_OS = "nbeditor-settings-targetOS"; //NOI18N + + private final SettingsType settingType; + private final String settingTypeFolderName; + private final String writableFileName; + private final String modulesWritableFileName; + private final String usersWritableFileName; + + public DefaultLocator(SettingsType settingType) { + assert settingType != null : "The parameter settingType can't be null"; //NOI18N + this.settingType = settingType; + this.settingTypeFolderName = "/" + settingType.getId() + "/"; //NOI18N + this.writableFileName = WRITABLE_FILE_PREFIX + settingType.getId() + WRITABLE_FILE_SUFFIX; + this.modulesWritableFileName = "/" + MODULE_FILES_FOLDER + "/" + WRITABLE_FILE_PREFIX + settingType.getId() + WRITABLE_FILE_SUFFIX; //NOI18N + this.usersWritableFileName = "/" + writableFileName; //NOI18N + } + + public final void scan( + FileObject baseFolder, + String mimeType, + String profileId, + boolean fullScan, + boolean scanModules, + boolean scanUsers, + Map> results + ) { + assert baseFolder != null : "The parameter baseFolder can't be null"; //NOI18N + assert results != null : "The parameter results can't be null"; //NOI18N + + FileObject mimeFolder = getMimeFolder(baseFolder, mimeType); + FileObject legacyMimeFolder = getLegacyMimeFolder(baseFolder, mimeType); + + if (scanModules) { + if (legacyMimeFolder != null && legacyMimeFolder.isFolder()) { + addModulesLegacyFiles(legacyMimeFolder, profileId, fullScan, results); + } + if (mimeFolder != null && mimeFolder.isFolder()) { + addModulesFiles(mimeFolder, profileId, fullScan, results); + } + } + + if (scanUsers) { + if (legacyMimeFolder != null && legacyMimeFolder.isFolder()) { + addUsersLegacyFiles(legacyMimeFolder, profileId, fullScan, results); + } + if (mimeFolder != null && mimeFolder.isFolder()) { + addUsersFiles(mimeFolder, profileId, fullScan, results); + } + } + } + + public final String getWritableFileName(String mimeType, String profileId, boolean modulesFile) { + assert mimeType != null : "The mimeType parameter must not be null"; //NOI18N + assert profileId != null : "The profileId parameter must not be null"; //NOI18N + + String part; + + if (mimeType.length() == 0) { + part = settingType.getId() + "/"; //NOI18N + } else { + part = mimeType + settingTypeFolderName; + } + + if (modulesFile) { + return part + profileId + modulesWritableFileName; + } else { + return part + profileId + usersWritableFileName; + } + } + + protected FileObject getLegacyMimeFolder(FileObject baseFolder, String mimeType) { + return mimeType == null ? baseFolder : baseFolder.getFileObject(mimeType); + } + + protected void addModulesLegacyFiles(FileObject mimeFolder, String profileId, boolean fullScan, Map> files) { + // Do nothing by default + } + + protected void addUsersLegacyFiles(FileObject mimeFolder, String profileId, boolean fullScan, Map> files) { + // Do nothing by default + } + + private FileObject getMimeFolder(FileObject baseFolder, String mimeType) { + return mimeType == null ? baseFolder : baseFolder.getFileObject(mimeType); + } + + private void addModulesFiles(FileObject mimeFolder, String profileId, boolean fullScan, Map> files) { + if (profileId == null) { + FileObject settingHome = mimeFolder.getFileObject(settingType.getId()); + if (settingHome != null && settingHome.isFolder()) { + FileObject [] profileHomes = settingHome.getChildren(); + for(FileObject f : profileHomes) { + if (!f.isFolder()) { + continue; + } + + String id = f.getNameExt(); + FileObject folder = f.getFileObject(MODULE_FILES_FOLDER); + if (folder != null && folder.isFolder()) { + addFiles(folder, fullScan, files, id, f, true); + } + } + } + } else { + FileObject folder = mimeFolder.getFileObject(settingType.getId() + "/" + profileId + "/" + MODULE_FILES_FOLDER); //NOI18N + if (folder != null && folder.isFolder()) { + addFiles(folder, fullScan, files, profileId, folder.getParent(), true); + } + } + } + + private void addUsersFiles(FileObject mimeFolder, String profileId, boolean fullScan, Map> files) { + if (profileId == null) { + FileObject settingHome = mimeFolder.getFileObject(settingType.getId()); + if (settingHome != null && settingHome.isFolder()) { + FileObject [] profileHomes = settingHome.getChildren(); + for(FileObject f : profileHomes) { + if (f.isFolder()) { + String id = f.getNameExt(); + addFiles(f, fullScan, files, id, f, false); + } + } + } + } else { + FileObject folder = mimeFolder.getFileObject(settingType.getId() + "/" + profileId); //NOI18N + if (folder != null && folder.isFolder()) { + addFiles(folder, fullScan, files, profileId, folder, false); + } + } + } + + private final void addFiles(FileObject folder, boolean fullScan, Map> files, String profileId, FileObject profileHome, boolean moduleFiles) { + Object [] writableFile = null; + List osSpecificFiles = new ArrayList(); + + FileObject [] ff = getOrderedChildren(folder); + for(FileObject f : ff) { + if (f.isData() && f.getMIMEType().equals(settingType.getMimeType())) { + Object targetOs = f.getAttribute(FA_TARGET_OS); + if (targetOs != null) { + try { + if (!isApplicableForThisTargetOs(targetOs)) { + continue; + } + } catch (Exception e) { + LOG.log(Level.WARNING, "Ignoring editor settings file with invalid OS type mask '" + targetOs + "' file: " + f.getPath()); //NOI18N + continue; + } + } + + List infos = files.get(profileId); + if (infos == null) { + infos = new ArrayList(); + files.put(profileId, infos); + } + Object [] oo = new Object [] { profileHome, f, moduleFiles }; + + // There can be a writable file in the modules folder and it + // needs to be added last so that it does not get hidden by + // other module files. + if (f.getNameExt().equals(writableFileName)) { + assert writableFile == null; + writableFile = oo; + } else if (targetOs != null) { + osSpecificFiles.add(oo); + } else { + infos.add(oo); + } + + // Stop scanning if this is not a full scan mode + if (!fullScan) { + break; + } + } else { + LOG.fine("Ignoring file: " + f.getPath() + " of type " + f.getMIMEType()); //NOI18N + } + } + + if (!osSpecificFiles.isEmpty()) { + List infos = files.get(profileId); + infos.addAll(osSpecificFiles); + } + + // Add the writable file if there is any + if (writableFile != null) { + List infos = files.get(profileId); + infos.add(writableFile); + } + } + + private boolean isApplicableForThisTargetOs(Object targetOs) throws NoSuchFieldException, IllegalAccessException { + if (targetOs instanceof Boolean) { + return ((Boolean) targetOs).booleanValue(); + } else if (targetOs instanceof String) { + Field field = Utilities.class.getDeclaredField((String) targetOs); + int targetOsMask = field.getInt(null); + int currentOsId = Utilities.getOperatingSystem(); + return (currentOsId & targetOsMask) != 0; + } else { + return false; + } + } + + protected static FileObject [] getOrderedChildren(FileObject folder) { + // Collect all children + Map children = new HashMap(); + for (FileObject f : folder.getChildren()) { + String name = f.getNameExt(); + children.put(name, f); + } + + // Collect all edges + Map> edges = new HashMap>(); + for (Enumeration attrNames = folder.getAttributes(); attrNames.hasMoreElements(); ) { + String attrName = attrNames.nextElement(); + Object attrValue = folder.getAttribute(attrName); + + // Check whether the attribute affects sorting + int slashIdx = attrName.indexOf('/'); //NOI18N + if (slashIdx == -1 || !(attrValue instanceof Boolean)) { + continue; + } + + // Get the file names + String name1 = attrName.substring(0, slashIdx); + String name2 = attrName.substring(slashIdx + 1); + if (!((Boolean) attrValue).booleanValue()) { + // Swap the names + String s = name1; + name1 = name2; + name2 = s; + } + + // Get the files and add them among the edges + FileObject from = children.get(name1); + FileObject to = children.get(name2); + + if (from != null && to != null) { + Set vertices = edges.get(from); + if (vertices == null) { + vertices = new HashSet(); + edges.put(from, vertices); + } + vertices.add(to); + } + } + + // Sort the children + List sorted; + + try { + sorted = Utilities.topologicalSort(children.values(), edges); + } catch (TopologicalSortException e) { + LOG.log(Level.WARNING, "Can't sort folder children.", e); //NOI18N + @SuppressWarnings("unchecked") + List whyTheHellDoINeedToDoThis = e.partialSort(); + sorted = whyTheHellDoINeedToDoThis; + } + + return sorted.toArray(new FileObject[sorted.size()]); + } + } // End of DefaultLocator class + + private static final class FontsColorsLocator extends DefaultLocator { + + private static final String [] M_LEGACY_FILE_NAMES = new String [] { + MODULE_FILES_FOLDER + "/defaultColoring.xml", // NOI18N + MODULE_FILES_FOLDER + "/coloring.xml", // NOI18N + MODULE_FILES_FOLDER + "/editorColoring.xml", // NOI18N + }; + + private static final String [] U_LEGACY_FILE_NAMES = new String [] { + "defaultColoring.xml", // NOI18N + "coloring.xml", // NOI18N + "editorColoring.xml", // NOI18N + }; + + public FontsColorsLocator() { + super(FONTSCOLORS); + } + + @Override + protected void addModulesLegacyFiles( + FileObject mimeFolder, + String profileId, + boolean fullScan, + Map> files + ) { + addFiles(mimeFolder, profileId, fullScan, M_LEGACY_FILE_NAMES, files, true); + } + + @Override + protected void addUsersLegacyFiles( + FileObject mimeFolder, + String profileId, + boolean fullScan, + Map> files + ) { + addFiles(mimeFolder, profileId, fullScan, U_LEGACY_FILE_NAMES, files, false); + } + + private void addFiles( + FileObject mimeFolder, + String profileId, + boolean fullScan, + String [] filePaths, + Map> files, + boolean moduleFiles + ) { + if (profileId == null) { + FileObject [] profileHomes = mimeFolder.getChildren(); + for(FileObject f : profileHomes) { + if (!f.isFolder()) { + continue; + } + + String id = f.getNameExt(); + addFiles(f, filePaths, fullScan, files, id, f, moduleFiles); //NOI18N + } + } else { + FileObject profileHome = mimeFolder.getFileObject(profileId); + if (profileHome != null && profileHome.isFolder()) { + addFiles(profileHome, filePaths, fullScan, files, profileId, profileHome, moduleFiles); + } + } + } + + private void addFiles(FileObject folder, String [] filePaths, boolean fullScan, Map> files, String profileId, FileObject profileHome, boolean moduleFiles) { + for(String filePath : filePaths) { + FileObject f = folder.getFileObject(filePath); + if (f != null) { + List pair = files.get(profileId); + if (pair == null) { + pair = new ArrayList(); + files.put(profileId, pair); + } + pair.add(new Object [] { profileHome, f, moduleFiles }); + if (!fullScan) { + break; + } + } + } + } + } // End of FontsColorsLocator class + + private static final class KeybindingsLocator extends DefaultLocator { + + private static final String M_KEYBINDING_FILE_NAME = MODULE_FILES_FOLDER + "/keybindings.xml"; // NOI18N + private static final String U_KEYBINDING_FILE_NAME = "keybindings.xml"; // NOI18N + + public KeybindingsLocator() { + super(KEYBINDINGS); + } + + @Override + protected FileObject getLegacyMimeFolder(FileObject baseFolder, String mimeType) { + if (mimeType == null || mimeType.length() == 0) { + return baseFolder.getFileObject(EditorSettingsImpl.TEXT_BASE_MIME_TYPE); + } else { + return super.getMimeFolder(baseFolder, mimeType); + } + } + + @Override + protected void addModulesLegacyFiles( + FileObject mimeFolder, + String profileId, + boolean fullScan, + Map> files + ) { + addFiles(mimeFolder, profileId, fullScan, M_KEYBINDING_FILE_NAME, files, true); + } + + @Override + protected void addUsersLegacyFiles( + FileObject mimeFolder, + String profileId, + boolean fullScan, + Map> files + ) { + addFiles(mimeFolder, profileId, fullScan, U_KEYBINDING_FILE_NAME, files, false); + } + + private void addFiles( + FileObject mimeFolder, + String profileId, + boolean fullScan, + String filePath, + Map> files, + boolean moduleFiles + ) { + if (profileId == null) { + FileObject [] profileHomes = mimeFolder.getChildren(); + for(FileObject f : profileHomes) { + if (!f.isFolder() || f.getNameExt().equals(MODULE_FILES_FOLDER)) { + continue; + } + + String id = f.getNameExt(); + FileObject file = f.getFileObject(filePath); + if (file != null) { + addFile(file, files, id, f, moduleFiles); + } + } + + FileObject file = mimeFolder.getFileObject(filePath); + if (file != null) { + addFile(file, files, DEFAULT_PROFILE_NAME, null, moduleFiles); + } + } else { + if (profileId.equals(DEFAULT_PROFILE_NAME)) { + FileObject file = mimeFolder.getFileObject(filePath); //NOI18N + if (file != null) { + addFile(file, files, profileId, null, moduleFiles); + } + } else { + FileObject profileHome = mimeFolder.getFileObject(profileId); + if (profileHome != null && profileHome.isFolder()) { + FileObject file = profileHome.getFileObject(filePath); + if (file != null) { + addFile(file, files, profileId, profileHome, moduleFiles); + } + } + } + } + } + + private void addFile(FileObject file, Map> files, String profileId, FileObject profileHome, boolean moduleFiles) { + List pair = files.get(profileId); + if (pair == null) { + pair = new ArrayList(); + files.put(profileId, pair); + } + pair.add(new Object [] { profileHome, file, moduleFiles }); + } + + } // End of KeybindingsLocator class +} Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/Utils.java =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/Utils.java,v retrieving revision 1.17 retrieving revision 1.12.2.6 diff -u -r1.17 -r1.12.2.6 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/Utils.java 26 Jan 2007 04:58:52 -0000 1.17 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/Utils.java 19 Mar 2007 04:28:57 -0000 1.12.2.6 @@ -21,16 +21,17 @@ import java.awt.Color; import java.awt.Font; -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; +import java.util.Set; import java.util.StringTokenizer; import java.util.WeakHashMap; import java.util.logging.Level; @@ -40,12 +41,15 @@ import javax.swing.text.StyleConstants; import org.netbeans.api.editor.mimelookup.MimePath; import org.netbeans.api.editor.settings.AttributesUtilities; +import org.openide.filesystems.FileAttributeEvent; +import org.openide.filesystems.FileChangeAdapter; +import org.openide.filesystems.FileChangeListener; +import org.openide.filesystems.FileEvent; import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileSystem; -import org.openide.filesystems.FileUtil; -import org.openide.filesystems.Repository; +import org.openide.filesystems.FileStateInvalidException; import org.openide.util.NbBundle; import org.openide.util.Utilities; +import org.openide.util.WeakListeners; /** @@ -154,80 +158,32 @@ return result.toArray(new KeyStroke[result.size ()]); } - static FileObject getFileObject(MimePath mimePath, String profile, String fileNameExt) { - String name = getFileName(mimePath, profile, fileNameExt); - FileSystem fs = Repository.getDefault().getDefaultFileSystem(); - return fs.findResource(name); - } - - /** - * Crates FileObject for given mimeTypes and profile. - */ - static FileObject createFileObject(MimePath mimePath, String profile, String fileName) { - String name = getFileName(mimePath, profile, fileName); - FileSystem fs = Repository.getDefault().getDefaultFileSystem(); + static String getLocalizedName(FileObject fo, String defaultValue) { try { - if (fileName == null) { - return FileUtil.createFolder(fs.getRoot(), name); - } else { - return FileUtil.createData(fs.getRoot(), name); - } - } catch (IOException ex) { - LOG.log(Level.WARNING, "Can't create editor settings file or folder: " + name, ex); //NOI18N - return null; - } - } - - /** - * Crates FileObject for given mimeTypes and profile. - */ - static void deleteFileObject(MimePath mimePath, String profile, String fileName) { - String name = getFileName(mimePath, profile, fileName); - FileSystem fs = Repository.getDefault().getDefaultFileSystem(); - FileObject fo = fs.findResource(name); - if (fo != null) { - try { - fo.delete(); - } catch (IOException ex) { - LOG.log(Level.WARNING, "Can't delete editor settings file " + fo.getPath(), ex); //NOI18N + return fo.getFileSystem().getStatus().annotateName(defaultValue, Collections.singleton(fo)); + } catch (FileStateInvalidException ex) { + if (LOG.isLoggable(Level.INFO)) { + logOnce(Level.INFO, "Can't find localized name of " + fo, ex); //NOI18N } + return defaultValue; } } - static String getFileName(MimePath mimePath, String profile, String fileName) { - StringBuilder sb = new StringBuilder("Editors"); - - if (mimePath.size() > 0) { - sb.append('/').append(mimePath.getPath()); - } - - if (profile != null) { - sb.append('/').append(profile); - } - - if (fileName != null) { - sb.append('/').append(fileName); - } - - return sb.toString(); - } - - private static FileObject createFile (FileObject fo, String next) throws IOException { - FileObject fo1 = fo.getFileObject (next); - if (fo1 == null) - return fo.createFolder (next); - return fo1; + static String getLocalizedName(FileObject fo, String key, String defaultValue) { + return getLocalizedName(fo, key, defaultValue, false); } - static String getLocalizedName(FileObject fo, String key, String defaultValue) { + static String getLocalizedName(FileObject fo, String key, String defaultValue, boolean silent) { assert key != null : "The key can't be null"; //NOI18N - Object [] bundleInfo = findResourceBundle(fo); + Object [] bundleInfo = findResourceBundle(fo, silent); if (bundleInfo[1] != null) { try { return ((ResourceBundle) bundleInfo[1]).getString(key); } catch (MissingResourceException ex) { - LOG.log(Level.WARNING, "The bundle '" + bundleInfo[0] + "' is missing key '" + key + "'.", ex); //NOI18N + if (!silent && LOG.isLoggable(Level.INFO)) { + logOnce(Level.INFO, "The bundle '" + bundleInfo[0] + "' is missing key '" + key + "'.", ex); //NOI18N + } } } @@ -235,7 +191,25 @@ } private static final WeakHashMap bundleInfos = new WeakHashMap(); - private static Object [] findResourceBundle(FileObject fo) { + private static final FileChangeListener listener = new FileChangeAdapter() { + @Override + public void fileDeleted(FileEvent fe) { + synchronized (bundleInfos) { + bundleInfos.remove(fe.getFile()); + } + } + + @Override + public void fileAttributeChanged(FileAttributeEvent fe) { + if (fe.getName() != null && fe.getName().equals("SystemFileSystem.localizingBundle")) { //NOI18N + synchronized (bundleInfos) { + bundleInfos.remove(fe.getFile()); + } + } + } + }; + private static final FileChangeListener weakListener = WeakListeners.create(FileChangeListener.class, listener, null); + private static Object [] findResourceBundle(FileObject fo, boolean silent) { assert fo != null : "FileObject can't be null"; //NOI18N synchronized (bundleInfos) { @@ -251,10 +225,14 @@ try { bundleInfo = new Object [] { bundleName, NbBundle.getBundle(bundleName) }; } catch (MissingResourceException ex) { - LOG.log(Level.WARNING, "Can't find resource bundle for " + fo.getPath(), ex); //NOI18N + if (!silent && LOG.isLoggable(Level.INFO)) { + logOnce(Level.INFO, "Can't find resource bundle for " + fo.getPath(), ex); //NOI18N + } } } else { - //[PENDING][HACK] LOG.log(Level.WARNING, "The file " + fo.getPath() + " does not specify its resource bundle.", new Throwable("@@@")); //NOI18N + if (!silent && LOG.isLoggable(Level.FINE)) { + logOnce(Level.FINE, "The file " + fo.getPath() + " does not specify its resource bundle.", null); //NOI18N + } } if (bundleInfo == null) { @@ -262,12 +240,30 @@ } bundleInfos.put(fo, bundleInfo); + fo.removeFileChangeListener(weakListener); + fo.addFileChangeListener(weakListener); } return bundleInfo; } } + private static final Set ALREADY_LOGGED = Collections.synchronizedSet(new HashSet()); + private static void logOnce(Level level, String msg, Throwable t) { + if (!ALREADY_LOGGED.contains(msg)) { + ALREADY_LOGGED.add(msg); + if (t != null) { + LOG.log(level, msg, t); + } else { + LOG.log(level, msg); + } + + if (ALREADY_LOGGED.size() > 100) { + ALREADY_LOGGED.clear(); + } + } + } + /** * Converts an array of mime types to a MimePath instance. */ @@ -285,7 +281,7 @@ * Creates unmodifiable copy of the original map converting AttributeSets * to their immutable versions. */ - public static Map immutize(Map map) { + public static Map immutize(Map map) { Map immutizedMap = new HashMap(); for(String name : map.keySet()) { @@ -310,5 +306,4 @@ return Collections.unmodifiableMap(immutizedMap); } - } Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/layer.xml =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/layer.xml,v retrieving revision 1.2 retrieving revision 1.2.6.1 diff -u -r1.2 -r1.2.6.1 --- editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/layer.xml 9 Nov 2006 01:57:19 -0000 1.2 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/layer.xml 10 Mar 2007 00:55:02 -0000 1.2.6.1 @@ -20,6 +20,17 @@ + + + + + + + + + + + Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/mime-resolvers.xml =================================================================== RCS file: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/mime-resolvers.xml diff -N editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/mime-resolvers.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/mime-resolvers.xml 10 Mar 2007 00:55:02 -0000 1.1.2.1 @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/api/EditorSettings.java =================================================================== RCS file: /cvs/editor/settings/storage/src/org/netbeans/modules/editor/settings/storage/api/EditorSettings.java,v retrieving revision 1.13 retrieving revision 1.9.4.1 diff -u -r1.13 -r1.9.4.1 Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/Bundle.properties =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/Bundle.properties diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/Bundle.properties --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/Bundle.properties 12 Mar 2007 01:16:10 -0000 1.1.2.2 @@ -0,0 +1,19 @@ +# The contents of this file are subject to the terms of the Common Development +# and Distribution License (the License). You may not use this file except in +# compliance with the License. +# +# You can obtain a copy of the License at http://www.netbeans.org/cddl.html +# or http://www.netbeans.org/cddl.txt. +# +# When distributing Covered Code, include this CDDL Header Notice in each file +# and include the License file at http://www.netbeans.org/cddl.txt. +# If applicable, add the following below the CDDL Header, with the fields +# enclosed by brackets [] replaced by your own identifying information: +# "Portions Copyrighted [year] [name of copyright owner]" +# +# The Original Software is NetBeans. The Initial Developer of the Original +# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun +# Microsystems, Inc. All Rights Reserved. + +Xyz/XoX/abc/text/plain/FontsColors/ProfileA=Nice Display Name Of Profile A +Xyz/XoX/abc/text/plain/Keybindings/ProfileA=Nice Display Name Of Profile A Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/EditorSettingsStorageTest.java =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/EditorSettingsStorageTest.java,v retrieving revision 1.11 retrieving revision 1.11.2.2 diff -u -r1.11 -r1.11.2.2 --- editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/EditorSettingsStorageTest.java 20 Dec 2006 02:09:15 -0000 1.11 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/EditorSettingsStorageTest.java 14 Mar 2007 08:09:23 -0000 1.11.2.2 @@ -61,9 +61,11 @@ EditorTestLookup.setLookup( new URL[] { getClass().getClassLoader().getResource( - "org/netbeans/modules/editor/settings/storage/test-layer.xml"), + "org/netbeans/modules/editor/settings/storage/test-layer.xml"), getClass().getClassLoader().getResource( - "org/netbeans/modules/editor/settings/storage/layer.xml"), + "org/netbeans/modules/editor/settings/storage/layer.xml"), + getClass().getClassLoader().getResource( + "org/netbeans/core/resources/mf-layer.xml"), // for MIMEResolverImpl to work }, getWorkDir(), new Object[] {}, @@ -159,7 +161,7 @@ AttributeSet attribs = fcs.getTokenFontColors(coloringName); assertNotNull("Can't find " + coloringName + " coloring", attribs); - assertEquals("Wrong bgColor", new Color(rgb), attribs.getAttribute(attributeKey)); + assertEquals("Wrong " + attributeKey, new Color(rgb), attribs.getAttribute(attributeKey)); } public void testSetColors() { Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/EditorTestLookup.java =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/EditorTestLookup.java,v retrieving revision 1.4 retrieving revision 1.4.4.1 diff -u -r1.4 -r1.4.4.1 --- editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/EditorTestLookup.java 8 Nov 2006 03:37:41 -0000 1.4 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/EditorTestLookup.java 12 Mar 2007 03:46:10 -0000 1.4.4.1 @@ -24,6 +24,8 @@ import java.io.File; import java.io.IOException; import java.net.URL; +import java.util.MissingResourceException; +import java.util.ResourceBundle; import junit.framework.Assert; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileSystem; @@ -35,6 +37,7 @@ import org.openide.loaders.DataFolder; import org.openide.loaders.FolderLookup; import org.openide.util.Lookup; +import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; @@ -146,9 +149,9 @@ createFileOnPath(mountPoint, resources[i]); } - LocalFileSystem lfs = new StatusFileSystem(); + LocalFileSystem lfs = new LocalFileSystem(); try { - lfs.setRootDirectory(mountPoint); + lfs.setRootDirectory(mountPoint); } catch (Exception ex) {} return lfs; @@ -171,24 +174,7 @@ } } - private static class StatusFileSystem extends LocalFileSystem { - Status status = new Status () { - public String annotateName (String name, java.util.Set files) { - return name; - } - - public java.awt.Image annotateIcon (java.awt.Image icon, int iconType, java.util.Set files) { - return icon; - } - }; - - public org.openide.filesystems.FileSystem.Status getStatus() { - return status; - } - - } - - private static class SystemFileSystem extends MultiFileSystem { + private static class SystemFileSystem extends MultiFileSystem implements FileSystem.Status { public SystemFileSystem(FileSystem [] orig) { super(orig); } @@ -196,5 +182,32 @@ public void setOrig(FileSystem [] orig) { setDelegates(orig); } - } + + public FileSystem.Status getStatus() { + return this; + } + + public String annotateName (String name, java.util.Set files) { + for(Object o : files) { + FileObject fo = (FileObject) o; + String bundleName = (String)fo.getAttribute ("SystemFileSystem.localizingBundle"); // NOI18N + if (bundleName != null) { + bundleName = org.openide.util.Utilities.translate(bundleName); + ResourceBundle b = NbBundle.getBundle(bundleName); + try { + return b.getString (fo.getPath()); + } catch (MissingResourceException ex) { + // ignore--normal + ex.printStackTrace(); + } + } + } + + return name; + } + + public java.awt.Image annotateIcon (java.awt.Image icon, int iconType, java.util.Set files) { + return icon; + } + } // End of SystemFileSystem class } Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/FontColorSettingsImplTest.java =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/FontColorSettingsImplTest.java,v retrieving revision 1.3 retrieving revision 1.3.8.2 diff -u -r1.3 -r1.3.8.2 --- editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/FontColorSettingsImplTest.java 4 Jan 2007 01:07:29 -0000 1.3 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/FontColorSettingsImplTest.java 10 Mar 2007 00:55:00 -0000 1.3.8.2 @@ -49,9 +49,11 @@ EditorTestLookup.setLookup( new URL[] { getClass().getClassLoader().getResource( - "org/netbeans/modules/editor/settings/storage/test-layer.xml"), + "org/netbeans/modules/editor/settings/storage/test-layer.xml"), getClass().getClassLoader().getResource( - "org/netbeans/modules/editor/settings/storage/layer.xml"), + "org/netbeans/modules/editor/settings/storage/layer.xml"), + getClass().getClassLoader().getResource( + "org/netbeans/core/resources/mf-layer.xml"), // for MIMEResolverImpl to work }, getWorkDir(), new Object[] {}, Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/LocatorTest.java =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/LocatorTest.java diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/LocatorTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/LocatorTest.java 16 Mar 2007 02:54:25 -0000 1.1.2.2 @@ -0,0 +1,311 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.editor.settings.storage; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.netbeans.core.startup.Main; +import org.netbeans.junit.NbTestCase; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.Repository; +import org.openide.util.Utilities; + +/** + * + * @author Vita Stejskal + */ +public class LocatorTest extends NbTestCase { + + private static final String FC_CONTENTS = + "\n" + + "\n" + + ""; + + private static final String KB_CONTENTS = + "\n" + + "\n" + + ""; + + /** Creates a new instance of LocatorTest */ + public LocatorTest(String name) { + super(name); + } + + protected void setUp() throws Exception { + super.setUp(); + + EditorTestLookup.setLookup( + new URL[] { + getClass().getClassLoader().getResource( + "org/netbeans/modules/editor/settings/storage/layer.xml"), + getClass().getClassLoader().getResource( + "org/netbeans/core/resources/mf-layer.xml"), // for MIMEResolverImpl to work + }, + getWorkDir(), + new Object[] {}, + getClass().getClassLoader() + ); + + // This is here to initialize Nb URL factory (org.netbeans.core.startup), + // which is needed by Nb EntityCatalog (org.netbeans.core). + // Also see the test dependencies in project.xml + Main.initializeURLFactory(); + } + + public void testOsSpecificFiles() throws Exception { + String currentOs = getCurrentOsId(); + String [] files = new String [] { + "Editors/text/x-whatever/FontsColors/PPP/Defaults/f.xml", + "Editors/text/x-whatever/FontsColors/PPP/Defaults/e.xml", + "Editors/text/x-whatever/FontsColors/PPP/Defaults/d.xml", + "Editors/text/x-whatever/FontsColors/PPP/Defaults/a.xml", + "Editors/text/x-whatever/FontsColors/PPP/file4.xml", + "Editors/text/x-whatever/FontsColors/PPP/file1.xml", + "Editors/text/x-whatever/FontsColors/PPP/file99.xml", + }; + + createOrderedFiles(files, FC_CONTENTS); + + FileObject f = Repository.getDefault().getDefaultFileSystem().findResource("Editors/text/x-whatever/FontsColors/PPP/Defaults/e.xml"); + f.setAttribute("nbeditor-settings-targetOS", currentOs); + + String [] osOrderedFiles = new String [] { + "Editors/text/x-whatever/FontsColors/PPP/Defaults/f.xml", + "Editors/text/x-whatever/FontsColors/PPP/Defaults/d.xml", + "Editors/text/x-whatever/FontsColors/PPP/Defaults/a.xml", + "Editors/text/x-whatever/FontsColors/PPP/Defaults/e.xml", + "Editors/text/x-whatever/FontsColors/PPP/file4.xml", + "Editors/text/x-whatever/FontsColors/PPP/file1.xml", + "Editors/text/x-whatever/FontsColors/PPP/file99.xml", + }; + + FileObject baseFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors"); + Map> results = new HashMap>(); + SettingsType.FONTSCOLORS.getLocator().scan(baseFolder, "text/x-whatever", null, true, true, true, results); + + assertNotNull("Scan results should not null", results); + assertEquals("Wrong number of profiles", 1, results.size()); + + List profileFiles = results.get("PPP"); + checkProfileFiles(osOrderedFiles, null, profileFiles, "PPP"); + } + + public void testFullLayout() throws Exception { + String [] files1 = new String [] { + "Editors/text/x-whatever/FontsColors/MyProfileA/Defaults/file1.xml", + "Editors/text/x-whatever/FontsColors/MyProfileA/Defaults/file2.xml", + "Editors/text/x-whatever/FontsColors/MyProfileA/Defaults/file3.xml", + "Editors/text/x-whatever/FontsColors/MyProfileA/Defaults/file4.xml", + "Editors/text/x-whatever/FontsColors/MyProfileA/file1.xml", + "Editors/text/x-whatever/FontsColors/MyProfileA/file2.xml", + "Editors/text/x-whatever/FontsColors/MyProfileA/file3.xml", + }; + + String [] files2 = new String [] { + "Editors/text/x-whatever/FontsColors/MyProfile2/Defaults/xyz.xml", + "Editors/text/x-whatever/FontsColors/MyProfile2/Defaults/abc.xml", + "Editors/text/x-whatever/FontsColors/MyProfile2/mrkev.xml", + "Editors/text/x-whatever/FontsColors/MyProfile2/okurka.xml", + "Editors/text/x-whatever/FontsColors/MyProfile2/cibule.xml", + }; + + createOrderedFiles(files1, FC_CONTENTS); + TestUtilities.createFile("Editors/text/x-whatever/FontsColors/MyProfileA/org-netbeans-modules-editor-settings-CustomFontsColors.xml", FC_CONTENTS); + createOrderedFiles(files2, FC_CONTENTS); + TestUtilities.createFile("Editors/text/x-whatever/FontsColors/MyProfile2/org-netbeans-modules-editor-settings-CustomFontsColors.xml", FC_CONTENTS); + + FileObject baseFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors"); + Map> results = new HashMap>(); + SettingsType.FONTSCOLORS.getLocator().scan(baseFolder, "text/x-whatever", null, true, true, true, results); + + assertNotNull("Scan results should not null", results); + assertEquals("Wrong number of profiles", 2, results.size()); + + List profileAFiles = results.get("MyProfileA"); + checkProfileFiles(files1, "Editors/text/x-whatever/FontsColors/MyProfileA/org-netbeans-modules-editor-settings-CustomFontsColors.xml", profileAFiles, "ProfileA"); + + List profile2Files = results.get("MyProfile2"); + checkProfileFiles(files2, "Editors/text/x-whatever/FontsColors/MyProfile2/org-netbeans-modules-editor-settings-CustomFontsColors.xml", profile2Files, "ProfileA"); + } + + public void testFullFontsColorsLegacyLayout() throws Exception { + String [] files = new String [] { + "Editors/NetBeans/Defaults/defaultColoring.xml", + "Editors/NetBeans/Defaults/coloring.xml", + "Editors/NetBeans/Defaults/editorColoring.xml", + "Editors/NetBeans/coloring.xml", + "Editors/NetBeans/editorColoring.xml", + }; + + createOrderedFiles(files, FC_CONTENTS); + + FileObject baseFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors"); + Map> results = new HashMap>(); + SettingsType.FONTSCOLORS.getLocator().scan(baseFolder, null, null, true, true, true, results); + + assertNotNull("Scan results should not null", results); + assertEquals("Wrong number of profiles", 1, results.size()); + + List profileFiles = results.get("NetBeans"); + checkProfileFiles(files, null, profileFiles, "NetBeans"); + } + + public void testFullFontsColorsMixedLayout() throws Exception { + String [] files = new String [] { + "Editors/text/x-whatever/NetBeans/Defaults/defaultColoring.xml", + "Editors/text/x-whatever/NetBeans/Defaults/coloring.xml", + "Editors/text/x-whatever/NetBeans/Defaults/editorColoring.xml", + "Editors/text/x-whatever/FontsColors/NetBeans/Defaults/file1.xml", + "Editors/text/x-whatever/FontsColors/NetBeans/Defaults/file2.xml", + "Editors/text/x-whatever/FontsColors/NetBeans/Defaults/file3.xml", + "Editors/text/x-whatever/FontsColors/NetBeans/Defaults/file4.xml", + "Editors/text/x-whatever/NetBeans/coloring.xml", + "Editors/text/x-whatever/NetBeans/editorColoring.xml", + "Editors/text/x-whatever/FontsColors/NetBeans/file1.xml", + "Editors/text/x-whatever/FontsColors/NetBeans/file2.xml", + "Editors/text/x-whatever/FontsColors/NetBeans/file3.xml", + }; + + createOrderedFiles(files, FC_CONTENTS); + TestUtilities.createFile("Editors/text/x-whatever/FontsColors/NetBeans/org-netbeans-modules-editor-settings-CustomFontsColors.xml", FC_CONTENTS); + + FileObject baseFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors"); + Map> results = new HashMap>(); + SettingsType.FONTSCOLORS.getLocator().scan(baseFolder, "text/x-whatever", null, true, true, true, results); + + assertNotNull("Scan results should not null", results); + assertEquals("Wrong number of profiles", 1, results.size()); + + List profileFiles = results.get("NetBeans"); + checkProfileFiles(files, "Editors/text/x-whatever/FontsColors/NetBeans/org-netbeans-modules-editor-settings-CustomFontsColors.xml", profileFiles, "NetBeans"); + } + + public void testFullKeybindingsLegacyLayout() throws Exception { + String [] files = new String [] { + "Editors/text/base/Defaults/keybindings.xml", + "Editors/Keybindings/NetBeans/Defaults/zz.xml", + "Editors/Keybindings/NetBeans/Defaults/dd.xml", + "Editors/Keybindings/NetBeans/Defaults/kk.xml", + "Editors/Keybindings/NetBeans/Defaults/aa.xml", + "Editors/text/base/keybindings.xml", + "Editors/Keybindings/NetBeans/papap.xml", + "Editors/Keybindings/NetBeans/kekeke.xml", + "Editors/Keybindings/NetBeans/dhdhdddd.xml", + }; + + createOrderedFiles(files, KB_CONTENTS); + TestUtilities.createFile("Editors/Keybindings/NetBeans/org-netbeans-modules-editor-settings-CustomKeybindings.xml", KB_CONTENTS); + + FileObject baseFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors"); + Map> results = new HashMap>(); + SettingsType.KEYBINDINGS.getLocator().scan(baseFolder, null, null, true, true, true, results); + + assertNotNull("Scan results should not null", results); + assertEquals("Wrong number of profiles", 1, results.size()); + + List profileFiles = results.get("NetBeans"); + checkProfileFiles(files, "Editors/Keybindings/NetBeans/org-netbeans-modules-editor-settings-CustomKeybindings.xml", profileFiles, "NetBeans"); + } + + public void testFullKeybindingsMixedLayout() throws Exception { + String [] files = new String [] { + "Editors/text/base/Defaults/keybindings.xml", + "Editors/text/base/keybindings.xml", + }; + + createOrderedFiles(files, KB_CONTENTS); + + FileObject baseFolder = Repository.getDefault().getDefaultFileSystem().findResource("Editors"); + Map> results = new HashMap>(); + SettingsType.KEYBINDINGS.getLocator().scan(baseFolder, null, null, true, true, true, results); + + assertNotNull("Scan results should not null", results); + assertEquals("Wrong number of profiles", 1, results.size()); + + List profileFiles = results.get("NetBeans"); + checkProfileFiles(files, null, profileFiles, "NetBeans"); + } + + private void checkProfileFiles(String [] paths, String writablePath, List files, String profileId) { + assertNotNull(profileId + ": No files", files); + assertEquals(profileId + ": Wrong number of files", + writablePath != null ? paths.length + 1 : paths.length, files.size()); + + for(int i = 0; i < paths.length; i++) { + FileObject profileHome = (FileObject) files.get(i)[0]; + FileObject settingFile = (FileObject) files.get(i)[1]; + boolean modulesFile = ((Boolean) files.get(i)[2]).booleanValue(); + + assertEquals(profileId + ": wrong file", paths[i], settingFile.getPath()); + } + + if (writablePath != null) { + FileObject profileHome = (FileObject) files.get(paths.length)[0]; + FileObject settingFile = (FileObject) files.get(paths.length)[1]; + boolean modulesFile = ((Boolean) files.get(paths.length)[2]).booleanValue(); + + assertEquals(profileId + ": wrong writable file", writablePath, settingFile.getPath()); + } + } + + private void createOrderedFiles(String [] files, String contents) throws IOException { + for(int i = 0; i < files.length; i++) { + FileObject f = TestUtilities.createFile(files[i], contents); + if (i + 1 < files.length) { + String [] thisFile = getNameParts(files[i]); + String [] nextFile = getNameParts(files[i + 1]); + + if (thisFile[0].equals(nextFile[0])) { + String ordering = thisFile[1] + "/" + nextFile[1]; + f.getParent().setAttribute(ordering, Boolean.TRUE); + } + } + } + } + + private String [] getNameParts(String path) { + int idx = path.lastIndexOf('/'); + if (idx != -1) { + return new String [] { path.substring(0, idx), path.substring(idx + 1) }; + } else { + return new String [] { "", path }; + } + } + + private String getCurrentOsId() { + int osId = Utilities.getOperatingSystem(); + for(Field field : Utilities.class.getDeclaredFields()) { + try { + int value = field.getInt(null); + if (value == osId) { + return field.getName(); + } + } catch (Exception e) { + // ignore + } + } + fail("Can't detect OS type "); + return null; // not reachable + } +} Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/MimeTypesTrackerTest.java =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/MimeTypesTrackerTest.java diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/MimeTypesTrackerTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/MimeTypesTrackerTest.java 16 Mar 2007 03:05:24 -0000 1.1.2.2 @@ -0,0 +1,294 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.editor.settings.storage; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.TreeSet; +import org.netbeans.junit.NbTestCase; + +/** + * + * @author Vita Stejskal + */ +public class MimeTypesTrackerTest extends NbTestCase { + + private static final String BASE = "Some/Folder/SomeWhere"; + + /** Creates a new instance of MimeTypesTrackerTest */ + public MimeTypesTrackerTest(String name) { + super(name); + } + + protected void setUp() throws Exception { + super.setUp(); + + EditorTestLookup.setLookup( + new URL[] { }, + getWorkDir(), + new Object[] {}, + getClass().getClassLoader() + ); + } + + public void testBasic() throws Exception { + TestUtilities.createFolder(BASE + "/text/plain"); + MimeTypesTracker mtt = new MimeTypesTracker(BASE, null); + Collection mimeTypes = mtt.getMimeTypes(); + + assertNotNull("MimeTypes should not be null", mimeTypes); + assertEquals("Wrong # of recognized mime types", 1, mimeTypes.size()); + assertEquals("Wrong mime type", "text/plain", mimeTypes.iterator().next()); + } + + public void testGC() throws Exception { + TestUtilities.createFolder(BASE + "/text/plain"); + MimeTypesTracker mtt = new MimeTypesTracker(BASE, null); + Collection mimeTypes = mtt.getMimeTypes(); + + assertNotNull("MimeTypes should not be null", mimeTypes); + assertEquals("Wrong # of recognized mime types", 1, mimeTypes.size()); + assertEquals("Wrong mime type", "text/plain", mimeTypes.iterator().next()); + + WeakReference ref = new WeakReference(mtt); + mtt = null; + assertGC("Can't GC the tracker", ref); + } + + public void testWellKnownMimeTypes() throws Exception { + // See http://www.iana.org/assignments/media-types/ for details + String [] mimeTypes = new String [] { + "application/pdf", //NOI18N + "audio/mpeg", //NOI18N + "image/jpeg", //NOI18N + "message/news", //NOI18N + "model/vrml", //NOI18N + "multipart/mixed", //NOI18N + "text/plain", //NOI18N + "video/mpeg" //NOI18N + }; + + for(String s : mimeTypes) { + TestUtilities.createFolder(BASE + "/" + s); + } + + MimeTypesTracker mtt = new MimeTypesTracker(BASE, null); + Collection recognized = mtt.getMimeTypes(); + + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", mimeTypes.length, recognized.size()); + assertEquals("Wrong mime types", new TreeSet(Arrays.asList(mimeTypes)), new TreeSet(recognized)); + } + + public void testFoldersNotRecognized() throws IOException { + String [] mimeTypes = new String [] { + "NetBeans/Default", //NOI18N + "Default", //NOI18N + "KeyBindings/whatever", //NOI18N + "Toolbars/Default", //NOI18N + "SideBar/MySideBar", //NOI18N + }; + + for(String s : mimeTypes) { + TestUtilities.createFolder(BASE + "/" + s); + } + + MimeTypesTracker mtt = new MimeTypesTracker(BASE, null); + Collection recognized = mtt.getMimeTypes(); + + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + } + + public void testFilesNotRecognized() throws IOException { + TestUtilities.createFile(BASE + "/text/hello.xml"); + TestUtilities.createFile(BASE + "/text"); + TestUtilities.createFile(BASE + "/application/pdf"); + + MimeTypesTracker mtt = new MimeTypesTracker(BASE, null); + Collection recognized = mtt.getMimeTypes(); + + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + } + + public void testRecognition() throws IOException { + final MimeTypesTracker mtt = new MimeTypesTracker(BASE, null); + + { + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + } + + { + TestUtilities.createFolder(BASE); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + } + + { + TestUtilities.createFolder(BASE + "/text"); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + } + + { + TestUtilities.createFolder(BASE + "/text/x-java"); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 1, recognized.size()); + assertEquals("Wrong mime type recognized", "text/x-java", recognized.iterator().next()); + } + + { + TestUtilities.delete(BASE + "/text/x-java"); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + } + { + TestUtilities.delete(BASE + "/text"); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + } + { + TestUtilities.delete(BASE); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + } + } + + public void testEvents() throws IOException { + final L listener = new L(); + final MimeTypesTracker mtt = new MimeTypesTracker(BASE, null); + mtt.addPropertyChangeListener(listener); + + { + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + assertEquals("Wrong # of events fired", 0, listener.events); + } + + { + TestUtilities.createFolder(BASE + "/text/x-java"); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 1, recognized.size()); + assertEquals("Wrong mime type recognized", "text/x-java", recognized.iterator().next()); + assertEquals("Wrong # of events fired", 1, listener.events); + assertEquals("Wrong change event name", MimeTypesTracker.PROP_MIME_TYPES, listener.lastEventName); + assertTrue("Wrong change event old value", listener.lastEventOldValue instanceof Map); + assertEquals("Wrong change event old value contents", 0, ((Map) listener.lastEventOldValue).size()); + assertTrue("Wrong change event new value", listener.lastEventNewValue instanceof Map); + assertEquals("Wrong change event new value contents", 1, ((Map) listener.lastEventNewValue).size()); + assertEquals("Wrong change event new value mime type", "text/x-java", ((Map) listener.lastEventNewValue).keySet().iterator().next()); + } + + { + listener.reset(); + TestUtilities.delete(BASE); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + assertEquals("Wrong # of events fired", 1, listener.events); + assertEquals("Wrong change event name", MimeTypesTracker.PROP_MIME_TYPES, listener.lastEventName); + assertTrue("Wrong change event old value", listener.lastEventOldValue instanceof Map); + assertEquals("Wrong change event old value contents", 1, ((Map) listener.lastEventOldValue).size()); + assertEquals("Wrong change event old value mime type", "text/x-java", ((Map) listener.lastEventOldValue).keySet().iterator().next()); + assertTrue("Wrong change event new value", listener.lastEventNewValue instanceof Map); + assertEquals("Wrong change event new value contents", 0, ((Map) listener.lastEventNewValue).size()); + } + } + + public void testEvents2() throws IOException { + final L listener = new L(); + final MimeTypesTracker mtt = new MimeTypesTracker(BASE, null); + mtt.addPropertyChangeListener(listener); + + { + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 0, recognized.size()); + assertEquals("Wrong # of events fired", 0, listener.events); + } + + { + TestUtilities.createFolder(BASE + "/text/plain"); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 1, recognized.size()); + assertEquals("Wrong mime type recognized", "text/plain", recognized.iterator().next()); + assertEquals("Wrong # of events fired", 1, listener.events); + } + + { + listener.reset(); + TestUtilities.createFolder(BASE + "/NetBeans"); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 1, recognized.size()); + assertEquals("Wrong mime type recognized", "text/plain", recognized.iterator().next()); + assertEquals("Wrong # of events fired", 0, listener.events); + } + + { + listener.reset(); + TestUtilities.createFolder(BASE + "/text/plain/NetBeans"); + Collection recognized = mtt.getMimeTypes(); + assertNotNull("MimeTypes should not be null", recognized); + assertEquals("Wrong # of recognized mime types", 1, recognized.size()); + assertEquals("Wrong mime type recognized", "text/plain", recognized.iterator().next()); + assertEquals("Wrong # of events fired", 0, listener.events); + } + } + + private static final class L implements PropertyChangeListener { + public int events; + public String lastEventName; + public Object lastEventOldValue; + public Object lastEventNewValue; + + public void propertyChange(PropertyChangeEvent evt) { + events++; + lastEventName = evt.getPropertyName(); + lastEventOldValue = evt.getOldValue(); + lastEventNewValue = evt.getNewValue(); + } + + public void reset() { + events = 0; + lastEventName = null; + lastEventOldValue = null; + lastEventNewValue = null; + } + } +} Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/ProfilesTrackerTest.java =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/ProfilesTrackerTest.java diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/ProfilesTrackerTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/ProfilesTrackerTest.java 16 Mar 2007 03:05:25 -0000 1.1.2.5 @@ -0,0 +1,390 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.editor.settings.storage; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.util.Map; +import java.util.Set; +import junit.framework.Test; +import junit.framework.TestResult; +import org.netbeans.core.startup.Main; +import org.netbeans.junit.NbTestCase; +import org.netbeans.junit.NbTestSuite; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.Repository; + +/** + * + * @author Vita Stejskal + */ +public class ProfilesTrackerTest extends NbTestCase { + + // This is also in Bundle.properties + private static final String BASE = "Xyz/XoX/abc"; + + // XXX: This is here just for junit to match the test names in the results properly + private SettingsType type = (SettingsType) Suite.ENV[0][2]; + private String folder = (String) Suite.ENV[0][1]; + private String contents = (String) Suite.ENV[0][0]; + + public static Test suite() { + return new Suite(ProfilesTrackerTest.class); + } + + /** Creates a new instance of MimeTypesTrackerTest */ + public ProfilesTrackerTest(String name) { + super(name); + } + + private void setEnv(SettingsType type, String folder, String contents) { + this.type = type; + this.folder = folder; + this.contents = contents; + } + + public String getName() { + return super.getName() + "(" + type + ")"; + } + + protected void setUp() throws Exception { + super.setUp(); + + EditorTestLookup.setLookup( + new URL[] { + getClass().getClassLoader().getResource( + "org/netbeans/modules/editor/settings/storage/layer.xml"), + getClass().getClassLoader().getResource( + "org/netbeans/core/resources/mf-layer.xml"), // for MIMEResolverImpl to work + }, + getWorkDir(), + new Object[] {}, + getClass().getClassLoader() + ); + + // This is here to initialize Nb URL factory (org.netbeans.core.startup), + // which is needed by Nb EntityCatalog (org.netbeans.core). + // Also see the test dependencies in project.xml + Main.initializeURLFactory(); + } + + protected void tearDown() { + assertGC("Perform GC", new WeakReference(new Object())); + } + + public void testBasic() throws Exception { + TestUtilities.createFile(BASE + "/text/plain/" + folder + "/ProfileA/abc.xml", contents); + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + Set profiles = pt.getProfilesDisplayNames(); + + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 1, profiles.size()); + assertEquals("Wrong profile display name", "ProfileA", profiles.iterator().next()); + } + + public void testBasicRoot() throws Exception { + TestUtilities.createFile(BASE + "/" + folder + "/ProfileA/abc.xml", contents); + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + Set profiles = pt.getProfilesDisplayNames(); + + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 1, profiles.size()); + assertEquals("Wrong profile display name", "ProfileA", profiles.iterator().next()); + } + + public void testSeveralMimes() throws Exception { + TestUtilities.createFile(BASE + "/text/plain/" + folder + "/ProfileA/abc.xml", contents); + TestUtilities.createFile(BASE + "/text/x-java/" + folder + "/ProfileA/abc.xml", contents); + TestUtilities.createFile(BASE + "/text/xml/" + folder + "/ProfileA/abc.xml", contents); + TestUtilities.createFile(BASE + "/text/plain/" + folder + "/ProfileB/abc.xml", contents); + TestUtilities.createFile(BASE + "/text/xml/" + folder + "/ProfileB/abc.xml", contents); + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + Set profiles = pt.getProfilesDisplayNames(); + + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 2, profiles.size()); + assertTrue("No 'ProfileA'", profiles.contains("ProfileA")); + assertTrue("No 'ProfileB'", profiles.contains("ProfileB")); + } + + public void testDisplayName() throws Exception { + TestUtilities.createFile(BASE + "/text/plain/" + folder + "/ProfileA/abc.xml", contents); + FileObject f = Repository.getDefault().getDefaultFileSystem().findResource(BASE + "/text/plain/" + folder + "/ProfileA"); + f.setAttribute("SystemFileSystem.localizingBundle", "org.netbeans.modules.editor.settings.storage.Bundle"); + + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + Set profiles = pt.getProfilesDisplayNames(); + + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 1, profiles.size()); + assertEquals("Wrong profile display name", "Nice Display Name Of Profile A", profiles.iterator().next()); + } + + public void testRollbackIndicator() throws Exception { + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + + { + TestUtilities.createFile(BASE + "/text/plain/" + folder + "/ProfileA/abc.xml", contents); + ProfilesTracker.ProfileDescription pd = pt.getProfileByDisplayName("ProfileA"); + assertNotNull("ProfileDescription should not be null", pd); + assertFalse("Wrong isRollbackAllowed value", pd.isRollbackAllowed()); + } + + { + TestUtilities.createFile(BASE + "/text/plain/" + folder + "/ProfileA/Defaults/abc.xml", contents); + ProfilesTracker.ProfileDescription pd = pt.getProfileByDisplayName("ProfileA"); + assertNotNull("ProfileDescription should not be null", pd); + assertTrue("Wrong isRollbackAllowed value", pd.isRollbackAllowed()); + } + } + + public void testGC() throws Exception { + TestUtilities.createFile(BASE + "/text/plain/" + folder + "/ProfileA/abc.xml", contents); + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + Set profiles = pt.getProfilesDisplayNames(); + + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 1, profiles.size()); + assertEquals("Wrong profile display name", "ProfileA", profiles.iterator().next()); + + WeakReference ref = new WeakReference(pt); + pt = null; + assertGC("Can't GC the tracker", ref); + } + + public void testRecognition() throws Exception { + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + + { + TestUtilities.createFolder(BASE); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + } + { + TestUtilities.createFolder(BASE + "/text"); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + } + { + TestUtilities.createFolder(BASE + "/text/x-jsp"); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + } + { + TestUtilities.createFolder(BASE + "/text/x-jsp/FontsColors"); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + } + { + TestUtilities.createFile(BASE + "/text/x-jsp/" + folder + "/MyProfile/abc.xml", contents); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 1, profiles.size()); + assertEquals("Wrong profile display name", "MyProfile", profiles.iterator().next()); + } + } + + public void testRecognition2() throws Exception { + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + + { + TestUtilities.createFile(BASE + "/text/x-jsp/" + folder + "/MyProfile/abc.xml", contents); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 1, profiles.size()); + assertEquals("Wrong profile display name", "MyProfile", profiles.iterator().next()); + } + { + TestUtilities.delete(BASE + "/text/x-jsp/" + folder + "/MyProfile/abc.xml"); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + } + { + TestUtilities.createFile(BASE + "/text/x-jsp/" + folder + "/MyProfile/abc.xml", contents); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 1, profiles.size()); + assertEquals("Wrong profile display name", "MyProfile", profiles.iterator().next()); + } + { + TestUtilities.delete(BASE); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + } + } + + public void testEvents() throws Exception { + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + L listener = new L(); + + pt.addPropertyChangeListener(listener); + { + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + assertEquals("Wrong # of events", 0, listener.events); + } + + { + TestUtilities.createFile(BASE + "/text/x-jsp/" + folder + "/MyProfile/abc.xml", contents); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 1, profiles.size()); + assertEquals("Wrong profile display name", "MyProfile", profiles.iterator().next()); + assertEquals("Wrong # of events", 1, listener.events); + assertEquals("Wrong change event name", ProfilesTracker.PROP_PROFILES, listener.lastEventName); + assertTrue("Wrong change event old value", listener.lastEventOldValue instanceof Map); + assertEquals("Wrong change event old value contents", 0, ((Map) listener.lastEventOldValue).size()); + assertTrue("Wrong change event new value", listener.lastEventNewValue instanceof Map); + assertEquals("Wrong change event new value contents", 1, ((Map) listener.lastEventNewValue).size()); + assertEquals("Wrong change event new value profile", "MyProfile", ((Map) listener.lastEventNewValue).keySet().iterator().next()); + } + + { + listener.reset(); + TestUtilities.delete(BASE); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + assertEquals("Wrong # of events", 1, listener.events); + assertEquals("Wrong change event name", ProfilesTracker.PROP_PROFILES, listener.lastEventName); + assertTrue("Wrong change event old value", listener.lastEventOldValue instanceof Map); + assertEquals("Wrong change event old value contents", 1, ((Map) listener.lastEventOldValue).size()); + assertEquals("Wrong change event new value profile", "MyProfile", ((Map) listener.lastEventOldValue).keySet().iterator().next()); + assertTrue("Wrong change event new value", listener.lastEventNewValue instanceof Map); + assertEquals("Wrong change event new value contents", 0, ((Map) listener.lastEventNewValue).size()); + } + } + + public void testEventsRoot() throws Exception { + ProfilesTracker pt = new ProfilesTracker(type, new MimeTypesTracker(BASE, null)); + L listener = new L(); + + pt.addPropertyChangeListener(listener); + { + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + assertEquals("Wrong # of events", 0, listener.events); + } + + { + TestUtilities.createFile(BASE + "/" + folder + "/MyProfile/abc.xml", contents); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 1, profiles.size()); + assertEquals("Wrong profile display name", "MyProfile", profiles.iterator().next()); + assertEquals("Wrong # of events", 1, listener.events); + assertEquals("Wrong change event name", ProfilesTracker.PROP_PROFILES, listener.lastEventName); + assertTrue("Wrong change event old value", listener.lastEventOldValue instanceof Map); + assertEquals("Wrong change event old value contents", 0, ((Map) listener.lastEventOldValue).size()); + assertTrue("Wrong change event new value", listener.lastEventNewValue instanceof Map); + assertEquals("Wrong change event new value contents", 1, ((Map) listener.lastEventNewValue).size()); + assertEquals("Wrong change event new value profile", "MyProfile", ((Map) listener.lastEventNewValue).keySet().iterator().next()); + } + + { + listener.reset(); + TestUtilities.delete(BASE); + Set profiles = pt.getProfilesDisplayNames(); + assertNotNull("Profiles should not be null", profiles); + assertEquals("Wrong # of recognized profiles", 0, profiles.size()); + assertEquals("Wrong # of events", 1, listener.events); + assertEquals("Wrong change event name", ProfilesTracker.PROP_PROFILES, listener.lastEventName); + assertTrue("Wrong change event old value", listener.lastEventOldValue instanceof Map); + assertEquals("Wrong change event old value contents", 1, ((Map) listener.lastEventOldValue).size()); + assertEquals("Wrong change event new value profile", "MyProfile", ((Map) listener.lastEventOldValue).keySet().iterator().next()); + assertTrue("Wrong change event new value", listener.lastEventNewValue instanceof Map); + assertEquals("Wrong change event new value contents", 0, ((Map) listener.lastEventNewValue).size()); + } + } + + private static final class L implements PropertyChangeListener { + public int events; + public String lastEventName; + public Object lastEventOldValue; + public Object lastEventNewValue; + + public void propertyChange(PropertyChangeEvent evt) { + events++; + lastEventName = evt.getPropertyName(); + lastEventOldValue = evt.getOldValue(); + lastEventNewValue = evt.getNewValue(); + } + + public void reset() { + events = 0; + lastEventName = null; + lastEventOldValue = null; + lastEventNewValue = null; + } + } + + private static final class Suite extends NbTestSuite { + + public static final Object [][] ENV = { + new Object [] { + "\n" + + "\n" + + "", + "FontsColors", + SettingsType.FONTSCOLORS + }, + new Object [] { + "\n" + + "\n" + + "", + "Keybindings", + SettingsType.KEYBINDINGS + }, + }; + + public Suite(Class klass) { + super(klass); + } + + @Override + public void run(TestResult result) { + for(int i = 0; i < ENV.length; i++) { + String contents = (String) ENV[i][0]; + String folder = (String) ENV[i][1]; + SettingsType type = (SettingsType) ENV[i][2]; + + for(int j = 0; j < testCount(); j++) { + Test test = testAt(j); + if (test instanceof ProfilesTrackerTest) { + ((ProfilesTrackerTest) test).setEnv(type, folder, contents); + } + } + + System.out.println("Running tests for: " + type); + super.run(result); + } + } + } +} Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/SettingsProviderTest.java =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/SettingsProviderTest.java,v retrieving revision 1.5 retrieving revision 1.3.2.2 diff -u -r1.5 -r1.3.2.2 --- editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/SettingsProviderTest.java 17 Jan 2007 04:09:01 -0000 1.5 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/SettingsProviderTest.java 10 Mar 2007 00:55:01 -0000 1.3.2.2 @@ -51,9 +51,11 @@ EditorTestLookup.setLookup( new URL[] { getClass().getClassLoader().getResource( - "org/netbeans/modules/editor/settings/storage/test-layer.xml"), + "org/netbeans/modules/editor/settings/storage/test-layer.xml"), getClass().getClassLoader().getResource( - "org/netbeans/modules/editor/settings/storage/layer.xml"), + "org/netbeans/modules/editor/settings/storage/layer.xml"), + getClass().getClassLoader().getResource( + "org/netbeans/core/resources/mf-layer.xml"), // for MIMEResolverImpl to work }, getWorkDir(), new Object[] {}, Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/TestUtilities.java =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/TestUtilities.java diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/TestUtilities.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/TestUtilities.java 16 Mar 2007 01:18:55 -0000 1.1.2.2 @@ -0,0 +1,111 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.editor.settings.storage; + +import java.io.IOException; +import java.io.OutputStream; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileSystem; +import org.openide.filesystems.Repository; + +/** + * + * @author Vita Stejskal + */ +public final class TestUtilities { + + /** Creates a new instance of TestUtilities */ + private TestUtilities() { + } + + public static FileObject createFile(String path) throws IOException { + return createFO(path, false, null); + } + + public static FileObject createFile(String path, String contents) throws IOException { + return createFO(path, false, contents); + } + + public static FileObject createFolder(String path) throws IOException { + return createFO(path, true, null); + } + + private static FileObject createFO(final String path, final boolean folder, final String contents) throws IOException { + Repository rp = Repository.getDefault(); + final FileSystem sfs = rp == null ? null : rp.getDefaultFileSystem(); + + if (sfs == null) { + throw new IOException("No system FS."); + } + + final FileObject [] createdFo = new FileObject[1]; + sfs.runAtomicAction(new FileSystem.AtomicAction() { + public void run() throws IOException { + FileObject fo = sfs.getRoot(); + String [] pathElements = path.split("/", -1); + for (int i = 0; i < pathElements.length; i++ ) { + String elementName = pathElements[i]; + + if (elementName.length() == 0) { + continue; + } + + FileObject f = fo.getFileObject(elementName); + if (f != null && f.isValid()) { + fo = f; + } else { + if (i + 1 < pathElements.length || folder) { + fo = fo.createFolder(elementName); + } else { + // The last element in the path should be a file + fo = fo.createData(elementName); + if (contents != null) { + OutputStream os = fo.getOutputStream(); + try { + os.write(contents.getBytes()); + } finally { + os.close(); + } + } + } + } + } + createdFo[0] = fo; + } + }); + + return createdFo[0]; + } + + public static void delete(String path) throws IOException { + Repository rp = Repository.getDefault(); + FileSystem sfs = rp == null ? null : rp.getDefaultFileSystem(); + + if (sfs == null) { + throw new IOException("No system FS."); + } + + FileObject fo = sfs.findResource(path); + if (fo != null) { + fo.delete(); + } + } + +} Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-2.xml =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-2.xml,v retrieving revision 1.2 retrieving revision 1.2.4.1 diff -u -r1.2 -r1.2.4.1 Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-3.xml =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-3.xml,v retrieving revision 1.1 retrieving revision 1.1.8.1 diff -u -r1.1 -r1.1.8.1 Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-4.xml =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-4.xml,v retrieving revision 1.1 retrieving revision 1.1.8.1 diff -u -r1.1 -r1.1.8.1 Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-5.xml =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-5.xml,v retrieving revision 1.1 retrieving revision 1.1.6.1 diff -u -r1.1 -r1.1.6.1 Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-all-languages.xml =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors-all-languages.xml,v retrieving revision 1.2 retrieving revision 1.2.8.1 diff -u -r1.2 -r1.2.8.1 Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors.xml =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fonts-and-colors.xml,v retrieving revision 1.2 retrieving revision 1.1.6.1 diff -u -r1.2 -r1.1.6.1 Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/test-layer.xml =================================================================== RCS file: /cvs/editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/test-layer.xml,v retrieving revision 1.5 retrieving revision 1.2.4.1 diff -u -r1.5 -r1.2.4.1 Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/ColoringStorageTest.java =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/ColoringStorageTest.java diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/ColoringStorageTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/ColoringStorageTest.java 16 Mar 2007 02:54:26 -0000 1.1.2.2 @@ -0,0 +1,178 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.editor.settings.storage.fontscolors; + +import java.awt.Color; +import java.net.URL; +import java.util.ArrayList; +import java.util.Map; +import javax.swing.text.AttributeSet; +import javax.swing.text.AttributeSet; +import javax.swing.text.StyleConstants; +import org.netbeans.api.editor.mimelookup.MimePath; +import org.netbeans.api.editor.settings.AttributesUtilities; +import org.netbeans.core.startup.Main; +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.editor.settings.storage.ColoringStorage; +import org.netbeans.modules.editor.settings.storage.EditorTestLookup; +import org.netbeans.modules.editor.settings.storage.SettingsType; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.Repository; + +/** + * + * @author Vita Stejskal + */ +public class ColoringStorageTest extends NbTestCase { + + /** Creates a new instance of ColoringStorageTest */ + public ColoringStorageTest(String name) { + super(name); + } + + protected void setUp() throws Exception { + super.setUp(); + + EditorTestLookup.setLookup( + new URL[] { + getClass().getClassLoader().getResource( + "org/netbeans/modules/editor/settings/storage/fontscolors/test-layer-ColoringStorageTest.xml"), + getClass().getClassLoader().getResource( + "org/netbeans/modules/editor/settings/storage/layer.xml"), + getClass().getClassLoader().getResource( + "org/netbeans/core/resources/mf-layer.xml"), // for MIMEResolverImpl to work + }, + getWorkDir(), + new Object[] {}, + getClass().getClassLoader() + ); + + // This is here to initialize Nb URL factory (org.netbeans.core.startup), + // which is needed by Nb EntityCatalog (org.netbeans.core). + // Also see the test dependencies in project.xml + Main.initializeURLFactory(); + } + + public void testAllLanguages() { + Map colorings = ColoringStorage.loadColorings(MimePath.EMPTY, "MyProfileXyz", true, true); //NOI18N + assertNotNull("Colorings map should not be null", colorings); + assertEquals("Wrong number of colorings", 1, colorings.size()); + + AttributeSet c = colorings.get("test-all-languages-super-default"); + assertNotNull("Should have test-all-languages-super-default coloring", c); + assertEquals("Wrong bgColor", new Color(0xABCDEF), c.getAttribute(StyleConstants.Background)); + } + + public void testAllLanguages2() { + Map colorings = ColoringStorage.loadColorings(MimePath.EMPTY, "MyProfileXyz", true, false); //NOI18N + assertNotNull("Colorings map should not be null", colorings); + assertEquals("Wrong number of colorings", 1, colorings.size()); + + AttributeSet c = colorings.get("test-all-languages-super-default"); + assertNotNull("Should have test-all-languages-super-default coloring", c); + assertEquals("Wrong bgColor", new Color(0xABCDEF), c.getAttribute(StyleConstants.Background)); + } + + public void testAllLanguagesHighlights() { + Map colorings = ColoringStorage.loadColorings(MimePath.EMPTY, "MyProfileXyz", false, true); //NOI18N + assertNotNull("Colorings map should not be null", colorings); + assertEquals("Wrong number of colorings", 1, colorings.size()); + + AttributeSet c = colorings.get("test-text-limit-line"); + assertNotNull("Should have test-text-limit-line coloring", c); + assertEquals("Wrong bgColor", new Color(0x010101), c.getAttribute(StyleConstants.Foreground)); + } + + public void testAllLanguagesHighlights2() { + Map colorings = ColoringStorage.loadColorings(MimePath.EMPTY, "MyProfileXyz", false, false); //NOI18N + assertNotNull("Colorings map should not be null", colorings); + assertEquals("Wrong number of colorings", 1, colorings.size()); + + AttributeSet c = colorings.get("test-text-limit-line"); + assertNotNull("Should have test-text-limit-line coloring", c); + assertEquals("Wrong bgColor", new Color(0x010101), c.getAttribute(StyleConstants.Foreground)); + } + + public void testMultipleFiles() { + MimePath mimePath = MimePath.parse("text/x-type-A"); + Map colorings = ColoringStorage.loadColorings(mimePath, "MyProfileXyz", true, false); //NOI18N + assertNotNull("Colorings map should not be null", colorings); + assertEquals("Wrong number of colorings", 3, colorings.size()); + + // Check coloring in module A only + { + AttributeSet c = colorings.get("module-A-coloring"); + assertNotNull("Should have module-A-coloring coloring", c); + assertEquals("Wrong bgColor", new Color(0xAA0000), c.getAttribute(StyleConstants.Background)); + } + { + // Check coloring in module B only + AttributeSet c = colorings.get("module-B-coloring"); + assertNotNull("Should have module-B-coloring coloring", c); + assertEquals("Wrong bgColor", new Color(0xBB0000), c.getAttribute(StyleConstants.Background)); + } + { + // Check shared coloring + AttributeSet c = colorings.get("both-modules-coloring"); + assertNotNull("Should have both-modules-coloring coloring", c); + assertEquals("Wrong bgColor", new Color(0xAA0000), c.getAttribute(StyleConstants.Background)); + assertEquals("Wrong foreColor", new Color(0x00BB00), c.getAttribute(StyleConstants.Foreground)); + assertEquals("Wrong underline", new Color(0x0000BB), c.getAttribute(StyleConstants.Underline)); + } + } + + public void testDeleteFiles() { + MimePath mimePath = MimePath.parse("text/x-type-A"); + ColoringStorage.deleteColorings(mimePath, "MyProfileXyz", true, true); + + FileObject profileHome = Repository.getDefault().getDefaultFileSystem().findResource("Editors/text/x-type-A/FontsColors/MyProfileXyz/Defaults"); + assertNotNull("Can't find profileHome", profileHome); + + FileObject [] files = profileHome.getChildren(); + assertEquals("There should be no files", 0, files.length); + + Map colorings = ColoringStorage.loadColorings(mimePath, "MyProfileXyz", true, true); //NOI18N + assertNotNull("Colorings map should not be null", colorings); + assertEquals("There should be no colorings", 0, colorings.size()); + } + + public void testWriteColorings() { + final String name = "new-coloring"; + final Color color = new Color(0x1F2F3F); + MimePath mimePath = MimePath.parse("text/x-type-A"); + ArrayList newColorings = new ArrayList(); + newColorings.add(AttributesUtilities.createImmutable(StyleConstants.Underline, color, StyleConstants.NameAttribute, name)); + + ColoringStorage.saveColorings(mimePath, "MyProfileXyz", true, false, newColorings); + + FileObject settingFile = Repository.getDefault().getDefaultFileSystem().findResource("Editors/text/x-type-A/FontsColors/MyProfileXyz/org-netbeans-modules-editor-settings-CustomFontsColors.xml"); + assertNotNull("Can't find custom settingFile", settingFile); + assertEquals("Wrong mime type", SettingsType.FONTSCOLORS.getMimeType(), settingFile.getMIMEType()); + + Map colorings = ColoringStorage.loadColorings(mimePath, "MyProfileXyz", true, false); //NOI18N + assertNotNull("Colorings map should not be null", colorings); + assertEquals("There should be no colorings", 4, colorings.size()); + + AttributeSet c = colorings.get(name); + assertNotNull("Should have " + name + " coloring", c); + assertEquals("Wrong underline", color, c.getAttribute(StyleConstants.Underline)); + } + +} Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/highlight-colorings-all-languages.xml =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/highlight-colorings-all-languages.xml diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/highlight-colorings-all-languages.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/highlight-colorings-all-languages.xml 14 Mar 2007 08:09:21 -0000 1.1.2.1 @@ -0,0 +1,6 @@ + + + + + + Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/module-A.xml =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/module-A.xml diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/module-A.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/module-A.xml 14 Mar 2007 08:09:21 -0000 1.1.2.1 @@ -0,0 +1,7 @@ + + + + + + + Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/module-B.xml =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/module-B.xml diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/module-B.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/module-B.xml 14 Mar 2007 08:09:23 -0000 1.1.2.1 @@ -0,0 +1,7 @@ + + + + + + + Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/test-layer-ColoringStorageTest.xml =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/test-layer-ColoringStorageTest.xml diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/test-layer-ColoringStorageTest.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/test-layer-ColoringStorageTest.xml 15 Mar 2007 21:46:30 -0000 1.1.2.2 @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/token-colorings-all-languages.xml =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/token-colorings-all-languages.xml diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/token-colorings-all-languages.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/fontscolors/token-colorings-all-languages.xml 14 Mar 2007 08:09:22 -0000 1.1.2.1 @@ -0,0 +1,6 @@ + + + + + + Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/KeybindingStorageTest.java =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/KeybindingStorageTest.java diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/KeybindingStorageTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/KeybindingStorageTest.java 16 Mar 2007 02:54:22 -0000 1.1.2.1 @@ -0,0 +1,139 @@ +/* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + * + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.modules.editor.settings.storage.keybindings; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.swing.KeyStroke; +import org.netbeans.api.editor.mimelookup.MimePath; +import org.netbeans.api.editor.settings.MultiKeyBinding; +import org.netbeans.core.startup.Main; +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.editor.settings.storage.EditorTestLookup; +import org.netbeans.modules.editor.settings.storage.KeyMapsStorage; +import org.netbeans.modules.editor.settings.storage.SettingsType; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.Repository; +import org.openide.util.Utilities; + +/** + * + * @author Vita Stejskal + */ +public class KeybindingStorageTest extends NbTestCase { + + /** Creates a new instance of KeybindingsStorageTest */ + public KeybindingStorageTest(String name) { + super(name); + } + + protected void setUp() throws Exception { + super.setUp(); + + EditorTestLookup.setLookup( + new URL[] { + getClass().getClassLoader().getResource( + "org/netbeans/modules/editor/settings/storage/keybindings/test-layer-KeybindingStorageTest.xml"), + getClass().getClassLoader().getResource( + "org/netbeans/modules/editor/settings/storage/layer.xml"), + getClass().getClassLoader().getResource( + "org/netbeans/core/resources/mf-layer.xml"), // for MIMEResolverImpl to work + }, + getWorkDir(), + new Object[] {}, + getClass().getClassLoader() + ); + + // This is here to initialize Nb URL factory (org.netbeans.core.startup), + // which is needed by Nb EntityCatalog (org.netbeans.core). + // Also see the test dependencies in project.xml + Main.initializeURLFactory(); + } + + public void testAllLanguages() { + Map, MultiKeyBinding> keybindings = KeyMapsStorage.loadKeyMaps(MimePath.EMPTY, "MyProfileXyz", true); //NOI18N + assertNotNull("Keybindings map should not be null", keybindings); + assertEquals("Wrong number of keybindings", 1, keybindings.size()); + + checkMapConsistency(keybindings); + + MultiKeyBinding mkb = keybindings.values().iterator().next(); + assertNotNull("MultiKeyBinding should not be null", mkb); + assertEquals("Wrong action name", "test-action-all-languages-A", mkb.getActionName()); + assertEquals("Wrong number of key strokes", 1, mkb.getKeyStrokeCount()); + assertEquals("Wrong key stroke", Utilities.stringToKey("O-A"), mkb.getKeyStroke(0)); + } + + public void testMultipleFiles() { + MimePath mimePath = MimePath.parse("text/x-type-A"); + Map, MultiKeyBinding> keybindings = KeyMapsStorage.loadKeyMaps(mimePath, "MyProfileXyz", true); //NOI18N + assertNotNull("Keybindings map should not be null", keybindings); + assertEquals("Wrong number of keybindings", 5, keybindings.size()); + + checkMapConsistency(keybindings); + + checkKeybinding(keybindings, "test-action-1", "D-1 A"); + checkKeybinding(keybindings, "test-action-2", "D-2 A"); + checkKeybinding(keybindings, "test-action-2", "D-2 B"); + checkKeybinding(keybindings, "test-action-4", "D-4 B"); + checkKeybinding(keybindings, "test-action-5", "D-5 B"); + } + + public void testWriteKeybindings() { + // Create new keybindings + Collection newKeybindings = new ArrayList(); + newKeybindings.add(new MultiKeyBinding(Utilities.stringToKeys("D-D D"), "the-super-action")); + + // Create new removed keybindings + Set> newRemovedKeybindings = new HashSet>(); + newRemovedKeybindings.add(Arrays.asList(Utilities.stringToKeys("O-A"))); + + KeyMapsStorage.saveKeyMaps(MimePath.EMPTY, "MyProfileXyz", false, newKeybindings, newRemovedKeybindings); + + FileObject settingFile = Repository.getDefault().getDefaultFileSystem().findResource("Editors/Keybindings/MyProfileXyz/org-netbeans-modules-editor-settings-CustomKeybindings.xml"); + assertNotNull("Can't find custom settingFile", settingFile); + assertEquals("Wrong mime type", SettingsType.KEYBINDINGS.getMimeType(), settingFile.getMIMEType()); + + Map, MultiKeyBinding> keybindings = KeyMapsStorage.loadKeyMaps(MimePath.EMPTY, "MyProfileXyz", false); //NOI18N + assertNotNull("Keybindings map should not be null", keybindings); + assertEquals("Wrong number of keybindings", 1, keybindings.size()); + checkKeybinding(keybindings, "the-super-action", "D-D D"); + } + + private void checkMapConsistency(Map, MultiKeyBinding> keybindings) { + for(Collection keyStrokes : keybindings.keySet()) { + MultiKeyBinding mkb = keybindings.get(keyStrokes); + assertEquals("Inconsistent keystrokes", keyStrokes, mkb.getKeyStrokeList()); + } + } + + private void checkKeybinding(Map, MultiKeyBinding> keybindings, String actionName, String keyStroke) { + Collection strokes = Arrays.asList(Utilities.stringToKeys(keyStroke)); + MultiKeyBinding mkb = keybindings.get(strokes); + assertNotNull("MultiKeyBinding should not be null", mkb); + assertEquals("Wrong action name", actionName, mkb.getActionName()); + assertEquals("Wrong key strokes", strokes, mkb.getKeyStrokeList()); + } +} Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/keybindings-all-languages.xml =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/keybindings-all-languages.xml diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/keybindings-all-languages.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/keybindings-all-languages.xml 16 Mar 2007 02:54:21 -0000 1.1.2.1 @@ -0,0 +1,6 @@ + + + + + + Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/module-A.xml =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/module-A.xml diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/module-A.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/module-A.xml 16 Mar 2007 02:54:23 -0000 1.1.2.1 @@ -0,0 +1,9 @@ + + + + + + + + + Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/module-B.xml =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/module-B.xml diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/module-B.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/module-B.xml 16 Mar 2007 02:54:23 -0000 1.1.2.1 @@ -0,0 +1,10 @@ + + + + + + + + + + Index: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/test-layer-KeybindingStorageTest.xml =================================================================== RCS file: editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/test-layer-KeybindingStorageTest.xml diff -N editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/test-layer-KeybindingStorageTest.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ editor/settings/storage/test/unit/src/org/netbeans/modules/editor/settings/storage/keybindings/test-layer-KeybindingStorageTest.xml 16 Mar 2007 02:54:21 -0000 1.1.2.1 @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +