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 "Scout/HowTo/3.8/Adding toolbars to views with the SWT client"

< Scout‎ | HowTo‎ | 3.8
m (Result)
(Added code to force redraw of toolbar when using setStoreAndRestore(true))
 
Line 1: Line 1:
 
{{ScoutPage|cat=HowTo 3.8}}  
 
{{ScoutPage|cat=HowTo 3.8}}  
  
The SWT client has different views. It is possible to add toolbar buttons to the view, these will then appear in the upper right corner of the view's header (to the left of the minimise/maximise buttons). This how-to explains how such toolbars can be added to views.
+
The SWT client has different views. It is possible to add toolbar buttons to the view, these will then appear in the upper right corner of the view's header (to the left of the minimise/maximise buttons). This how-to explains how such toolbars can be added to views.  
  
= Steps =
+
= Steps =
== Registering the toolbar classes ==
+
  
Each toolbar must be registered for the view it will be attached to. This is done in the '''SWT plugin.xml''' file by adding a '''menuContribution''' to the '''org.eclipse.ui.menus''' extension. The menuContribution needs a '''locationURI''' attribute which is built as follows:
+
== Registering the toolbar classes  ==
<pre>toolbar:<class name of the view you want the toolbar added to></pre>
+
  
The menuContribution also needs a '''dynamic''' element which indicates the class that will manage the toolbar.
+
Each toolbar must be registered for the view it will be attached to. This is done in the '''SWT plugin.xml''' file by adding a '''menuContribution''' to the '''org.eclipse.ui.menus''' extension. The menuContribution needs a '''locationURI''' attribute which is built as follows:
<pre>
+
<pre>toolbar:&lt;class name of the view you want the toolbar added to&gt;</pre>
        <menuContribution
+
The menuContribution also needs a '''dynamic''' element which indicates the class that will manage the toolbar.  
 +
<pre>       &lt;menuContribution
 
             allPopups="false"
 
             allPopups="false"
             locationURI="toolbar:org.eclipse.minicrm.ui.swt.views.OutlineView">
+
             locationURI="toolbar:org.eclipse.minicrm.ui.swt.views.OutlineView"&gt;
         <dynamic
+
         &lt;dynamic
 
               class="org.eclipse.minicrm.ui.swt.toolbars.ViewToolBarOutline"
 
               class="org.eclipse.minicrm.ui.swt.toolbars.ViewToolBarOutline"
               id="org.eclipse.minicrm.ui.swt.views.toolbar.OutlineView">
+
               id="org.eclipse.minicrm.ui.swt.views.toolbar.OutlineView"&gt;
         </dynamic>
+
         &lt;/dynamic&gt;
       </menuContribution>
+
       &lt;/menuContribution&gt;
       <menuContribution
+
       &lt;menuContribution
 
             allPopups="false"
 
             allPopups="false"
             locationURI="toolbar:org.eclipse.minicrm.ui.swt.views.TableView">
+
             locationURI="toolbar:org.eclipse.minicrm.ui.swt.views.TableView"&gt;
         <dynamic
+
         &lt;dynamic
 
               class="org.eclipse.minicrm.ui.swt.toolbars.ViewToolBarTable"
 
               class="org.eclipse.minicrm.ui.swt.toolbars.ViewToolBarTable"
               id="org.eclipse.minicrm.ui.swt.views.toolbar.TableView">
+
               id="org.eclipse.minicrm.ui.swt.views.toolbar.TableView"&gt;
         </dynamic>
+
         &lt;/dynamic&gt;
       </menuContribution>
+
       &lt;/menuContribution&gt;
</pre>
+
</pre>  
 +
== Implementing the toolbar classes  ==
  
== Implementing the toolbar classes ==
+
Each distinct toolbar needs its own class, but as the only difference between toolbars is what actions are added as buttons, we can use a common class that covers the necessary functionality.
  
Each distinct toolbar needs its own class, but as the only difference between toolbars is what actions are added as buttons, we can use a common class that covers the necessary functionality.
+
*Create a new package '''org.eclipse.minicrm.ui.swt.toolbars'''  
*Create a new package '''org.eclipse.minicrm.ui.swt.toolbars'''
+
 
