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.
Related
My application is designed to load up an XML file and display an error(s) (if any).
The problem I have is how to display both (the XML and Errors) on screen without coupling (my application does currently work).
My application currently looks like (no laughing or comments about me going on a Photoshop\UI course please):
The brown colour is a different view called XmlView.
The red box is where I want errors to be displayed.
So, the user clicks File->Open, selects the file and the .XML content is displayed in my XmlView (brown) and my error messages are shown in red. This works but, I have a horrible feeling my design is poor as I have totally coupled my MainWindow and XmlView.
The way I have this working is, when the user selects a valid XML file (from File->Open), I create an instance of my XmlView and bind it to my Views property of my MainWindow class. My XmlView takes 1 parameter which is the MainWindow type.
So, within my XmlView, to update my ErrorList, I would write code similar to
_mainWindow.ErrorList.Add(//newError)
But this now means my XmlView knows about my MainWindow which I thought was undesired.
So, finally, my question! Is my design poor or is this OK?
You should consider using an MVVM framework if you are doing MVVM.
It would depend on whose responsibility it was to load the XML, but I would suggest the XmlViewModel, not the MainViewModel.
In that case the MainViewModel should just be a conductor of other view models. In your first case, it would instantiate the XmlViewModel, passing the file path and set it as its current view.
The XmlViewModel would be responsible for loading and validating the XML. It too could have a child view model which displays the validation errors. It should load the XML asynchronously, with some form of busy notification.
The MainViewModel is likely to want to conduct many view models, so if you were going to use a framework such as Caliburn.Micro, this would be a conductor type.
I am developing a Prism application where I need to load some data in the model in the background after the application has loaded. I have a separate view which is hidden which would show this data via a view model. I dont want to increase the application load time and neither do I want to increase the view load time. The only solution I could think of is to raise a Shell Loaded event and let the view model or model subscribe to it.
Is this a good approach or is there a better approach?
Also, I am not sure whether I should raise the Shell Loaded event in the Run of the Bootstrapper or in the Shell ViewModel. How do I link a routed command (for ex: Loaded) to an ICommand
I try to avoid to handle these kinds of events in the bootstrapper. So attaching the Loaded event of the shell view to the shell view model is a good way to go. The only reason to actually raise this event in the bootstrapper is if you need the StartupEventArgs (which I sometimes do).
There are quite a few ways of handling the loaded event.
100% MVVM use an attached property that passes the event straight to an ICommand or method. Ex: how to call a window's Loaded event in WPF MVVM?
Just handle the Loaded event it in the code behind and call the Loaded method / Command in the VM from there. This a simple and easy solution to get started.
To reduce loading time, you should try to avoid putting too much work on the UI thread. You may want to investigate the TPL or a nice framework called ReactiveUI which provides a very convient mechanism to load things asynchronously.
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.
I have a plugin which contains class A that brings up a view defined in class B via the following line of code:
(VideoLogView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView("Videolog.VideoLogView");
What I need to do in the createPartControl() method of the view (class B object) is access a method in the class A object.
How can this be done?
Thanks.
Look like you are facing the classic issue of "how do I pass arguments to my view" ?
This thread illustrates it best:
I was facing the same problem at the beggining of my RCP project. I was getting weird about the fact that there was no way to pass an argument to a view as the viewed model.
Why? Because (emphasis mine):
You are on an opened, pluggable platform.
You contribute to existing developments, others should be able to contribute to yours.
Therefore you will not "pass" arguments to a view, this would lock the whole thing into a non-opened design.
Instead, your view will ask the platform (or will listen to the platform) to determine which information to manage.
Other views (from other plugins that don't yet exist) might also want to manage the same information on the same event.
What you should do then is to ask the workbench for the current selection. I guess your view is opening on a double click action or simple selection so the object you want to manage in your view will be currently selected.
This is how you could retrieve the workbench selection from your view :
ISelection s = this.getSite().getWorkbenchWindow().getSelectionService().getSelection();
where "this" is a ViewPart.
Then you have to make your initial view (the one initiating the view creation from a given event like DoubleClick) a selection provider. A JFace viewer is a selection provider, so you can use it if you're using jface, or you can implement the ISelectionProvider interface when you're using custom SWT controls (that was my case).
The article "Eclipse Workbench: Using the Selection Service" can also give you some pointers.
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.