Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF » Manually creating and firing events from inside another listener
Manually creating and firing events from inside another listener [message #1000450] Mon, 14 January 2013 14:55 Go to next message
Maya L. is currently offline Maya L.
Messages: 2
Registered: January 2013
Junior Member
Hi all,

I have an object with a TreeViewer wrapped inside it, which has a modified TreeListener that resolves EMF proxies using a ComposedAdapterFactory when a TreeExpansionEvent is handled. I would like the same modified expansion to take place when a selection in the TreeViewer is double-clicked on. I have manually created a TreeExpansionEvent and called the modified TreeListener's treeExpanded() from inside the DoubleClickListener; I also tried to add the event to the the Display and system EventQueues. In both cases, the debugger goes through the TreeListener's code, calls on the ComposedAdapterFactory's getChildren() and resolves the proxies, but unlike when the twistie is opened on the tree, double clicking and firing an event does not eventually lead to any OS calls and so the tree doesn't actually expand.

Does anyone have any idea on what I could do to make the double click trigger the tree expansion? The TreeViewer is in an inner class. One thing I thought of, after a suggestion from the SWT forum, is to write my own Tree extension that overrides the expand methods to resolve proxies so that I don't need specialized listeners. Is this a good approach?

Here is the doubleClickListener; There's also a variation I tried without the runnable and simply calls the TreeListener, mtvl

@Override
public void doubleClick(DoubleClickEvent event) {
   treeViewer.getDisplay();
   Object selectedFirstElement = (EObject) ((TreeSelection) workloadViewer.getSelection()).getFirstElement();
   Display.getCurrent().syncExec(new Runnable() {
      @Override
      public void run() {
         final TreeExpansionEvent te = new TreeExpansionEvent(treeViewer.getTreeViewer(), treeViewer.getSelection().getFirstElement());
         mtvl.treeExpanded(te);
}});


Thanks!
(Cross-posted from SWT, since this is really a question that involves both SWT and EMF: http://www.eclipse.org/forums/index.php/t/447691/)
Re: Manually creating and firing events from inside another listener [message #1000605 is a reply to message #1000450] Tue, 15 January 2013 00:00 Go to previous messageGo to next message
Ed Merks is currently offline Ed Merks
Messages: 25918
Registered: July 2009
Senior Member
Maya,

Comments below.

On 14/01/2013 8:55 PM, Maya L. wrote:
> Hi all,
>
> I have an object with a TreeViewer wrapped inside it, which has a
> modified TreeListener that resolves EMF proxies using a
> ComposedAdapterFactory when a TreeExpansionEvent is handled. I would
> like the same modified expansion to take place when a selection in the
> TreeViewer is double-clicked on. I have manually created a
> TreeExpansionEvent and called the modified TreeListener's
> treeExpanded() from inside the DoubleClickListener; I also tried to
> add the event to the the Display and system EventQueues. In both
> cases, the debugger goes through the TreeListener's code, calls on the
> ComposedAdapterFactory's getChildren() and resolves the proxies, but
> unlike when the twistie is opened on the tree, double clicking and
> firing an event does not eventually lead to any OS calls and so the
> tree doesn't actually expand.
SWT widgets don't "do their thing" because they listen to events, they
fire events when they "do their thing". Not only that, but if you
manually do something with them, that doesn't fire any events, e.g., if
you call the TreeViewer's setSelection with the reveal parameter set to
true...
> Does anyone have any idea on what I could do to make the double click
> trigger the tree expansion? The TreeViewer is in an inner class. One
> thing I thought of, after a suggestion from the SWT forum, is to write
> my own Tree extension that overrides the expand methods to resolve
> proxies so that I don't need specialized listeners. Is this a good
> approach?
Why aren't proxies just resolved when getChildren is called on the item
provider? Note that you can specialize hasChildren so that getChildren
is not called just to determine if there needs to be an expansion
decoration; setting the GenModel's "Optimized Has Children" should do
the trick.
>
> Here is the doubleClickListener; There's also a variation I tried
> without the runnable and simply calls the TreeListener, mtvl
>
>
> @Override
> public void doubleClick(DoubleClickEvent event) {
> treeViewer.getDisplay();
> Object selectedFirstElement = (EObject) ((TreeSelection)
> workloadViewer.getSelection()).getFirstElement();
> Display.getCurrent().syncExec(new Runnable() {
> @Override
> public void run() {
> final TreeExpansionEvent te = new
> TreeExpansionEvent(treeViewer.getTreeViewer(),
> treeViewer.getSelection().getFirstElement());
> mtvl.treeExpanded(te);
> }});
>
> Thanks!
> (Cross-posted from SWT, since this is really a question that involves
> both SWT and EMF: http://www.eclipse.org/forums/index.php/t/447691/)
Re: Manually creating and firing events from inside another listener [message #1003754 is a reply to message #1000605] Mon, 21 January 2013 18:43 Go to previous messageGo to next message
John Reysa is currently offline John Reysa
Messages: 21
Registered: July 2009
Junior Member
Hi Ed,
Thanks for the reply.

The proxies are not resolved because we have the load option PROXY_ATTRIBUTES set to true which you added to avoid loading the individual children from a database which helped with performance.

At first we tried treeViewer.expandToLevel(ourEmfObject, 1);
If ourEmfObject was a proxy, it removed the expand triangle (hasChildren) on the UI and a refresh on it's parent did not bring the triangle back.

After reading your response, we tried the following (this code is in a doubleClick listener for the treeViewer.
Leaf leaf = (Leaf) treeViewer.getSelection().getFirstElement();
if (leaf.eIsProxy())
{
  Branch branch = (Branch) leaf.eContainer();
  leaf = branch.getChildren().get(branch.getChildren().indexOf(leaf));
}
treeViewer.expandToLevel(leaf, 1);


This works if you double-click twice.
I suspect there is something about the resolution of proxy that updates the tree after the first double click. Any suggestions on the right way to do this?


[Updated on: Mon, 21 January 2013 22:15]

Report message to a moderator

Re: Manually creating and firing events from inside another listener [message #1003763 is a reply to message #1003754] Mon, 21 January 2013 19:15 Go to previous messageGo to next message
John Reysa is currently offline John Reysa
Messages: 21
Registered: July 2009
Junior Member
One other note. Optimized Has Children is set to false.
Do you still recommend setting it to true if PROXY_ATTRIBUTES is set on load options?
Re: Manually creating and firing events from inside another listener [message #1003773 is a reply to message #1003763] Mon, 21 January 2013 19:47 Go to previous messageGo to next message
John Reysa is currently offline John Reysa
Messages: 21
Registered: July 2009
Junior Member
It appears adding a refresh makes it work. Resolving the proxy created a unique object so the id's did not match when searching to tree for the expand.

Leaf leaf = (Leaf) treeViewer.getSelection().getFirstElement();
if (leaf.eIsProxy())
{
  Branch branch = (Branch) leaf.eContainer();
  leaf = branch.getChildren().get(branch.getChildren().indexOf(leaf));
  treeViewer.refresh(branch);
}
treeViewer.expandToLevel(leaf, 1);


Summary of questions now...
1. Is this the recommended approach?
2. Should we set "optimized has children" if we are using the "PROXY_ATTRIBUTES" load option?
3. A related question: Each tree element is loaded with an emf load from a database (using mongo)
How do you "reload" an object that changes in the database.
We tried an unload/load, but a new object comes back and loses it's eContainer.
(The object does not have a reference to parent)
Is there a recommended way to handle this situation?

[Updated on: Mon, 21 January 2013 22:15]

Report message to a moderator

Re: Manually creating and firing events from inside another listener [message #1003889 is a reply to message #1003754] Tue, 22 January 2013 02:38 Go to previous messageGo to next message
Ed Merks is currently offline Ed Merks
Messages: 25918
Registered: July 2009
Senior Member
John,

Comments below.

On 22/01/2013 12:43 AM, John Reysa wrote:
> Hi Ed, Thanks for the reply.
> The proxies are not resolved because we have the load option
> PROXY_ATTRIBUTES set to true which you added to avoid loading the
> individual children from a database which helped with performance.
Ah, that sounds familiar. :-)
>
> At first we tried treeViewer.expandToLevel(ourEmfObject, 1);
> If ourEmfObject was a proxy, it removed the expand triangle
> (hasChildren) on the UI and a refresh on it's parent did not bring the
> triangle back.
Because the proxy really has no children, only its resolved replacement
actually has children?
> After reading your response, we tried the following (this code is in a
> doubleClick listener for the treeViewer.
>
> Leaf leaf = (Leaf) treeViewer.getSelection().getFirstElement();
I see, you're really showing unresolved proxies in the tree.
> if (leaf.eIsProxy())
> {
> Branch branch = (Branch) leaf.eContainer();
> leaf = branch.getChildren().get(branch.getChildren().indexOf(leaf));
You're doing this to resolve the proxy.
> }
> treeViewer.getTreeViewer().expandToLevel(leaf, 1);
The issue is probably one of timing. This very recent improvement might
help with this case, i.e., changes to preserve the expansion during an
update.

http://git.eclipse.org/c/emf/org.eclipse.emf.git/commit/?id=884d645931f6f0caacaf092c166ce19942f37176

An important thing to note is how
org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider.notifyChanged(Notification)
updates the viewer, in particular it posts an event and as part of that
processing, merges notifications. So I expect your
treeViewer.getTreeViewer().expandToLevel(leaf, 1); is happening *before
*the viewer has updated in response to the resolve notification.

>
> This works if you double-click twice. I suspect there is something
> about the resolution of proxy that updates the tree after the first
> double click. Any suggestions on the right way to do this?
It might well be the case that the changes I committed above would make
your stuff work without any changes on your side... Then again, the
proxies might be considered stale and be ignored in that processing...
Given your current state of EMF, doing the expand in an asyncExec will
probably do the trick.
>
>
Re: Manually creating and firing events from inside another listener [message #1003890 is a reply to message #1003763] Tue, 22 January 2013 02:41 Go to previous messageGo to next message
Ed Merks is currently offline Ed Merks
Messages: 25918
Registered: July 2009
Senior Member
John,

The optimized has children basically just looks at the features used to
populate children and checks if any of them have content without
resolving proxies. Unless your getChildren code is modified in some way
to produce children other than from the children features, this should
work well and be faster.


On 22/01/2013 1:15 AM, John Reysa wrote:
> One other note. Optimized Has Children is set to false. Do you still
> recommend setting it to true if PROXY_ATTRIBUTES is set on load options?
Re: Manually creating and firing events from inside another listener [message #1003897 is a reply to message #1003773] Tue, 22 January 2013 02:48 Go to previous message
Ed Merks is currently offline Ed Merks
Messages: 25918
Registered: July 2009
Senior Member
John,

Comments below.

On 22/01/2013 1:47 AM, John Reysa wrote:
> It appears adding a refresh makes it work. Resolving the proxy
> created a unique object so the id's did not match when searching to
> tree for the expand.
> Leaf leaf = (Leaf) treeViewer.getSelection().getFirstElement();
> if (leaf.eIsProxy())
> {
> Branch branch = (Branch) leaf.eContainer();
> leaf = branch.getChildren().get(branch.getChildren().indexOf(leaf));
> treeViewer.refresh(branch)
> }
> treeViewer.getTreeViewer().expandToLevel(leaf, 1);
>
> Summary of questions now...
> 1. Is this the recommended approach?
I imagine that works because you're doing up front what would be done
later by the viewer refresh logic in the adapter factory content
provider. Posting your expand should do the trick as well I believe.
> 2. Should we set "optimized has children" if we are using the
> "PROXY_ATTRIBUTES" load option?
I'd suggest trying it yes. I don't imagine it would cause any problems
and is likely to improve performance, especially if there are many children.
> 3. A related question: Each tree element is loaded with an emf load
> from a database (using mongo)
> How do you "reload" an object that changes in the database. We tried
> an unload/load, but a new object comes back and loses it's eContainer.
> (The object does not have a reference to parent)
> Is there a recommended way to handle this situation?
That's tricky if you don't actually have a container proxy on the
children. That scenario is supported but it's not until the parent
resolves its proxy to the child that the child will have a container
pointer back to the parent. You could use much the same approach as
you're using above. I.e., get the object's container, determine its
index in that container's containment feature, then unload the resource
(no need to reload it) and get the child at the recorded index of the
container's containment feature, which should resolve the proxy, reload
the unloaded resource, and then views should update.
Previous Topic:[CDO] Different object was registered for OID:http://example.com#MyType#c09f11a0-
Next Topic:EMF Ecore output xmi, can have only text content element ?
Goto Forum:
  


Current Time: Thu Jul 24 21:44:39 EDT 2014

Powered by FUDForum. Page generated in 0.02698 seconds