TWiki
>
Public Web
>
DpHipe
>
DpHipeTools
(revision 25) (raw view)
Edit
Attach
Tags:
view all tags
---+ !!Adding Tools to HIPE <!-- Some short-cuts * Set REGISTRY = [[DpHipeRegistry][Extension Registry]] * Set TOOL = [[HcssDoc:api/herschel/ia/gui/kernel/Tool.html][Tool]] * Set CATEGORY = [[HcssDoc:api/herschel/ia/gui/kernel/Tool.Category.html][Category]] --> <img src="%ATTACHURLPATH%/hipe-tools.jpg" align="RIGHT" alt="Task, tools and variables" width='359' height='215' /> %STARTINCLUDE% <!-- summary --> Tools are processing units that operate on specific data elements.%BR% From the Java point of view, a tool is an implementation of the %TOOL% interface.%BR% The well-known Tasks are examples of tools within [[DpHipe][HIPE]]. In this case, [[HcssDoc:api/herschel/ia/task/views/TaskTool.html][TaskTool]] is used under the hoods. If a data element is selected, a list of tools that can operate on that data should appear. Double clicking on the tool will open an associated view (for non-task tools) or a dialog for settings parameters (for task tools). This section explains: * how you can create a Tool and register it for being available for dedicated data * how you can make [[DpHipe][HIPE]] aware of an existing Task, * how your task can react better on an active data element, * the default task dialog and how you implement and contribute a dedicated input dialog for your task, * how you can implement and contribute a specific parameter editor %STOPINCLUDE% %TOC% <br clear="all"/> ---++ Adding a Task as a Tool ---+++ Task Registry <blockquote> Up to now you have made you task globally available to the system by specifying an instance of that task within the ==__init__.py== file of your sub-system, e.g.: <pre> # __init__.py file compute=ComputeTask() </pre> To make your task appear in the "Run Tools" view, you need to add the following lines: <pre> from herschel.ia.task.views import TaskToolFactory <b>TaskToolFactory.register(compute)</b> </pre> For PCSS (PACS' builds) users, this ==__init__.py== file is located at $install_dir/data/toolbox/your_sub_system. You can also specify that your task belongs to one or more %CATEGORY% : <pre> from herschel.ia.gui.kernel.Tool import Category TaskToolFactory.register(compute, <b>[Category.IMAGE, Category.PACS]</b>)) </pre> Your task will now be enabled whenever a session variable is selected which matches the type of the *first* input parameter within your task! Within your task, you can control which parameter signs-up to be the prime parameter (the one which reacts on a selected data variable) by the Task API: <pre> class ComputeTask extends Task { ComputeTask() { super("compute"); prime = new TaskParameter("spectrum", SpecificProduct.class) : getSignature().<b>setPrimeInput(prime)</b> } } </pre> Naming conventions for task when to be registered in Hipe should follow this example assuming that the task will perform the functionality named "reduce" : <pre> Name of the Class : ReduceTask Name of the Task (getName()) : reduce Name of the variablein Jython : reduce </pre> </blockquote> ---+++ Prime input validation <blockquote> The mechanism above makes you task to become a tool within the system and it appears whenever a variable of type ==SpecificProduct== (i.e. the type of the value of the Parameter) is selected. Sometimes this may not be enough, e.g. is certain situations your task will only run on a ==SpecificProduct== if it contains certain _contents_. A typical situation would be when a SPIRE reduction operates on a ObservationContext: such a task should not be listed whenever a HIFI observation is selected... You can write a ==ParameterValidator== to do just that: <pre> prime = new TaskParameter("spectrum", SpecificProduct.class) prime.setParameterValidator(new ParameterValidatorAdapter() { public void validate(Object value) throws ParameterValidationException { SpecificProduct s = (SpecificProduct)value; if (! (logic that would validate the contents of the value...)) { throw new ParameterValidationException(reason); } } }); </pre> In other words, rather than writing this logic within the pre-amble or execution block of your task, we recommend you to move that logic into the parameter validation. This way we achieve two things: * make the logic appear where it should be and therefore keeping the execution block of your task concentrated to the _algorithm_, and * make your task appear as a _tool_ within [[DpHipe][HIPE]] that can be ran against _specific_ data. </blockquote> ---+++ Task Dialogs ---++++ Default Task Dialog <blockquote> The system generates a default input dialog for all registered tasks within the software. As the system does not know the intent of your task, it can only provide a dry-listing of all requested parameters; such a dialog may not be suitable for your purposes. The default dialog for the crop task: <br /> <img src="%ATTACHURLPATH%/crop.jpg" alt="crop.jpg" width='354' height='371' /> As for instance you may want to have more control over how the input parameters are presented to the user: * you may only want to provide a sub-set of parameters (and leave the full-set to expert users on the command-line) * you may want to organize your parameters by grouping them in tabs, or putting a border around a group of parameters * you may want to have more informative tooltips, labels or even input fields that are more suitable for your task. To adapt to these scenarios and more, the system provides three ways for customizing you Task dialogs: * Parameter Modifiers * Signature Components * Task Panels. </blockquote> ---++++ Parameter Modifiers <blockquote> The system provides a default dialog displaying an input area for setting the values of the parameter based on a composition of [[HcssDoc:api/herschel/ia/gui/apps/modifier/Modifier.html][Modifiers]] The input area for the crop task: <br /> <img src="%ATTACHURLPATH%/crop_input.jpg" alt="crop_input.jpg" width='354' height='371' /> The composition of [[HcssDoc:api/herschel/ia/gui/apps/modifier/Modifier.html][Modifiers]] is created based on the types of the values of the Task Parameters of the Task Signature. The Modifier for the first Parameter of the crop task: <br /> <img src="%ATTACHURLPATH%/crop_modifier.jpg" alt="crop_modifier.jpg" width='354' height='371' /> Currently the system contains basic implementation for the simple [[HcssDoc:api/herschel/ia/gui/apps/modifier/package-summary.html][types]] Integer, Float, Long, Double so there's still a lot of space for improvements and contribution. If your Task Parameter isn't one of the mentioned types you need to: * Implement a Modifier * Register it to the system. </blockquote> ----+++++ Implement a Modifier <blockquote> The [[HcssDoc:api/herschel/ia/gui/apps/modifier/Modifier.html][Modifier]] interface consists of two explicit contracts * Support the drag and drop features (the set/getVariableSelection) * Support the inspection for Object (the set/getObject) and two implicit contracts inherited by the %EXTENSION_REGISTRY% * Be JComponent * Have an empty constructor </blockquote> ----+++++ Register a Modifier <blockquote> The registration of the Modifier is done again in the ==__init__.py== via theExtensionRegistry with the usual syntax (please note the name of the factory: factory.modifier). Be aware that the registration is system wise so the registration overrides any other registered modifier for that type. <pre> REGISTRY.register(COMPONENT,Extension( "MyModifier", "herschel.ia.mymodifier.MyModifier", "factory.modifier", "herschel.ia.MyClass") </pre> In case the Modifier you have created is only applicable to a specific task or even to a specific parameter of a specific task you can simply assign it to the Task Parameter itself: <pre> // In your task constructor TaskParameter parameter = new TaskParameter("input", String.class); parameter.setModifier(new MyModifer()); </pre> </blockquote> ---++++ Signature Components <blockquote> In case the default input area based on Modifiers doesn't fit your needs you can just replace it by your own implementation. Rotate Alternative Signature: <br /> <img src="%ATTACHURLPATH%/rotate.jpg" alt="rotate.jpg" width='361' height='371' /> If this is the case you need to: * Implement a Task Signature Component * Register it to the system. ----+++++ Implement a Task Signature Component <blockquote> The [[HcssDoc:api/herschel/ia/task/gui/dialog/TaskSignatureComponent.html][TaskSignatureComponent]] interface consists of four explicit contracts * Support the setVariableSelection for initial assignment from the Tool Window * Assign the Signature to display ( the setSignature) * Return a map of parameters and assigned values ( the getParameters *note* return value ca be simplified to Map<TaskParameter, VariableSelection> ) * Clear and check user inputs (used by the default buttons) and the two implicit contracts inherited by the %REGISTRY% * Be JComponent * Have an empty constructor </blockquote> ----+++++ Register a Task Signature Component <blockquote> The registration of the Task Signature Component is done again in the ==__init__.py== via the %REGISTRY% with the usual syntax (please note the name of the factory: factory.editor.tool.task.signature). <pre> REGISTRY.register(COMPONENT,Extension( "Rotate Signature", "herschel.ia.task.example.RotateSignatureComponent", "factory.editor.tool.task.signature", "herschel.ia.image.Rotate")) </pre> See also the %REGISTRY% documentation for more details. </blockquote> ---++++ Custom Task Dialogs Eventually, if the above options still do not accommodate you needs you can replace the the default Task Panel with your own implementation If this is the case you need to: * Implement a Task Panel * Register it to the system. ----+++++ Implement a Task Panel <blockquote> The [[HcssDoc:api/herschel/ia/task/gui/dialog/TaskPanel.html][TaskPanel]] interface consists of three explicit contracts * Support the setVariableSelection for initial assignment from the Tool Window * Assign the Task to display ( the setTask) * Notify request of executions to the framework by * Allow for setting the Site Event handler for notifying request of execution (the setSiteEventHandler method ) * Notify the execution requests calling the trigger method of [[HcssDoc:api/herschel/ia/gui/kernel/SiteEventHandler.html][SiteEventHandler]] passing a [[HcssDoc:api/herschel/ia/gui/kernel/event/CommandExecutionRequestEvent.html][CommandExecutionRequestEvent]].%BR%You can create this event through the [[HcssDoc:api/herschel/ia/task/gui/dialog/TaskCommandExecutionEventFactory.html][TaskCommandExecutionEventFactory]]. and the two implicit contracts inherited by the %REGISTRY% * Be JComponent * Have an empty constructor </blockquote> The Rotate Panel example (herschel.ia.task.example.RotatePanel): <br /> <img src="%ATTACHURLPATH%/rotate_panel.jpg" alt="rotate_panel.jpg" width='323' height='326' /> ----+++++ Register a Task Panel <blockquote> The registration of the Task Panel Component is done again in the ==__init__.py== via the %REGISTRY% with the usual syntax (please note the name of the factory: factory.editor.tool.task.signature). <pre> REGISTRY.register(COMPONENT,Extension( "Rotate Task Panel", "herschel.ia.task.example.RotatePanel", "factory.editor.tool.task", "herschel.ia.image.Rotate")); </pre> See also the %REGISTRY% documentation for more details. </blockquote> ---+++ Task compliance <blockquote> * write user documentation (jtags)! That will be automatically picked up whenever a user asks the system for help on your task. * the name of the task should be a legal variable name in the global name-space. For example your instance of ==MyTask== should report itself as e.g.: "myTask" and not "This is my task". * if your prime parameter is not the first parameter in your task, specify the prime parameter using the ==setPrimeInput== method in the signature * write a parameter validator for your prime parameter if your task should be listed not only on prime data type but on prime data contents as well. </blockquote> ---++ Adding a Tool that is not a Task If you have an existing task and want to make it available in HIPE, you just need to follow the steps described in the [[#Adding_a_Task_as_a_Tool][above section]]. Now, a task has its limitations. It is somewhat an atomic operation for which you provide some inputs and expect some result.%BR% Therefore, it is not expected for acting interactively with a user, and it is not meant for holding internal status either, that a user can modify during its execution. If you need more flexibility, you can write your own implementation of the %TOOL% interface.%BR% Besides, you would most probably need a viewer associated to your tool, for letting the user interact with it. This follows in some way the MVC pattern: your target data is the Model, your associated viewer is the View, and your tool is the Controller. ---+++ Tool Implementation The %TOOL% interface is simple: <pre> public interface Tool { // Known categories to which a tool may belong to public enum Category { SPIRE, PACS, HIFI, GENERAL, IMAGE } // Get the tool name String getName(); // Get the actual object that does the work Object getToolObject(); // Set the actual object that does the work void setToolObject(Object o); // Get an array of categories to which this tool belongs to Category[] getCategories(); // Return the prime input parameter Parameter getPrimeInput(); } </pre> You provide the variable types you are interested in within the prime input: just return a [[HcssDoc:api/herschel/ia/gui/kernel/ToolParameter.html][ToolParameter]] initiated with the proper class of data you want to handle. <blockquote> <pre> private ToolParameter _prime = new ToolParameter("data", MyTargetDataType.class); public Parameter getPrimeInput() { return _prime; } </pre> </blockquote> The actual job to be done can be delegated to a third object (the "tool object"), or just be executed by the tool class itself.%BR% In this latter case, the method =Object getToolObject()= should return =this=. Moreover, you may return the categories you think the tool is meaningful for, through the proper implementation of =Category[] getCategories()=. ---+++ Tool Viewer Every tool has an associated viewer, which must implement [[HcssDoc:api/herschel/ia/gui/kernel/parts/EditorComponent.html][EditorComponent]] (by extending [[HcssDoc:api/herschel/ia/gui/kernel/parts/AbstractEditorComponent.html][AbstractEditorComponent]] or one of its subclasses). ---+++ Tool Registry Once you have your tool and the corresponding viewer, you need to register them like this: <blockquote> <pre> # Associate the tool with the viewer REGISTRY.register(COMPONENT,Extension( "My Tool", "herschel.path.to.MyToolComponent", "factory.editor.tool", "herschel.path.to.MyTool")) # Register the tool so it is automatically available for the proper variables in HIPE from herschel.ia.gui.kernel import ToolFactory from herschel.path.to import MyTool ToolFactory.register(MyTool()) </pre> </blockquote> ---+++ Communicating Tool & Viewer In the viewer, you can access the tool and the selected data within the =makeEditorContent= method provided by =AbstractEditorComponent=.%BR% At this point, you can let the tool know about the viewer as well, if you want: <blockquote> <pre> protected boolean makeEditorContent() { // Get the tool and the selected data ToolSelection selection = getSelection(); Tool tool = selection.getTool(); Object data = selection.getSelection().getValue(); // Optional - you would need to provide a setViewer method ((MyTool)tool).setViewer(this); // Build the editor contents ... } </pre> </blockquote> ---+++ Simple sample This simple reproducible example wraps up the just explained steps altogether.%BR% It is just a button whose label is changed by the tool when the user clicks on it: 1. *The tool class* <blockquote> <pre> public class ButtonTool implements Tool { private Category[] _categories = { Category.GENERAL }; private ToolParameter _prime = new ToolParameter("data", ArrayData.class); private ArrayData _data; private boolean _flag = true; public Category[] getCategories() { return _categories; } public String getName() { return "Button Tool"; } public Parameter getPrimeInput() { return _prime; } public Object getToolObject() { return this; } public void setToolObject(Object o) { // do nothing } public void setData(ArrayData data) { _data = data; } void updateLabel(JButton button) { int size = _data.getSize(); int rank = _data.getRank(); button.setText("Data has " + (_flag? "size " + size : "rank " + rank)); _flag = !_flag; } } </pre> </blockquote> 2. *The viewer class* <blockquote> <pre> public class ButtonToolComponent extends AbstractEditorComponent<ToolSelection> { private static final long serialVersionUID = 1L; private static int _counter = 1; private ButtonTool _tool; public ButtonToolComponent() { super(new BorderLayout()); } protected Class<ToolSelection> getSelectionType() { return ToolSelection.class; } protected boolean makeEditorContent() { final JButton button = new JButton(); setName("Button Tool " + _counter++); _tool = (ButtonTool)getSelection().getTool(); _tool.setData((ArrayData)getSelection().getSelection().getValue()); _tool.updateLabel(button); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { _tool.updateLabel(button); } }); add(button); return true; } public Icon getComponentIcon() { return IconLibrary.VARIABLE; } } </pre> </blockquote> 3. *The registration* <blockquote> <pre> REGISTRY.register(COMPONENT,Extension( "Button Tool", "herschel.your.package.ButtonToolComponent", "factory.editor.tool", "herschel.your.package.ButtonTool")) from herschel.ia.gui.kernel import ToolFactory from herschel.your.package import ButtonTool ToolFactory.register(ButtonTool()) </pre> </blockquote> 4. *Executing the example* <blockquote> For executing this simple tool, just include it in a package owned by you, open the workbench in HIPE, and execute the following in the console: <pre> x = Int1d.range(12) y = Double2d([[1,2,3],[4,5,6]]) </pre> Then open the x and y variables with the Button Tool and click the button: its label is updated by the tool. </blockquote> ---++ Triggering Events For a full detailed section about triggering events have a look at DpHipeEventExecution <!-- Author: Main.JorgoBakker - 21 Dec 2007 -->
Attachments
Attachments
Topic attachments
I
Attachment
History
Action
Size
Date
Who
Comment
jpg
crop_input.jpg
r1
manage
16.6 K
2008-02-15 - 10:21
UnknownUser
Edit
|
Attach
|
Watch
|
P
rint version
|
H
istory
:
r113
|
r27
<
r26
<
r25
<
r24
|
B
acklinks
|
V
iew topic
|
Raw edit
|
More topic actions...
Topic revision: r25 - 2008-08-13
-
JaimeSaiz
Public
Log In
Public Web
Create New Topic
Index
Search
Changes
Notifications
Statistics
Preferences
Webs
Public
TWiki