Eclipse plugin: How to change a JFace Tree model out of a command - eclipse

I have created a plugin with a JFace Tree similar to this tutorial: tutorial
And I also have defined a menu entry with a command. The handler of the command should change the Model of the tree and update it. But I have no idea how I can get the right tree view (TreeViewer / ViewPart) and how I can access the model out of the command handler. Can someone help?

Solution 1 - Use your own API
You can inject die active MPart into your Handler and then use part.getObject() to get your contribution class. you can then access your own API to get the Model and the TreeViewer.
#Execute
public void executeHandler(#Named(IServiceConstants.ACTIVE_PART) MPart part) {
MyPart myPart = (MyPart)part.getObject();
MyModel myModel = myPart.getMyModel();
TreeViewer viewer = myPart.getMyTreeViewer();
}
Solution 2 - Use DI
When you initialize your TreeViewer, put it into the IEclipseContext of the Part. You can then have the TreeViewer injected into your Handler.
public class MyPart {
#PostConstruct
void postConstruct(Composite parent, IEclipseContext context) {
TreeViewer viewer = new TreeViewer(parent);
context.set(TreeViewer.class, viewer);
}
}
public class MyHandler {
#Execute
public void executeHandler(TreeViewer viewer) {
}
}
You can do the same thing with the model of course. If there is only one instance of the model (if MyModel is a singleton) you can put it in the context of the application rather that that of the part. A good place to do this would be in an AddOn (or in the LifeCycleHandler).
Alternativly you can define the MyModel class to be #Creatable #Singleton, so it will be created by DI on demand. This is handy, when all the stuff your MyModel needs is in the context already.
My favorite Solution in situations like this is to create a ModelService as an OSGi-Service. OSGi Services are always available through the IEclipseContext.
For more info on DI check out this tutorial by Lars Vogel (Chapters 18, 31, 32):
http://www.vogella.com/articles/EclipseRCP/article.html#dependencyinjectione4
http://www.vogella.com/articles/EclipseRCP/article.html#extentcontext
http://www.vogella.com/articles/EclipseRCP/article.html#ownobjects

Related

Abstract components via org.osgi.service.component annotations

I am migrating from org.apache.felix.scr annotations to org.osgi.service.component annotations. I have a set of Components that inherit from a common abstract class. In the felix case, I can use a #Component annotation with the option componentAbstract=true on the super class, and then use #Reference annotation in the super class. I cannot find how to migrate this to osgi annotations.
Is it possible to use Component annotations in a super class of a Component? And if so, what is then the appropriate way to handle the properties and metatype generation?
So, what I am looking for, is something like this
/* No component definition should be generated for the parent, as it is
abstract and cannot be instantiated */
#Component(property="parent.property=parentValue")
public abstract class Parent {
#Reference
protected Service aService;
protected activate(Map<String,Object> props) {
System.out.println("I have my parent property: "+props.get("parent.property"));
#Override
public abstract void doSomething();
}
/* For this class, the proper Component definition should be generated, also
including the information coming from the annotations in the parent */
#Component(property="child.property=childValue")
public class Child extends Parent {
#Activate
public activate(Map<String,Object> props) {
super.activate(props);
System.out.println("I have my child property: "+props.get("child.property"));
}
public void doSomething() {
aService.doSomething();
}
}
By default BND will not process DS annotations in parent classes. You can change that with -dsannotations-options: inherit but please see http://enroute.osgi.org/faq/ds-inheritance.html why you shouldn't!
2021-02-23 UPDATE: It seems like the page mentioned above is no longer available. I don't know if it was moved elsewhere or simply removed but its content (in Markdown format) is still available on GitHub: https://github.com/osgi/osgi.enroute.site/blob/pre-R7/_faq/ds-inheritance.md

Load a ListBox content dynamically on page load

I'm currently working on a simple GWT project. One of the things I'd like to do is that when the page loads I can dynamically populate the contents of a ListBox based on certain criteria. I actually don't see any handlers for a ListBox to handle the initial render event but I see change handlers.
How does one populate a ListBox contents with data from the server side on pageload with GWT?
Right now I have a class that implements EntryPoint that has a
final ListBox fooList = new ListBox();
I also have a set of beans but I also have a class implementing RemoteService. Since I can't seem to get direct calls to my user defined packages directly in the EntryPoint (which makes sense) how do I populate that ListBox with server side content on initial page load? Right now I'm using a List but I figure if I cant get that to work I can get a DB call to work...
I've tried things in the EntryPoint like:
for (String name : FOOS) {
fooList.addItem(name, name);
}
However FOOS would derive from a server side data and the EntryPoint is supposed to be largerly limited to what can compile to JS! I can't get user defined classes to be recognized on that side as that string is the result of a set of user defined classes.
I also tried creating a method in the class implementing RemoteService that returns a ListBox. This also didn't compile when I tried to call this method. Perhaps I don't fully understand how to call methods in a RemoteService service implementing class.
I've searched a lot and I can't find anything that clearly explains the fundamentals on this. My background is much more ASP.NET and JSPs so perhaps I'm missing something.
I'm using GWT 2.6 is that is relevant.
The usual procedure is the following:
Create a bean class for the data you want to transmit between client and server. Let's call it MyBean.
Place MyBean in the shared package of your project.
This class has to implement either Serializable or IsSerializable, otherwise GWT will complain that it doesn't know how to transmit it.
Create your RemoteService that contains the method you want to use to transmit MyBean from/to the server.
Once you get your data on the client using an AsyncCallback and your RemoteService, fill the ListBox using your beans, e.g. by calling MyBean#getName() or MyBean#toString().
Success!
I based my example on the GWT sample project ( I named it example), just replace the classes and it should work :
public class Example implements EntryPoint {
/**
* Create a remote service proxy to talk to the server-side Greeting
* service.
*/
private final GreetingServiceAsync greetingService = GWT
.create(GreetingService.class);
/**
* This is the entry point method.
*/
public void onModuleLoad() {
final ListBox listBox = new ListBox();
RootPanel.get("sendButtonContainer").add(listBox);
greetingService.getSomeEntries(new AsyncCallback<String[]>() {
#Override
public void onSuccess(String[] result) {
for (int i = 0; i < result.length; i++) {
listBox.addItem(result[i]);
}
}
#Override
public void onFailure(Throwable caught) {
}
});
}
}
This is our EntryPoint, it creates a listbox and calls the server with a AsyncCallback to get some dynamic data. If the call is successfull (onSuccess), the data is written into the listbox.
The GreetingService interface define the synchronous methods, it is implemented in the GreetingServiceImpl class :
#RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
String[] getSomeEntries() ;
}
The asynchronous counterpart is the GreetingServiceAsync interface, we used it before to call the server :
public interface GreetingServiceAsync {
void getSomeEntries(AsyncCallback<String[]> callback) ;
}
The GreetingServiceImpl class is located on the server. Here you could call for example a database:
#SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
#Override
public String[] getSomeEntries() {
String[] entries = { "Entry 1","Entry 2","Entry 3" };
return entries;
}
}
Now if you want to use some Bean/Pojo between the server and client, replace the String[] in each class/interface with the object name, put the class in the shared package and consider that it implements Serializable/IsSerializable.

