Home » Eclipse Projects » Eclipse Scout » Expanding the outline tree(Can it be done automatically?)
| | | |
Re: Expanding the outline tree [message #1015310 is a reply to message #1003967] |
Thu, 28 February 2013 08:03 |
Urs Beeli Messages: 573 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 #1018163 is a reply to message #1016726] |
Wed, 13 March 2013 09:40 |
Urs Beeli Messages: 573 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 |
Urs Beeli Messages: 573 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:
[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 |
Urs Beeli Messages: 573 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.
|
|
|
Goto Forum:
Current Time: Fri Sep 20 15:26:59 GMT 2024
Powered by FUDForum. Page generated in 0.04540 seconds
|