How to activate my eclipse plugin when a specific editors opens - eclipse

My plugin needs to listen to changes (selection and content) of xtext based editors provided by another third-party plugin.
Edit1
The issue is not how to listen to the specific events in general.
Instead the issue is how to trigger the listener registration, since there's no code of my plugin executed (lazy loading) unless it is used by the user through a command for instance.
Edit2
Using org.eclipse.ui.IStartup extension point the issue is that in IStartup.earlyStartup() PlatformUI.getWorkbench().getActiveWorkbenchWindow(); is returning null. It looks like this is too early in the startup phase to register the listeners.

You can use an org.eclipse.ui.IPartListener2 listener to be told about all parts opening, closing, being activated ....
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IPartService partService = window.getPartService();
partService.addPartListener(your listener);
The
public void partOpened(IWorkbenchPartReference partRef)
method of the listener will be called when a part (editor or view) is opened. The partRef.getId() method will give you the id of the part.
Use the org.eclipse.ui.startup extension point to declare that your plugin needs to be started early. This lets you declare a class implementing org.eclipse.ui.IStartup that is called during Eclipse startup.
Note that the startup runs quite early so not everything is set up. Use Display.asyncExec to schedule code to run later:
Display.getDefault().asyncExec(runnable);

Related

How to get/inject EPartService outside part or in LifeCycle Manager or How to control life cycle of e4 RCP app in true sense?

