| <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> |
| <html> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| <meta name="GENERATOR" content="Microsoft FrontPage 4.0"> |
| <title>User Settings: FAQ</title> |
| <link rel="stylesheet" href="http://dev.eclipse.org/default_style.css" type="text/css"> |
| </head> |
| <body text="#000000" bgcolor="#FFFFFF"> |
| |
| |
| <table BORDER=0 CELLSPACING=5 CELLPADDING=2 WIDTH="100%" > |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2" BGCOLOR="#0080C0"><b><font face="Arial,Helvetica" color="#FFFFFF">User Settings: FAQ</font></b></td> |
| </tr> |
| |
| <tr> |
| <td align="left" colspan="2"> |
| <font size=-1><i>last updated: January 19, 2005</i></font> |
| </td> |
| </tr> |
| |
| <tr> |
| <td align="left" colspan="2"> |
| General: |
| <ol> |
| <li><a href="#whatIs">What is a scope?</a></li> |
| <li><a href="#platformScopes">What scopes are contributed by the Platform?</a></li> |
| <li><a href="#tree">This is confusing, how can I picture this in my mind?</a></li> |
| <li><a href="#basicGet">How do I know if auto-build is turned on? (How do I get a preference value?)</a></li> |
| <li><a href="#basicSet">How can I set the auto-build preference? (How do I set a preference value?)</a></li> |
| <li><a href="#backwardsCompatibilityScopes">Why doesn't the backwards compatibility layer check all the scopes for a value?</a></li> |
| <li><a href="#flush">When are my preference changes saved to disk?</a></li> |
| <li><a href="#customization">How does the plug-in customization story work?</a></li> |
| </ol> |
| Conversion: |
| <ol> |
| <li><a href="#convert">What should I do to convert my code to the new mechanism?</a></li> |
| <li><a href="#convertProject">How do I convert my project property page to use project preferences?</a></li> |
| <li><a href="#imemento">How do I convert my IMemento values?</a></li> |
| </ol> |
| Listeners: |
| <ol> |
| <li>How do I know when changes have happened to my preference?</li> |
| <li>But I want to listen to changes in ALL scopes, not just one.</li> |
| </ol> |
| Nodes: |
| <ol> |
| <li><a href="#nodes">Why should I use nodes?</a></li> |
| <li><a href="#illegalStateException">Why am I getting an IllegalStateException when calling APIs?</a></li> |
| </ol> |
| Extensions: |
| <ol> |
| <li><a href="#extension">How do I extend the preferences and add my own scope?</a></li> |
| </ol> |
| </td> |
| </tr> |
| |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="whatIs"></a>What is a |
| scope?</b><p></p> |
| In Eclipse 2.1 there was only one place to store preferences via the Runtime APIs. |
| Users would ask a particular plug-in for its preferences |
| (<code>Plugin.getPluginPreferences()</code>) and the preferences would be store per plug-in, |
| per workspace. This allowed some conveniences but it was obvious that |
| the new preference mechanism needed to be extensible and allow settings to be |
| stored in different places...users want to share their preferences between |
| workspaces, configurations, and even share them with other users. This is the |
| main reason that we created "scopes" for the preference store. |
| <p> |
| A scope basically refers to where the preferences are stored. Different |
| preference scopes can be contributed by plug-ins so the number of scopes |
| available to clients is not limited to those defined by the platform. |
| </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="platformScopes"></a>What |
| scopes are contributed by the Platform?</b><p></p> |
| INSTANCE - |
| The instance scope can also be thought of as "workspace". That is, the |
| preferences which are stored in this scope are stored per workspace, or |
| per running instance of Eclipse. This scope corresponds to the default |
| location of preferences in Eclipse 2.1. The instance area is derived from |
| the location returned by <code>org.eclipse.core.runtime.Platform#getInstanceLocation()</code>. |
| Preferences stored in this scope will not be available to other running instances |
| of Eclipse. |
| <p></p> |
| CONFIGURATION - The configuration scope is used to store preferences on a per |
| configuration level. Being able store preferences per configuration means |
| that all workspaces share the same preferences. For instance, if you are an |
| Eclipse developer and you have a single Eclipse install but you have multiple |
| workspaces for different projects/branches that you are working on, the |
| preferences stored in the configuration scope will be shared between these |
| workspaces. The configuration area is derived from the location returned by |
| <code>org.eclipse.core.runtime.Platform#getConfigurationLocation()</code>. |
| <p></p> |
| DEFAULT - The default preference scope was initially created to provide a backwards |
| compatibility story for the plug-in customization code in Eclipse 2.1. Preferences |
| stored in the default scope are not persisted to disk and are a part of the plug-in |
| customization story. |
| <p></p> |
| PROJECT - There was a request for per project preferences so the project scope |
| handles this. Preferences which are stored in this scope are shared stored in the |
| project content area and are therefore automatically shared with the repository. |
| This enables items like java compiler settings to be shared between team members |
| working on the same project. |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="tree"></a>This |
| is confusing, how can I picture this in my mind?</b> |
| <p></p> |
| The preferences can be thought of as a tree with each node |
| having a name and children. The "path" of a node is the names of it and |
| all its ancestors separated by a path separator. |
| <p> |
| Start at the root node. The root node's name |
| is empty and has a path of "/". The root node's children are the names of the scopes |
| which are defined. (e.g. instance, configuration, user, default, project, etc) Therefore |
| their paths are: /instance, /configuration, /user, /default, and /project. |
| </p><p> |
| The path structure under the scope name is defined by the scope itself. The scopes |
| contributed by the Platform Runtime (instance, configuration, user, default) define |
| the next segement to be a qualifier. (like a plug-in or bundle id) |
| An example of the full path for the autobuild preference for the resources plug-in |
| in the instance scope would be:<br> |
| <code>/instance/org.eclipse.core.resources/description.autobuild</code> |
| </p><p> |
| The project scope (as defined by the resources plug-in) defines its path structure to be |
| <code>/project/<projectName>/<qualifier>/key</code> and therefore the full path for |
| the resources' plug-in auto-build preference for the project "MyProject" would be:<br> |
| <code>/project/MyProject/org.eclipse.core.resources/description.autobuild</code> |
| </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="basicGet"></a>How do I know if |
| auto-build is turned on? (How do I get a preference value?)</b> |
| <p></p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%">1.</td> |
| <td WIDTH="98%"> |
| Through the backwards compatibility layer. |
| <p>All the plug-in preference APIs which existed in Eclipse 2.1 still exist and |
| are fully supported through a backwards compatibility layer. All the client has |
| to do is ask the org.eclipse.core.resources plug-in for its preferences.</p> |
| <p>The downside to this is that not all of the preference scopes are checked |
| for a value. In this case first the INSTANCE scope is checked, and then the |
| DEFAULT scope. If a value doesn't exist in either scope, then the default-default |
| value for that type is returned.</p> |
| <p> <code> |
| String key = ResourcesPlugin.PREF_AUTO_BUILDING;<br> |
| return ResourcesPlugin.getPluginPreferences().getBoolean(key);<br> |
| </code> </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%">2.</td> |
| <td WIDTH="98%"> |
| Via navigation from the root node. |
| <p>The new Eclipse preference mechanism is structured in a hierarchial means and |
| therefore the user is able to retrieve the root of the hierarchy and navigate |
| to the particular preference node that they desire. This is, of course, assuming |
| the know the path structure of the node they are trying to retrieve. The example |
| below retrives the value from the INSTANCE scope.</p> |
| <p> <code> |
| String qualifier = ResourcesPlugin.getDescriptor().getUniqueIdentifier();<br> |
| String key = ResourcesPlugin.PREF_AUTO_BUILDING;<br> |
| boolean defaultValue = false;<br> |
| Preferences node = Platform.getPreferencesService().getRootNode().node(InstanceScope.SCOPE).node(qualifier);<br> |
| return node.getBoolean(key, defaultValue);</code> </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%">3.</td> |
| <td WIDTH="98%"> |
| Through the context objects. |
| <p>If the user knows which preference scope their preference is in but they don't know |
| the hierarchy structure of the scope (or don't want to have to deal with it), then they |
| are able to use the scope context API to retrieve the correct node for their preferences.</p> |
| <p> <code> |
| String qualifier = ResourcesPlugin.getDescriptor().getUniqueIdentifier();<br> |
| String key = ResourcesPlugin.PREF_AUTO_BUILDING;<br> |
| boolean defaultValue = false;<br> |
| Preferences node = new InstanceScope().getNode(qualifier);<br> |
| if (node != null)<br> |
| return node.getBoolean(key, defaultValue);</code> </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%">4a.</td> |
| <td WIDTH="98%"> |
| Search through the preferences service. (manual lookup order) |
| <p>Having preferences stored in a single location, although useful, is uninteresting |
| compared to being able to store preferences in multiple scopes. If a user has |
| a collection of multiple preference nodes that they would like to check for |
| a particular preference value, then they are able to use the API on IPreferencesService |
| to check the multiple nodes and return the first found value, or the specified |
| default if it is not found. The example below first checks the INSTANCE scope and |
| then checks the USER scope.</p> |
| <p> <code> |
| IPreferencesService service = Platform.getPreferencesService();<br> |
| String qualifier = ResourcesPlugin.getDescriptor().getUniqueIdentifier();<br> |
| String key = ResourcesPlugin.PREF_AUTO_BUILDING;<br> |
| String defaultValue = "false";<br> |
| Preferences root = service.getRootNode();<br> |
| Preferences instanceNode = root.node(InstanceScope.SCOPE).node(qualifier);<br> |
| Preferences userNode = root.node(UserScope.SCOPE).node(qualifier);<br> |
| Preferences[] nodes = new Preferences[] {instanceNode, userNode};<br> |
| return service.get(key, defaultValue, nodes);<br> |
| </code> </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%">4b.</td> |
| <td WIDTH="98%"> |
| Search through the preferences service. (default lookup order) |
| <p>Navigation from the root node to other nodes in the preference hierarchy can |
| be cumbersome so we expect most preference users to take advantage of this second |
| API. It is a convenience method to the above method.</p> |
| <p>First they (in most cases the plug-in developer who is contributing the preference) |
| set the scope lookup order (if none is specified then the default-default |
| {project, instance, configuration, user, default} is used. </p> |
| <p>Some scopes require extra context to determine which preference nodes |
| are the right ones to look at. So if necessary, callers are able to create |
| IScopeContext instances to aid in lookup. <em>Note that these are not |
| necessary for the INSTANCE, CONFIGURATION, USER, and DEFAULT scopes.</em> |
| </p> |
| <p> |
| In the example below, we first look to see if the preference has been set on the project |
| preferences for "MyProject" and then we check the INSTANCE preferences. |
| </p><p> |
| <code> |
| IPreferencesService service = Platform.getPreferencesService();<br> |
| String qualifier = ResourcesPlugin.getDescriptor().getUniqueIdentifier();<br> |
| String key = ResourcesPlugin.PREF_AUTO_BUILDING;<br> |
| boolean defaultValue = false;<br> |
| String[] lookupOrder = new String[] {ProjectScope.SCOPE, InstanceScope.SCOPE};<br> |
| service.setDefaultLookupOrder(qualifier, key, lookupOrder);<br> |
| IScopeContext contexts = new IScopeContext[] {new ProjectScope("MyProject")};<br> |
| return service.getBoolean(qualifier, key, defaultValue, contexts);</code> </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="basicSet"></a>How can I set the |
| auto-build preference? (How do I set a preference value?)</b></td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%">1.</td> |
| <td WIDTH="98%"> |
| Through the backwards compatibility layer. |
| <p>Again, all the old APIs exist and are fully functional.</p> |
| <p> <code> |
| String key = ResourcesPlugin.PREF_AUTO_BUILDING;<br> |
| boolean value = true;<br> |
| ResourcesPlugin.getPluginPreferences().setValue(key, value);<br> |
| </code> </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%">2.</td> |
| <td WIDTH="98%"> |
| Via navigation from the root node. |
| <p>If the user knows which scope they wish to store the preference in and |
| knows the path structure for the hierarchy of that scope, then they are able |
| to navigate directly to that preference node and set their preference value. In |
| the example below we are setting the auto-build setting in the INSTANCE scope.</p> |
| <p> <code> |
| String qualifier = ResourcesPlugin.getDescriptor().getUniqueIdentifier();<br> |
| String key = ResourcesPlugin.PREF_AUTO_BUILDING;<br> |
| boolean value = true;<br> |
| IEclipsePreferences root = Platform.getPreferencesService().getRootNode();<br> |
| root.node(InstanceScope.SCOPE).node(qualifier).putBoolean(key, value);<br> |
| </code> </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%">3.</td> |
| <td WIDTH="98%"> |
| Through the scope context. |
| <p>If the user knows which scope they wish to set the preference value in |
| but doesn't know the path structure for that scope, (or prefers not to |
| navigate it themselves) then they can use the convenience methods in IScopeContext |
| to determine the correct preference node. This is the method in which |
| we envision most clients setting preference values. In the example below |
| we are storing the preference in the project preferences for "MyProject".</p> |
| <p> <code> |
| String qualifier = ResourcesPlugin.getDescriptor().getUniqueIdentifier();<br> |
| String key = ResourcesPlugin.PREF_AUTO_BUILDING;<br> |
| boolean value = true;<br> |
| IScopeContext context = new ProjectScope(MyProject);<br> |
| IEclipsePreferences node = context.getNode(qualifier);<br> |
| if (node != null)<br> |
| node.putBoolean(key, value);</code> </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="convert"></a>What |
| should I do to convert my code to the new mechanism?</b> |
| <p></p> |
| Getting a value using the old code only checks the INSTANCE and DEFAULT scopes:<br> |
| <code> |
| ResourcesPlugin.getPluginPreferences().getBoolean(key);</br> |
| </code> |
| </p><p> |
| Getting a value using the new code looks in all scopes as defined by the look-up order |
| set in the preferences service:<br> |
| <code> |
| Platform.getPreferencesService().getBoolean(ResourcesPlugin.PI_RESOURCES, key, defaultValue);<br> |
| </code> |
| </p><p> |
| Setting a value using the old code either puts the value in the INSTANCE scope or clears |
| it if it is the same as the value in the DEFAULT scope:<br> |
| <code> |
| ResourcesPlugin.getPluginPreferences().setValue(key, value);<br> |
| </code> |
| </p><p> |
| Setting a value using the new code is a bit more complicated. Clients must know which |
| scope they wish to store their value in. For instance:<br> |
| <code> |
| Preferences node = new InstanceScope().getNode(ResourcesPlugin.PI_RESOURCES);<br> |
| if (node != null)<br> |
| node.put(key, value);<br> |
| </code> |
| </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="convertProject"></a>How |
| do I convert my project property page to use project preferences?</b> |
| <p></p> |
| Rather than use the generalized look-up mechanism to find out your project-specific |
| values, I would create a project context and do the lookup from there. This ensures |
| that you either get the value that is defined in the project scope or nothing. (the |
| default value that you specify) For example: |
| <p> |
| <code> |
| // setup<br> |
| IScopeContext context = new ProjectScope(MyProject);<br> |
| IEclipsePreferences node = context.getNode("org.eclipse.jdt.core");<br> |
| int defaultValue = JavaCore.SEVERITY_IGNORE;<br> |
| String key = JavaCore.NON_NLS_SEVERITY;<br> |
| int value = defaultValue;<br> |
| </code><p></p> |
| <code>...</code><p></p> |
| <code> |
| // get the value<br> |
| if (node != null) <br> |
| value = node.getInt(key, defaultValue);<br> |
| if (value == defaultValue) {<br> |
| // value isn't set in the project scope.<br> |
| // value is "inherited" from another scope.<br> |
| } else {<br> |
| // we have a value set in the project scope<br> |
| }<br> |
| <p></p> |
| </code> |
| <code>...</code><p></p> |
| <code> |
| // set the value<br> |
| if (node != null) {<br> |
| if (value == defaultValue) {<br> |
| // value is same as default so no need to store it<br> |
| node.remove(key);<br> |
| } else {<br> |
| // set a project-specific value<br> |
| node.put(key, value);<br> |
| }<br> |
| </code> |
| <p></p> |
| <code>...</code><p></p> |
| <code> |
| // save the changes<br> |
| if (node != null) {<br> |
| // save the project specific values<br> |
| node.flush();<br> |
| }<br> |
| </code> |
| </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="imemento"></a>How do I convert my IMemento values?</b> |
| <p></p> |
| Its easy! IMementos are a method of storing hierarchial data and that's just what the node |
| hierarchy is. |
| <p>To set a complex IMemento preference value using Eclipse 2.1 preferences: |
| </p><p> |
| <code> |
| String key = "providers";<br> |
| XMLMemento root = XMLMemento.createWriteRoot(key);<br> |
| IMemento dev = root.createChild("dev.eclipse.org");<br> |
| dev.putString("connnectionType", "pserver");<br> |
| dev.putString("login", "anonymous");<br> |
| dev.putString("path", "/home/eclipse");<br> |
| IMemento example = root.createChild("cvs.example.com");<br> |
| example.putString("connnectionType", "pserver");<br> |
| example.putString("login", "anonymous");<br> |
| example.putString("path", "/home/cvs");<br> |
| Writer writer = new StringWriter();<br> |
| try {<br> |
| root.save(writer);<br> |
| } finally {<br> |
| writer.close();<br> |
| }<br> |
| MyPlugin.getDefault().getPluginPreferences().setValue(key, writer.toString());<br> |
| ...<br> |
| MyPlugin.getDefault().savePluginPreferences();<br> |
| </code> |
| </p><p> |
| To set the same complex values using Eclipse 3.0 preferences: |
| </p><p> |
| <code> |
| // Note: can create other context here including Project<br> |
| IScopeContext context = new InstanceScope();<br> |
| Preferences root = context.getNode("org.eclipse.team");<br> |
| // Note: should not be null<br> |
| if (root != null) {<br> |
| Preferences dev = root.node("providers/dev.eclipse.org");<br> |
| dev.put("connectionType", "pserver");<br> |
| dev.put("login", "anonymous");<br> |
| dev.put("path", "/home/eclipse");<br> |
| Preferences example = root.node("providers/cvs.example.com");<br> |
| example.put("connectionType", "pserver");<br> |
| example.put("login", "anonymous");<br> |
| example.put("path", "/home/cvs");<br> |
| ...<br> |
| root.flush();<br> |
| }<br> |
| </code> |
| </p><p> |
| To get a value using the Eclipse 2.1 preferences: |
| </p><p> |
| <code> |
| String xmlString = MyPlugin.getDefault().getPluginPreferences().getString("providers");<br> |
| Reader reader = new StringReader(xmlString);<br> |
| XMLMemento root = XMLMemento.createReadRoot(reader);<br> |
| IMemento dev = root.getChild("dev.eclipse.org");<br> |
| return dev.getString("connnectionType");<br> |
| </code> |
| </p><p> |
| To get the same value using Eclipse 3.0 preferences: |
| </p><p> |
| <code> |
| // Note: can create other context here including Project<br> |
| IScopeContext context = new InstanceScope();<br> |
| Preferences root = context.getNode("org.eclipse.team");<br> |
| // Note: should not be null<br> |
| if (root != null) {<br> |
| Preferences node = root.node("providers/dev.eclipse.org");<br> |
| return node.get("connectionType", null);<br> |
| }<br> |
| </code> |
| </p> |
| </td> |
| </tr> |
| |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="backwardsCompatibilityScopes"></a>Why |
| doesn't the backwards compatibility layer check all the scopes for a value?</b> |
| <p></p> |
| The backwards compatibility layer only checks for preference values in the INSTANCE and |
| DEFAULT scopes for two main reasons. |
| <p> |
| Firstly. we wanted to maintain true backwards compatibility. If the "get" methods checked |
| for preference values in scopes other than INSTANCE and DEFAULT, then the behaviour would |
| not be the same as was in Eclipse 2.1. That is, if there was a value set for another |
| scope it would be returned. |
| </p><p> |
| The second reason is that it confuses the current UI story. People have created many |
| preference pages which show the current preference values. This maps on to the preferences |
| stored in the INSTANCE scope. If we changed the backwards compatibility story to look |
| in the other scopes for preference values, then the values presented to the user would |
| be mixed...some would be from the INSTANCE scope, some from the USER scope, etc etc. |
| </p><p> |
| The short story is that we have to try to develop a UI which presents preferences and |
| their scopes to the user in a simple and managable way. |
| </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="flush"></a>When are my preference changes saved to disk?</b> |
| <p></p> |
| The short answer is "whenever you change them you need to save them". In Eclipse 2.1 there |
| was API to save plug-in preferences (<code>Plugin.savePluginPreferences()</code>) which clients |
| were encouraged to call on plug-in shutdown and when they changed their preference values |
| (like in a preference page). |
| <p> |
| It is important to note that this old API now corresponds to saving the preferences for |
| that plug-in in the INSTANCE scope only. |
| </p><p> |
| Now, it is recommended that people save their preference changes to disk by calling the |
| <code>Preferences.flush()</code> method. For instance, preference page owners would |
| call this after setting all the preference values when the user hits "OK". |
| </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="nodes"></a>Why should I use nodes?</b> |
| <p></p> |
| For most plug-ins, simple key/value pairs are well suited for their preference |
| values and they will never have to take advantage of the node hierarchy other than |
| the basic traversal. The interesting use case is for those clients who previously used |
| mark-up (like XML) |
| to encode their preference values. XML and its elements are essentially containers...a |
| way to group together similar values in a hierarchical manner. The use of nodes can |
| simplify this for clients. |
| </p><p> |
| Each node in the hierarchy has a name and its path is represented by its name and |
| all its parents' names separated by the path separator. This allows preference keys |
| at arbitrary depths in the tree so a node's children nodes could be used in a "contains" |
| relationship. |
| </p><p> |
| Think, for instance, of the list of Team provider connections in Eclipse. Rather than |
| having a single preference key and the value being wrapped in a wad of XML, it could |
| be split across multiple nodes and be more accessible. For instance consider the |
| following: |
| <p> |
| <code> /instance/org.eclipse.team/providers/example.com/path=/home/eclipse</code><br> |
| <code> /instance/org.eclipse.team/providers/example.com/login=anonymous</code><br> |
| <code> /instance/org.eclipse.team/providers/example.com/connectionType=pserver</code><br> |
| <code> /instance/org.eclipse.team/providers/dev.eclipse.org/path=/home/eclipse</code><br> |
| <code> /instance/org.eclipse.team/providers/dev.eclipse.org/login=anonymous</code><br> |
| <code> /instance/org.eclipse.team/providers/dev.eclipse.org/connectionType=pserver</code><br> |
| </p> |
| In this example the list of providers could be retrieved as children of the |
| <code>/instance/org.eclipse.team/providers</code> node and then each individual provider's |
| login information as preferences in children nodes. |
| </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><b><a name="illegalStateException"></a>Why am I getting an IllegalStateException when calling APIs?</b> |
| <p></p> |
| Since the Preferences APIs include the ability to add nodes to the hierarchy, they |
| also include methods to remove nodes from the hierarchy. If a node has been removed and |
| a client still has a reference to it, the client will get an |
| <code>IllegalStateException</code> when calling APIs on that node. The only valid methods |
| to call on a removed node are: <code>name(), absolutePath()</code> and <code>nodeExists()</code>. |
| <p> |
| If clients aren't sure whether or not their node may have been removed since the last |
| time they accessed it, they are encouraged to re-retrieve the node from the hierarchy. |
| </p><p> |
| <code> |
| if (!node.nodeExists(""))<br> |
| node = service.getRootNode().node(node.absolutePath());<br> |
| </code> |
| </p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><p><b><a name="customization"></a>How does the plug-in customization |
| story work?</b> </p> |
| <p>Check out the separate <a href="plugin_customization.html">document</a> |
| on plug-in customization. It explains the order that preference defaults are applied |
| and compares this to the way it worked in Eclipse 2.1.</p> |
| <p></p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td ALIGN=LEFT VALIGN=TOP COLSPAN="2"><hr></td> |
| </tr> |
| <tr> |
| <td ALIGN=RIGHT VALIGN=TOP WIDTH="2%"><img SRC="../../images/Adarrow.gif" BORDER=0 height=16 width=16></td> |
| <td WIDTH="98%"><p><b><a name="extension">How do I extend the preferences and add my own scope?</a></b> </p> |
| |
| <p>1. Extend the org.eclipse.core.runtime.preferences extension point. |
| <code><pre> |
| <extension point="org.eclipse.core.runtime.preferences"> |
| <scope name="myScope" class="com.example.preferences.MyScope"/> |
| </extension> |
| </pre></code> |
| </p> |
| <p>2. Have your class implement IScope and IEclipsePreferences. |
| <code><pre> |
| public class MyScope implements IScope, IEclipsePreferences { |
| ... |
| } |
| </pre></code> |
| </p> |
| <p>Here is an <a href="example_scope.zip">example</a> plug-in which creates a new scope.</p> |
| <p></p> |
| </td> |
| </tr> |
| |
| </table> |