问题
I am trying to develop an eclipse plug-in. I am aware about the basics of this thing.
In a sample plugin template when we click the menu entry (or button with eclipse icon in below image in this case) in testing instance of eclipse, execute method of sampleHandler.java is executed and a pop-up shown in image below appears.
I want to invoke 'execute' method whenever I press some key (lets say backspace) in code editor instead of clicking any menu entry (or button).
SampleHandler.java
public class SampleHandler extends AbstractHandler {
public SampleHandler() {
}
/**
* the command has been executed, so extract extract the needed information
* from the application context.
*/
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
MessageDialog.openInformation(
window.getShell(),
"Sdfsdfsadf",
"Hello, Eclipse world");
return null;
}
}
I tried suggestions given in other posts but I am unable to achieve the desired functionality.
As per my understanding from referenced post in above line, I tried below code -
package eventlisten.handlers;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
/**
* Our sample handler extends AbstractHandler, an IHandler base class.
* @see org.eclipse.core.commands.IHandler
* @see org.eclipse.core.commands.AbstractHandler
*/
public class SampleHandler extends AbstractHandler {
/**
* The constructor.
*/
public SampleHandler() {
}
/**
* the command has been executed, so extract extract the needed information
* from the application context.
*/
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
MessageDialog.openInformation(window.getShell(),"EventListen","Trying event listen");
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IEditorPart editor = page.getActiveEditor();
IEditorInput input = editor.getEditorInput();
IDocument document=(((ITextEditor)editor).getDocumentProvider()).getDocument(IDocument.class);
document.addDocumentListener(new IDocumentListener() //**this is line 45**
{
@Override
public void documentAboutToBeChanged(DocumentEvent event) {
// TODO Auto-generated method stub
System.out.println("Hello");
}
@Override
public void documentChanged(DocumentEvent event) {
// TODO Auto-generated method stub
System.out.println("Hello second");
}
});
return null;
}
}
But after showing the pop-up , it throws the exception -
java.lang.NullPointerException
at eventlisten.handlers.SampleHandler.execute(SampleHandler.java:45)
at org.eclipse.ui.internal.handlers.HandlerProxy.execute(HandlerProxy.java:290)
at org.eclipse.core.commands.Command.executeWithChecks(Command.java:499)
at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:508)
at org.eclipse.ui.internal.handlers.HandlerService.executeCommand(HandlerService.java:169)
at org.eclipse.ui.internal.handlers.SlaveHandlerService.executeCommand(SlaveHandlerService.java:241)
at org.eclipse.ui.menus.CommandContributionItem.handleWidgetSelection(CommandContributionItem.java:829)
at org.eclipse.ui.menus.CommandContributionItem.access$19(CommandContributionItem.java:815)
at org.eclipse.ui.menus.CommandContributionItem$5.handleEvent(CommandContributionItem.java:805)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1276)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3562)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3186)
at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2701)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2665)
at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2499)
at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:679)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:668)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:353)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:180)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:629)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:584)
at org.eclipse.equinox.launcher.Main.run(Main.java:1438)
at org.eclipse.equinox.launcher.Main.main(Main.java:1414)
Can someone guide me through the process? Let me know in case more information is required.
回答1:
Your first problem seems to be that you only interact with the documents when the user presses the button. There are better ways to set this up.
As far as I can tell, you want to either detect when a user modifies a document (probably by typing), any key is typed anywhere, or when the AST of the code is modified. You will probably only find one of the solutions below useful or relevant.
Listening to Document Changes
The solution you attempted is closest to the first one, so I'll start there. I did something like this (in the post you linked, as it turns out). Start by making your plugin extend the org.eclipse.ui.startup extension point, and define a class to override IStartup
That earlyStartup()
will look something like:
@Override
public void earlyStartup() {
IWorkbench wb = PlatformUI.getWorkbench();
wb.addWindowListener(generateWindowListener());
}
We'll listen for windows to open, and when they do,
private IWindowListener generateWindowListener()
{
return new IWindowListener() {
@Override
public void windowOpened(IWorkbenchWindow window) {
IWorkbenchPage activePage = window.getActivePage();
activePage.addPartListener(generateIPartListener2());
}
@Override
public void windowDeactivated(IWorkbenchWindow window) {}
@Override
public void windowClosed(IWorkbenchWindow window) {}
@Override
public void windowActivated(IWorkbenchWindow window) {}
};
}
This part listener is where you should get the EditorPart
, which means you can add the document listener:
private IPartListener2 generateIPartListener2()
{
return new IPartListener2() {
private void checkPart(IWorkbenchPartReference partRef) {
IWorkbenchPart part = partRef.getPart(false);
if (part instanceof IEditorPart)
{
IEditorPart editor = (IEditorPart) part;
IEditorInput input = editor.getEditorInput();
if (editor instanceof ITextEditor && input instanceof FileEditorInput) //double check. Error Editors can also bring up this call
{
IDocument document=(((ITextEditor)editor).getDocumentProvider()).getDocument(input);
document.addDocumentListener(/* your listener from above*/);
}
}
}
@Override
public void partOpened(IWorkbenchPartReference partRef) {
checkPart(partRef);
}
@Override
public void partInputChanged(IWorkbenchPartReference partRef)
{
checkPart(partRef);
}
@Override
public void partVisible(IWorkbenchPartReference partRef){}
@Override
public void partHidden(IWorkbenchPartReference partRef) {}
@Override
public void partDeactivated(IWorkbenchPartReference partRef) {}
@Override
public void partClosed(IWorkbenchPartReference partRef) {}
@Override
public void partBroughtToTop(IWorkbenchPartReference partRef) {}
@Override
public void partActivated(IWorkbenchPartReference partRef) {}
};
}
Listening to just the keypressess
This ends up being simpler to implement, but may be very noisy. We'll be looking at the Display and the Listener, which gets right into the SWT event loop.
You'll want to do the earlyStartup() extension again, and have something like:
@Override
public void earlyStartup() {
Display display = Display.getDefault();
display.setFilter(SWT.KeyUp, new Listener() {
@Override
public void handleEvent(Event event) {
//do stuff here. Be careful, this may cause lag
}
});
}
Listening to Java AST changes The final one has the simplicity of the raw keyup approach, but will probably be as semantically useful as the first one I suggested. We will be listening to the JavaCore directly.
Again, in the earlyStartup method()
JavaCore.addElementChangedListener(new IElementChangedListener() {
@Override
public void elementChanged(ElementChangedEvent event)
{
//do stuff with the event
}
});
Conclusion: With luck, one of these three methods is useful to you. I've had reason to use each in my Eclipse development career -- each is useful in its own way.
I hope this helps.
来源:https://stackoverflow.com/questions/26871970/eclipse-plugin-development-how-to-listen-events-in-eclipse-editor