Minimal JFace application making use of FilteredTree - eclipse-rcp

In my RCP application I have a JFace dialog making use of FilteredTree, which depends on the running PlatformUI.
Now I want to add a main method to the dialog class, so I can start this dialog for testing purpose quickly. But I get an exception from within the FilteredTree ctor:
Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/e4/core/di/InjectionException
at org.eclipse.ui.PlatformUI.isWorkbenchRunning(PlatformUI.java:114)
at org.eclipse.ui.plugin.AbstractUIPlugin.imageDescriptorFromPlugin(AbstractUIPlugin.java:669)
at org.eclipse.ui.dialogs.FilteredTree.<clinit>(FilteredTree.java:196)
at my.MyDialog.createDialogArea(MyDialog.java:361)
Is there a simple solution?

You can't just add a main method. Eclipse has a huge amount of initialization that must be done before plug-in code can be run and this requires that the normal Eclipse main method is used.

Related

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.

Difference between syncExec() and asyncExec() of Display class

I'm working on a plugin project in which I'm using Eclipse background processing.
What's the difference between the syncExec() and asyncExec() methods of the Display class? In which situations are they applicable? Any example could be helpful.
from Q: Why do I get the error "org.eclipse.swt.SWTException: Invalid thread access"?
To allow background threads to perform operations on objects belonging to the UI-thread, the methods syncExec(Runnable runnable) and asyncExec(Runnable runnable) of Display are used. These are the only methods in SWT that can be called from any thread. They allow a runnable to be executed by the UI-thread, either synchronously, causing the background thread to wait for the runnable to finish, or asynchronously allowing the background thread to continue execution without waiting for the result. A runnable that is executed using syncExec() most closely matches the equivalent direct call to the UI operation because a Java method call always waits for the result before proceeding, just like syncExec().
Adding to Tom Seidel's answer, here are examples of situations where you might want to use one or the other:
Use asyncExec when you want to update something in the UI without caring about the results. For example updating a label or a progress bar.
Use syncExec where the code following that method call needs to be sure that the UI is in a consistent state, or needs some data from the UI. For example getting some data from a user dialog. Or you update a widget and before doing anything else (e.g. another UI update) you want to know that the widget update has completed.
SWT implements single threaded UI model. In this model, only the UI-thread can invoke UI operations. If you try and access an SWT object from outside the UI-thread, you get the exception "org.eclipse.swt.SWTException: Invalid thread access". So to allow other threads to perform operations on objects belonging to the UI-thread, SWT provides syncExec and asyncExec methods.
This link may help you with an example

Toolbar items dynamically

I need to create dynamically buttons in main toolbar. I found a solution, but I can create just one button (dynamic contribution item - class extending ContributionItem). But I need to create more than one button, but I cannot find the solution.
I'm fighting with task to create plugin, which parses a XML file containing structure of menu and toolbars. We've already done this plugin for Visual Studio. Its quite easy in principle, but I found swiftly, that not for Eclipse. There is one small but critical otherness. Plugins are implemented declaratively in Eclipse. The file plugin.xml is the gist of plugin's infrastructure, Java code is just ancillary.
The customer wants to refresh the menu and toolbar whenever the selected project is changed. Eclipse lacks several features needed to get the task done. Main menu and main toolbar are cteated at Eclipse's start-up and then they can be hardly rebuilt.
In the most cases the conditions defined at enabledWhen/visibleWhen elements are sufficient to filter contributions according to the context (active part, selected object, whatever else).
If you need to have more freedom, please try E4 ToolControl that allows you to implement your own UI elements:
#PostConstruct
public void createControls(Composite parent) {
//your custom code here
}
More details here https://www.vogella.com/tutorials/EclipseRCP/article.html#toolcontrols
From my understanding you want to have different buttons on the main toolbar depending on the selection of the project explorer (eg. 1 project is java project, the other is javascript etc.). First you will have to contribute to the main toolbar. I think there are some tutorial available so google will help.
The main steps are:
1. create a command (org.eclipse.ui.commmands)
2. create a handler (org.eclipse.ui.handlers) with the previously declared command id
3. contribute to the main toolbar (org.eclipse.ui.menus) with menucontribution and commandId with the following locationURI: toolbar:org.eclipse.ui.main.toolbar?after=misc
showing/hiding, enabling/disabling a menu item/button also can be done declaratively or "mixed". Declaratively means eg. using enabledWhen/visibleWhen...
Mixed means using property tester (org.eclipse.core.expressions.propertyTester). With this you can define your "enablement logic" in Java code.
In Eclipse e4 the UI is generated from a, EMF based, model. The Application.e4xmi serves as a base for that model. Contributions to the model can be done via fragments, which are again XML, or via processors. Processors are written in Java and use e4 services, like the part service, to modify the model at runtime.
I think you want to write a processor that parses your custom XML and modifies the eclipse e4 model accordingly.

GWT MVP Presenter Unable to Update View Listbox Component

I am writing a GWT MVP application using the gwt-platform library (very nice once you get used to it). My issue occurs when my presenter attempts to update the contents of a Listbox. The problem occurs on line 66 of the below file:
https://github.com/dartmanx/mapmaker2/blob/master/src/main/java/org/jason/mapmaker/client/presenter/MapmakerStackPanelPresenter2.java
I am sure that the application is calling the onSuccess() method (a breakpoint in the debugger works), and that the result is populated.
One thing I've noticed is that the associated view, MapmakerStackPanelViewImpl2.java, seems to be initialized twice. I find myself wondering if I'm trying to update a control on that view that is not attached to the actual user interface. That file is here:
https://github.com/dartmanx/mapmaker2/blob/master/src/main/java/org/jason/mapmaker/client/view/MapmakerStackPanelView2.java
Any help would be appreciated.
The problem was that there were two copies of the view floating around. I used Gin to inject the view into the constructor of the presenter, and problem went away.

How do you update a JFace Viewer from inside a Job?

Caveat: I'm still struggling with proper MVC in Eclipse plugin development, so if you see anything here that is most likely causing me more pain that I should be enduring, please let me know.
The question:
I have a View with a JFace Tree Viewer and a Table (not a table viewer... that will be changed down the road).
I have an action that is initialized with a reference to the View (this seems terrible to me, but I don't yet know how to do it the right way). When the action is run -- via a button on the view -- the action:
1) gets the Tree Viewer from the View
2) gets the underlying model
3) creates a Job
a) inside the job, loops over the model and does various things to it, including adding additional children into the model
b) uses a function exposed in the view that "clears" the Table in the view
4) adds a JobChangeListener that implements "done()".
a) inside the done() method, it expands the treeviewer via this code:
loadMethodsJob.addJobChangeListener(new JobChangeAdapter(){
public void done(IJobChangeEvent event){
view.enableActions();
view.getTestsViewer().expandAll();
}
});
Inside the Job, whenever I attempt to access the elements in the viewer, I get Invalid Thread Access errors. I believe I understand why I get them when running inside the job, but I'm not sure how to work around them correctly if I can't interact with the widgets in the job change listener. I can get it to work if I wrap every interaction with the widgets in a getDisplay().synchExec(....), but I seem to remember reading that this is not preferable.
I feel like I'm on the cusp of a big leap in understanding with Eclipse SWT, so I appreciate any guidance in getting there.
Any UI component in SWT can be accessed only by a UI thread.
Since the done method of the job runs in a separate non-UI thread, the invalid thread access is fired.
By wrapping every interaction in a Display.syncExec , you are making sure that it runs in the display thread (The UI thread).
There shouldn't be any problem with the above approach.