How to get workbench/view in Eclipse (e4)? - eclipse

I'm developing an Eclipse plugin in which I need to access a view.
I've found this way to get the workbench, but I guess it only worked in Eclipse 3.x and I am using Eclipse 4 so it doesn't work:
IWorkbench workbench = PlatformUI.getWorkbench();
IViewPart part = workbench.getActiveWorkbenchWindow().getActivePage()
.findView("id_of_the_view");
I then found this way:
#Inject
private static EPartService epartService;
MPart mPart = epartService.findPart("id_of_the_view");
MyViewClass part = (MyViewClass)mPart.getObject();
which throws a NullPointerException. I've made sure the view is open.
What am I missing?
Edit:
I've also tried this, as found here (german)
#Inject
private static EPartService epartService;
#Inject
private static MApplication application;
#Inject
private static EModelService modelService;
...
MUIElement element = modelService.find("id_of_the_view", application);
if(element instanceof MPart) {
MPart part = (MPart) element;
...
}
but I also get a NPE in the .find()-line.

You're right. In E4 you should use injection.
To avoid NPEs, you can get the reference to the IEclipseContext in part constructor.
public class MyPart {
private IEclipseContext context;
#Inject
public MyPart(IEclipseContext context) {
this.context = context;
}
}
Assuming you have your part class defined in a plugin, and that the class is referenced as Part in an E4 Application, you can get a reference to the Part instance using its id
Somewhere in your code you use the id to get an instance of your part
// somewhere in your code ..
// (where you can access the context instance)
MPart myPart = getPart(context, "com.example.myPart");
The easy way is to use EPartService.findPart() , as follows:
/** with this method I can get reference to the part */
public static MPart getPart(IEclipseContext context, String partId) {
EPartService partService = context.get(EPartService.class);
MPart part = partService.findPart(partId);
return part;
}
Beware of static methods. Context Objects and static members are not friends !!
For multiple matches, or advanced searches, you can use EPartService.findElements(), as follows :
public static List<MPart> getParts(IEclipseContext context,
MWindow workbenchWindow, String partId) {
EPartService partService = context.get(EPartService.class);
EModelService modelService = context.get(EModelService.class);
List<MPart> parts =
modelService.findElements(workbenchWindow, partId, MPart.class,
null, EModelService.OUTSIDE_PERSPECTIVE
| EModelService.IN_ANY_PERSPECTIVE
| EModelService.IN_SHARED_AREA);
return parts;
}

Related

Eclipse RCP Inject into instance of IWizard

