Eclipse RCP :- If a view contains huge selection like 4000 objects then applications takes time to show context menus - eclipse

We have built a large scale application over eclipse rcp framework. This issue we are facing across the application if large number are objects are selected say 4000 or 5000 objects. In this case, following actions takes time and UI goes in Not Responding state.
1.Select and Right Click Context menu display
2. Keeping selection, change the view and come back to earlier view.
3. Keeping selection, change the application(like excel, word) and come back to view.
My analysis says, the eclipse rcp takes time to evaluate the menu contributions and handlers for the current selected objects. We are also using Property Testers nested inside Iterate expression which I think is taking time to evaluate. Pain is it does the evaluation every time I switch the view and does not cache the result.
I need your opinion:
Has anyone else encountered this issue before? Is there any good way to handle large selection in handlers, menu contributions which will improve the performance.
Thanks in advanced.
~Prasad

It might be that the main problem are your property testers, because those are evaluated each time something changes visually in your app: new shell (like menu, dialog, wizard etc.) is opened or some panel is expanded/collapsed or you switch perspective or view/editor or you go switch application.
May be as a first step you could try to disable those (or make them dummy and do nothing/or constant action) to see if it affects performance of the application. If it does, then you might think about redesigning your application and replace property testers with, for example combination of org.eclipse.ui.AbstractSourceProvider and org.eclipse.ui.contexts.IContextService.
I am not sure, of course, about your real use cases, but here is some idea:
Source providers can also be used within plugin.xml as a variable.
Then you can register a bunch of contexts (I am not sure, of course, about real use cases, just suggesting here), which can be programmatically activated under some conditions:
final IContextService contextManager = (IContextService) activeWorkbenchWindow.getService(IContextService.class);
contextManager.activateContext("your context id");
Another step would be to register context activation listeners:
final IContextService contextManager = (IContextService) activeWorkbenchWindow.getService(IContextService.class);
contextManager.addContextManagerListener(new IContextManagerListener() {
#Override
public void contextManagerChanged(ContextManagerEvent contextManagerEvent) {
if (!contextManagerEvent.isActiveContextsChanged()) {
return;
}
[process context changes: possibly notify source providers about context changes]
}
});
Make your SourceProvider listen to context changes and refresh state, when something has been actually changed:
#Override
public void contextActivated() {
fireSourceChanged(getSourcePriority(), refreshState());
}
If it is not the case or not possible in you application, then, may be, some other workaround would be to introduce caching in source provider or improve your algorithm performance, by, for example, making some long running operations on parallel with multiple Thread. If you are using Java 8 this should be fairly easy.
Of course there is always a case, that SWT is slow by itself to redraw all the widgets - in this case you may be should look into using alternatives to standard SWT widgets with better performance. For example, using Nattable instead of default SWT/JFace viewers.
I hope this could give you some ideas.

Related

How to pass a View to my ViewModel so an I*Service can use that View to do something

