Intercept action for project

Hi,

I wrode a little plugin, that needs to intercept some of actions (run, debug, stop, restart). I implemented this with AnActionListener and in there I checked the actionId. This all worked well. But my logic throws errors if I have more than one project open. So I thought good. I will compare the action events project with my saved instance. This works for one project but not for the other one. I get an error saying "cannot share data context between Swing events".
This makes complete sense because I execute an action in one window, and in the other window my listener tries to excess the data context.

What is the correct way to do something like this?

I could sorround my project check with try...catch but that looks and feels dirty.

10 comments

Hi Manne,

You said 'I compare the action events project with my saved instance' - how you do that? Please also provide a stack trace of the exception you get.

Denis

0

I have a project component. I get the current project as a constructor property. I save this property in a final field in my component. The component also implement AnActionListener.
When I test my plugin with one project opened. Everything is fine. But when I open two projects and then execute an action I get the following error in one of the two plugin components. (there two at that time because of the two opened projects :))

cannot share data context between Swing events; initial event count = 4716; current event count = 4777
java.lang.Throwable
    at com.intellij.openapi.diagnostic.Logger.error(Logger.java:54)
    at com.intellij.ide.impl.DataManagerImpl$MyDataContext.getData(DataManagerImpl.java:342)
    at com.intellij.openapi.actionSystem.DataKey.getData(DataKey.java:75)
    at com.intellij.openapi.actionSystem.AnActionEvent.getData(AnActionEvent.java:139)
    at com.intellij.openapi.actionSystem.AnActionEvent.getProject(AnActionEvent.java:95)
    at de.tslarusso.MyComponent.afterActionPerformed(MyComponent.java:168)
    at com.intellij.openapi.actionSystem.impl.ActionManagerImpl.fireAfterActionPerformed(ActionManagerImpl.java:1065)
    at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(IdeKeyEventDispatcher.java:610)
    at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.d(IdeKeyEventDispatcher.java:464)
    at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.dispatchKeyEvent(IdeKeyEventDispatcher.java:208)
    at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:479)
    at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:333)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

I need to compore the projects, because I want to execute some action only in the corrosponding project. This error only happens for actions that are triggered by key strokes. It works for clicks on action buttons.

Hope those information makes my problem a little bit clearer

0

That's not a good design because ActionManager is an application-level component. That means that when you register an action listener which is a project component itself, that project will be not eligible for gc while the application is alive, i.e. there is a memory leak.

You should declare your AnActionListener as an application-level component/service and encapsulate project-specific logic inside it instead.

Denis

0

I tried that also.
I created a application component, registered this component as an action listener.
But when i tried to access the project I got the same error.

I will tried this solution. Maybe I did something wrong.

0

I`m using an application component as action listener now. The problem still exist though. The error happens only for action triggered by keyboard shortcuts. I think that this is a general problem.
I got no errors when I`m using the

public void beforeActionPerformed( AnAction anAction, DataContext dataContext, AnActionEvent anActionEvent )
method.

What is the alternative to an actionlistener? I read that someone meantioned to subclass a given action and put the new action in that place. How should that work? Is this even possible?
As I wrode in my question, I need to intercept the debug/run configuration actions and stop/rerun actions from the console toolbar.

Thanks so far
0

You can try to listen not for actions but commands instead (see com.intellij.openapi.command.CommandProcessor.addCommandListener()). CommandEvent object given to a CommandListener holds a project reference explicitly.

Denis

0

That was a good idea. But the command name property is null for all the actions/commands
I want to intercept. This way I`m not able to distinguish between the different commands.

0

No good advice then. Will ask our UI guys if they have any suggestion.

Denis

0

Use ApplicationComponent and AnActionListener. Do all your logic in beforeActionPerformed() method, so you won't have troubles with data context sharing. Get proper project from DataContext: PlatformDataKeys.PROJECT.getData(dataContext) or event.getData(PlatformDataKeys.PROJECT)
That's it.

0

Please sign in to leave a comment.