Eclipse: Converting actions in commands for a specific view - eclipse

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.

Related

How to activate my eclipse plugin when a specific editors opens

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);

Eclipse RAP multi-window/tab

I would like to have a multi-tab/windowed Eclipse RAP application.
I am able to open a second window using
UrlLauncher launcher = RWT.getClient().getService(UrlLauncher.class);
launcher.openURL("/gasf?foo=other_perspective");
Where I use the foo paramter to select the perspetive I want. However using this method will create a speparate http session, thus the various listeners and so on won't communicate with my first window.
I also tried opening a second window/page using
PlatformUI.getWorkbench().getActiveWorkbenchWindow().openPage("other_perspective" , null);
But this merely changes the current window perspective but does not open a second window or tab in my browser.
Has anyone achieved a multi-tab RAP application with working selectionlisteners between the tabs?
Thanks for any help you can provide
EDIT:
THANKS a lot ralfstx, as you pointed out, I can share the listeners or anything using the shared HTTP session, so far so good. Now the next step is to be able to update a tab based on an external event.
To try my idea of refresh from another tab, I did a dummy timer that does something 2 seconds later (i.e. simulate something triggered from another tab) with:
final ServerPushSession pushSession = new ServerPushSession();
pushSession.start();
Display display = Display.getDefault();
NavigationView navigationView = ((NavigationView) window.getActivePage().findView(NavigationView.ID));
timer.schedule(new TimerTask() {
#Override
public void run() {
display.asyncExec(new Runnable() {
public void run() {
navigationView.doSomething();
}
});
}
}, 2000);
This works! The pushSession.start() forces the UI to refresh without any user interaction. So now the action doSomething() is executed on the navigationView as soon as the 2 seconds are reached.
My only remaining concern is how much load this puts on the server, but its a reasonable solution at least. I validated your answer.
EDIT2:
Just to be complete, to make sure not bump in an invalid Thread access error since we are updating a display from another display, in the doSomething() method we must execute actions using display.asyncExec:
Display display = Display.getCurrent();
public void doSomething() {
display.asyncExec(new Runnable() {
public void run() {
treeViewer.refresh();
}
});
}
With the current architecture of RAP, you can't spread workbench windows over different browser tabs. Every new browser starts a new UISession which implies another Display (see Scopes in RAP).
However, the HttpSession should be the same (unless you have cookies turned off), so you could use this as a means of communicating between different browser tabs.

Creating a "live" view in the background

I'd like to define an Eclipse view that is self-contained, but able to respond to selection events as soon as the Workbench app is launched, even if the view is not visible, as long as it appears as one of the "background views" in a folder. In other words, I need a "hook" which is invoked when placeholder for my view is created.
The problem is that when a Workbench app launches, the background views are normally not instantiated. You can of course implement an IPerspectiveFactory to do an initial perspective layout in Eclipse, but the factory is only used when the perspective is initially chosen; after that, on subsequent launches, Eclipse persists mementos that don't involve creating the view.
Is there any way to accomplish this?
I think it would be a good idea to separate the data model that's driving your view from the view UI. This will allow the data model to be continuously updated and the view to be added or removed without having to maintain any kind of state.
You can add the data model as a SelectionService listener in your plugin Activator:
private ISelectionListener listener;
public void start(BundleContext context) throws Exception {
super.start(context);
listener = new ISelectionListener() {
#Override
public void selectionChanged(IWorkbenchPart part,
ISelection selection) {
// Update model
}
};
PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getSelectionService()
.addSelectionListener(listener);
}
public void stop(BundleContext context) throws Exception {
PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getSelectionService().removeSelectionListener(listener);
super.stop(context);
}
When the view is created it can use the data model to populate the UI components and listen to the data model for any live updates.
You'll need to make sure that your plugin is activated when the application is launched. The following question can help with that.
auto-start OSGi service
Edit
The following code can be used to activate your view (calling createPartControl) even if the view is currently hidden. By placing this code in your activator it can start listening to model events as soon as your plugin is activated.
PlatformUI.getWorkbench().addWindowListener(new IWindowListener() {
...
#Override
public void windowActivated(IWorkbenchWindow window) {
IViewReference view = window.getActivePage().findViewReference(
VIEW_ID);
if (view != null) {
view.getPart(true);
}
}
});

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.

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
}