https://github.com/brianchance/MvvmCross-UserInteraction is a very nice plugin for showing cross platform Alerts!
But for this question, can we assume it can not use a UIAlertView (or some other top level MessageBox type call on other platforms) but needs to show a Message within a given subsection of the screen (i.e. on IPhone you would need to supply a UIView to the plugin which it will use to show the message within).
So, how would you set this up so the ViewModel knows what View to use as its display container?
As a specific example, if I wanted an Error Service, as so -
public interface IErrorPFService
{
void Show();
void Hide();
void SetErrors(List<Error> errors);
}
and I create a platform specific implementation for it.
If I inject this into my ViewModel so it can control Error Show/Hide/Set how do I tell it the UIView (or equivalent) that I want my Errors to show within?
Can I just expose the IErrorPFService field as a public property and do -
MyViewModel.ErrorPFService = new ErrorPFService(View);
in my ViewDidLoad ...
Or is this coupled incorrectly vs Mvvm Practice?
I would expect the ViewModel to subscribe itself to the ErrorService.
When receiving a message it would expose it in a collection(?) and the View would bind to that collection.
This way the View is unknown to the service and the ViewModel has the chance to influence the View contrary to your solution.
It would help if you could give an example for the scenario you are describing.
Sometimes, the way you visually want to display something might not be the best way, so if it's possible for you, you might find a different and simpler way, which spares you from having to find a solution regarding what you are describing.
Generally, I always do the best I can to avoid the idea of having to actually pass a 'view' or an abstraction of it, from the view-model to view. Also, cross-platform wise, things can work very different in terms of UI interaction. You can find yourself in a situation when things are complicated just because UI works differently than what you expected.
But let's try find another perspective:
At any given point, the view knows what data \ feature it's displaying. So when you are calling from the view-model an user interaction action (by a service, property change, event, etc) the view should 'expect' it.
For example, the platform specific user interaction implementation is able to get the currently displayed top-view and interact it in a platform specific manner or based a relationship. In your example, the message-box can be displayed in a specific sub-view of the top level view.
In advanced scenarios, I guess you could try to create a cross-platform approach for this, but you should try to put in balance all the abstraction you want to create just for that. Think about doing this as a plan ... Z. If possible. Again, giving an example might help.

GWT event handlers blocking UI

I'm new to GWT. I creating a MVP based project (as described here) that uses a number of custom events. There are several widgets (10+) that listen for some global events and perform some action (including writing to the DOM) in the event handlers.
What I'm finding is that the UI blocks and doesn't update until each and every one of the handlers for the one event finishes processing. This is causing the UI to perform slowly on page load and for any other events that cause the widget to update.
I created a similar project in plain JavaScript/jQuery and this was not an issue with that project. In fact, the UI was blazing fast. What am I doing wrong here? The documentation states that GWT is very performant, so I have to conclude that I'm just doing it wrong.
One example, I have a drop down that selects a date preset (like Yesterday, or Last Week). When this happens I set the selected preset in the model like so:
public void setDateRange(DatePreset dateRange) {
this.dateRange = dateRange;
eventBus.fireEvent(new DateChangedEvent(dateRange));
}
Each of the widgets has access to the same eventbus and registers to handler DateChanged events. Each of the widgets needs to do a fair amount of logic and processing (including making an ajax call) to then update itself with correct data.
#Override
public void onDateChanged(DateChangedEvent event) {
DatePreset dateRange = event.getDate();
… additional processing and logic
… ajax call
}
I've determined after some basic profiling that each widget requires about 100-150ms to finish processing (which means there's a UI delay of over one to two seconds). When I say blocking, I mean the dropdown where I selected the date preset doesn't even close (and I see the spinny wheel) until everything finishes.
What can I do to make this run faster (and without UI blocking)? I am open to any ideas. Thanks!
Measuring the speed of the project in developer mode can be a reason for this extreme slowness.
You can check out the real speed of the application if you deploy it to an appserver or if you delete the &gwt.codesvr=127.0.0.1:9997 part from the end of the url in devmode.

GWT MVP - maintaining multiple displays that are separate of one another

I have a GWT App and I am using GWT MVP with Places / Activities.
My application layout is something like
MENU | CONTENT
The Menu and the Content displays will change dynamically and one changes separately from the other. What I mean by this is that when the Content display changes I do not want to have to update the Menu display and vice versa. Both displays need to be able to respond to PlaceChangeEvents and update themselves when these occur. The problem is that each display should only update in response to certain PlaceChangeEvents, ignoring PlaceChangeEvents that are directed at the other display. However this does not work using the 'standard' GWT MVP pattern because even when each display has it's own ActivityManager they will automatically pick up ALL PlaceChangeEvents because there is a single PlaceController listening on a single EventBus. The only way I can see to do this is by having two EventBus's and two PlaceControllers - one for the Menu and one for the Content. So my question is whether this is a good solution or is there a simpler/better way that I am missing? One problem with this solution is that the PlaceHistoryHandler can only be registered with one of the EventBus's.
Place changes are actually controlled by ActivityMappers. They get a Place and return the corresponding Activity. This is where you control how Places are mapped to Activities:
You need to create two ActivityMappers (MenuActivityMapper, ContentActivityMapper) and then instantiate two ActivityManagers each with it's own ActivityMappers. Then for each ActivityManager you call setDisplay(AcceptsOneWidget display) where for each you pass in an area (display) where it will show it's content.
For menu you will probably only use one Activity, since it's available in all Places. So MenuActivityMapper.getActivity() will always return the same instance of the MenuActivity. To enable MenuActivity to still adapt it's look based on place changes, MenuActivity should listen to PlaceChangeEvents.

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.

