This Bugzilla instance is deprecated, and most Eclipse projects now use GitHub or Eclipse GitLab. Please see the deprecation plan for details.
Bug 384758 - Contexts do not restrict Key bindings visibility on E4.2 anymore
Summary: Contexts do not restrict Key bindings visibility on E4.2 anymore
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 4.2   Edit
Hardware: PC Windows Vista
: P3 major (vote)
Target Milestone: 4.2.2   Edit
Assignee: Paul Webster CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 396128 (view as bug list)
Depends on:
Blocks:
 
Reported: 2012-07-10 13:29 EDT by Sebastien Dubois CLA
Modified: 2013-05-28 12:06 EDT (History)
8 users (show)

See Also:


Attachments
Example demonstrating the problem (5.07 KB, application/octet-stream)
2012-08-22 14:38 EDT, Brian de Alwis CLA
no flags Details
plugin.xml file (95.91 KB, text/xml)
2012-11-26 17:25 EST, Sebastien Dubois CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Sebastien Dubois CLA 2012-07-10 13:29:59 EDT
I have a plugin that uses contexts (org.eclipse.ui.contexts extension point) to restrict some key bindings to a specific View part.  The context is activated/deactivated programmatically using the IContextService#activateContext and IContextService#deactivate context methods.  This works fine in E3.7, and the key bindings are applied correctly when the View Part is activated.  However, on E4 using the compatibility layer, it seems that activating/deactivating the context has no effect, and the key bindings are always applied i.e. not restricted to the view part anymore.
Comment 1 Paul Webster CLA 2012-07-10 13:44:48 EDT
If you can describe a small example, I'll test it.

ex: do you use activate your context once when you view is created (that scopes it to when the view is active)?

Or do you need to narrow the scope of your keybindings even more, say only when your view is active and in a certain mode?

What context do your contexts derive from?

