<!-- ANALYTICS CODE - DO NOT EDIT --> %INCLUDE{"%ATTACHURL%/GoogleAnalytics.txt" raw="on"}% <!-- END OF ANALYTICS CODE --> <!-- * Set TOPICTITLE = HIPE preferences --> | *PDF Version* | [[%SCRIPTURLPATH%/genpdf%SCRIPTSUFFIX%/%WEB%/%TOPIC%?pdforientation=portrait&pdftoclevels=2][Portrait]] | [[%SCRIPTURLPATH%/genpdf%SCRIPTSUFFIX%/%WEB%/%TOPIC%?pdforientation=landscape&pdftoclevels=2][Landscape]] | %ICON{"help"}% *Did you spot something wrong or missing on this page? If you have an account on this TWiki, you can fix it yourself by editing the page. If you don't have an account, you can leave a message at the bottom of the page to tell us about it. Thank you in advance!* ---+ !!HIPE preferences <!-- Some short-cuts * Set DRMROOT = http://herschel.esac.esa.int/hcss-doc-12.0/index.jsp#hcss_drm: * Set Registry = [[DpHipeRegistry][Extension Registry]] * Set JythonModule = =__init__.py= * Set Configuration = [[%DRMROOT%herschel.share.util.Configuration][Configuration]] * Set PreferencesPanel = [[%DRMROOT%herschel.ia.gui.kernel.prefs.PreferencesPanel][PreferencesPanel]] * Set PreferenceHandler = [[%DRMROOT%herschel.ia.gui.kernel.prefs.PreferenceHandler][PreferenceHandler]] * Set PreferenceListener = [[%DRMROOT%herschel.ia.gui.kernel.prefs.PreferenceListener][PreferenceListener]] * Set AbstractPreferenceHandler = [[%DRMROOT%herschel.ia.gui.kernel.prefs.AbstractPreferenceHandler][AbstractPreferenceHandler]] * Set UserPreferences = [[%DRMROOT%herschel.ia.gui.kernel.prefs.UserPreferences][UserPreferences]] * Set EditorComponent = [[DpHipeComponents#Editor_Area][editor component]] --> %STARTINCLUDE% This section explains the relationship between preferences and properties in HIPE, and how you can contribute to: * Introduce preferences and develop a GUI panel for them in your module. * Make a bridge between preferences and existing properties. * Use preferences in client code. * Listen to changes in preferences to adapt your functionality dynamically. %STOPINCLUDE% %TOC% %STARTSECTION{"contrGuide"}% ---++ Introduction Preferences in HIPE respond to the request of customizing the tool in a user friendly way, from the User Vision document : «The Main Interface (...) should provide a new pull-down menu accessible from the top bar with label “Properties” to allow user to change the configuration during the session. This should not be done with Propgen.» That menu option is called "Preferences" instead of "Properties", since it is a more common label in GUI applications, and a standard in Mac OS X. The preferences dialog can be accessed in three different ways: 1. By clicking on the preferences icon in the _Welcome_ view. 2. By pressing the menu option Edit -> Preferences. 3. By pressing Alt+Enter at any moment. We talk here about _user_ preferences, meaning those preferences affecting the session that the user may want to change in a user friendly way. Therefore we don't consider _system_ preferences, which are used by developers for introducing some flexibility in the functionality they provide, but users shouldn't be concerned of. The existing properties mechanism may still suffice for them. <!-- The preferences framework is decoupled from the old configuration properties, so that it could be developed while not being dependent on the [[Hcss.PropertyRoadmap][property roadmap]].--> Nevertheless, preferences can reuse properties and even be just a wrapper for them if needed, as explained later. This way, the break is not dramatic, although replacing properties by preferences is encouraged. ---++ Categories Preferences are organized in categories, which have a hierarchical structure.%BR% Each category may have a parent category (at most one). A category with no parent is called a _root_ category.%BR% It is like a tree, where more than one root is allowed. Every category is identified by a string that contains its whole path, including its ancestors. This full path must be unique. The path of a category is similar to an absolute path in Unix, with the difference that the leading '/' is omitted. For example: <pre> General <i>A root category</i> General/Appearance <i>A child category under General</i> General/Appearance/Console <i>Another child category under General/Appearance</i> Data Access <i>Another root category</i> </pre> Preferences lie under a particular category. They are identified by a name called _key_, which must be unique within that category, but can be reused in other categories. The following set of HIPE preferences (mostly based on Eclipse/IDLDE's preferences) was agreed as the starting structure for organising HIPE's configuration. They are out of date, see below the text tree for a screenshot of a newer version: <pre> General Appearance Console <i>Already in 1.1: buffer size and prompt</i>. Extras: readline and buffer for history recovery (i.e. !0 brings up command 0 on history) Fonts <i>Already in 1.1: general font sizes</i> Window <i>Already in 1.1: size window and position at startup</i> Logs & History <i>Size of log, auto-save time</i> Key Shortcuts <i>Possible SCR</i> File Associations <i>File associations for automatic importing of .py, .fits, .txt</i> Perspectives <i>list of perspectives, save/load customized perspectives (possible SCR)</i> Startup & Shutdown <i>Memory @ start-up, save session dir/name, tips&tricks (possible SCR)</i> Editors & Viewers Text Editor <i>80 columns, line number on/off, rectangle cut&paste option</i> Jython Editor <i>80 columns, line number on/off, colors, tabs, completion mode</i> PlotXY Viewer <i>memory default size, default symbol, line, axes, multiplots</i> Image Viewer <i>Initial zoom, lookup table, cut values, orientation, task properties</i> Spectrum Explorer <i>Initial zoom, linestyle (histogram), zoom-mode, task properties</i> Cube Analysis Tool <i>Initial zoom, lookup table, cut values, orientation, linestyle, task properties</i> Task Dialog <i>use all parameters</i> Help <i>To be provided by Marco Soldati</i> Jython Code <i>Automatic import statements, working and output directories</i> Interpreter <i>Error handling, line by line, error codes</i> Install & Update <i>To be defined</i> Automatic Update <i>Update server, frequency of update checks, notification</i> Data Access Storages & Pools <i>Management of existing product storages and pools</i> Local Store <i>Absolute path, cache configuration</i> Import FITS <i>Requested metadata for importing images, spectra, cubes and tables</i> Import ASCII <i>Ascii table formats handling with AsciiTableReader, defaults </i> HSA <i>URL, temporary retrieval directory (possible SCR), delay/retry times </i> </pre> ---++ Preferences dialog The explained approach leads to a preferences dialog in which the user may navigate between categories, select one of them, see and change any of its associated preferences, and accept or cancel the changes. The preferences dialog then looks like this: <img src="%ATTACHURLPATH%/Screen_Shot_2014-02-19_at_12.13.39.png" alt="Preferences Dialog (HIPE 13)" width='767' height='658' /> ---++ How to contribute Adding and using preferences has few simple steps. From one side, if you want to introduce a new category, you need to write a _preferences panel_, and then _register_ it. Afterwards, client code would want to read those preferences, which is done through the ==UserPreferences== class.%BR% Probably it would also want to listen to modifications, so the user doesn't need to restart HIPE for his changes being applied. Optionally, you may want to link a preference to an existing property that you just want to migrate to the preferences framework. A step by step approach is described in the following subsections. ---+++ Develop a preferences panel When the user clicks on a category within the tree, the corresponding panel is shown at the right side of the dialog. Creating a panel requires to extend %PreferencesPanel% -basically reproduced here- by implementing a couple of methods: <blockquote> <pre> public abstract class PreferencesPanel extends JPanel { protected PreferencesPanel() {} protected abstract void makeContent(); protected abstract void registerHandlers(); protected final void registerHandler(String key, PreferenceHandler<?> handler) { ... } } </pre> </blockquote> * =registerHandlers=: <blockquote> In this method you call =registerHandler= once per preference. This is how you specify the keys belonging to the associated category. Each preference is handled by a %PreferenceHandler%, which provides the means of updating the GUI with the existing preference value and to get any change that the user introduces, and more. You may consider to extend %AbstractPreferenceHandler% or use one of its basic extensions, instead of implementing the interface directly. </blockquote> * =makeContent=: <blockquote> Here you create and add to the panel the graphical components for showing and changing the preferences associated to this category. </blockquote> *Example:* <blockquote> <pre> public class SimplePreferencesPanel extends PreferencesPanel { private static final long serialVersionUID = 1L; private JTextField fieldA; // text field associated to preference keyA private IntegerField fieldB; // text field associated to preference keyB @Override protected void registerHandlers() { // Preference keyA with type String and default value "text" registerHandler("keyA", new StringPreferenceHandler("text", fieldA)); // Preference keyB with type Integer and default value 3 registerHandler("keyB", new IntegerPreferenceHandler(3, fieldB)); } @Override protected void makeContent() { setLayout(new GridLayout(2, 2, 5, 5)); // just for the example; you may consider to use a better layout fieldA = new JTextField(); add(new JLabel("Key A:")); add(fieldA); fieldB = new IntegerField(); add(new JLabel("Key B:")); add(fieldB); } } </pre> </blockquote> ---+++ Register the category and the panel If you have developed the preferences panel, you have done the hard work. Registering the category and its associated panel is straightforward. As usual, it is done in the %Registry% within a %JythonModule% file. *Example:* <blockquote> <pre> from herschel.ia.gui.kernel import ExtensionRegistry, Extension from herschel.ia.gui.kernel.prefs import UserPreferences CATEGORY = UserPreferences.CATEGORY REGISTRY = ExtensionRegistry.getInstance() # Preferences categories REGISTRY.register(CATEGORY, Extension( "Some/Category", "herschel.some.package.SimplePreferencesPanel", None, # unused None)) # unused # Cleanup del(ExtensionRegistry, Extension, UserPreferences, CATEGORY, REGISTRY) </pre> </blockquote> %BR% You may want to organize your categories under a common parent category, but don't have any preference associated to that parent category. In this case, you don't need to create a panel for the parent category: <blockquote> <pre> REGISTRY.register(CATEGORY, Extension( "Parent/Category", None, # empty panel None, # unused None)) # unused </pre> </blockquote> The framework creates here an empty panel for you, with a message saying that preferences can be found in children categories. ---+++ Read preferences The next step is to use the preferences in client code. This is very easy and just implies using %UserPreferences% where you would use %Configuration%. *Example:* The preferences defined in the previous example could be accessed like this: <blockquote> <pre> String preferenceA = UserPreferences.get("Some/Category", "keyA"); int preferenceB = UserPreferences.getInt("Some/Category", "keyB"); </pre> </blockquote> Any preference can be read as a string, so: <blockquote> <pre> String preferenceB = UserPreferences.get("Some/Category", "keyB"); </pre> </blockquote> would also be valid. ---+++ Change preferences Preferences are supposed to be changed only by users, within the preferences dialog.%BR% This is the reason why =UserPreferences= just provides methods for reading preferences, but not for changing them. Now, it may be the case that you need to update preferences from some user action.%BR% For instance, user presses Ctrl-+, so all font sizes must be increased. This communication can be performed through events: the requester code triggers an event, which is listened and handled by the corresponding preferences panel. *Example:* We have an editor with a split panel, and want to detect any drag in the split separator by the user, so its new position is saved as a preference. <blockquote> <pre> // The notifier class public class SplittedEditor extends AbstractEditorComponent<SomeSelection> { // Suppose we detect changes in the split pane here private void splitMoved(float newLocation) { SiteEvent event = new PreferenceChangeRequestEvent(this, category, key, newLocation); getPart().getEventHandler().trigger(event); } } // The preferences panel public class SomePreferencesPanel extends PreferencesPanel implements SiteEventListener { @Override protected void makeContent() { // Fill the panel ... // and register to split changes SiteEventHandler eventHandler = SiteUtil.getSite().getEventHandler(); eventHandler.addEventListener(PreferenceChangeRequestEvent.class, this); } @Override public void selectionChanged(SiteEvent event) { Float location = (Float)((PreferenceChangeRequestEvent)event).getNewValue(); setValue("splitLocation", location); // update the value in the panel saveChanges(); // and save it } } </pre> </blockquote> ---+++ Listen to changes in preferences Suppose the user opens an %EditorComponent% you have developed, then opens the preferences dialog, changes some preference related to the presentation of your editor, and presses OK. The user would expect that these changes would be applied to the opened editor, not only to editors opened from that moment on. To solve this situation, your editor should listen to preference changes by implementing =PreferenceListener= and registering with =UserPreferences.addListener=. ---+++ Link to properties Now, what happens with plain old properties? There may be three different situations: <blockquote> ---++++ 1. Brand new preferences If you create new preferences that have no correspondence to existing properties, all we have seen till now should be enough for you; you don't need to worry about properties. ---++++ 2. Take a property as default value The more common situation may be that you want to migrate some existing property to the new preferences mechanism. This means that the preference should take the value of the associated property while the user doesn't override it.%BR% After being overridden, the saved preference is used and the property will not be taken into account. If this is the case, the only thing you need to do is to add few code when registering the handler of the associated preference. Something like this: <blockquote> <pre> <b>String def = Configuration.getProperty("hcss.some.property", "text"); // default value</b> registerHandler("keyA", new StringPreferenceHandler(<b>def</b>, fieldA)); </pre> </blockquote> ---++++ 3. Maintain the old property mechanism Although the previous two approaches are recommended, it may be the case that you cannot use =UserPreferences= in your client code, for example because your module cannot depend on =ia_gui_kernel=, but still want to provide a panel for the user in the preferences window. For instance, you want to add a panel for letting the user to set the Versant server and a database name. %BR% In this case, your panel should be written in a module that can depend on =ia_gui_kernel=; however, =herschel.versant.store= (in this example) can only use %Configuration% for reading the preferences values. The solution is to provide the %PreferenceHandler% the name of the associated property, so the framework would override the property in =hipe.props=. As simple as: <blockquote> <pre> registerHandler("keyA", new StringPreferenceHandler("text", fieldA, <b>"hcss.some.property"</b>)); </pre> </blockquote> In this case, the property would also be used as default value, if existing. </blockquote> ---+++ Allowed types for preferences As seen above, you can specify the type you want for each preference. The %PreferenceHandler% enforces you to provide the correct types when writing their implementations. The valid types for preferences depend on whether their associated handler uses a property (=PreferenceHandler.getProperty()= returns not null) or not, that is, if you provide a property when constructing %AbstractPreferenceHandler% or not (see examples above). * If you don't provide a property to the handler, the valid types are =Boolean=, =Integer=, =Long=, =Float=, =Double=, =String= and =byte[]=. * If you provide a property to the handler, the valid types are reduced to =Boolean=, =Integer=, =Double= and =String=. The reason is that %Configuration% provides methods for getting the property as boolean, int, double or String, but doesn't provide methods for the other types. %ENDSECTION{"contrGuide"}% %BR% <span class="commentPlugin commentPluginOutputOneliner"> * when you register your preferences REGISTRY.register(CATEGORY, Extension( "Editors & Viewers/CASSIS", "herschel.some.package.SimplePreferencesPanel", None, # unused None)) # unused does the first argument have to be "Data Acess", "Editors & Viewers", ... , "General" ??? -- Main.JeanMichelGlorian - 05 Jan 2012 - 09:54</span></span><!--/commentPlugin--> <span class="commentPlugin commentPluginOutputOneliner"> * The category where to locate a panel shall be decided by the users, in principle the module's mentor, the DPUG or an equivalent responsible/board if it is a plugin. -- Main.JaimeSaiz - 24 Feb 2012 - 13:31</span></span><!--/commentPlugin--> <!-- * Set ALLOWTOPICCHANGE = Main.RegisteredUsersGroup, Main.TWikiAdminGroup --> <hr/> <!-- COMMENT BOX CODE - DO NOT EDIT --> <div id="disqus_thread"></div> <script type="text/javascript"> var disqus_shortname = 'herscheltwiki'; // required: replace example with your forum shortname (function() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); })(); </script> <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> <a href="http://disqus.com" class="dsq-brlink">blog comments powered by <span class="logo-disqus">Disqus</span></a> <!-- END OF COMMENT BOX CODE --> <hr/>
Attachments
Attachments
Topic attachments
I
Attachment
History
Action
Size
Date
Who
Comment
png
Screen_Shot_2014-02-19_at_12.13.39.png
r1
manage
134.4 K
2014-02-19 - 11:11
AlvarGarcia
Preferences dialog (HIPE 13)
This topic: Public
>
DpHipe
>
DpHipePreferences
Topic revision: r36 - 2014-03-05 - JaimeSaiz