My application consists of many parts and they are defined in application's e4xmi file. I want to hide and show them dynamically. I am using EpartService to do so in handlers, where I can inject it.
But I also want to control the show/hide of parts with something like life cycle manager, where I can not inject EPartService. Is there any way to achieve and fully control RCP application's life cycle?
There seems the exact same question here and void of solution:
https://www.eclipse.org/forums/index.php/t/595958/
I want to implement 'remember me like feature' where part having sign in screen is shown instead of other parts. Also after log out same sign-in part is to be shown. So I need to control life cycle of RCP app. But I cant inject EPartService before anything in Application's e4xmi is initiated.
If you are creating a class from something which is injected (such as the LifeCycle class) you can create your class with injection using ContextInjectionFactory:
#Inject
IEclipseContext context;
MyClass myClass = ContextInjectionFactory.make(MyClass.class, context);
Or if you just pass an IEclipseContext to the class you can get the part service using:
EPartService partService = context.get(EPartService.class);
Note: There is a separate instance of the part service for each part. Depending on what you are doing you may need to make sure you have the service for the active part.
If you are not locked in to using SWT, you could use the e(fx)clipse e4 renderer for JavaFX instead.
e(fx)clipse has more possibilities to control the lifecycle of the application. For example you can return a Boolean from #PostContextCreate to signal whether you want to continue the startup or not. You will not be able to use EPartService here though, but you can roll your own login dialog using dependency injection as greg-449 has described it in his answer.
public class StartupHook {
#PostContextCreate
public Boolean startUp(IEclipseContext context) {
// show your login dialog
LoginManager loginManager = ContextInjectionFactory.make(LoginManager.class, context);
if(!loginManager.askUserToLogin()) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}
(You can also restart the application. Form
more details see http://tomsondev.bestsolution.at/2014/11/03/efxclipse-1-1-new-features-api-to-restart-your-e4-app-on-startup/).

Refresh Eclipse 4 RCP view on wizard perform finish

Rookie question that I'm not having much luck with. In my e4 RCP application, I have a couple of instances where I create an object in a wizard that should then appear in one of my views.
The desired behavior is similar to how the eclipse Package Explorer View updates after a new project is created.
I was thinking I could just grab the view from the partService and run my own update method:
MPart ingredientsView = partService.showPart("com.personal.recipes.part.ingredientsview", PartState.ACTIVATE);
IngredientsView iv = (IngredientsView) ingredientsView.getObject();
iv.updateView();
While this works in other places, when called from a wizard 'partService' is null and the app NPE's out.
So what is the proscribed method of forcing e4 views to update after modifying their contents?
EDIT:
I tried to use the ContextInjectionFactory like #greg-449 showed in his answer, but I'm uncertain where to place it in my code, or how to define the context. I'm launching the wizard from a toolbar button, and placed the following code in my handler:
#Execute
public void execute(Shell shell) {
IEclipseContext context = EclipseContextFactory.create();
IWizard ingredientWizard = ContextInjectionFactory.make(IngredientWizard.class, context);
WizardDialog wizardDialog = new WizardDialog(shell, ingredientWizard);
wizardDialog.open();
}
However, when I tried to get the part service with #Inject EPartService partService; I got an InjectionException saying no error was found.
Once injection is available, using the EventBroker looks like the way to go.
enter code hereThe best way to update a view is to use a model for the content of the view. Your wizard seems to allow editing or creating ingredients. When you perform the finish of your wizard you are probably modifying some ingredient data. The ingredient model should be informed of these changes. If the view uses a content provider that observes this model is will update automatically when the model sees the update (this is the observer pattern).
How this works depends on the nature of your data. You could use the PropertyChange-Support in Java.
To do so let the content provider implement the org.eclipse.jface.util.IPropertyChangeListener interface and fire property change events when the data is changed.
UPDATE
My ContentProvider implements the property change interface. Whenever a property change event is received the viewer is refreshed(asynchronously). All my persistence operations are handled by data managers similar to Fowler's the table data gateway pattern but sometimes for more than one table. The data manager fires the property change event. This way the UI (wizard) does not need to know about persistence
Injection is only done on objects that the application model knows about. So it is not done on Wizards or Dialogs unless you do it 'manually' using ContextInjectionFactory when you create the dialog:
IWizard wizard = ContextInjectionFactory.make(YourWizardClass.class, eclipseContext);
WizardDialog dialog = new WizardDialog(shell, wizard);
This will do injection on your wizard class giving you access to the EPartService.
You could also use the 'event broker' (IEventBroker) to broadcast an event to anything that is interested rather than finding your specific view.

Eclipse 4.2(juno) did not call saveState method of ViewPart when workspace is closing

I have a eclipse-plugin that have two perspectives. There is a view which extends ViewPart in one of the two perspectives. In this view, I overrided saveState method of ViewPart to save my data.
First, I open the prespective that has this view. Then i add some data in the view which should be save in saveState.
Next, I navigate to the other perspective that does not have this view.
Finally, I close the eclipse's workspace.
In eclipse 4.2(juno), saveState method of the view do not have been called. My data lost.
In eclipse 3.6(Helios), saveState method of the view have been called. My date has been persisted.
Does anyone know the reason? How can I insure that the saveState will be called when closing the workspace on all version of eclipse?
Eclipse e4 has no ApplicationWorkbenchAdvisor class and the application model has no property to set this,totally different with Eclipse 3.x.
You can get more from the wiki and vogella tutorial blog.
With joy, this problem persists into 4.4.2.
At its base, the issue is the compatibility layer WorkbenchPart.getViewReferences() only searches the currently active perspective. This behavior is different than the 3.x. The relevant code from the 4.4.2 Eclipse WorkbenchPart is here (notice the call to getCurrentPerspective()).
public IViewReference[] getViewReferences() {
MPerspective perspective = getCurrentPerspective();
if (perspective != null) {
List<MPlaceholder> placeholders = modelService.findElements(window, null,
MPlaceholder.class, null, EModelService.PRESENTATION);
List<IViewReference> visibleReferences = new ArrayList<IViewReference>();
for (ViewReference reference : viewReferences) {
for (MPlaceholder placeholder : placeholders) {
if (reference.getModel() == placeholder.getRef()
&& placeholder.isToBeRendered()) {
// only rendered placeholders are valid view references
visibleReferences.add(reference);
}
}
}
return visibleReferences.toArray(new IViewReference[visibleReferences.size()]);
}
return new IViewReference[0];
}
Therefore, if one has a view open and then changes to a perspective where that view is not shown, the saveState() method will not be called.
We have added an OSGI event listener for the UIEvents.UILifeCycle.appShutdownStarted and made a call to the saveState(). However, it is necessary to obtain the IMemento manually, since it is not present. Example code is in the org.eclipse.ui.internal.ViewReference (http://grepcode.com/file/repository.grepcode.com/java/eclipse.org/4.2.2/org.eclipse.ui/workbench/3.104.0/org/eclipse/ui/internal/ViewReference.java#ViewReference).
One could also add a part close listener with the IPartListener class to potentially persist settings if the user closes the view rather than application shutting down.
We have not found an OSGI event for the part being closed, but there may be one.
This discussion (Eclipse call ViewPart saveState on View close) suggested using IDialogSettings rather the IMemento. This discussion also proposed perhaps adding something into the dispose() method, but it is unclear how many resources are necessarily still available at the point of the dispose() being called.

Eclipse: Converting actions in commands for a specific view

My original RCP was started in 3.x and currently I am running it on Juno with the compatibility layer. I was looking into doing a soft migration so I have started to slowly change my practices. One of the things I am doing is to change my actions into commands.
I have a view (which is like a directory explorer) currently that adds actions to the toolbar and popup menu of the view. These actions call specific methods in the view, for example to go up one directory.
It was easy to do this by action because I just create my action in the View class itself and programmatically add them to the toolbar
IToolBarManager mgr = getViewSite().getActionBars().getToolBarManager();
mgr.add(upDirectory);
mgr.add(refresh);
mgr.add(changeRoot);
and the creation of the actions are called from the createPartControl()
upDirectory = new Action("Go up one directory") {
public void run() {
goUpOneDirectory();
}
};
where goUpOneDirectory() is a method in the view
If I want to convert this to a command, I want to be able to access this method of the view in my handler. So I tried the following,
private void createHandlers()
{
IHandlerService handlerService = (IHandlerService) getSite().getService(IHandlerService.class);
IHandler upDirHandler = new AbstractHandler() {
public Object execute(ExecutionEvent event)
throws ExecutionException {
goUpOneDirectory();
return null;
}
};
handlerService.activateHandler("updir.id", upDirHandler);
}
And createHandlers is called in the createPartControl, and the command is added via the plugin.xml to the toolbar of the view. The problem is that the moment my view is out of focus it disables the buttons in the toolbar for these commands.
I want them to remain enabled at all times. How can I do that?
I know that the isEnabled() returns true all the time so I am not sure why it happens. The activateHanlder is called once in createPartControl so I feel that it should remain active all the time.
Edit: Ok I just saw this ,
IHandlerService from the workbench part site is the part handler
service. Any handlers activated through the part handlers service will
only be active when that part is active. Any listeners added to the
part handler service will be removed when the part is disposed, and
any active handlers will be deactivated (but not disposed).
So how can I get this,
IHandlerService from the workbench is the global handler service. it
provides no special activation scoping or lifecycle.
Sorry, I should have waited a bit longer before asking, I figured it out!
I changed the,
IHandlerService handlerService = (IHandlerService) getSite().getService(IHandlerService.class);
to
IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class);
and it worked.
I will leave the question in case it helps other people.

Change opacity of a TreeItem

I have a server and client using gwt.
In my client page i have a tree item displayed.
I want to do one of the following:
- disable the tree item when a function is called.
- made opaque the entire client page or only the tree item when a function is called.
By made opaque, i want to do the same as occur when i debug my project with eclipse and i stop and i get the following in the client page
GWT Code Server Disconnected
Most likely, you closed GWT Development Mode. Or, you might have lost network connectivity. To fix this, try restarting GWT Development Mode and REFRESH this page.
Please give me some indication on how to do it and if it is possible.
you create a handler for you function call(s) and add the style when the funciton is called. Because GWT works with javascript it changes your appearance during runtime.
item.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
event.getItem().setStyleName("newStyle");
}
});
and in the css you define you style:
newStyle: {
...
your style definition
}