Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Riena/Detached Views"

(Riena Detached Views)
 
(7 intermediate revisions by 4 users not shown)
Line 1: Line 1:
== Riena Detached Views ==
+
{{#eclipseproject:rt.riena}}
 +
{{RienaBreadcrumbs | [[Riena Project]] | [[Riena Getting started|Getting Started]] | Detached Views}}
  
This document explains how to easily open auxiliary 'detached' views when a certain navigation node is selected in the main window.
+
{| align="right"
 +
| __TOC__
 +
|}
  
[[Image:riena_detached_views.png]]
+
This document explains how to easily open auxiliary 'detached' views when a certain navigation node is selected in the main window, as shown in the following screenshot:
  
Riena has a mechanism that allows developers to show a <tt>ViewPart</tt> in a separate 'detached' shell/window. This can be used to show one or more views in separate shells. These shells are draggable, moveable, but not closeable.
+
[[Image:riena_detached_views.png]]
  
Only one view can be shown in each 'detached' shell. This view can be a regular <tt>ViewPart</tt> or an implementation of Riena's <tt>SubModuleView</tt>.
+
Riena has a mechanism that allows developers to show a <tt>ViewPart</tt> in a separate 'detached' shell/window. This can be used to show one or more views in separate shells. These shells are draggable, moveable, but not closeable. Only one view can be shown in each 'detached' shell. This view can be a regular <tt>ViewPart</tt> or an implementation of Riena's <tt>SubModuleView</tt>.
  
==== Hooking into the Navigation Tree ====
+
== Hooking into the Navigation Tree ==
  
 
To show / hide / dispose the 'detached' shells, we want to react to events in the navigation tree on the left of the main window. Typically when a node is selected, the corresponding <tt>SubModuleView</tt> is shown in the workarea (i.e. main area on the right). When this happens we would like to show additional 'detached' views. When the navigation node becomes unselected, we would like to hide these views.
 
To show / hide / dispose the 'detached' shells, we want to react to events in the navigation tree on the left of the main window. Typically when a node is selected, the corresponding <tt>SubModuleView</tt> is shown in the workarea (i.e. main area on the right). When this happens we would like to show additional 'detached' views. When the navigation node becomes unselected, we would like to hide these views.
  
To accomplish that we need to attach a custom listener to the view's navigation node. This is typically done in the <tt>#basicCreatePartControl(...)</tt> method of our sub module:
+
To accomplish that we need to attach a custom listener to the view's navigation node. This is typically done in the <tt>basicCreatePartControl(...)</tt> method of our sub module:
  
 
<source lang="java">
 
<source lang="java">
Line 22: Line 25:
 
</source>
 
</source>
  
The class <tt>NodeListener</tt> extends <tt>SimpleNavigationNodeAdapter</tt>. This adapter has several methods, that are invoked at different points during the lifecycle of a navigation node. When the node becomes selected (=activated) the method <tt>#activated((INavigationNode source)</tt> is invoked -- in that case we show the detached view. When the node becomes de-selected (=deactivated) the method <tt>#deactivated(INavigationNode source)</tt> is invoked -- in that case we hide the detached view. When the node is destroyed (=disposed) the method <tt>#disposed(INavigationNode source)</tt> is invoked -- in that case perform any necessary clean-up.
+
The class <tt>NodeListener</tt> extends <tt>SimpleNavigationNodeAdapter</tt>. This adapter has several methods, that are invoked at different points during the lifecycle of a navigation node. When the node becomes selected (=activated) the method <tt>activated((INavigationNode source)</tt> is invoked in that case we show the detached view. When the node becomes de-selected (=deactivated) the method <tt>deactivated(INavigationNode source)</tt> is invoked in that case we hide the detached view. When the node is destroyed (=disposed) the method <tt>disposed(INavigationNode source)</tt> is invoked in that case perform any necessary clean-up.
  
 
<source lang="java">
 
<source lang="java">
Line 37: Line 40:
 
</source>
 
</source>
  
==== Showing / Hiding detached views ====
+
== Showing / Hiding detached views ==
  
 
To show / hide / dispose the detached views we need to manage a Shell for each view. Riena provides the class <tt>DetachedViewsManager</tt>, which makes this easy.
 
To show / hide / dispose the detached views we need to manage a Shell for each view. Riena provides the class <tt>DetachedViewsManager</tt>, which makes this easy.
Line 43: Line 46:
 
# We need to create a new instance of <tt>DetachedViewsManager</tt> in our listener as a class variable. The manager needs to know the main window, so we pass it a reference to <tt>Shell</tt> or to <tt>IWorkbenchSite</tt> via the constructor.
 
# We need to create a new instance of <tt>DetachedViewsManager</tt> in our listener as a class variable. The manager needs to know the main window, so we pass it a reference to <tt>Shell</tt> or to <tt>IWorkbenchSite</tt> via the constructor.
 
# To show a view, we invoke <tt>dvManager.showView(String id, Class<? extends ViewPart> viewClazz, int position)</tt>. The first time this method is invoked for a given <tt>id</tt>, it will create a new shell and show a new view of the type <tt>viewClazz</tt> in it. It will then open the shell at the given <tt>position</tt>. The second time this method is invoked, the shell with the specified <tt>id</tt> will already exist, so it will just make it visible. More information on the parameters:
 
# To show a view, we invoke <tt>dvManager.showView(String id, Class<? extends ViewPart> viewClazz, int position)</tt>. The first time this method is invoked for a given <tt>id</tt>, it will create a new shell and show a new view of the type <tt>viewClazz</tt> in it. It will then open the shell at the given <tt>position</tt>. The second time this method is invoked, the shell with the specified <tt>id</tt> will already exist, so it will just make it visible. More information on the parameters:
#* <tt>id</tt>: is an arbitrary String, used to identify the shell hosting this view
+
#; <tt>id</tt>: is an arbitrary String, used to identify the shell hosting this view
#* <tt>viewClazz</tt>: a class specifying a ViewPart which we want to show in the shell. This class must have a parameterless constructor.
+
#; <tt>viewClazz</tt>: a class specifying a ViewPart which we want to show in the shell. This class must have a parameterless constructor.
#* <tt>position</tt>: one of SWT.{TOP,BOTTOM,LEFT,RIGHT}. Will open the shell on the appropriate side of the main window. There is also an alternative method <tt>#showView(..., Rectangle bounds)</tt> which will open the shell with a position and size we specify. The location preference is only considered when the shell is created (i.e. the first time we invoked this method)</tt>
+
#; <tt>position</tt>: one of SWT.{TOP,BOTTOM,LEFT,RIGHT}. Will open the shell on the appropriate side of the main window. There is also an alternative method <tt>#showView(..., Rectangle bounds)</tt> which will open the shell with a position and size we specify. The location preference is only considered when the shell is created (i.e. the first time we invoked this method)</tt>
 
# To hide a view, we invoke <tt>dvManager.hideView(String id)</tt>, where <tt>id</tt> is the name of the shell we wish to hide.
 
# To hide a view, we invoke <tt>dvManager.hideView(String id)</tt>, where <tt>id</tt> is the name of the shell we wish to hide.
# To clean-up, we invoke <tt>dvManager.dispose()</tt>. This will dispose all shells that have been created but are currently hidden. Typically this is done in the <tt>#disposed(...)</tt> method of the node listener. Afterwards it is also a good idea to remove the node listener itself from the navigation node.
+
# To clean-up, we invoke <tt>dvManager.dispose()</tt>. This will dispose all shells that have been created but are currently hidden. Typically this is done in the <tt>disposed(...)</tt> method of the node listener. Afterwards it is also a good idea to remove the node listener itself from the navigation node.
  
 
Here is the full code for the <tt>NodeListener</tt> class:
 
Here is the full code for the <tt>NodeListener</tt> class:
Line 70: Line 73:
 
</source>
 
</source>
  
==== Special Requirements ====
+
== Special Requirements ==
 +
When opening a Riena SubModuleView, such as the <tt>TreeSubModuleView</tt>, as a detached view you must be aware of the following:
 +
 
 +
Riena strictly separates view and controller. The view is responsible for creating the UI. The controller is responsible for the business logic / ridgets. The SubModuleViews shown in the main window have a controller attached to them. This pairing is normally kept in the navigation node. The '''views opened in 'detached' mode do not have a navigation node.''' As such, they do not have any way of knowing which controller to create :-(. '''To work around this limitation it is important to implement the <tt>createController(...)</tt> method'''.
 +
 
 +
If a SubModuleView subclass does ''not'' have this method, two things will happen:
 +
# no controller will be created. You will notice that the widgets are there, but their labels / behavior / anything done in the controller is missing.
 +
# a warning is written out to the application's log.
 +
 
 +
Fortunately, implementing the <tt>createController</tt> method is easy, as shown below:
 +
<source lang="java">
 +
public class TreeSubModuleView extends SubModuleView<TreeSubModuleController> {
 +
 
 +
  protected TreeSubModuleController createController(ISubModuleNode node) {
 +
    return new TreeSubModuleController(node);
 +
  }
 +
  // ...
 +
}
 +
</source>
  
==== References ====
+
== References ==
  
 
See:
 
See:
 
* class <tt>DetachedSubModuleView</tt> in the <tt>org.eclipse.riena.example.client</tt> bundle  
 
* class <tt>DetachedSubModuleView</tt> in the <tt>org.eclipse.riena.example.client</tt> bundle  
 
* class <tt>DetachedViewsManager</tt> in the <tt>org.eclipse.riena.ui.swt</tt> bundle
 
* class <tt>DetachedViewsManager</tt> in the <tt>org.eclipse.riena.ui.swt</tt> bundle
 +
* class <tt>SnippetDetachedView001</tt> in the <tt>org.eclipse.riena.sample.snippets</tt> bundle
  
 
[[Category:Riena]]
 
[[Category:Riena]]

Latest revision as of 08:56, 20 June 2011

{{#eclipseproject:rt.riena}}

Riena ProjectGetting Started ▶ Detached Views

This document explains how to easily open auxiliary 'detached' views when a certain navigation node is selected in the main window, as shown in the following screenshot:

Riena detached views.png

Riena has a mechanism that allows developers to show a ViewPart in a separate 'detached' shell/window. This can be used to show one or more views in separate shells. These shells are draggable, moveable, but not closeable. Only one view can be shown in each 'detached' shell. This view can be a regular ViewPart or an implementation of Riena's SubModuleView.

Hooking into the Navigation Tree

To show / hide / dispose the 'detached' shells, we want to react to events in the navigation tree on the left of the main window. Typically when a node is selected, the corresponding SubModuleView is shown in the workarea (i.e. main area on the right). When this happens we would like to show additional 'detached' views. When the navigation node becomes unselected, we would like to hide these views.

To accomplish that we need to attach a custom listener to the view's navigation node. This is typically done in the basicCreatePartControl(...) method of our sub module:

protected void basicCreatePartControl(Composite parent) {
  // ...
  getNavigationNode().addSimpleListener(new NodeListener());
}

The class NodeListener extends SimpleNavigationNodeAdapter. This adapter has several methods, that are invoked at different points during the lifecycle of a navigation node. When the node becomes selected (=activated) the method activated((INavigationNode source) is invoked – in that case we show the detached view. When the node becomes de-selected (=deactivated) the method deactivated(INavigationNode source) is invoked – in that case we hide the detached view. When the node is destroyed (=disposed) the method disposed(INavigationNode source) is invoked – in that case perform any necessary clean-up.

private final class NodeListener extends SimpleNavigationNodeAdapter {
  public void activated(INavigationNode<?> source) {
    // show detached views
  }
  public void deactivated(INavigationNode<?> source) {
    // hide detached views
  } 		
  public void disposed(INavigationNode<?> source) {
    // clean-up
}

Showing / Hiding detached views

To show / hide / dispose the detached views we need to manage a Shell for each view. Riena provides the class DetachedViewsManager, which makes this easy.

  1. We need to create a new instance of DetachedViewsManager in our listener as a class variable. The manager needs to know the main window, so we pass it a reference to Shell or to IWorkbenchSite via the constructor.
  2. To show a view, we invoke dvManager.showView(String id, Class<? extends ViewPart> viewClazz, int position). The first time this method is invoked for a given id, it will create a new shell and show a new view of the type viewClazz in it. It will then open the shell at the given position. The second time this method is invoked, the shell with the specified id will already exist, so it will just make it visible. More information on the parameters:
    id
    is an arbitrary String, used to identify the shell hosting this view
    viewClazz
    a class specifying a ViewPart which we want to show in the shell. This class must have a parameterless constructor.
    position
    one of SWT.{TOP,BOTTOM,LEFT,RIGHT}. Will open the shell on the appropriate side of the main window. There is also an alternative method #showView(..., Rectangle bounds) which will open the shell with a position and size we specify. The location preference is only considered when the shell is created (i.e. the first time we invoked this method)</tt>
  3. To hide a view, we invoke dvManager.hideView(String id), where id is the name of the shell we wish to hide.
  4. To clean-up, we invoke dvManager.dispose(). This will dispose all shells that have been created but are currently hidden. Typically this is done in the disposed(...) method of the node listener. Afterwards it is also a good idea to remove the node listener itself from the navigation node.

Here is the full code for the NodeListener class:

private final class NodeListener extends SimpleNavigationNodeAdapter {
  private final DetachedViewsManager dvManager = new DetachedViewsManager(getSite());
 
  public void activated(INavigationNode<?> source) {
    dvManager.showView("viewRight", TreeSubModuleView.class, SWT.RIGHT);
  }
 
  public void deactivated(INavigationNode<?> source) {
    dvManager.hideView("viewRight"); //$NON-NLS-1$
  }
 
  public void disposed(INavigationNode<?> source) {
    dvManager.dispose();
    getNavigationNode().removeSimpleListener(this);
  }
}

Special Requirements

When opening a Riena SubModuleView, such as the TreeSubModuleView, as a detached view you must be aware of the following:

Riena strictly separates view and controller. The view is responsible for creating the UI. The controller is responsible for the business logic / ridgets. The SubModuleViews shown in the main window have a controller attached to them. This pairing is normally kept in the navigation node. The views opened in 'detached' mode do not have a navigation node. As such, they do not have any way of knowing which controller to create :-(. To work around this limitation it is important to implement the createController(...) method.

If a SubModuleView subclass does not have this method, two things will happen:

  1. no controller will be created. You will notice that the widgets are there, but their labels / behavior / anything done in the controller is missing.
  2. a warning is written out to the application's log.

Fortunately, implementing the createController method is easy, as shown below:

public class TreeSubModuleView extends SubModuleView<TreeSubModuleController> {
 
  protected TreeSubModuleController createController(ISubModuleNode node) {
    return new TreeSubModuleController(node);
  } 
  // ...
}

References

See:

  • class DetachedSubModuleView in the org.eclipse.riena.example.client bundle
  • class DetachedViewsManager in the org.eclipse.riena.ui.swt bundle
  • class SnippetDetachedView001 in the org.eclipse.riena.sample.snippets bundle

Back to the top