GWT app UI wont display - java

I have implemented a simple GWT app that uses 1 Place and 1 Activity (which I have implemented as a Presenter which extends an AbstractActivity and which contains a Composite "view" subclass). The 1 and only UI object in the view is a GWT-Bootstrap NavBar that I want presented at the very top of my "home page".
I'm running the app locally from inside Eclipse and am not getting any compiler or runtime errors. When I go to the URL that the Development Mode console points me to, I get a slight pause in the browser (I assume this is the browser "downloading" the JavaScript) and then I see a blank white screen (instead of my NavBar). The window title is correct (I set this in the module's HTML page) and when I view source I see the same HTML source, so I know that the app's JavaScript is getting to the browser properly. It's just not rendering the NavBar.
I have sprinkled System.out.println() statements throughout onModuleLoad(), my default ActivityManager, ActivityMapper, PlaceHistoryMapper, presenter and view Composite, and all these sysout statements print in the dev console; telling me that I have wired everything together correctly, and that at runtime when the PlaceHistoryHandler#handleCurrentHistory method is called (from inside onModuleLoad), I should be seeing my NavBar.
The only possibilities I can think of are:
I have configured gwt-bootstrap incorrectly; or
I'm not using UiBinder correctly
Something else is wrong with how I am using Activities and Places, or perhaps how I am attaching the UI to RootLayoutPanel inside onModuleLoad().
As for gwt-bootstrap:
I placed the JAR on my project's classpath (I know this because when I include a new UiField of type NavBar inside my widget/view, I don't get any compiler errors)
I added <inherits name="com.github.gwtbootstrap.Bootstrap"/> to my GWT module XML
So if there's anything else I have to configure, please let me know!
As for the UiBinder stuff, here's my widget/view:
public class WebRootDisplay extends BaseDisplay {
private static WebRootDisplayUiBinder uiBinder = GWT
.create(WebRootDisplayUiBinder.class);
interface WebRootDisplayUiBinder extends UiBinder<Widget, WebRootDisplay> {
}
#UiField
Navbar navBar;
public WebRootDisplay(EventBus eventBus) {
super(eventBus);
System.out.println("I get this printing to the console at runtime.");
initWidget(uiBinder.createAndBindUi(this));
System.out.println("...and this too!");
}
}
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:b="urn:import:com.github.gwtbootstrap.client.ui">
<g:HTMLPanel>
<b:Navbar ui:field="navBar">
<b:Nav>
<b:NavLink href="http://www.google.com">
Home
</b:NavLink>
</b:Nav>
</b:Navbar>
</g:HTMLPanel>
</ui:UiBinder>
One thing I noticed is that I've got my NavBar inside an HTMLPanel in the UiBinder XML. I did this because I used the Google-Eclipse plugin to generate a new UiBinder for me (which autogenerated both the Composite (which I then modified to extend BaseDisplay, which itself extends Composite) as well as the UiBinder snippet. I figured GWT wants me to put all the UI fields inside this HTMLPanel...(?)
If I'm missing anything here please let me know. I'm not instantiating the NavBar field because I believe that's what createAndBindUi does for me.
If both my gwt-bootstrap config and my use of UiBinder looks correct, then something else is obviously wrong and I will have to post more code. I just wanted to hold off on that initially before these first two items were ruled out. Thanks in advance!
Update
Here is onModuleLoad:
public void onModuleLoad() {
// Some homegrown DI stuff. I have verified that the injector works properly.
ApplicationScope appScope = new ApplicationScope();
setInjector(new ApplicationInjector(appScope,
InjectorProvider.newMasterProvider()));
// Add the sole composite child to the RootLayoutPanel.
// I have verified that injectWebRootDisplay returns a fully configured
// WebRootDisplay instance.
RootLayoutPanel.get().add(injector.injectWebRootDisplay());
historyHandler.register(placeController, eventBus, defaultPlace);
historyHandler.handleCurrentHistory();
}

Could you paste the onModuleLoad() part of your code please?
If you don't got any Exception and error message, I think you should check that you add the view properly to the RootPanel, or when you run the app you should check that the view is there in a div in the HTML and just unvisible or something similar.
The UiBinder part looks fine in a first look.
EDIT:
This onModuleLoad() doesn't said too much to me, but you could try something.
I always use the RootLayoutPanel.get() method in the following way:
RootLayoutPanel.get("someDivId").add(injector.injectWebRootDisplay());
So I always add a div or table to the placeholder HTML with a id, so you can refer to that div when you get the RootPanel. I'm not confident about this is necessary, but I saw this at the first time, and it's working properly.
If you have question or problem, please let me know. :)

