Accessing a composite using E4 - eclipse

In my RCP application, I have a 'Part' which has 2 composites(leftComposite & rightComposite which are tied to parentComposite). Once the user clicks on the menu, i'm trying to access one of the composites(through handler/command) and make it invisible.
How do I access the composite, which belong to a specific Part?

You can get the current MPart by injecting it in the handler. From the MPart you get you class for the part using MPart.getObject(). To actually deal with the Composites in the part you will have to write code in your class to remember the composites and do what you want.
So the handler would look something like:
#Execute
void execute(#Named(IServiceConstants.ACTIVE_PART) MPart part)
{
MyClass myClass = (MyClass)part.getObject();
// Call code in `MyClass` to do what you want
}

Related

Eclipse plugin development - e4 part with input: instantiate input

Eclipse 4 does not have any notion of an editor, only parts. So how do we receive the file for our "editor" parts? I'm talking about an e4 equivalent of the IEditorPart.init method, and the IEditorInput it receives.
I've stumbled upon this example by Tom Schindl. He is able to inject the input in the part constructor. For the input object to be available for injection, it has to be instantiated in the IEclipseContext somehow. This article refers to Schindl's example, and leads me to consider the following approach: intercept "Open file" commands (if they exist) from the Eclipse platform, create an input instance for the "editor" part and put it in the context (IEcpliseContext.set(class, value)), and open the part with the EPartService.
So the question is: is this the right approach to creating an e4 "editor"? And is it possible to implement?
It is easier to put the input data in the part's transient data since it is tricky to get the data injected at the right point.
For something that behaves like an editor you will probably use a Part Descriptor so that you can create multiple parts from the single descriptor.
You would create the part using something like:
#Inject
EPartService partService;
// Create from part descriptor
MPart part = partService.createPart("part descriptor id");
// Set input in transient data
part.getTransientData().put("inputKey", inputData);
// Add to part stack
MPartStack partStack = ... stack you want to use
partStack.getChildren().add(part);
// Show
partService.showPart(part, PartState.ACTIVATE);
In your part code you get the transient data by injecting the MPart. For example in the constructur:
#Inject
public MyClass(MPart myPart)
{
Object input = part.getTransientData().get("inputKey");
....
}

DI and inheritance

Another question appeared during my migration from an E3 application to a pure E4.
I got a Structure using inheritance as in the following pic.
There I have an invocation sequence going from the AbstractRootEditor to the FormRootEditor to the SashCompositeSubView to the TableSubView.
There I want to use my EMenuService, but it is null due to it can´t be injected.
The AbstractRootEditor is the only class connected to the Application Model (as a MPart created out of an MPartDescriptor).
I´d like to inject the EMenuService anyway in the AbstractSubView, otherwise I would´ve the need to carry the Service through all of my classes. But I don´t have an IEclipseContext there, due to my AbstractSubView is not connected with Application Model (Do I ?).
I there any chance to get the service injected in the AvstractSubView?
EDIT:
I noticed that injecting this in my AbstractSubView isn´t possible (?), so I´m trying to get it into my TableSubView.
After gregs comment i want to show some code:
in the AbstractRootEditor:
#PostConstruct
public final void createPartControl(Composite parent, #Active MPart mPart) {
...
ContextInjectionFactory.make(TableSubView.class, mPart.getContext());
First I got an Exception, saying that my TableSubView.class got an invalid constructor, so now the Constructor there is:
public TableSubView() {
this.tableInputController=null;
}
as well as my Field-Injection:
#Inject EMenuService eMenuService
This is kind of not working, eMenuService is still null
If you create your objects using ContextInjectionFactory they will be injected. Use:
MyClass myClass = ContextInjectionFactory.make(MyClass.class, context);
where context is an IEclipseContext (so you have to do this for every class starting from one that is injected by Eclipse).
There is also a seconds version of ContextInjectionFactory.make which lets you provide two contexts the second one being a temporary context which can contain additional values.

Eclipse 4 RCP - how to change what is showed in specific area?

I have splitted my application into two main areas.
Part(A)
PartStashContainer(B)
The content of A should be set based on what user wants.
So basically i can have 1..N classes which could be used in Class URI of Part in application model.
I don't know if i should replace the whole Part(A) with new dynamically created Part(C) which has content i want, or i should somehow to modify the existing Part (call setContributionURI, or setObject methods on Part object?).
It does make more sense to me to modify the existing Part, because it is defined in Application model and therefore already describing the location where the content should be.
Possible solutions:
Modify the Part object so it "reload" its content based on new setup (But how? Can setContributionURI or setObject methods help?)
Remove the old Part and add dynamically on same place in Application model the new Part (using EModelService and EPartService).
other solution??
If you want to reuse the Part then do something like:
MPart part = find or inject your part
MyClass myClass = (MyClass)part.getObject();
... call a method of MyClass to change the contents
MyClass is the class you specify for the object in the application model. You should add a method to that to let you change the contents.
Don't try to call setObject, this is really only for use by Eclipse. I don't think setContributionURI would do anything after the part is created (but I am not sure).
If you want to use different classes for the different data then you really should use different Parts.

In GWT, How to use custom widget tag in an .ui.xml file with and without parameters for the tag in the same file

I am creating a custom widget, say "CustomWid" in UiBinder.
And in CustomWid.java file I am writing two constructors
one with zero args like
CustomWid(){....}
another with some args like
CustomWid(String a,String b){......}
So,Now I am using my custom widget in another .ui.xml file,in that .ui.xml file
it is working fine when we give
<my:CustomWid/> alone,
and also fine when we give like
<my:CustomWid a="srt1" b="str2"/> alone
But "MY PROBLEM" is whenever I am trying to give both the tags in the one .ui.xml as
<my:CustomWid/>
<my:CustomWid a="str1" b="str2"/>
Now it is throwing error when i am using both types of tags in a single .ui.xml
I mean How to use my custom widget tag like a prdefined tag?
I am using #uiConstructor, but it showing error
Please developers... I need answer as early as possible
UiBinder will only ever use a single constructor for a given widget: either its zero-arg constructor, or a #UiConstructor (I'm surprised that you say it works when using either one or the other call but not both: one should fail in every case, and one should succeed in every case; if you haven't annotated a constructor with #UiConstructor, then <my:CustomWid/> should always work and <my:CustomWid a="str1" b="str2"/> should always fail)
There are two solutions here:
use setters for the a and b attributes (void setA(String a) and void setB(String b))), and possibly check later (say, in onLoad or onAttach) that you have either none or both of A and B, but not one without the other (if that's your rule).
use #UiField(provided = true) when you need to use the other constructor (if you choose to have UiBinder use the zero-arg constructor –i.e. no #UiConstructor–, then that means you'll have to move the a="str1" b="str2" from the XML to the Java code: #UiField(provided = true) CustomWid myCustomWid = new CustomWid("str1", "str2")).
The first option has my preference.
It Will not show any errors...'
#UiConstructor
public Component(String displayText,String heading)
{
initWidget(uiBinder.createAndBindUi(this));
this.displayText.setText(displayText);
this.heading.setText(heading);
}`
now use another constructor with default parameters also it will work
public Component()
{
initWidget(uiBinder.createAndBindUi(this));
}
now if you add with xml parameters component and without parameters also works in the same page.

GWT Reflection loading Form

I have a circumstance where I have to create a lot of forms for an application, the forms are all located in the same package. They are named like: A11111.java, A11112.java, etc.
When the user clicks in the NavigationPane, I wish to load the form into a TabItem and display the form. The issue is I need to dynamically generate the name of the form by appending the form name to the location, such as String formName = "com.foo.appName.client.forms" + e.getData("formCode"); something like that, where e is the event of the user click.
I have looked at several Reflection methods, but you cannot pass a derived string to them. How best to do this? Several posts mention using generators, but I get lost trying to sort their logic, and none have to do with displaying forms.
Note, I am not passing any variables to the forms, or calling any methods in the form java files, also the forms are created using uibinding.
Thanks in advance
if you're aiming at lazy-loading classes via the class-loader, like you would when using the command design pattern, note that it can't be done within a GWT application, as the frameworks JRE emulation only provides a subset of types and/or methods available in the JRE, so most of the reflection API - like forName() - will not be available.
rather than lazy-loading classes, think in terms of lazy-rendering widgets to the DOM. this can be achieved by instantiating all your form classes on module load, but only render upon tab-switching. place all your render-related functionality inside onRender() callbacks and you're good to go:
public class FormItem extends TabItem {
#Override
protected void onRender(Element parent, int index) {
super.onRender(parent, index);
// render related functionality
}
}