*Create the abstract class '''ViewToolBar''' in that package
 
*Create the abstract class '''ViewToolBar''' in that package
<pre>
+
<pre>   package org.eclipse.minicrm.ui.swt.toolbars;
    package org.eclipse.minicrm.ui.swt.toolbars;
+
  
 
     import java.util.ArrayList;
 
     import java.util.ArrayList;
Line 54: Line 52:
 
     public abstract class ViewToolBar extends CompoundContributionItem {
 
     public abstract class ViewToolBar extends CompoundContributionItem {
 
       private IContributionItem[] oldItems = null;
 
       private IContributionItem[] oldItems = null;
 +
      private ToolBar m_parent = null;
 +
      private int m_index = 0;
 +
 +
      public ViewToolBar() {
 +
        super();
 +
        ((SwtEnvironment) Activator.getDefault().getEnvironment()).addViewToolBar(this);
 +
      }
 +
 +
      public ViewToolBar(String id) {
 +
        super(id);
 +
        ((SwtEnvironment) Activator.getDefault().getEnvironment()).addViewToolBar(this);
 +
      }
 +
 +
      public void refreshToolBar() {
 +
        if (m_parent != null) {
 +
          fill(m_parent, m_index);
 +
        }
 +
      }
  
 
       @Override
 
       @Override
 
       public void fill(ToolBar parent, int index) {
 
       public void fill(ToolBar parent, int index) {
 +
        m_parent = parent;
 +
        m_index = index;
 +
 
         if (index == -1) {
 
         if (index == -1) {
 
           index = parent.getItemCount();
 
           index = parent.getItemCount();
Line 63: Line 82:
 
         disposeOldItems();
 
         disposeOldItems();
 
         oldItems = getContributionItems();
 
         oldItems = getContributionItems();
         for (int i = 0; i < oldItems.length; i++) {
+
         for (int i = 0; i &lt; oldItems.length; i++) {
 
           IContributionItem item = oldItems[i];
 
           IContributionItem item = oldItems[i];
 
           int oldItemCount = parent.getItemCount();
 
           int oldItemCount = parent.getItemCount();
Line 76: Line 95:
  
 
       private void disposeOldItems() {
 
       private void disposeOldItems() {
         if (oldItems != null) {
+
         if (oldItems&nbsp;!= null) {
           for (int i = 0; i < oldItems.length; i++) {
+
           for (int i = 0; i &lt; oldItems.length; i++) {
 
             IContributionItem oldItem = oldItems[i];
 
             IContributionItem oldItem = oldItems[i];
 
             oldItem.dispose();
 
             oldItem.dispose();
Line 94: Line 113:
 
       protected IContributionItem[] getContributionItems() {
 
       protected IContributionItem[] getContributionItems() {
 
         ISwtEnvironment env = Activator.getDefault().getEnvironment();
 
         ISwtEnvironment env = Activator.getDefault().getEnvironment();
         if (env != null && env.isInitialized()) {
+
         if (env&nbsp;!= null &amp;&amp; env.isInitialized()) {
 
           IClientSession iSession = env.getClientSession();
 
           IClientSession iSession = env.getClientSession();
           if ((iSession != null) && (iSession instanceof ClientSession))
+
           if ((iSession&nbsp;!= null) &amp;&amp; (iSession instanceof ClientSession))
 
           {
 
           {
  
 
             ClientSession session = (ClientSession) iSession;
 
             ClientSession session = (ClientSession) iSession;
 
             IAction[] buttons = session.getViewButtons(getView());
 
             IAction[] buttons = session.getViewButtons(getView());
             if (buttons != null && buttons.length > 0) {
+
             if (buttons&nbsp;!= null &amp;&amp; buttons.length &gt; 0) {
 
               return getButtonContribution(buttons, env);
 
               return getButtonContribution(buttons, env);
 
             }
 
             }
Line 110: Line 129:
  
 
       private IContributionItem[] getButtonContribution(IAction[] buttonActions, ISwtEnvironment env) {
 
       private IContributionItem[] getButtonContribution(IAction[] buttonActions, ISwtEnvironment env) {
         ArrayList<IContributionItem> contributionItems = new ArrayList<IContributionItem>();
+
         ArrayList&lt;IContributionItem&gt; contributionItems = new ArrayList&lt;IContributionItem&gt;();
         for (IAction buttonAction : buttonActions) {
+
         for (IAction buttonAction&nbsp;: buttonActions) {
 
           if (!buttonAction.isVisible()) {
 
           if (!buttonAction.isVisible()) {
 
             continue;
 
             continue;
Line 117: Line 136:
 
           if (buttonAction.isSeparator()
 
           if (buttonAction.isSeparator()
 
               //ignore trailing separator
 
               //ignore trailing separator
               && contributionItems.size() > 0 && contributionItems.get(contributionItems.size() - 1).isSeparator()) {
+
               &amp;&amp; contributionItems.size() &gt; 0 &amp;&amp; contributionItems.get(contributionItems.size() - 1).isSeparator()) {
 
             continue;
 
             continue;
 
           }
 
           }
Line 141: Line 160:
 
       abstract protected String getView();
 
       abstract protected String getView();
 
     }       
 
     }       
</pre>
+
</pre>  
 +
*This class uses the '''ClientSession.getViewButtons()''' method to retrieve the configured actions (see more about this below). It also defines an abstract method '''getView()''' which defines the key value to which configured actions are attached
 +
*For each distinct toolbar, we need to define a class which extends '''ViewToolBar''', these are the classes that are attached to the views using the '''&lt;dynamic&gt;''' element in the plugin.xml file.
  
*This class uses the '''ClientSession.getViewButtons()''' method to retrieve the configured actions (see more about this below). It also defines an abstract method '''getView()''' which defines the key value to which configured actions are attached
+
If more than one view need identical toolbars, it is possible to use the same extended class for those views  
*For each distinct toolbar, we need to define a class which extends '''ViewToolBar''', these are the classes that are attached to the views using the '''<dynamic>''' element in the plugin.xml file.
+
<pre>   package org.eclipse.minicrm.ui.swt.toolbars;
 
+
If more than one view need identical toolbars, it is possible to use the same extended class for those views
+
<pre>
+
    package org.eclipse.minicrm.ui.swt.toolbars;
+
  
 
     public class ViewToolBarOutline extends ViewToolBar {
 
     public class ViewToolBarOutline extends ViewToolBar {
Line 157: Line 174:
 
     }
 
     }
 
</pre>
 
</pre>
       
 
 
<pre>
 
<pre>
 
     package org.eclipse.minicrm.ui.swt.toolbars;
 
     package org.eclipse.minicrm.ui.swt.toolbars;
Line 167: Line 183:
 
       }
 
       }
 
     }       
 
     }       
</pre>
+
</pre>  
 
*The key values are best added to the '''org.eclipse.minicrm.shared.Strings''' class.
 
*The key values are best added to the '''org.eclipse.minicrm.shared.Strings''' class.
  
== Transferring the actions between client and server ==
+
== Transferring the actions between client and server ==
Building the dynamic menu (''DesktopMenuBar'') is done using ''Desktop.getMenus()'' which returns all instances of ''AbstractMenu''. Building the main toolbar (''ApplicationActionBarAdvisor'') is done using ''Desktop.getViewButtons()'' and ''Desktop.getToolButtons()'' which return all instances of ''AbstractOutlineViewButton'' and ''AbstractOutlineViewButton''.
+
 
 +
Building the dynamic menu (''DesktopMenuBar'') is done using ''Desktop.getMenus()'' which returns all instances of ''AbstractMenu''. Building the main toolbar (''ApplicationActionBarAdvisor'') is done using ''Desktop.getViewButtons()'' and ''Desktop.getToolButtons()'' which return all instances of ''AbstractOutlineViewButton'' and ''AbstractOutlineViewButton''.  
 +
 
 +
Since Scout does not support view toolbars out of the box, a little more work is needed to set up the buttons in the client and to access them from the SWT renderer. Accessing the buttons from the SWT clien is done using the '''getViewButtons()''' method, mentioned in the previous chapter. As it is easier to extend the '''ClientSession''' than the desktop itself, we are adding a container to the ClientSession to and from which buttons can be added and retrieved:
  
Since Scout does not support view toolbars out of the box, a little more work is needed to set up the buttons in the client and to access them from the SWT renderer. Accessing the buttons from the SWT clien is done using the '''getViewButtons()''' method, mentioned in the previous chapter. As it is easier to extend the '''ClientSession''' than the desktop itself, we are adding a container to the ClientSession to and from which buttons can be added and retrieved:
 
 
*Add the following member to '''ClientSession''':
 
*Add the following member to '''ClientSession''':
<pre>private Map<String, List<IAction>> viewButtons = new HashMap<String, List<IAction>>();</pre>
+
<pre>private Map&lt;String, List&lt;IAction&gt;&gt; viewButtons = new HashMap&lt;String, List&lt;IAction&gt;&gt;();</pre>  
 
*Add the following methods to '''ClientSession''':
 
*Add the following methods to '''ClientSession''':
<pre>
+
<pre>     public void addViewButton(String key, IAction buttonAction) {
      public void addViewButton(String key, IAction buttonAction) {
+
         if (key&nbsp;!= null &amp;&amp; buttonAction&nbsp;!= null) {
         if (key != null && buttonAction != null) {
+
           List&lt;IAction&gt; actions = viewButtons.get(view);
           List<IAction> actions = viewButtons.get(view);
+
 
           if (actions == null) {
 
           if (actions == null) {
             actions = new ArrayList<IAction>();
+
             actions = new ArrayList&lt;IAction&gt;();
 
           }
 
           }
           if (actions != null) {
+
           if (actions&nbsp;!= null) {
 
             actions.add(buttonAction);
 
             actions.add(buttonAction);
 
             viewButtons.put(key, actions);
 
             viewButtons.put(key, actions);
Line 192: Line 209:
  
 
       public IAction[] getViewButtons(String key) {
 
       public IAction[] getViewButtons(String key) {
         List<IAction> result = null;
+
         List&lt;IAction&gt; result = null;
         if (key != null) {
+
         if (key&nbsp;!= null) {
 
           result = viewButtons.get(key);
 
           result = viewButtons.get(key);
           if (result != null) {
+
           if (result&nbsp;!= null) {
 
             return result.toArray(new IAction[result.size()]);
 
             return result.toArray(new IAction[result.size()]);
 
           }
 
           }
Line 201: Line 218:
 
         return null;
 
         return null;
 
       }     
 
       }     
</pre>
+
</pre>  
 +
== Defining the actions  ==
  
== Defining the actions ==
+
Next we need to define the actions for our view toolbar buttons. They cannot be of type ''ViewButton'' or ''ToolButton'', as they would otherwise be included in the main window toolbar (unless you want to add one of the "main toolbar buttons" to a view toolbar). Create classes that derive from '''AbstractAction''', you can will need to set an ''iconId'' and override ''execAction'', optionally, you can define a ''tooltip'':  
 
+
<pre> public class OutlineTreeExpandCommand extends AbstractAction {
Next we need to define the actions for our view toolbar buttons. They cannot be of type ''ViewButton'' or ''ToolButton'', as they would otherwise be included in the main window toolbar (unless you want to add one of the "main toolbar buttons" to a view toolbar). Create classes that derive from '''AbstractAction''', you can will need to set an ''iconId'' and override ''execAction'', optionally, you can define a ''tooltip'':
+
<pre>
+
  public class OutlineTreeExpandCommand extends AbstractAction {
+
 
     @Override
 
     @Override
 
     public String getIconId() {
 
     public String getIconId() {
Line 220: Line 235:
 
     @Override
 
     @Override
 
     protected void execAction() throws ProcessingException {
 
     protected void execAction() throws ProcessingException {
       if (extendedTreeForm != null) {
+
       if (extendedTreeForm&nbsp;!= null) {
 
         extendedTreeForm.setTreeNodeState(true);
 
         extendedTreeForm.setTreeNodeState(true);
 
       }
 
       }
Line 239: Line 254:
 
     @Override
 
     @Override
 
     protected void execAction() throws ProcessingException {
 
     protected void execAction() throws ProcessingException {
       if (extendedTreeForm != null) {
+
       if (extendedTreeForm&nbsp;!= null) {
 
         extendedTreeForm.setTreeNodeState(false);
 
         extendedTreeForm.setTreeNodeState(false);
 
       }
 
       }
Line 261: Line 276:
 
     }
 
     }
 
   }   
 
   }   
</pre>
+
</pre>  
 +
== Creating and registering the actions  ==
  
== Creating and registering the actions ==
+
As a last step, we need to instantiate and register our commands when the '''Desktop''' is being started.
  
As a last step, we need to instantiate and register our commands when the '''Desktop''' is being started.
+
We need to use the same key values that the extended classes use in their '''getView()''' methods.  
 
+
<pre> @Override
We need to use the same key values that the extended classes use in their '''getView()''' methods.
+
<pre>
+
  @Override
+
 
   protected void initConfig() {
 
   protected void initConfig() {
 
     super.initConfig();
 
     super.initConfig();
  
 
     ClientSession session = ClientSession.get();
 
     ClientSession session = ClientSession.get();
     if (session != null) {
+
     if (session&nbsp;!= null) {
 
       session.addViewButton(Strings.TableView, new TableActionCommand());
 
       session.addViewButton(Strings.TableView, new TableActionCommand());
 
       session.addViewButton(Strings.OutlineView, new OutlineTreeCollapseCommand());
 
       session.addViewButton(Strings.OutlineView, new OutlineTreeCollapseCommand());
 
       session.addViewButton(Strings.OutlineView, new OutlineTreeExpandCommand());
 
       session.addViewButton(Strings.OutlineView, new OutlineTreeExpandCommand());
 
     }
 
     }
 +
</pre>
 +
 +
== Ensuring recreation and redrawing ==
 +
 +
In principle, the steps above are already sufficient to show the view specific toolbars. However, to make sure they are also correctly shown if '''ApplicationWorkbenchAdvisor.initialize()''' calls ''configurer.setSaveAndRestore(true);'', a few more additions are needed.
 +
 +
*Add the following members to SwtEnvironment:
 +
<pre>
 +
    private Set<ViewToolBar> m_viewToolBars = new HashSet<ViewToolBar>();
 +
    private Set<IRefreshableToolbarView> m_views = new HashSet<IRefreshableToolbarView>();
 +
</pre> 
 +
*Add these two methods to SwtEnvironment:
 +
<pre>
 +
      public void addViewToolBar(ViewToolBar viewToolBar) {
 +
        m_viewToolBars.add(viewToolBar);
 +
      }
 +
 +
      public void addView(IRefreshableToolbarView view) {
 +
        m_views.add(view);
 +
      }
 
</pre>
 
</pre>
 +
*Change the environmentListener that is being created in SwtEnvironment.initialize(). Change
 +
<pre>
 +
    m_advisor.initViewButtons(d);
 +
</pre>       
 +
to
 +
<pre>
 +
    m_advisor.initViewButtons(d);
 +
    Iterator<ViewToolBar> itb = m_viewToolBars.iterator();
 +
    while (itb.hasNext()) {
 +
      itb.next().refreshToolBar();
 +
    }
 +
    Iterator<IRefreshableToolbarView> itv = m_views.iterator();
 +
    while (itv.hasNext()) {
 +
      itv.next().refreshToolbar();
 +
    }     
 +
</pre>
 +
*Create a new interface IRefreshableToolbarView:
 +
<pre>
 +
    public interface IRefreshableToolbarView {
 +
 +
      public void refreshToolbar();
 +
    }
 +
</pre>
 +
*For each view that has a toolbar make sure that it implements this interface:
 +
<pre>
 +
    public class TableView extends ValidationAbstractScoutView implements IRefreshableToolbarView {
 +
</pre>       
 +
and registers itself with the environment:
 +
<pre>
 +
      public TableView() {
 +
        ((SwtEnvironment) Activator.getDefault().getEnvironment()).addView(this);
 +
      }
 +
</pre>       
 +
Also make sure to add the following method:
 +
<pre>
 +
      @Override
 +
      public void refreshToolbar() {
 +
        getViewSite().getActionBars().getToolBarManager().update(true);
 +
      }
 +
</pre>
 +
  
 
= Result  =
 
= Result  =
  
The result looks like this:
+
The result looks like this:  
  
 
[[Image:ViewToolbar.png]]
 
[[Image:ViewToolbar.png]]

Latest revision as of 08:50, 18 March 2013

The Scout documentation has been moved to https://eclipsescout.github.io/.

The SWT client has different views. It is possible to add toolbar buttons to the view, these will then appear in the upper right corner of the view's header (to the left of the minimise/maximise buttons). This how-to explains how such toolbars can be added to views.

Steps

Registering the toolbar classes

Each toolbar must be registered for the view it will be attached to. This is done in the SWT plugin.xml file by adding a menuContribution to the org.eclipse.ui.menus extension. The menuContribution needs a locationURI attribute which is built as follows:

toolbar:<class name of the view you want the toolbar added to>

The menuContribution also needs a dynamic element which indicates the class that will manage the toolbar.

        <menuContribution
            allPopups="false"
            locationURI="toolbar:org.eclipse.minicrm.ui.swt.views.OutlineView">
         <dynamic
               class="org.eclipse.minicrm.ui.swt.toolbars.ViewToolBarOutline"
               id="org.eclipse.minicrm.ui.swt.views.toolbar.OutlineView">
         </dynamic>
      </menuContribution>
      <menuContribution
            allPopups="false"
            locationURI="toolbar:org.eclipse.minicrm.ui.swt.views.TableView">
         <dynamic
               class="org.eclipse.minicrm.ui.swt.toolbars.ViewToolBarTable"
               id="org.eclipse.minicrm.ui.swt.views.toolbar.TableView">
         </dynamic>
      </menuContribution>

Implementing the toolbar classes

Each distinct toolbar needs its own class, but as the only difference between toolbars is what actions are added as buttons, we can use a common class that covers the necessary functionality.

  • Create a new package org.eclipse.minicrm.ui.swt.toolbars
  • Create the abstract class ViewToolBar in that package
    package org.eclipse.minicrm.ui.swt.toolbars;

    import java.util.ArrayList;

    import org.eclipse.jface.action.Action;
    import org.eclipse.jface.action.ActionContributionItem;
    import org.eclipse.jface.action.IContributionItem;
    import org.eclipse.jface.action.Separator;
    import org.eclipse.minicrm.client.ClientSession;
    import org.eclipse.minicrm.ui.swt.Activator;
    import org.eclipse.scout.rt.client.IClientSession;
    import org.eclipse.scout.rt.client.ui.action.IAction;
    import org.eclipse.scout.rt.ui.swt.ISwtEnvironment;
    import org.eclipse.scout.rt.ui.swt.action.SwtScoutAction;
    import org.eclipse.swt.widgets.ToolBar;
    import org.eclipse.ui.actions.CompoundContributionItem;

    public abstract class ViewToolBar extends CompoundContributionItem {
      private IContributionItem[] oldItems = null;
      private ToolBar m_parent = null;
      private int m_index = 0;

      public ViewToolBar() {
        super();
        ((SwtEnvironment) Activator.getDefault().getEnvironment()).addViewToolBar(this);
      }

      public ViewToolBar(String id) {
        super(id);
        ((SwtEnvironment) Activator.getDefault().getEnvironment()).addViewToolBar(this);
      }

      public void refreshToolBar() {
        if (m_parent != null) {
          fill(m_parent, m_index);
        }
      }

      @Override
      public void fill(ToolBar parent, int index) {
        m_parent = parent;
        m_index = index;

        if (index == -1) {
          index = parent.getItemCount();
        }

        disposeOldItems();
        oldItems = getContributionItems();
        for (int i = 0; i < oldItems.length; i++) {
          IContributionItem item = oldItems[i];
          int oldItemCount = parent.getItemCount();
          if (item.isVisible()) {
            item.fill(parent, index);
          }
          int newItemCount = parent.getItemCount();
          int numAdded = newItemCount - oldItemCount;
          index += numAdded;
        }
      }

      private void disposeOldItems() {
        if (oldItems != null) {
          for (int i = 0; i < oldItems.length; i++) {
            IContributionItem oldItem = oldItems[i];
            oldItem.dispose();
          }
          oldItems = null;
        }
      }

      @Override
      public void dispose() {
        disposeOldItems();
        super.dispose();
      }

      @Override
      protected IContributionItem[] getContributionItems() {
        ISwtEnvironment env = Activator.getDefault().getEnvironment();
        if (env != null && env.isInitialized()) {
          IClientSession iSession = env.getClientSession();
          if ((iSession != null) && (iSession instanceof ClientSession))
          {

            ClientSession session = (ClientSession) iSession;
            IAction[] buttons = session.getViewButtons(getView());
            if (buttons != null && buttons.length > 0) {
              return getButtonContribution(buttons, env);
            }
          }
        }
        return new IContributionItem[0];
      }

      private IContributionItem[] getButtonContribution(IAction[] buttonActions, ISwtEnvironment env) {
        ArrayList<IContributionItem> contributionItems = new ArrayList<IContributionItem>();
        for (IAction buttonAction : buttonActions) {
          if (!buttonAction.isVisible()) {
            continue;
          }
          if (buttonAction.isSeparator()
              //ignore trailing separator
              && contributionItems.size() > 0 && contributionItems.get(contributionItems.size() - 1).isSeparator()) {
            continue;
          }

          contributionItems.add(getMenuContributionItem(buttonAction, env));
        }
        return contributionItems.toArray(new IContributionItem[contributionItems.size()]);
      }

      private IContributionItem getMenuContributionItem(IAction buttonAction, ISwtEnvironment env) {
        if (!buttonAction.isVisible()) {
          return null;
        }

        if (buttonAction.isSeparator()) {
          return new Separator();
        }

        Action swtAction = new SwtScoutAction(buttonAction, env).getSwtAction();
        return new ActionContributionItem(swtAction);
      }

      abstract protected String getView();
    }      
  • This class uses the ClientSession.getViewButtons() method to retrieve the configured actions (see more about this below). It also defines an abstract method getView() which defines the key value to which configured actions are attached
  • For each distinct toolbar, we need to define a class which extends ViewToolBar, these are the classes that are attached to the views using the <dynamic> element in the plugin.xml file.

If more than one view need identical toolbars, it is possible to use the same extended class for those views

    package org.eclipse.minicrm.ui.swt.toolbars;

    public class ViewToolBarOutline extends ViewToolBar {
      @Override
      protected String getView() {
        return Strings.OutlineView;
      }
    }
    package org.eclipse.minicrm.ui.swt.toolbars;

    public class ViewToolBarTable extends ViewToolBar {
      @Override
      protected String getView() {
        return Strings.TableView;
      }
    }      
  • The key values are best added to the org.eclipse.minicrm.shared.Strings class.

Transferring the actions between client and server

Building the dynamic menu (DesktopMenuBar) is done using Desktop.getMenus() which returns all instances of AbstractMenu. Building the main toolbar (ApplicationActionBarAdvisor) is done using Desktop.getViewButtons() and Desktop.getToolButtons() which return all instances of AbstractOutlineViewButton and AbstractOutlineViewButton.

Since Scout does not support view toolbars out of the box, a little more work is needed to set up the buttons in the client and to access them from the SWT renderer. Accessing the buttons from the SWT clien is done using the getViewButtons() method, mentioned in the previous chapter. As it is easier to extend the ClientSession than the desktop itself, we are adding a container to the ClientSession to and from which buttons can be added and retrieved:

  • Add the following member to ClientSession:
private Map<String, List<IAction>> viewButtons = new HashMap<String, List<IAction>>();
  • Add the following methods to ClientSession:
      public void addViewButton(String key, IAction buttonAction) {
        if (key != null && buttonAction != null) {
          List<IAction> actions = viewButtons.get(view);
          if (actions == null) {
            actions = new ArrayList<IAction>();
          }
          if (actions != null) {
            actions.add(buttonAction);
            viewButtons.put(key, actions);
          }
        }
      }

      public IAction[] getViewButtons(String key) {
        List<IAction> result = null;
        if (key != null) {
          result = viewButtons.get(key);
          if (result != null) {
            return result.toArray(new IAction[result.size()]);
          }
        }
        return null;
      }    

Defining the actions

Next we need to define the actions for our view toolbar buttons. They cannot be of type ViewButton or ToolButton, as they would otherwise be included in the main window toolbar (unless you want to add one of the "main toolbar buttons" to a view toolbar). Create classes that derive from AbstractAction, you can will need to set an iconId and override execAction, optionally, you can define a tooltip:

  public class OutlineTreeExpandCommand extends AbstractAction {
    @Override
    public String getIconId() {
      return Icons.Expand;
    }

    @Override
    protected String getConfiguredTooltipText() {
      return TEXTS.get("Expand");
    }

    @Override
    protected void execAction() throws ProcessingException {
      if (extendedTreeForm != null) {
        extendedTreeForm.setTreeNodeState(true);
      }
    }
  }

  public class OutlineTreeCollapseCommand extends AbstractAction {
    @Override
    public String getIconId() {
      return Icons.Collapse;
    }

    @Override
    protected String getConfiguredTooltipText() {
      return TEXTS.get("Collapse");
    }

    @Override
    protected void execAction() throws ProcessingException {
      if (extendedTreeForm != null) {
        extendedTreeForm.setTreeNodeState(false);
      }
    }
  }

  public class TableActionCommand extends AbstractAction {
    @Override
    public String getIconId() {
      return Icons.Action;
    }

    @Override
    protected String getConfiguredTooltipText() {
      return TEXTS.get("TableAction");
    }

    @Override
    protected void execAction() throws ProcessingException {
      system.out.println("TableAction");
    }
  }  

Creating and registering the actions

As a last step, we need to instantiate and register our commands when the Desktop is being started.

We need to use the same key values that the extended classes use in their getView() methods.

  @Override
  protected void initConfig() {
    super.initConfig();

    ClientSession session = ClientSession.get();
    if (session != null) {
      session.addViewButton(Strings.TableView, new TableActionCommand());
      session.addViewButton(Strings.OutlineView, new OutlineTreeCollapseCommand());
      session.addViewButton(Strings.OutlineView, new OutlineTreeExpandCommand());
    }

Ensuring recreation and redrawing

In principle, the steps above are already sufficient to show the view specific toolbars. However, to make sure they are also correctly shown if ApplicationWorkbenchAdvisor.initialize() calls configurer.setSaveAndRestore(true);, a few more additions are needed.

  • Add the following members to SwtEnvironment:
    private Set<ViewToolBar> m_viewToolBars = new HashSet<ViewToolBar>();
    private Set<IRefreshableToolbarView> m_views = new HashSet<IRefreshableToolbarView>();
  • Add these two methods to SwtEnvironment:
      public void addViewToolBar(ViewToolBar viewToolBar) {
        m_viewToolBars.add(viewToolBar);
      }

      public void addView(IRefreshableToolbarView view) {
        m_views.add(view);
      }
  • Change the environmentListener that is being created in SwtEnvironment.initialize(). Change
    m_advisor.initViewButtons(d);

to

    m_advisor.initViewButtons(d);
    Iterator<ViewToolBar> itb = m_viewToolBars.iterator();
    while (itb.hasNext()) {
      itb.next().refreshToolBar();
    }
    Iterator<IRefreshableToolbarView> itv = m_views.iterator();
    while (itv.hasNext()) {
      itv.next().refreshToolbar();
    }      
  • Create a new interface IRefreshableToolbarView:
    public interface IRefreshableToolbarView {

      public void refreshToolbar();
    }
  • For each view that has a toolbar make sure that it implements this interface:
    public class TableView extends ValidationAbstractScoutView implements IRefreshableToolbarView {

and registers itself with the environment:

      public TableView() {
        ((SwtEnvironment) Activator.getDefault().getEnvironment()).addView(this);
      }

Also make sure to add the following method:

      @Override
      public void refreshToolbar() {
        getViewSite().getActionBars().getToolBarManager().update(true);
      }


Result

The result looks like this:

ViewToolbar.png

Copyright © Eclipse Foundation, Inc. All Rights Reserved.