Well, I've tried a local example looking exactly like yours code, and I think that problem is not in UI binder. The code you provided so far, is correct, so it most likely that the error is somewhere else.
The biggest suspect is the BaseDisplay class. As far as I can see, this class is not from GWT or gwt-bootstrap. You can really quickly check it, by changing WebRootDisplay class, so it extends classic GWT Composite class instead of BaseDisplay (and disabling all mvp stuff for while). If it works, you have a proof that the problem is caused by 'BaseDisplay'
Since I don't have the full code, I can only assume that WebRootDisplay is used also for displaying the views, and most likely the error is that when view is added to that class, previously added widget (in your case it is a NavBar which you add in constructor of WebRootDisplay) is removed. Most likely the problem should be in methods setWidget and initWidget

In my experience with GWT Activities and Places, a common culprit of a blank white page is failing to register the Place's Tokenizer with the PlaceHistoryMapper as so:
/**
* PlaceHistoryMapper interface is used to attach all places which the
* PlaceHistoryHandler should be aware of. This is done via the #WithTokenizers
* annotation or by extending PlaceHistoryMapperWithFactory and creating a
* separate TokenizerFactory.
*/
#WithTokenizers({
MyPlace.Tokenizer.class,
SomeOtherPlace.Tokenizer.class})
public interface AppPlaceHistoryMapper extends PlaceHistoryMapper {}
See https://developers.google.com/web-toolkit/doc/latest/DevGuideMvpActivitiesAndPlaces#PlaceHistoryMapper
Another cause for a white page (particularly when using RootLayoutPanel.get() with a single place is failing to map the place correctly in the ActivityMapper:
/**
* AppActivityMapper associates each Place with its corresponding
* {#link Activity}
*
* #param clientFactory
* Factory to be passed to activities
*/
public class AppActivityMapper implements ActivityMapper {
private ClientFactory clientFactory;
public AppActivityMapper(ClientFactory clientFactory) {
super();
this.clientFactory = clientFactory;
}
#Override
public Activity getActivity(Place place) {
if (place instanceof MyPlace)
return new MyActivity((MyPlace) place, clientFactory);
else if (place instanceof SomeOtherPlace)
return new SomeOtherActivity((SomeOtherPlace) place, clientFactory);
return null; // If your return null with single place bound to RootLayoutPanel
// you may get a blank white page
}
}
See https://developers.google.com/web-toolkit/doc/latest/DevGuideMvpActivitiesAndPlaces#ActivityMapper
Without a more complete code sample it is impossible to determine exactly what is happening, but the two causes outlined above are common oversights which may help anyone who comes across this thread.

Instead of System.println use GWT.log messages. Then open the Javascript console (of Firebug or Chrome) and see where your code ends up. GWT.log will print out in the browser console, so you can see what the compiled JS code does.
Also, if you compile with the Pretty mode, you'll see the generated Javascript code in the browser and be able to step through and see what is being called (or not).

Related

GWT Initialize ClientBundle With Multiple CssResources

I'm working on updating some legacy code to GWT 2 and I'm running into some odd behaviour. I have a custom interface that extends ClientBundle as per the gwt docs. Within that bundle I define several CssResources to point to the various .css documents for my module. The problem comes when I go to actually initialize my module. I have some code in the initializer that gets the static reference to each CssResource and calls ensureInjected(). The problem is, only the first call actually does anything. Any subsequent calls seem to be getting ignored and the css styles are not getting added to the application. What do I need to do to work with multiple css documents for a single module?
CssBundle.java
public interface CssBundle extends ClientBundle {
public static final CssBundle INSTANCE = (CssBundle) GWT.create(CssBundle.class);
/* CSS */
#Source("mypath/public/Client.css")
public ClientCss mainCSS();
#Source("mypath/resources/css/mini/ext-all.css")
public ExtAllCss extAllCSS();
}
ClientCss.java
public interface ClientCss extends CssResource {
String applicationTitle();
String branding();
String bugReportDirections();
#ClassName("Caption")
String caption();
}
ExtAllCss.java
public interface ExtAllCss extends CssResource {
#ClassName("close-icon")
String closeIcon();
#ClassName("close-over")
String closeOver();
#ClassName("col-move-bottom")
String colMoveBottom();
}
MyModule.java
public class MyModule extends Composite
{
public void initialize()
{
//this css shows up in the client
CssBundle.INSTANCE.mainCSS().ensureInjected();
//this does nothing
CssBundle.INSTANCE.extAllCSS().ensureInjected();
}
}
That code looks exactly right, but might not function the way you expect - instead of each ensureInjected() causing a new <style> block to be created, instead they just enqueue the styles that they need to be made available, and at the end of the current event loop a single <style> is added with all of the various collected styles. This limits the number of times that the document potentially needs to be restyled, and also helps reduce the number of style tags (old IE had a bug where there was a max number of tags possible).
To confirm this, check the entire contents of the <style> tag, you should see that both css files are appended there, one after the other.

Use Errai Ui with GWT

I'd really like to use Errai UI(3.2.4) in my GWT (2.8) application. I already have one setup with an EntryPoint implementation and an onModuleLoad. I have restGWT setup and interacting with my server (which uses Jersey).
All of the documentation I find assumes that you are building a full-on Errai project, starting from scratch using the forge addon thing. I'm not. I just want to use the templating stuff and data-binding. I'm working with a barebones setup and I can't even make a label show in my app.
I have this GWT entry point:
public class App implements EntryPoint
{
#Inject
private ApplicationContainer applicationContainer;
public void onModuleLoad()
{
RootPanel.get("root").add(applicationContainer);
}
}
And the ApplicationContainer:
#Templated
public class ApplicationContainer extends Composite
{
#DataField
private Element applicationContainer = DOM.createDiv();
#PostConstruct
public void init()
{
GWT.log("Initializing");
}
}
And it's accompanying template:
<div id="applicationContainer" data-field="applicationContainer">
Application Container
</div>
I should see "Application Container" in the browser, but I get this error in the browser console:
ComplexPanel.java:96 Uncaught TypeError: Cannot read property 'removeFromParent_0_g$' of undefined
The widget and the template are named the same and in the same package. My widget is created just like the documentation shows: http://erraiframework.org/getting-started/index.html#ErraiUIPage
Can someone tell me what I'm missing here? Examples for this are very minimal, and they all assume a complete Errai project. Do I still need an #EntryPoint? Do I need #PostConstruct? Is Errai even designed to work like this?
Thanks for any help.
Yes, the #EntryPoint annotation is important and I'm not sure you'll be able to mix up part of this framework with some other approach. It doesn't mean you need to use all the modules, but you should rather follow the Errai's guidelines if about the part you use.
Please see example entry point here:
https://github.com/errai/errai/blob/3.2.4.Final/errai-demos/errai-jpa-demo-todo-list/src/main/java/org/jboss/errai/demo/todo/client/local/ClientEntryPoint.java
You'll find also more examples from the path .../3.2.4.Final/errai-demos/
Above is about Errai 3.x.
Please also note that Errai 4.x brings some changes if it is just about the Errai UI. It's nicely described here:
http://errai-blog.blogspot.com/2016/04/errai-400beta1-released.html
Now your #Templated bean do not need to extend Composite. The root element of the template is accessible as a #DataField etc.
Hope you'll find it helpful. Good luck!
The answer to your questions is here: https://github.com/errai/errai-tutorial
You basically need to migrate your app to use Maven so you get the dependencies right first, then use the POM in this project and snap it in your project.
Then you can include a Bootstrap file to add a #EntryPoint class however this is not necessary you can just add a Page in the client path e.g.:
com.mycompany.app.client
-->MyPage.html
-->MyPage.java
Where the java file here contains the default page, i.e.
#Dependent
#Templated
#Page(role = DefaultPage.class)
public class MyPage extends Composite{}

Understanding GWT onModuleLoad

Behold, my first GWT app's EntryPoint impl:
public class MyModule implements EntryPoint {
private SimplePanel mainPanel = new SimplePanel();
#Override
public void onModuleLoad() {
// Extract all root-level dependencies from the injector.
// Using Gin here.
EventBus eventBus = injector.getEventBus();
PlaceController placeController = injector.getPlaceController();
SignInEventListener signInEventListener = injector.getSignInEventListener();
PlaceHistoryMapper placeHistoryMapper = injector.getPlaceHistoryMapper();
// Start the activity manager.
activityManager = new ActivityManager(signInEventListener, eventBus);
activityManager.setDisplay(mainPanel);
// Start the place history mapper.
placeHistoryHandler = new PlaceHistoryHandler(placeHistoryMapper);
placeHistoryHandler.register(placeController, eventBus, startingPlace);
// Add the main panel to the RootPanel.
RootPanel.get().add(mainPanel);
// Navigate to the place represented by the current URL, otherwise the startingPlace.
placeHistoryHandler.handleCurrentHistory();
}
}
Several questions:
My call to the placeHistoryHandler's register(...) method is showing up as being deprecated. Why is it deprecated and what should it be (as of GWT 2.5.1)?
Is there one RootPanel per module/EntryPoint or is there only one RootPanel per GWT app (regardless of how many modules you have)?
What is the connection/relation between the mainPanel (above) that itself has been added to the RootPanel, and the AcceptsOneWidget that gets passed into each AbstractActivity#start method?
Look here: GWT deprecated: PlaceHistoryHandler.register?
The RootPanel is most likely the <body> element. So there is exactly one.
In most cases you will add one AcceptsOneWidget to the RootPanel. Your Activity has to create its view and set it into the AcceptsOneWidget passed to the start()
Take a look at the Activity and Places section of gwtproject.org
1) See Christian Kuetbach answer
2) In your GWT app you should have a MyModule.html file. This file has been define as the welcome file in your web.xml file. Inside this file you will see that is included the javascript version of your application MyModule.nocache.js (after gwt compilation). The RootPanel as said by Christian is the of your html page. Be careful you can use RootLayoutPanel or RootPanel depending if you want to use Layout Panels or not.
3) When using Activities and Places, the Activity Manager is given a widget container. Inside this widget container the framework will put the view of the new activity when changing place. That is the meaning of
activityManager.setDisplay(mainPanel);
Your are saying that when you go from one place to another, the activity view that corresponds to that place should be put inside mainPanel.

