Views and Subviews
The RCP user interface contains a framework to dynamically create an appropriate editor (or more specifically a view, cause nothing can be changed or saved right now, but the editor extension is used due to the availability of an editorinput and some other advantages over views).
Creating an editor/view is pretty straightforward and is using the eclipse mechanism of creating an editor:
IWorkbenchPage page = ... InputDefinition inputDefinition = new InputDefinition(); ... fill input ... RootEditorInput input = new RootEditorInput(inputDefinition); page.openEditor(input, FormRootEditor.ID);
The InputDefinition is our own class used to describe an editor (like the name of the header, icon, ID of the editor, ID definition, etc.). The repository definition attribute is available from the Repository Manager.
The idMappings is very important because it defines the concrete IDs (platform, sensor type, method) for the specific sub views. The easiest way to define the IDs is to use the methods:
- setIdDefinition : Takes one parameter, the object IdDefinition, which holds one platform, one sensor type and one method id.
- getIdDefinition : Returns the IdDefinition object.
These two methods can be used if every sub view accesses the same IDs.
As this is not always the case, we can also specify the IDs per subview, like this:
- addIdMapping : Takes an ID (String) and the IdDefinition object. The ID can be taken from the classes that implements one of the available InputController (like InvocOverviewInputController, MemoryInputController, InvocDetailInputController, etc.).
- getAndRemoveIdDefinition : This method is accessed in the InputController classes to access their valid InputDefinition objects (that's why it is important to set the correct ID). As the name implies, the input definition is deleted from the map once it is accessed so that it is possible to show the same sub view several times with different input. The order of the adding is important to get the correct display results.
These two options cannot be used at the same time, so either all sub views are accessing the same IDs, or everyone has its own ID definition object.
This mechanism is very automatic, but creating an own editor with its sub-views programatically is very straightforward:
SashCompositeSubView invocSubView = new SashCompositeSubView(); ISubView invocOverview = new TableSubView(new InvocOverviewInputController()); TabbedCompositeSubView invocTabbedSubView = new TabbedCompositeSubView(); ISubView invocDetails = new TreeSubView(new InvocDetailInputController()); ISubView invocSql = new TableSubView(new SqlInvocInputController()); ISubView invocMethods = new TableSubView(new MethodInvocInputController()); invocTabbedSubView.addSubView(invocDetails, "Call Hierarchy", NovaSpy.getDefault().getImageDescriptor(NovaSpyConstants.IMG_CALL_HIERARCHY)); invocTabbedSubView.addSubView(invocSql, "SQL", NovaSpy.getDefault().getImageDescriptor(NovaSpyConstants.IMG_DATABASE)); invocTabbedSubView.addSubView(invocMethods, "Methods", NovaSpy.getDefault().getImageDescriptor(NovaSpyConstants.IMG_METHOD_PUBLIC)); invocSubView.addSubView(invocOverview, 1); invocSubView.addSubView(invocTabbedSubView, 2);
This example is taken from the sub view factory and creates the invocation overview editor. The base of all is the sash composite sub view which aligns its children either vertical or horizontal with a sash in between. Two sub views are added as the children of the composite view: Directly a table sub view displaying the overview of invocations and another composite sub view (this time a tabbed one which displays a tab for each child). The tabbed composite view contains 3 children: Details for the invocation, that is the real invocation tree, the invocation SQL table displaying all SQLs occurred in this invocation and the method table view, containing all methods aggregated from this invocation sequence.
The possibilities of combining the composite sub views with other ones in any way are nearly endless. The main benefit of the system is to allow the user later to create its own views based on his needs and requirements.
The below image visualizes the system:
For more examples on how to create the sub-views, just take a look at the factory: info.novatec.novaspy.rcp.editor.SubViewFactory.java
Preferences (Button, Panel, ...)
It was important for the design that the creation of the preference objects (like buttons, the panel etc.) is decoupled from the concrete sub-views. For this purpose, two methods were added to the ISubView interface:
- getPreferenceIds : This method returns a Set of PreferenceIdEnum objects. Every object in this enumeration creates an appropriate control in the preference area. For example the UPDATE_IDobject creates a button which is used to refresh/update the contained sub-views (like retrieving new data from the sever, refreshing their views to display the correct content etc.)
- preferenceEventFired : This method is executed whenever something is changed in the preferences where the sub-views should be notified of. Like if a button is pressed/switched, or a slider is moved, ... . In this method, the sub-views are handling the events like that for example:
if (PreferenceIdEnum.ITEMCOUNT_ID.equals(preferenceEvent.getPreferenceId())) { Map<IPreferenceEnum, Object> preferenceMap = preferenceEvent.getPreferenceMap(); int limit = (Integer) preferenceMap.get(PreferenceIdEnum.ItemCountIdEnum.COUNT_SELECTION_ID); tableInputController.setLimit(limit); this.doRefresh(); }
They are checking if the event ID is the one we are interested in (here in the ITEMCOUNT_ID). Then we are extracting the value (limit) and afterwards doing with it whatever we need to do.