PW
Comment 2 Sebastien Dubois CLA 2012-07-10 13:52:36 EDT
(In reply to comment #1)
> If you can describe a small example, I'll test it.
> 
> ex: do you use activate your context once when you view is created (that scopes
> it to when the view is active)?
> 
> Or do you need to narrow the scope of your keybindings even more, say only when
> your view is active and in a certain mode?

I actually tried both ways i.e. activating the context in the ViewPart createPartControl method and also by activating the context in a PartListener I implemented in the View part e.g.

getSite().getPage().addPartListener(fPartListener = new IPartListener() {
...
   public void partDeactivated(IWorkbenchPart part) {
	if (part instanceof MyView && null != myContext) {
	   IContextService contextService = (IContextService) getSite().getService(IContextService.class);				      
           contextService.deactivateContext(myContext);
	   myContext = null;
	}
   }
   ...
   public void partActivated(IWorkbenchPart part) {
if (part instanceof ReviewNavigatorView && null == fR4EContext) {
					IContextService contextService = (IContextService) getSite().getService(IContextService.class);
					fR4EContext = contextService.activateContext(R4EUIConstants.R4E_CONTEXT_ID);
				}

> 
> What context do your contexts derive from?
> 
> PW
Comment 3 Sebastien Dubois CLA 2012-07-10 13:55:23 EDT
Sorry I mistyped the code should read

getSite().getPage().addPartListener(fPartListener = new IPartListener() {
...
   public void partDeactivated(IWorkbenchPart part) {
    if (part instanceof MyView && null != myContext) {
       IContextService contextService = (IContextService)
getSite().getService(IContextService.class);                      
           contextService.deactivateContext(myContext);
       myContext = null;
    }
   }
   ...
   public void partActivated(IWorkbenchPart part) {
   if (part instanceof MyView && null == myContext) {
      IContextService contextService = (IContextService)getSite().getService(IContextService.class);
      myContext = contextService.activateContext(R4EUIConstants.MY_CONTEXT_ID);
   }
  }
});


> 
> What context do your contexts derive from?

  My custom context has org.eclipse.ui.contexts.window has the parent

/Sebastien
Comment 4 Paul Webster CLA 2012-07-11 10:13:37 EDT
I would recommend doing activating your context once in createPartControl(*), as a general best practice for your usecase.  Could you try that again as a workaround?

IContextService contextService 
  = (IContextService)getSite().getService(IContextService.class);
contextService.activateContext(R4EUIConstants.R4E_CONTEXT_ID);


But the partActived/partDeactivated should work as well, we'll look into it.

PW
Comment 5 Sebastien Dubois CLA 2012-07-11 10:33:51 EDT
(In reply to comment #4)
> I would recommend doing activating your context once in createPartControl(*),
> as a general best practice for your usecase.  Could you try that again as a
> workaround?
> 
> IContextService contextService 
>   = (IContextService)getSite().getService(IContextService.class);
> contextService.activateContext(R4EUIConstants.R4E_CONTEXT_ID);
> 
> 
> But the partActived/partDeactivated should work as well, we'll look into it.
> 
> PW

Actually activating the context in the createPartControl is what I've done initially, but it didn't work either, so I then tried to do it in partActived/partDeactivated.

So bottom line, the workaround you are suggesting doesn't seem to work either

/Sebastien
Comment 6 Brian de Alwis CLA 2012-08-22 14:38:19 EDT
Created attachment 220160 [details]
Example demonstrating the problem

Here's a small demo bundle (ca.mt.dummy) that:
  * creates a custom keybinding context ca.mt.dummy.context;
  * adds a "dummy" editor that activates the ca.mt.dummy.context using the context service;
  * binds M1+D in the ca.mt.dummy.context to an open-dummy-editor command.

Create a new Eclipse product launch with org.eclipse.sdk.ide that includes this bundle.

After opening the first dummy editor (using the Dummy toolitem or Help > Open Dummy Editor), you should be able to use M1+D from within a dummy editor to open new dummy editors.  It sometimes works, but often fails.

The cause is that each part's context-activation causes a RunAndTrack (a ContextService$UpdateExpression) against activePart to enable or disable the applicable context as the part is activated or deactivated.  But we can't control the ordering that these RATs are notified, and so we sometimes (often?) process the part-activation (which adds the keybinding-context) and then the part-deactivation (which removes the keybinding-context), such that the result is entirely dependent on the RAT order.

Working on a fix.
Comment 7 Brian de Alwis CLA 2012-08-22 16:03:26 EDT
The problem is a bit more straightforward than I realized.  Whenever the active part changes, the ContextService$UpdateExpression RATs are invoked.  The in pseudocode, the RAT does:

   if activePart = me then
      activate my context
   else
      deactivate my context

But the deactive-my-context doesn't check that this part *was* the last active part.  So if I have three Dummy Editors open and switch to the Package Explorer, there are three deactivations of ca.mt.dummy.context; if I switch back to a Dummy Editor, I get one activation and 2 deactivations.

Somehow the UpdateExpression RATs need to know whether they were active previously.
Comment 8 Brian de Alwis CLA 2012-08-23 15:49:59 EDT
(In reply to comment #5)
> Actually activating the context in the createPartControl is what I've done
> initially, but it didn't work either, so I then tried to do it in
> partActived/partDeactivated.

Sebastien: delay the re-activation using a Display.timerExec(), like say 30ms.
Comment 9 Laura V CLA 2012-09-13 05:59:39 EDT
Hi there
I have a similar problem, can you please tell me if it belongs to this bug or I should open a new one?
we have a pure e4 application.
We have a part with 3 grids in it.
We want the users to be able to delete a row using the DEL key.
For this, each table has its own command / handler (we have already a context menu using these handlers and they work fine).
So I defined 3 binding contexts on the part.
Then I defined a Focus Listener on the grids and so I dynamically activated / deactivated them on focus gained / lost:

contextService.activateContext("myContext1");

But...it's not working. Always the same handler is called.
I added a key listener to the table and calling
contextService.getActiveContextIds();
I saw that there are always all my 3 contexts in there (also one from eclipse: org.eclipse.ui.contexts.window). That means, they never get deactivated  
(I debugged and saw the deactivate method gets called...no idea why it has no effect?!)
Am I doing something wrong? Or is it a bug? Or is there a quicker way to do this?
Thanks

Laura
Comment 10 Paul Webster CLA 2012-09-13 07:26:59 EDT
(In reply to comment #9)
> Hi there
Hi Laura,

Could you please open a new bug for this? Eclipse Platform/UI


Thanx
PW
Comment 11 Laura V CLA 2012-09-14 03:14:49 EDT
 
> Could you please open a new bug for this? Eclipse Platform/UI


Will do it.
THx 

Laura
Comment 12 Paul Webster CLA 2012-10-31 14:18:44 EDT
Brian, what if we cached the last eval from each UpdateExpression, and only executed an activate/deactivate if the new eval changed.

That might not 100% solve the problem, but at least that should reduce the # of contenders down to 2 (one deactivate and one activate)?

PW
Comment 13 Paul Webster CLA 2012-11-05 10:49:42 EST
Brian, I've released a caching step to http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?h=R4_2_maintenance&id=f3024549d09ec72b0326e8d06563ae53bb77cd99

It should only activate or deactivate when its expression actually changes.

I've also added an improvement via bug 390379 that includes ref-counting and only firing when the activeContexts IDs would change.

But I'm still able to replicate the problem via your example ... it needs some more investigation.

PW
Comment 14 Paul Webster CLA 2012-11-13 08:47:55 EST
With Bogdan's fix from http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?h=gheorghe/contextDeferUpdates&id=e7d7c1533308013507bc092d9bda787ea974f99d it now reliably fails with one more deactivate than activate when using M1+D to open the next editor.

While in the PartServiceImpl.activate it issues a ModelServiceImpl.bringToTop

That creates the DummyEditor which activates its context in createPartControl(*).  That creates an UpdateExpression RAT, which evaluates to false as the active part is not yet the new one.

That's one deactivateContext.

Then WorkbenchPage sets the new active editor, and UpdateExpression is run again, adding a activateContext.  Then the UpdateExpression from the original editor runs, adding a deactivateContext.

That leaves us with +1 and -2, which wipes out the existing context already activated.

PW
Comment 15 Paul Webster CLA 2012-11-13 09:14:44 EST
When the UpdateExpression is first created, it goes from null to FALSE, and then from FALSE to true.  The transition from null to FALSE shouldn't deactivate a context, as it has never been activated.

http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?h=R4_2_maintenance&id=2fc58f83f01d492b66cfbdb08ab67ba4da64505d

Brian, could you also test to make sure it works in your scenarios.

Sebastien, it should show up in this week's M build, M20121114-1200 from http://download.eclipse.org/eclipse/downloads/  if you could test it in your scenario when it becomes available.

PW
Comment 16 Brian de Alwis CLA 2012-11-13 09:49:54 EST
This greatly improves the situation.  But if I open several dummy editors, and then close an editor (thus switching to a different dummy editor), the context isn't restored.
Comment 17 Paul Webster CLA 2012-11-13 10:20:08 EST
On closing a part, the dispose blindly deactivated its contexts:

http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?h=R4_2_maintenance&id=dae54ce66efbd830eac95db3dea446306f3ef47b

On close, disposing the part causes an extra deactivate after the UpdateExpression for that part has done the deactivate. The UpdateExpression needs to do the final deactivate, as it knows via its cached value if it has an activate to clear.

PW
Comment 18 Paul Webster CLA 2012-11-13 14:00:26 EST
.
Comment 19 Sebastien Dubois CLA 2012-11-13 14:09:03 EST
(In reply to comment #15)
> When the UpdateExpression is first created, it goes from null to FALSE, and
> then from FALSE to true.  The transition from null to FALSE shouldn't
> deactivate a context, as it has never been activated.
> 
> http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/
> ?h=R4_2_maintenance&id=2fc58f83f01d492b66cfbdb08ab67ba4da64505d
> 
> Brian, could you also test to make sure it works in your scenarios.
> 
> Sebastien, it should show up in this week's M build, M20121114-1200 from
> http://download.eclipse.org/eclipse/downloads/  if you could test it in your
> scenario when it becomes available.
> 
> PW

Sure I will try it out as ASAP.

/Sebas
Comment 20 Sebastien Dubois CLA 2012-11-26 17:25:28 EST
   I tested the new code in M20121121-1200 and it seems the solution is partly working.

  Basically all Key Bindings that are using default contextIds seem to work fine.  However, I also have bindings that use a context I defined myself (which has org.eclipse.ui.contexts.window as parent) and these ones do not seem to be activated and do not appear anywhere.

See included plugin.xml file for our plugin setup
Comment 21 Sebastien Dubois CLA 2012-11-26 17:25:58 EST
Created attachment 223984 [details]
plugin.xml file
Comment 22 Sebastien Dubois CLA 2012-11-26 17:36:45 EST
(In reply to comment #20)
>    I tested the new code in M20121121-1200 and it seems the solution is
> partly working.
> 
>   Basically all Key Bindings that are using default contextIds seem to work
> fine.  However, I also have bindings that use a context I defined myself
> (which has org.eclipse.ui.contexts.window as parent) and these ones do not
> seem to be activated and do not appear anywhere.
> 
> See included plugin.xml file for our plugin setup

Actually I just re-read the whole thread (it's been a long time), and it seems that we get the opposite effect as the original problem i.e. my custom keys bindings, the ones that are defined with my custom context, now do not appear anywhere, even when they should.  Funny thing is that I did some tests on the released E4.2.1 and the problem does not seem to appear there.  So this could be another issue.
Comment 23 Paul Webster CLA 2012-12-10 14:45:27 EST
*** Bug 396128 has been marked as a duplicate of this bug. ***
Comment 24 Paul Webster CLA 2013-01-17 13:13:22 EST
in M20130116-1800
PW
Comment 25 Heiko Böttger CLA 2013-05-28 12:03:16 EDT
I just tried 4.3RC2, most of the problems I have seen in 4.2 are solved now, however it looks like there is still something wrong. We use the keybinding "ALT+PageUp" which is also assign to "Next Sub-Tab". This works in 3.8 but not in 4.3.
Comment 26 Paul Webster CLA 2013-05-28 12:06:22 EDT
Please open a new bug with the key that's not working and your usecase.  Thanks.

PW