Eclipse: How to customize painting of markers on VerticalRuler

I am developing an Eclipse plug-in that shows custom multi-line markers in Eclipse's own AbstractTextEditor.
Here is what I have so far:
a custom marker with the super type "org.eclipse.core.resources.textmarker"
an annotationType (org.eclipse.ui.editors.annotationTypes)
a markerAnnotationSpecification (org.eclipse.ui.editors.markerAnnotationSpecification)
This is all working well, my markers show up in the editor. But I need to customize the way they are drawn on the VerticalRuler, so they do not only show up as an icon, but as a vertical line spanning the affected source lines.
I know, that this can be done with Annotations by implementing IAnnotationPresentation and overwriting paint().
But how can I do this for markers?
Edit: Here is a screenshot of what I am trying to achieve:
I solved this by contributing a RulerColumn (extension point org.eclipse.ui.workbench.texteditor.rulerColumns) and configuring markerAnnotationSpecification to not include verticalRulerPreferenceKey and verticalRulerPreferenceValue (so it will not be shown on the default AnnotationRulerColumn).
In case someone also finds the documentation on how to best implement IContributedRulerColumn a bit sparse: it seems the way to go is to subclass AbstractContributedRulerColumn and have the methods delegate to a subclass of AbstractRulerColumn.
For example:
public class MyRulerColumn extends AbstractContributedRulerColumn {
private IVerticalRulerColumn delegate = new AbstractRulerColumn() { … }
public void setModel(IAnnotationModel model) {
delegate.setModel(model);
}
…
}
Customizing the appearance is then as easy as overwriting one of the paint… methods in the delegate.