I am trying to inject some of my Wizard's fields.
I can successfully inject my own OSGi DS using the following helper class:
public class UtilRCP {
public static void inject(Plugin plugin, Object object) {
IEclipseContext serviceContext = EclipseContextFactory.getServiceContext(plugin.getBundle().getBundleContext());
ContextInjectionFactory.inject(object, serviceContext);
}
}
Other Services from the RCP ecosystem such as PartService or MApplication fail to be injected (null / no actual value was found for the argument "MApplication").
Here is the code
public class MyWizard extends MyAbstractWizard implements IImportWizard {
private MyWizardPage page;
#Inject
private EPartService partService;
#Inject
private DatabaseProvider databaseProvider;
#Inject
private MApplication application;
public MyWizard() {
System.err.println("Create");
System.err.println(databaseProvider);
System.err.println(partService);
System.err.println(application);
}
#Override
public void init(IWorkbench workbench, IStructuredSelection selection) {
UtilRCP.inject(Activator.getDefault(), this);
System.err.println("Init");
System.err.println(databaseProvider);
System.err.println(partService);
System.err.println(application);
}
#Override
public void addPages() {
super.addPages();
page = new MyWizardPage();
addPage(page);
}
#Override
public boolean performFinish() {
return true;
}
}
The service context has very limited contents and is not suitable for use like this.
In a 3.x style wizard like this you can get the workbench context from the IWorkbench object using:
#Override
public void init(IWorkbench workbench, IStructuredSelection selection) {
IEclipseContext context = (IEclipseContext)workbench.getService(IEclipseContext.class);
Note that when a dialog is active there is no active 'part' (because a dialog is not a part). This can cause problems with various APIs. In particular the application (workbench) part service will give an exception complaining that there is no active part.
You can get a working part service by explicitly getting the part service for the top level window using:
#Inject
MApplication application;
#Inject
EModelService modelService;
MWindow window = (MWindow)modelService.find("top level window id", application);
EPartService partService = window.getContext().get(EPartService.class);
I believe the top level window id for a 3.x RCP is "IDEWindow".
If its an E4 application, you can find the main window id in your Application.e4xml.

How to inject objects of custom classes (in eclipse e4) into an Handler class (defined for a menu item in Application's XMI file)

I'm new to Eclipse e4 and I am trying to inject an object of my custom class into a Handler class like below :
public class MenuHandler {
#Inject
Test2 user;
#Execute
public void execute(MApplication app, EPartService partService, EModelService modelService) {
System.out.println(user.getUserName()); // DefaultUser
user.setUserName("anotherUser");
System.out.println(user.getUserName()); //anotherUser
}
}
#Creatable
public class Test2 {
private String userName = "DefaultUser";
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
Having this code and If I launch my RCP application, and upon clicking the menu item (defined in the 'Application.e4xmi' file) my handler class ('MenuHandler') is not getting executed. Whereas if I remove the #Inject annotation from the handler class (i.e.., upon removing #Inject Test2 user; ) then the handler class is getting executed without any issues.
I think some problem exists if I have the annotation "#Inject" inside the Handler class.
Any suggestion will be greatly appreciated !
Maybe you should try to create and inject your custom object in the LifeCycleManager of your e4 application.
public class LifeCycleManager {
#PostContextCreate
public void postContextCreate(IEclipseContext context) {
final MCustomContext customContext = PersistenceUtils.load(MCustomContext.class);
context.set(MCustomContext.class, customContext);
}
}
This works fine for me.

How to Inject EPartService

I am developing e4 application. I want to inject EPartService outside the Part and Handler
when i am injecting EPartService then i will get null pointer error
public class DisplayRuntimePart {
#Inject EPartService partService;
private void displayPart(){
MPart part=partService.findPart("com.rcpe4.myproject.part.datapart");
mpart.setVisible(true);
partService.showPart(mpart, PartState.CREATE);
}
}
I am also read this question but till not solve my problem E4 EPartService findPart() throwing java.lang.Null Pointer Exception
Edit
I am inject EPartService in Part class. Class URI in Application.e4xml is bundleclass://com.abc.test/com.abc.test.part.MyPart in this class I am write code as follows.
Class Mypart{
#Inject EPartService prtservice;
#Inject
public MyPart() {
}
#PostConstruct
public void postConstruct(Composite parent) {
parent.setLayout(new FillLayout(SWT.HORIZONTAL));
htmlBrowser = new Browser(parent, SWT.NONE);
}
#PreDestroy
public void preDestroy() {
}
#Focus
public void onFocus() {
}
#Persist
public void save() {
}
public dispalyPart(){
MPart mpart=partService.findPart("com.abc.test.part.datapart"); **Here Getting Null Pointer Exception**
mpart.setVisible(true);
partService.showPart(mpart, PartState.CREATE);
}
}
Eclipse only does direct injection on objects that it 'knows' about - basically objects mentioned in the application model (e4xmi) files or created using something like EPartService.showPart.
If you want to do direct injection on objects that you create then you need to create them using ContextInjectionFactory. For example:
#Inject IEclipseContext context;
...
MyClass myClass = ContextInjectionFactory.make(MyClass.class, context);
you can also do injection on a class created in the normal way with:
ContextInjectionFactory.inject(myClass, context);
(this will not do injection on the constructor).
Note: Since this code is using direct injection you must run it from a class that the Eclipse application model does know about such as a command handler or an MPart.

How to pass additional data to GWT sub-editors?

i have this issue:
I have a PresenterWidget which contains sub-editors.
There are "container" elements which should be editable by this widget. These containers can be assigned to groups. To do so, i would like to fetch a list of all available groups from the server. So the widget is set up like this (i use GWTP):
public class ContainerEditorDialogPresenterWidget extends PresenterWidget<ContainerEditorDialogPresenterWidget.MyView> implements
ContainerEditorDialogUiHandlers {
private final PlaceManager placeManager;
private List<GroupDTO> groupList = new ArrayList<GroupDTO>();
private final DispatchAsync dispatcher;
#Inject
ContainerEditorDialogPresenterWidget(EventBus eventBus,
MyView view, PlaceManager placeManager, DispatchAsync dispatcher) {
super(eventBus, view);
getView().setUiHandlers(this);
this.dispatcher = dispatcher;
fetchGroups();
}
...
public void fetchGroups(){
FetchGroupsAction action = new FetchGroupsAction();
dispatcher.execute(action, new AsyncCallbackImpl<FetchGroupsResult>() {
#Override
public void onSuccess(FetchGroupsResult result) {
groupList = result.getGroupDtos();
eventBus.fireEvent(new GroupListUpdatedEvent(groupList));
}
});
}
So i call fetchGroups in the constructor to get it as early as possible. Since it is an AynchCallback, i get the result back "at some time". I then try to pass the values to the sub-editor with a GroupListUpdatedEvent. In there i have a Editor declared like this:
public class GroupListEditor extends Composite implements
IsEditor<ListEditor<String, GroupItemEditor>> {
private static StringListEditorUiBinder uiBinder = GWT
.create(StringListEditorUiBinder.class);
interface StringListEditorUiBinder extends
UiBinder<Widget, GroupListEditor> {
}
//Gives us access to the event bus.
#Inject private EventBus eventBus;
...
public GroupListEditor() {
initWidget(uiBinder.createAndBindUi(this));
eventBus.addHandler(GroupListUpdatedEvent.TYPE, new GroupListUpdatedEvent.GroupListUpdatedHandler() {
#Override
public void onGroupListUpdatedEvent(GroupListUpdatedEvent event) {
Log.debug("onContainerUpdatedEvent caught");
allGroups = event.getGroupList();
if(allGroups != null) {
for (GroupDTO g : allGroups) {
lbAllGroups.addItem(g.getName(), g.getId().toString());
}
lbAllGroups.setVisibleItemCount(5);
Log.debug("Item list = " + lbAllGroups.getItemCount());
} else {
Log.debug("GROUP LIST is Null!");
}
}
});
}
When i try to register the handler, i get an exception. So i expect the eventBus is not injected properly. What do i miss, how can i use events and the event bus if i am not in a Presenter?
And: Is this the right way at all to populate Editors with "utility" data? I guess Editor should be related directly to the data they care for. But how do i handle this kind of supplemental data?
Thanks :)
Do you use #UiField in your ContainerEditorDialogPresenterWidgetView for your GroupListEditor ?
If so then Dependency Injection won't work because you basically manually create the GroupListEditor which leads to EventBus being NULL.
I would also use Constructor Injection instead of field injection.
GroupListEditor:
#Inject
public GroupListEditor(EventBus eventBus) {
this.eventBus = eventBus;
}
ContainerEditorDialogPresenterWidgetView:
public class ContainerEditorDialogPresenterWidgetView {
#UiField(provided=true)
GroupListEditor groupListEditor;
#Inject
public ContainerEditorDialogPresenterWidgetView(GroupListEditor groupListEditor);
this.groupListEditor = groupListEditor;
initWidget();
}
}
Alternatively you could get an instance of your GroupListEditor via the Ginjector directly.

GWT editor frame work is not working

I have a bean named SignUpBean and it's editor is SignUpBeanEditor and following is its Driver interface.
public interface SignUpDriver extends SimpleBeanEditorDriver<SignUpBean, SignUpEditor>{
}
Following is entry point class
public class Signup implements EntryPoint {
private SignUpDriver signUpDriver;
private SignUpEditor signUpEditor;
private SignUpBean signUpBean;
private VerticalPanel verticalPanel;
private Label signUpLbl;
private Button submitButton;
private Button cancelButton;
private RequestBuilder requestBuilder;
final SignUpConverter signUpConverter=GWT.create(SignUpConverter.class);
public void onModuleLoad() {
signUpLbl = new Label("Sign Up");
signUpDriver = GWT.create(SignUpDriver.class);
signUpBean = new SignUpBean();
signUpEditor = new SignUpEditor();
submitButton = new Button("Submit");
cancelButton = new Button("Cancel");
signUpDriver.initialize(signUpEditor);
signUpDriver.edit(signUpBean);
System.out.println(signUpBean.getUserName());
submitButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
SignUpBean signUpBeanEdited=signUpDriver.flush();
}
}
}
}
I am getting only null value from signUpBeanEdited after giving value in UI. If i am initializing SignUpBean with constructor then also data is not binding to UI. My problem is I cant bind data in GWT UI using editor framework.
The fields( sub editors ) declared in SignUpEditor should be of at least DEFAULT scope. I guess you declared them as private. If so, the Editor Impl classes generated cannot access the fields to bind the data.
Changing scope to at least DEFAULT might solve your problem.