Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » scout » Expanding the outline tree(Can it be done automatically?)
Expanding the outline tree [message #1003539] Mon, 21 January 2013 13:27 Go to next message
Urs Beeli is currently offline Urs Beeli
Messages: 335
Registered: October 2012
Location: Bern, Switzerland
Senior Member
In my StandardOutline I have a few AbstractPageWithTable pages that contain AbstractPageWithNodes as children and those in turn again contain multiple AbstractPageWithTable as children (basically giving me a three-level tree hierarchy).

When launching my application, all nodes of the outline tree view are collapsed. Expanding each node manually can become quite tedious and I was therefore wondering about a few things:

  • is it possible to initially show the tree fully expanded? I've looked at the properties and advanced properties of the outline but couldn't find anything that sounded like it would do the trick
  • is it possible to fully expand/collaps the tree through a command that can be triggered by the user (e.g. from a View->Expand/Collaps all menu)?
  • taking this one step further, would it be possible to add two buttons to expand/collapse the tree to the header of the outline tree view (similar to those offered in many eclipse views)? How would I go about this?
    index.php/fa/13035/0/
Re: Expanding the outline tree [message #1003916 is a reply to message #1003539] Tue, 22 January 2013 08:22 Go to previous messageGo to next message
Jeremie Bresson is currently offline Jeremie Bresson
Messages: 765
Registered: October 2011
Senior Member
As far as I know there is no such possibility by default (for the moment).

If you want to implement such a behavior, some additional/custom implementation is required.
Re: Expanding the outline tree [message #1003931 is a reply to message #1003539] Tue, 22 January 2013 09:13 Go to previous messageGo to next message
Adrian Moser
Messages: 67
Registered: March 2011
Member
Urs, did you try

  @Override
  protected boolean getConfiguredExpanded() {
    return true;
  }


on the pages?

Adrian
Re: Expanding the outline tree [message #1003967 is a reply to message #1003931] Tue, 22 January 2013 10:35 Go to previous messageGo to next message
Urs Beeli is currently offline Urs Beeli
Messages: 335
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Adrian

Thanks for that pointer, I had been looking for such a property on the Outline, not the contained pages.

Unfortunately it does not fully expand the tree, the only difference I could see was that PageWithNodes now auto-expand when I click on them (whereas before I had to manually expand them).
Re: Expanding the outline tree [message #1015310 is a reply to message #1003967] Thu, 28 February 2013 08:03 Go to previous messageGo to next message
Urs Beeli is currently offline Urs Beeli
Messages: 335
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Ok, I've looked into this a little further and found a solution. As I've already extended the OutlineTreeForm with a SnapBox to add outline buttons, I simply added two more buttons to it, one to collapse and one to expand the tree. In their execClickAction() methods I am calling expandAll() and collapseAll() on the tree.

At first, this didn't work because my AbstractPageWithDetails didn't expand. After a little investigation I found out that they are added to the tree as VirtualPages and therefore do not contain enough information to know if they need to expand or not. Upon the first "expandAll" action I now resolve all the pages in my tree (which takes a few seconds) and after that expandAll() and collapseAll() works as expected.

Here is my code, if anyone is interested.

public class ExtendedOutlineTreeForm extends AbstractForm implements IOutlineTreeForm {
  private boolean m_resolved = false;

...

  public void setTreeNodeState(boolean state) {
    ITree tree = getOutlineTreeField().getTree();
    ITreeNode root = tree.getRootNode();
    if (state) {
      if (!m_resolved) {
        resolveAllTreeNodes(root, state);
        m_resolved = true;
      }
      else {
        tree.expandAll(root);
      }
    }
    else {
      tree.collapseAll(root);
    }
  }

  public void resolveAllTreeNodes(ITreeNode root, boolean state) {
    for (ITreeNode child : root.getChildNodes()) {
      if (child instanceof VirtualPage) {
        try {
          root.resolveVirtualChildNode(child);
        }
        catch (ProcessingException e) {
          e.printStackTrace();
        }
      }
    }
    root.getTree().expandAll(root);
    for (ITreeNode child : root.getChildNodes()) {
      resolveAllTreeNodes(child, state);
    }
  }

  ...

      public class CollapseButton extends AbstractButton {
        ...

        @Override
        protected void execClickAction() throws ProcessingException {
          setTreeNodeState(false);
        }
      }

      public class ExpandButton extends AbstractButton {
        ...

        @Override
        protected void execClickAction() throws ProcessingException {
          setTreeNodeState(true);
        }
      }

  ...
}



I don't know if this is the most elegant solution, but it certainly seems to work.

[Updated on: Thu, 28 February 2013 08:03]

Report message to a moderator

Re: Expanding the outline tree [message #1016726 is a reply to message #1015310] Thu, 07 March 2013 13:49 Go to previous messageGo to next message
Claudio Guglielmo is currently offline Claudio Guglielmo
Messages: 127
Registered: March 2010
Senior Member
Quote:
taking this one step further, would it be possible to add two buttons to expand/collapse the tree to the header of the outline tree view (similar to those offered in many eclipse views)? How would I go about this?

This is not supported so far, but it shouldn't be a big deal if you use swt, see http://www.vogella.com/articles/EclipseCommands/article.html#toolbar__viewtoolbar.

I've never used it by myself but maybe it helps you.
Re: Expanding the outline tree [message #1018163 is a reply to message #1016726] Wed, 13 March 2013 09:40 Go to previous messageGo to next message
Urs Beeli is currently offline Urs Beeli
Messages: 335
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Claudio, thanks a lot for this pointer.

I have managed to add a static toolbar to my view (i.e. all the buttons/commands need to be defined in the plugin.xml).

However, the commands reside in the SWT plugin, so a click on this button calls
org.eclipse.minicrm.ui.swt.commands.MyCommandHandler.execute()


My next step would be to find out how to forward this to some client code (e.g. to show a form), if anyone can give me a hint on how to proceed here, it would be much appreciated.
The step after that will be to support dynamic view-toolbars, I guess I'll have to mimic the functionality of DesktopMenuBar, I'll have a look how it goes.

I'll let you know what I find out, if you or anyone else has hints on how to proceed, it will be much appreciated.
Re: Expanding the outline tree [message #1018279 is a reply to message #1018163] Wed, 13 March 2013 14:51 Go to previous messageGo to next message
Urs Beeli is currently offline Urs Beeli
Messages: 335
Registered: October 2012
Location: Bern, Switzerland
Senior Member
Here I am again.

I have succesfully managed to add dynamic toolbars to my views. I proceeded as follows:

In org.eclipse.minicrm.ui.swt\plugin.xml I added the following entries to the org.eclipse.ui.menus extensions:
      <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>


Then I created a new packages org.eclipse.minicrm.ui.swt.toolbars in which I created an abstract class to take care of the dynamic filling of the toolbars (I modelled it on DesktopMenuBar and CompoundContributionItem):
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;

  @Override
  public void fill(ToolBar parent, int 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();
}


Then, for each view intended to have a toolbar, I created small classes extending this abstract class:
package org.eclipse.minicrm.ui.swt.toolbars;

public class ViewToolBarOutline extends ViewToolBar {
  @Override
  protected String getView() {
    return "OutlineView";
  }
}

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

public class ViewToolBarTable extends ViewToolBar {
  @Override
  protected String getView() {
    return "TableView";
  }
}


These classes are used so we can have different toolbar buttons for each view. By returning a different view-name, we can then request the corresponding buttons from the ClientSession using getViewButtons().

This method is of course still missing. The DesktopMenuBar (and potentially ApplicationActionBarAdvisor) get access to menus, view buttons and tool buttons defined in the client's Desktop class directly through getMenus(), getViewButtons() and getToolButtons(). Unless we want to duplicate those buttons on our views, we cannot use these three methods (nor the comfortable mechanism of just adding classes of the correct type to Desktop) for our purpose.

Instead, I added a container to the ClientSession, which is filled by the Desktop on startup and which can be queried by the ViewToolBar class when creating the toolbars.

Add the following member and methods to ClientSession:
  private Map<String, List<IAction>> viewButtons = new HashMap<String, List<IAction>>();

  public void addViewButton(String view, IAction buttonAction) {
    if (view != null && buttonAction != null) {
      List<IAction> actions = viewButtons.get(view);
      if (actions == null) {
        actions = new ArrayList<IAction>();
      }
      if (actions != null) {
        actions.add(buttonAction);
        viewButtons.put(view, actions);
      }
    }
  }

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


Now all that remains is to create the actions to be used on the view-toolbars in Desktop:
  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");
    }
  }


As a last step, we need to instantiate and register our commands when the Desktop is being started:
  @Override
  protected void initConfig() {
    super.initConfig();

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


And the result looks like this:
index.php/fa/13832/0/

[Updated on: Wed, 13 March 2013 14:52]

Report message to a moderator

Re: Expanding the outline tree [message #1020541 is a reply to message #1018279] Mon, 18 March 2013 12:18 Go to previous message
Urs Beeli is currently offline Urs Beeli
Messages: 335
Registered: October 2012
Location: Bern, Switzerland
Senior Member
In this post I had been wondering how to store/restore windows positions/sizes as well as View configurations with SWT. I was told to add
configurer.setSaveAndRestore(true);

to ApplicationWorkbenchAdvisor.initialize().

While this worked, it has the drawback that the global Coolbar is not restored correctly (it only shows the first button).

The implementation of the View toolbars described above has a similar problem, if SaveAndRestore is set to true, the view specific toolbars are no longer shown on startup. Minimizing and restoring a view, or switching between views sharing the same region forces the toolbar to be shown again.

Analysing the problem a bit further, I found the reason for this: Without storing the window position/size (in workbench.xml) the fill() method of our toolbar are only called after the client and SwtEnvironment have been initialised. If we are storing the window position/size, these methods are called much earlier (when the XML file is read), at which point we cannot yet access the client/SwtEnvironment to create the buttons.

To allow for this, we must store the parent and index with which our fill() methods were called, so we can call them again when the client is ready to provide this information. We also need to tell each view to force an update of the toolbar.

This requires the following code changes:

ViewToolBar needs two new members:
  private ToolBar m_parent = null;
  private int m_index = 0;

which are set when the fill() method is called:
  @Override
  public void fill(ToolBar parent, int index) {
    m_parent = parent;
    m_index = index;

    // ... rest of method as above
  }


Then, we must register the toolbar with the SwtEnvironment, so it can tell the toolbar to configure itself once the necessary information is availbale:
  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);
    }
  }


SwtEnvironment must be extended to allow for this:
  private Set<ViewToolBar> m_viewToolBars = new HashSet<ViewToolBar>();
  private Set<IRefreshableToolbarView> m_views = new HashSet<IRefreshableToolbarView>();

  public void addViewToolBar(ViewToolBar viewToolBar) {
    m_viewToolBars.add(viewToolBar);
  }

  public void addView(IRefreshableToolbarView view) {
    m_views.add(view);
  }


Now, the listener for SwtEnvironmentEvent.STARTED must be extended. 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();
  }


Finally, all our views must register themselves with the Environment as well. Define a new interface:
public interface IRefreshableToolbarView {

  public void refreshToolbar();
}


and make sure every view implements it and adds the following methods (shown for TableView, needed for all views that have a toolbar).
public class TableView extends ValidationAbstractScoutView implements IRefreshableToolbarView {

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

  @Override
  protected ISwtEnvironment getSwtEnvironment() {
    return Activator.getDefault().getEnvironment();
  }

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


This ensures that the view specific toolbars are correctly redrawn even when setting SaveAndRestore to true.
Previous Topic:Translations editor does not work anymore
Next Topic:How to store SWT window size and view distribution
Goto Forum:
  


Current Time: Sat Oct 25 12:45:24 GMT 2014

Powered by FUDForum. Page generated in 0.02790 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software