Unexpected behavior overriding getWorkbenchErrorHandler in Eclipse RCP

I think I've discovered a kind of Schrödinger's cat problem in my code. The body of a function is never executed if I change one line within the body of that same function; but if I leave that line alone, the function executes. Somehow the program knows ahead of time what the body is, and decides not to call it...
I'm working on an Eclipse RCP application in Java, and have need to use their Error Handling System. According to the page linked,
There are two ways for adding handlers to the handling flow.
using extension point org.eclipse.ui.statusHandlers
by the workbench advisor and its method {#link WorkbenchAdvisor#getWorkbenchErrorHandler()}.
So I've gone into my ApplicationWorkbenchAdvisor class, and overridden the getWorkbenchErrorHandler method:
#Override
public synchronized AbstractStatusHandler getWorkbenchErrorHandler()
{
System.out.println("IT LIVES!");
if (myErrorHandler == null)
{
AbstractStatusHandler delegate = super.getWorkbenchErrorHandler();
MyStatusHandler otherThing = new MyStatusHandler(delegate);
myErrorHandler = otherThing;
}
return myErrorHandler;
}
The MyStatusHandler is meant to act as a wrapper for the delegate handler. I've re-named the class for anonymity. As it is, above, this function is never called. The println never happens, and even in debug mode with breakpoints, they never trigger. Now the wierd part: If I change the line that assigns the myErrorHandler to
myErrorHandler = delegate;
then the function is called; multiple times, in fact!
This problem has me and two java-savvy coworkers stumped, so I'm hoping the good people of SO can help us!
As it turned out, my problem was that the MyErrorHandler class was defined in a different plugin, which presumably wasn't fully loaded yet. That doesn't seem to add up entirely, but once I moved the class definition of my error handler into the same plugin that was calling it during startup, the problems went away.

Categories