Where to store "global" data in Eclipse RCP Application?

I'm a beginner with Eclipse RCP and I'm trying to build an application for myself to give it a go. I'm confused about how one actually goes about handling model objects. None of the examples I can find deal with the problem I'm having, so I suspect I'm going about it the wrong way.
Say I need to initialise the application with a class that holds authenticated user info. I used my WorkbenchWindowAdvisor (wrong place?) to perform some initialisation (e.g. authentication) to decide what view to show. Once that's done, a view is shown. Now, that view also needs access to the user info I had earlier retrieved/produced.
The question is, how is that view supposed to get that data? The view is wired up in the plugin.xml. I don't see any way I can give the data to the view. So I assume the view has to retrieve it somehow. But what's the proper place for it to retrieve it from? I thought of putting static variables in the IApplication implementation, but that felt wrong. Any advice or pointers much appreciated. Thanks.
The problem you are facing here is in my opinion not RCP related. Its more an architectural problem. Your view is wired with business logicand!
The solution can be done by two (common) design-patterns:
Model-View-Controler (MVC)
Model-View-Presenter (MVP)
You can find plenty information about this in the web. I am going to point a possible solution for your particular problem using MVP.
You will need to create several projects. One is of course an RCP plugin, lets call it rcp.view. Now you create another one, which doesnt make UI contributions (only org.eclipse.core.runtime to start with) and call it rcp.presenter. To simplify things, this plugin will also be the model for now.
Next steps:
Add the rcp.presenter to the
dependencies of rcp.view (its
important that the presenter has no
reference to the view)
Export all packages that you are
going to create in the rcp.presenter
so they are visible
In rcp.presenter create an interface
IPerspective that has some methods
like (showLogiDialog(), showAdministratorViews(User user), showStandardViews(User user))
Create a class PerspectivePresenter that takes IPerspective in the constructor and saves it in an attribute
In rcp.view go to your Perspective, implement your interface IPerspective, and in the constructor create a new reference presenter = new PerspectivePresenter(this)
call presenter.load() and implenent
this in the presenter maybe like this
code:
public void load()
{
User user = view.showLoginDialog(); // returns a user with the provided name/pw
user.login(); // login to system/database
if(user.isAdministrator())
view.showAdministratorViews(user);
else
view.showStandardViews(user);
}
As you can see, the view just creates a reference to the presenter, which is responsible for all the business logic, and the presenter tells the view what to display. So in your Perspective you implement those interface functions and in each one you can set up your Perspective in a different way.
For each View it goes in the same way, you will need a presenter for the view which performs operations and tells the view (using the interface) what to display and passing down the final data. The view doesnt care about the logic. This is also very usefull when using JFace-Databindings (then only bound data is passed to the view).
For example, the WorkbenchWindowAdisor will just create everything that is needed in the application. Other views, perspectives, then can enable/disable menus and so on depending on the data they got (like when isAdministrator you might want to enable an special adminMenu).
I know this is quite a heavy approach, but the Eclipse RCP is designed for big (as the name says rich) applications. So you should spend some time in the right architecture. My first RCP app was like you described...I never knew where to store things and how to handle all the references. At my work I learned about MVP (and I am still learning). It takes a while to understand the concept but its worth it.
You might want to look at my second post at this question to get another idea on how you could structure your plugins.