GWT Request Factory and Editor Framework Exception

When attempting to edit a new (proxy) entity using RequestFactoryEditorDriver.edit() I am getting the following error: "Exception caught: Attempting to edit an EntityProxy previously edited by another RequestContext". I am fairly sure that this is a result of my misunderstanding of the request factory/editor framework architecture. Here is the editor code that I think pertains to this problem:
public class OrgMaintenanceWidget extends Composite implements Editor<IOrgProxy> {
... other fields ...
private IOrgEditorDriver _orgEditorDriver;
interface IOrgEditorDriver extends RequestFactoryEditorDriver<IOrgProxy, OrgMaintenanceWidget> {}
public OrgMaintenanceWidget(final IClientFactory clientFactory) {
... widget initialization ...
_orgEditorDriver = GWT.create(IOrgEditorDriver.class);
_orgEditorDriver.initialize(_clientFactory.getRequestFactory().getEventBus(),
_clientFactory.getRequestFactory(), this);
}
#UiHandler("newButton")
public void onNewButtonClick(final ClickEvent clickEvent) {
_org = _clientFactory.getCache().getOrgCache().newOrg();
_orgEditorDriver.edit(_org, _clientFactory.getRequestFactory().orgRequestContext());
}
...
}
It's the "_orgEditorDriver.edit()" line that causes the exception. The "newOrg()" method is:
public IOrgProxy newOrg() {
return _clientFactory.getRequestFactory().orgRequestContext().create(IOrgProxy.class);
}
The RequestFactory is simply:
public interface IRequestFactory extends RequestFactory {
IOrgRequestContext orgRequestContext();
}
I am sure that I'm missing something fundamental about editing a new entity. When I edit an existing entity everything is fine ... the UI components are populated automatically, and flushing the editor back to the entity works very nicely. Here's the code that initiates editing for an existing entity:
#UiHandler("newButton")
public void onNewButtonClick(final ClickEvent clickEvent) {
_org = _clientFactory.getCache().getOrgCache().newOrg();
_orgEditorDriver.edit(_org, _clientFactory.getRequestFactory().orgRequestContext());
}
Any help would be greatly appreciated, and I'll try to publish any lessons learned.
This code:
_clientFactory.getRequestFactory().orgRequestContext().create(IOrgProxy.class);
Means:
Create new orgRequestContext()
Create new IOrgProxy using this context
Edit new IOrgProxy using this context, because as docs say: "Returns a new mutable proxy that this request can carry to the server, perhaps to be persisted.", it means that the proxy is edited by this request.
This code:
_orgEditorDriver.edit(_org, _clientFactory.getRequestFactory().orgRequestContext());
Means:
Again, create new orgRequestContext() (because each invocation of getRequestFactory().orgRequestContext() provides new instance of orgRequestContext()
"Start driving the Editor and its sub-editors with data." as docs say. But as a part of it, use passed orgRequestContext() to edit passed IOrgProxy instance, so that the proxy is editable.
Because the proxy was already edited while created by other RequestContext, you get the exception, because there is fundamental rule in RequestFactory, that proxy can be edited only by one RequestContext.
See also this thread.
I think you can't create an object with one RequestContext and then edit it with another one.
So you can solve this in two ways:
Persist the created object with the RequestContext you used when you created the object. The save method should return the persisted object and this persisted object can be passed to the editor with a fresh new RequestContext
Somewhere save the RequestContext you used for creating the object and pass it to the edit function of your Driver
Solution two could look something like this:
#UiHandler("newButton")
public void onNewButtonClick(final ClickEvent clickEvent) {
IOrgRequestContext ctx = _clientFactory.getRequestFactory().orgRequestContext();
_org = ctx.create(IOrgProxy.class);
_orgEditorDriver.edit(_org,ctx );
}

Binding a bean property to a TextField in GXT 3.0

I am working on a ExtGWT 3.0 (beta) application.
I have a simple Java bean containing one property:
public class MyBean {
private String content;
// getter and setter here...
}
I want to bind the property to a TextField.
I have created an interface:
interface MyBeanProperties extends PropertyAccess<MyBean> {
ValueProvider<MyBean, String> content();
}
But what's next? How do I tell the TextField to bind to that particular property of a particular MyBean object?
PropertyAccess is used to generically refer to an objects properties, often for data widgets that use a Store like the grid or charts. For binding a form to a bean, check out GWT's editor framework at http://code.google.com/webtoolkit/doc/latest/DevGuideUiEditors.html. There are some examples for this with GXT at http://www.sencha.com/examples/#ExamplePlace:basicbinding%28uibinder%29
Roughly, you'll build a form widget that wraps all the properties you need, and make an editor driver for that editor and its bean:
public class MyBeanEditor implements Editor<MyBean> {
// do any kind of widget setup you like, just make sure to have methods/fields
// package protected or higher that extends Editor (Field extends Editor)
TextField content;
}
//... declare the driver
interface Driver extends SimpleBeanEditorDriver<MyBean, MyBeanEditor> {}
//... use the driver to bind a form to a bean
Driver driver = GWT.create(Driver.class);
driver.initialize(myBeanEditorInstance);
driver.edit(myBean);
//... when save is clicked (or a timer, or whatever), get the value and do
// something with it
MyBean model = driver.flush();

GWT - binding activityMapper with GIN not working

I´m trying to do my first steps with GWT/GIN.
I´ve downloaded the hellomvp example from google and followed this tutorial to get started with gin.
My problem is about this line in the configure-method of the HelloGinModule-class:
bind(ActivityMapper.class).to(AppActivityMapper.class).in(Singleton.class);
In my point of view it should bind my class "AppActivityMapper" as the active ActityManager.
But in fact the class constructor (or any method of the class) is never called, so the fired events are not caught.
The class AppActivityMapper looks like this:
public class AppActivityMapper implements ActivityMapper {
Provider<HelloActivity> helloActivityProvider;
Provider<GoodbyeActivity> goodbyeActivityProvider;
#Inject
public AppActivityMapper(final Provider<HelloActivity> helloActivityProvider, final Provider<GoodbyeActivity> goodbyeActivityProvider) {
this.helloActivityProvider = helloActivityProvider;
this.goodbyeActivityProvider = goodbyeActivityProvider;
}
#Override
public Activity getActivity(Place place) {
if (place instanceof HelloPlace) {
return helloActivityProvider.get();
} else if (place instanceof GoodbyePlace) {
return goodbyeActivityProvider.get();
}
return null;
}
}
In my example this code from my View-Class is called after clicking on a link:
presenter.goTo(new GoodbyePlace(name));
The event is fired to the event bus. But nothing happens.
Thanks in advance
You have defined an activity mapper somewhere in you GIN. But activity mapper have to be used in activity manager. Where do you create activity manager which will use your AppActivityMapper?
UPDATE:
The most logical thing is to keep activity manager out of the gin. E.g. in your ginjector you will have a method:
interface MyInjector extends Ginjector {
... //other methods
ActivityMapper getActivityMapper();
}
Than , when you create ginjector instance, you can create a manager and put correct activity mapper into it. for example:
MyInjector injector = GWT.create(MyInjector.class);
ActivityManager manager = new ActivityManager(injector.getActivityMapper(), injector.getEventBus());
If you have multiple managers and mappers, may be it will be better to extend ActivityManager class (so you can inject stuff into its constructor). Another solution is to use #Provides to initialize ActivityManager.