Disclosure panel header widget client bundle,#sprite is not working - gwt

I am having DisclosurePanel, as header content i have HorizontalPanel which is applied style, these styles is having background image, which uses ClientBundle with #sprite.
But issue is the style is not applying for the header widget (Horizontal Panel)
here my code goes
Entry class
public class Test implements EntryPoint {
/**
* This is the entry point method.
*/
public void onModuleLoad() {
TestClientBundle.INSTANCE.testCsss().ensureInjected();
DisclosurePanel dp = new DisclosurePanel();
HorizontalPanel hp = new HorizontalPanel();
dp.setStyleName("blue");
Label l = new Label("testing the DP with IMG-CSS bundle");
hp.add(l);
dp.setHeader(hp);
dp.setContent(new Label("Body"));
RootPanel.get().add(dp);
}
}
ClientBundle interface
public interface TestClientBundle extends ClientBundle {
TestClientBundle INSTANCE = GWT.create(TestClientBundle.class);
#Source("blue.jpg")
public ImageResource blue();
#Source("test.css")
public CssResource testCsss();
}
Css File
#external .blue;
#sprite .blue {
gwt-image: 'blue';
cursor: pointer;
text-decoration: none;
}
Is it known issue in GWT or my code is wrong?

Instead of
dp.setStyleName("gates_playbookimage_blue");
you need to have a way to refer to that css class name - you need a CssResource interface:
public interface MyCssResource extends CssResource {
String gates_playbookimage_blue();
}
Reference this from your clientbundle instead of CssResource:
public interface TestClientBundle extends ClientBundle {
TestClientBundle INSTANCE = GWT.create(TestClientBundle.class);
#Source("playbook_blue.jpg")
public ImageResource playbookBlue();
#Source("test.css")
public MyCssResource testCsss();
}
Now you can do this:
MyCssResource css = TestClientBundle.INSTANCE.testCsss();
css.ensureInjected();
//...
dp.setStyleName(css.gates_playbookimage_blue());
This will let the css compiler rewrite your css as needed, and be sure to pass in the rewritten class name to your widget.

Related

Why am I not able to update my navigation bar (PermanentSlot)?

Short summary:
I try to update a navigation bar after a place change event. To do so I created a GWTP Test*.java that I try to render in a SLOT_NavBar. However, this is not working. In order to see if I did something wrong I just made itself render in my SLOT_AdminToolMainContent slot which is working perfectly fine. The question is why I can render TestView in one slot but not in the other. GWTP is not giving me any clues about what I'm doing wrong here and I can't find anything in the documention that would help me out here.
I'm sure the problem must be either a misunderstanding from my side or something really stupid that I'm doing but I just fail to see the reason why this is not working.
I'm having here a "root" presenter:
AdminToolPresenter.java
public class AdminToolPresenter extends Presenter<AdminToolPresenter.MyView, AdminToolPresenter.MyProxy> {
public interface MyView extends View {
}
#ProxyStandard
#NameToken(AdminNameTokens.adminTool)
#UseGatekeeper(AdminGatekeeper.class)
public interface MyProxy extends ProxyPlace<AdminToolPresenter> {
}
/** */
public static final PermanentSlot<MenuPresenter> SLOT_Menu = new PermanentSlot<>();
/** */
public static final NestedSlot SLOT_AdminToolMainContent = new NestedSlot();
/** */
private MenuPresenter menuPresenter;
#Inject
public AdminToolPresenter(EventBus eventBus, MyView view, MyProxy proxy, MenuPresenter menuPresenter) {
super(eventBus, view, proxy, RevealType.RootLayout);
this.menuPresenter = menuPresenter;
}
#Override
protected void onBind() {
this.setInSlot(SLOT_Menu, this.menuPresenter);
}
#Override
protected void onReveal() {
LOGGER.fine("AdminToolPresenter.onReveal()");
}
}
and its view:
AdminToolView.java
public class AdminToolView extends ViewImpl implements AdminToolPresenter.MyView {
#SuppressWarnings("unused")
private final static Logger LOGGER = Logger.getLogger(AdminToolView.class.getName());
public interface Binder extends UiBinder<Widget, AdminToolView> {
}
#UiField HTMLPanel menuPanel;
#UiField SimplePanel adminMainContent;
#Inject
public AdminToolView(Binder uiBinder) {
this.initWidget(uiBinder.createAndBindUi(this));
this.bindSlot(AdminToolPresenter.SLOT_Menu, this.menuPanel);
this.bindSlot(AdminToolPresenter.SLOT_AdminToolMainContent, this.adminMainContent);
}
}
Everything I'm doing with this is working just fine for example:
TestPresenter.java
public class TestPresenter extends Presenter<TestPresenter.MyView, TestPresenter.MyProxy> implements TestUiHandlers {
private final static Logger LOGGER = Logger.getLogger(TestPresenter.class.getName());
interface MyView extends View , HasUiHandlers<TestUiHandlers> {
}
#NameToken(AdminNameTokens.test)
#ProxyStandard
interface MyProxy extends ProxyPlace<TestPresenter> {
}
#Inject
TestPresenter(EventBus eventBus, MyView view, MyProxy proxy) {
// This is working just fine. The content gets displayed correctly in the SLOT_AdminToolMainContent slot
super(eventBus, view, proxy, AdminToolPresenter.SLOT_AdminToolMainContent);
this.getView().setUiHandlers(this);
}
#Override
public void prepareFromRequest(PlaceRequest request) {
LOGGER.severe("prepareFromRequest");
super.prepareFromRequest(request);
}
}
TestView.java
class TestView extends ViewWithUiHandlers<TestUiHandlers> implements TestPresenter.MyView {
interface Binder extends UiBinder<Widget, TestView> {
}
#UiField SimplePanel main;
#Inject TestView(Binder uiBinder) {
this.initWidget(uiBinder.createAndBindUi(this));
}
}
No problem at all! However, if I try to bind this to another slot:
The issue
#Inject
TestPresenter(EventBus eventBus, MyView view, MyProxy proxy) {
// MenuPresenter.SLOT_NavBar instead of AdminToolPresenter.SLOT_AdminToolMainContent
super(eventBus, view, proxy, MenuPresenter.SLOT_NavBar);
this.getView().setUiHandlers(this);
}
Then it's simply doing nothing! I only changed the slot - so why is this not working? Here is the MenuPresenter and related code:
MenuPresenter.java
public class MenuPresenter extends PresenterWidget<MenuPresenter.MyView> implements MenuUiHandlers {
private final static Logger LOGGER = Logger.getLogger(MenuPresenter.class.getName());
interface MyView extends View, HasUiHandlers<MenuUiHandlers> {
}
/** Slot for the navigation bar. */
public static final NestedSlot SLOT_NavBar = new NestedSlot();
#Inject
MenuPresenter(EventBus eventBus, MyView view) {
super(eventBus, view);
this.getView().setUiHandlers(this);
}
#Override
protected void onReveal() {
LOGGER.severe("onReveal()");
}
}
MenuView.java
class MenuView extends ViewWithUiHandlers<MenuUiHandlers> implements MenuPresenter.MyView {
interface Binder extends UiBinder<Widget, MenuView> {
}
#UiField HTMLPanel navBarPanel;
#UiField MaterialSideNav sideNav;
private PlaceManager placeManager;
#Inject MenuView(Binder uiBinder, PlaceManager placeManager) {
this.initWidget(uiBinder.createAndBindUi(this));
this.bindSlot(MenuPresenter.SLOT_NavBar, this.navBarPanel);
this.placeManager = placeManager;
}
}
MenuView.ui.xml
<!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:m="urn:import:gwt.material.design.client.ui"
xmlns:m.addins="urn:import:gwt.material.design.addins.client.ui">
<ui:with field="tokens" type="com.mz.client.admin.place.AdminNameTokens"/>
<ui:style gss="true">
/* .. */
</ui:style>
<g:HTMLPanel ui:field="main">
<g:HTMLPanel addStyleNames="{style.navbar-wrapper}">
<g:SimplePanel ui:field="navBarPanel" />
</g:HTMLPanel>
<m:MaterialHeader>
<m:MaterialNavBar backgroundColor="white" activates="sideNav" layoutPosition="RELATIVE" addStyleNames="{style.nav-bar}">
<m:MaterialNavSection>
</m:MaterialNavSection>
</m:MaterialNavBar >
<m:MaterialSideNav ui:field="sideNav" m:id="sideNav" type="FIXED" alwaysShowActivator="true" width="280" addStyleNames="{style.side-nav}" >
<m:MaterialLink targetHistoryToken="{tokens.getHome}" iconType="HOME" iconPosition="LEFT" textColor="black" text="Home" />
</m:MaterialSideNav>
</m:MaterialHeader>
</g:HTMLPanel>
</ui:UiBinder>
Please explain to me why this is not working - it is driving me nuts. I'm not getting anything from GWTP like "dude, you're trying to do something strange here". No warning, error or info. Just nothing and I don't see what I do wrong here!
To give you an idea how this looks like: The blue bar is the <g:SimplePanel ui:field="navBarPanel"/> which you see in MenuView:
Did You tried to replace PernamentSlot with SingleSlot? I am not sure that you can update PernamentSlot.
Did You tried to replace PresenterWidget with Presenter in class extension in MenuPresenter class?
MenuView is widget, no place, So it seems that You did not add this view anywhere, so it simply doesn't display it self. Try to put some static content to this view and see is it even reveal itself.
Try in main view add in constructor widget.add(new MenuView());. where widget is initialized(using java or uibinder) view element.
To display regular Presenter (which is a place)You have to have a url for it (f.e.: localhost:8080/myApp | localhost:8080/myApp#MenuPresenter).
To display PresenterWidget You have to call it somewhere!
According to documentation here:
NestedSlot: Same as SingleSlot, but can only take Presenters that have
Proxies (no PresenterWidget).
and You try to put there a PresenterWidget- WHICH IS WRONG, try to:
replace NestedSlot with Slot or SingleSlot(accepts PresenterWidget),
or change MenuPresenter to extend regular Presenter instead of PresenterWidget.
Try do this and give me feedback.
You should try to clean and install Your whole application and restart SuperDevMode and Your server.
I've recreate described functionality. It works. I've base on this article
Layout example
Layout example. Hope this will help.
package pl.korbeldaniel.cms.client.place.app;
public class AppModule extends AbstractPresenterModule {
#Override
protected void configure() {
install(new UiModule());
bindPresenter(AppPresenter.class, AppPresenter.MyView.class, AppView.class, AppPresenter.MyProxy.class);
bindPresenter(HomePresenter.class, HomePresenter.MyView.class, HomeView.class, HomePresenter.MyProxy.class);
bindPresenter(ErrorPresenter.class, ErrorPresenter.MyView.class,
bindPresenter(TesttPresenter.class, TesttPresenter.MyView.class, TesttView.class, TesttPresenter.MyProxy.class);
}
}
package pl.korbeldaniel.cms.client.place.app;
public class AppPresenter extends TabContainerPresenter<AppPresenter.MyView, AppPresenter.MyProxy> implements AppUiHandlers, CurrentUserChangedHandler, AsyncCallStartHandler, AsyncCallFailHandler, AsyncCallSucceedHandler {
#ProxyStandard
public interface MyProxy extends Proxy<AppPresenter> {}
public interface MyView extends TabView, HasUiHandlers<AppUiHandlers> {}
public static final NestedSlot SLOT_NavBar = new NestedSlot();
private final TesttPresenter testtPresenter;
#Inject
AppPresenter(EventBus eventBus, MyView view, MyProxy proxy, TesttPresenter testtPresenter) {
super(eventBus, view, proxy, SLOT_TAB_CONTENT, SLOT_REQUEST_TABS, SLOT_CHANGE_TAB, RevealType.Root);
this.testtPresenter = testtPresenter;
getView().setUiHandlers(this);
}
#Override
protected void onBind() {
super.onBind();
setInSlot(SLOT_NavBar, testtPresenter);
}
}
package pl.korbeldaniel.cms.client.place.app;
public class AppView extends ViewWithUiHandlers<AppUiHandlers> implements AppPresenter.MyView {
public interface Binder extends UiBinder<Widget, AppView> {}
#UiField MaterialRow navBarPanel;
#Inject
AppView(Binder uiBinder) {
initWidget(uiBinder.createAndBindUi(this));
bindSlot(AppPresenter.SLOT_NavBar, navBarPanel);
}
}
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui' xmlns:m="urn:import:gwt.material.design.client.ui"
<m:MaterialPanel>
<m:MaterialRow ui:field="navBarPanel" />
</m:MaterialPanel>
</ui:UiBinder>
package pl.korbeldaniel.cms.client.playground.test.testt;
import pl.korbeldaniel.cms.client.place.app.AppPresenter;
public class TesttPresenter extends Presenter<TesttPresenter.MyView, TesttPresenter.MyProxy> {
public interface MyView extends View {}
#ProxyStandard
public interface MyProxy extends Proxy<TesttPresenter> {}
#Inject
public TesttPresenter(EventBus eventBus, MyView view, MyProxy proxy) {
super(eventBus, view, proxy, AppPresenter.SLOT_NavBar);
}
}
package pl.korbeldaniel.cms.client.playground.test.testt;
import pl.korbeldaniel.cms.client.place.app.AppPresenter;
public class TesttView extends ViewImpl implements TesttPresenter.MyView {
public interface Binder extends UiBinder<Widget, TesttView> {}
#UiField
SimplePanel main;
#Inject
public TesttView(Binder uiBinder) {
initWidget(uiBinder.createAndBindUi(this));
main.add(new Label("____________________________________________________________________________________________________________________>TEST "));
Window.alert("TESTT");
this.bindSlot(AppPresenter.SLOT_NavBar, this.main);
}
}
<!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">
<g:SimplePanel ui:field="main"></g:SimplePanel>
</ui:UiBinder>

UIBinder with Widget

I am trying to add a widget to a panel using UIBinder but the composite simply doesn't load, here is my xml:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:my='urn:import:com.abc.client.test.ui'>
<g:HTMLPanel ui:field="mainLayoutPanel">
<g:SimplePanel ui:field="menuPanel" >
<my:MainMenuViewImpl ui:field="mainMenu"/>
</g:SimplePanel>
<!-- the widget causing the issue -->
<my:FinancialsNav ui:field="nav"/>
<g:SimplePanel ui:field="mainPanel" />
</g:HTMLPanel>
</ui:UiBinder>
The corresponding java class:
public class AppLayoutImpl extends Composite implements AppLayout{
#UiField
HTMLPanel mainLayoutPanel;
interface AppLayoutUiBinder extends UiBinder<Widget,AppLayoutImpl>{}
private static AppLayoutUiBinder binder=GWT.create(AppLayoutUiBinder.class);
#UiField
SimplePanel menuPanel;// nav at the top
#UiField(provided=true)
FinancialsNav nav;// nav on the side
#UiField
SimplePanel mainPanel;// center
#UiField(provided=true)
MainMenuViewImpl mainMenu;
public AppLayoutImpl(ClientFactory clientFactory){
mainMenu=clientFactory.getMainMenuView();
nav=clientFactory.getNav();
initWidget(binder.createAndBindUi(this));
}
#Override
public Widget asWidget(){
return this;
}
}
And the Widget causing the issue:
public class FinancialsNav extends Composite implements ClickHandler{
private VerticalPanel nav=new VerticalPanel();
// Operations
private DisclosurePanel operationsWrapper=new DisclosurePanel(Proto2.constants.financials_navigation_operations());
private NavButton product=new NavButton(Proto2.constants.financials_navigation_products(),
SharedUtilities.PRODUCT_TOKEN);
private NavButton generalOptions=new NavButton(Proto2.constants.financials_navigation_generalOptions(),"");
private ArrayList<NavButton[]> buttons;
private NavButton[] operationsButtons={product,vc,fc,emp,others};
//...
private NavButton[] optionsButtons={generalOptions};
private final EventBus bus;
public FinancialsNav(EventBus bus){
this.bus=bus;
buildNav();
initWidget(nav);
}
private void buildNav(){
buttons=new ArrayList<NavButton[]>();
buttons.add(operationsButtons);
//...
buttons.add(optionsButtons);
int n=buttons.size();
int nn;
for(int i=0;i<n;i++){
nn=buttons.get(i).length;
for(int j=0;j<nn;j++){
(buttons.get(i)[j]).addClickHandler(this);
(buttons.get(i)[j]).setStylePrimaryName(NAV_BUTTON_STYLE);
if(i==0){
operationsWrapper.add(buttons.get(i)[j]);
//...
}else if(i==4){
optionsWrapper.add(buttons.get(i)[j]);
}
}
}
nav.add(operationsWrapper);
// ...
nav.add(optionsWrapper);
}
The FinancialsNav widget works fine when not used with UIBinder and the rest of AppLayout works as expected when the FinancialsNav isn't there.
I spent hours on this looking at various tutorials and examples but simply could not find what is wrong with the code. I also tried various workaround such as declaring a panel in the UIBinder instead of the FinancialsNav and the adding the nav to the panel.
Also everything is in the same package so it shouldn't be an import issue.
Any help would be much appreciated...
Here is the clientFactory
public class ClientFactoryImpl implements ClientFactory{
private static final EventBus eventBus=new SimpleEventBus();
private static final PlaceController placeController=new PlaceController(eventBus);
private static final CreatePlanServiceAsync createPlanService=GWT.create(CreatePlanService.class);
private static final FinancialsNav navView=new FinancialsNav(eventBus);
private static final MainMenuViewImpl mainMenuView=new MainMenuViewImpl();
#Override
public EventBus getEventBus(){
return eventBus;
}
#Override
public PlaceController getPlaceController(){
return placeController;
}
#Override
public FinancialsNav getNav(){
return navView;
}
#Override
public MainMenuViewImpl getMainMenuView(){
return mainMenuView;
}
#Override
public CreatePlanServiceAsync getCreatePlanService(){
return createPlanService;
}
}
FinancialsNav widgets has constructor with arguments. So create no argument constructor.
The entry <my:FinancialsNav ui:field="nav"/> is equals to new FinancialsNav().
In most cases this means that they must be default instantiable; that is, they must provide a zero-argument constructor. you have to pass argument
/** Used by MyUiBinder to instantiate FinancialsNav */
#UiFactory FinancialsNav makeFinancialsNav() { // method name is insignificant. do start with make
return new FinancialsNav(eventBus);
}
Refer Using a widget that requires constructor args
Can you show clientFactory code!!
Ok I found the error, actually not directly related to UIBinder.
Simultaneously to implementing UIBinder I was trying to reduce the number of tables used by the panels in my app.
As I noticed that the disclosure panel is based on a table I removed an intermediary vertical panel I had in the FinancialsNav.
Hence having DisclosurePanel --> Buttons instead of DisclosurePanel --> VerticalPanel --> Buttons. And that is causing the entire block not to show.
#adenoyelle and #bumika: thank you for help

How to use GWT's Editor Framework with gwt-platform?

I'm using gwt-platform and tried to implement GWT's editor framework. But I don't get it working from within the presenter. There are some answers around the web, that say I have to inject the EditorDriver somehow into the Presenter, but I don't know how to do this...
At the moment I tried this without success:
public class MyPresenter extends Presenter<MyPresenter.MyView, MyPresenter.MyProxy> implements MyUiHandlers {
public interface MyView extends View, HasUiHandlers<MyUiHandlers>, Editor<MyModel> {}
#ProxyStandard
#NameToken(NameTokens.myPage)
#NoGatekeeper
public interface MyProxy extends ProxyPlace<MyPresenter> {}
interface Driver extends SimpleBeanEditorDriver<MyModel, MyView> {}
private Driver editorDriver;
DispatchAsync dispatcher;
#Inject
public MyPresenter(EventBus eventBus, MyView view, MyProxy proxy, DispatchAsync dispatcher) {
super(eventBus, view, proxy);
getView().setUiHandlers(this);
this.dispatcher = dispatcher;
MyModel m = new MyModel();
m.setId(1L);
m.setUsername("username");
m.setPassword("password");
editorDriver = GWT.create(Driver.class);
editorDriver.initialize(this.getView());
editorDriver.edit(m);
}
...
}
It works if I explicitly specify the ViewImplementation, but that's not the way MVP should work:
interface Driver extends SimpleBeanEditorDriver<MyModel, MyViewImpl> {}
...
editorDriver.initialize((MyViewImpl) this.getView());
I would be nice if someone could give me an example how to do it right.
Thanks
An approach similar to what was used in an earlier version of the Expenses sample worked for me:
An interface that the view should implement. The wildcard is used so that the presenter does not need to know the concrete view implementation:
import com.google.gwt.editor.client.Editor;
import com.gwtplatform.mvp.client.View;
/**
* Implemented by views that edit beans.
*
* #param <B> the type of the bean
*/
public interface BeanEditView<B> extends View, Editor<B> {
/**
* #return a new {#link SimpleBeanEditorDriver} initialized to run
* this editor
*/
SimpleBeanEditorDriver<B, ?> createEditorDriver();
}
Your presenter should look something like this now:
public class MyPresenter extends Presenter<MyPresenter.MyView, MyPresenter.MyProxy> implements MyUiHandlers {
public interface MyView extends BeanEditView<MyModel>, HasUiHandlers<MyUiHandlers> {}
#ProxyStandard
#NameToken(NameTokens.myPage)
#NoGatekeeper
public interface MyProxy extends ProxyPlace<MyPresenter> {}
private SimpleBeanEditorDriver<MyModel, ?> editorDriver;
DispatchAsync dispatcher;
#Inject
public MyPresenter(EventBus eventBus, MyView view, MyProxy proxy, DispatchAsync dispatcher) {
super(eventBus, view, proxy);
getView().setUiHandlers(this);
this.dispatcher = dispatcher;
MyModel m = new MyModel();
m.setId(1L);
m.setUsername("username");
m.setPassword("password");
editorDriver = getView().createEditorDriver();
}
...
}
And the view implmementation:
public class MyViewImpl extends ViewWithUiHandlers<MyUiHandlers> implements
MyPresenter.MyView {
public interface Binder extends UiBinder<Widget, MyViewImpl> { }
private static Binder uiBinder = GWT.create(Binder.class);
/**
* The driver to link the proxy bean with the view.
*/
public interface EditorDriver extends SimpleBeanEditorDriver<MyModel, MyViewImpl> { }
private final Widget widget;
public MyViewImpl() {
widget = uiBinder.createAndBindUi(this);
}
#Override
public SimpleBeanEditorDriver<MyModel, ?> createEditorDriver() {
EditorDriver driver = GWT.create(EditorDriver.class);
driver.initialize(this);
return driver;
}
#Override
public Widget asWidget() {
return widget;
}
...
}
That's as close as I could get to MVP with GWT's Editor Framework. I couldn't find a way for the view implementation to NOT know the model but I don't think it's really necessary.
If anyone has any improvements on this, I'm glad to hear.
Found some additional comments on GWT Editors. It seems that it might just not be possible to completely separate the model. As Thomas Broyer puts it in his answer to another Editor question:
"MVP is not set in stone (it's not even defined; it was coined by Martin Fowler but he retired the term in favor of two more specific patterns), so you're only violating the rules you gave to yourself. Put differently, the Editor framework as a whole can be seen as violating MVP: each editor know the model, not necessarily the exact instance it's editing (as with ValueAwareEditor or LeafValue), but at least the kind of objects it's an editor of."
The issue is that the Driver.class passed to GWT.create
editorDriver = GWT.create(Driver.class);
must the concrete class that holds all sub-editors, i.e. all the uibinded widgets.
One solution is the following:
The view interface extends the editor interface for the Model object
public interface MyView extends View, ..., Editor<MyModel>
The view implementation MyViewImpl defines a driver type
interface MyDriverImpl extends SimpleBeanEditorDriver<MyModel,MyViewImpl>
The driver is instantiated in MyViewImpl by
SimpleBeanEditorDriver<MyModel,MyView> driver = GWT.create(MyDriverImpl.class);
The parent type
SimpleBeanEditorDriver<MyModel,MyView>
can be used to pass references of the driver to the presenter
MVP says that you use the presenter to completely seperate the model from the view. In addition I'd say that your approach puts logic inside the view...
I hope that there's another solution ;)

CellWidget not getting displayed

I am trying to make a basic cellbrowser widget work in my App. For now just the Structure so that I can replace it later with something meaningfull.
I looked up the samples and implemented one however when I try integarting it in my Application, it wont work!
Here is the part of code. What is the problem? Why cant I see the widget?
public class ListViewImpl extends Composite implements ListView
{
private static ListViewImplUiBinder uiBinder = GWT
.create(ListViewImplUiBinder.class);
interface ListViewImplUiBinder extends UiBinder<Widget, ListViewImpl>
{
}
private Presenter presenter;
#UiField(provided=true)
CellBrowser cellbrowser;
public ListViewImpl()
{
TreeViewModel model = new ListTreeViewModel();
cellbrowser=new CellBrowser(model,null);
cellbrowser.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
cellbrowser.setAnimationEnabled(true);
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public void setPresenter(Presenter presenter)
{
this.presenter=presenter;
}
#Override
public Widget asWidget() {
return this;
}
}
The Uibinder file goes as -->
<ui:style>
.browser {
border: 1px solid #ccc;
}
.out
{
outline:#ccc solid thick;
}
</ui:style>
<g:HTMLPanel styleName='{style.out}' >
<c:CellBrowser addStyleNames='{style.browser}' defaultColumnWidth='300' ui:field='cellbrowser' />
</g:HTMLPanel>
The ListTreeView model class is perfect as when I use the code in a standalone application and add CellBrowser to RootLayoutPanel. It works!
CellBrowser is a RequiresResize widget (it uses a SplitLayoutPanel internally), so just like with all RequiresResize widget, you have to either put it within a ProvidesResize widget, or give it explicit dimensions.

Spring ROO GWT with GIN injection on widgets created by ui:binder

I'm trying to access some objects inside a ui:binder component, but not sure of how to access the eventBus, requestFactory, etc without writing nasty code that will keep me awake at night (also take note that I'm completely new to JAVA, background is in Perl/Python/PHP).
My ui.xml file:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:ig='urn:import:com.ig.client.scaffold.ui.widget'>
<ui:style>
...
</ui:style>
<g:HorizontalPanel>
...
</g:HorizontalPanel>
</ui:UiBinder>
Injecting the eventBus this way fails with
com.ig.client.scaffold.ui.widget.R has no default (zero args) constructor.
public class R extends Composite {
interface MyUiBinder extends UiBinder<Widget, R> {}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
private final EventBus eventBus;
#UiField SimplePanel fieldA, ...;
#Inject
public R(EventBus eventBus){
this.eventBus = eventBus;
initWidget(uiBinder.createAndBindUi(this));
}
}
So, as per the error message, I create a UIFactory and then I get an error
... '{style.entityComponent}'> missing required attribute(s): eventBus Element ... (seems like it is trying to find the eventBus in the ui:binder stylesheet.
public class R extends Composite {
interface MyUiBinder extends UiBinder<Widget, R> {}
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
private final EventBus eventBus;
#UiField SimplePanel fieldA, ...;
public #UiConstructor R(EventBus eventBus){
this.eventBus = eventBus;
initWidget(uiBinder.createAndBindUi(this));
}
#Inject
#UiFactory R makeR(){
return new R(eventBus);
}
}
From reading and reading and more reading for the past couple of days, I haven't seen anyone accessing the eventBus, requestFactory and historyController directly in the view binding to the ui:binder widget which led to the conclusion that it's probably not a best practice
anyway.
Let's say I have an oject, let's call it Proxy, proxy contains handleButtonClick which then calls eventBus.doSomething(). How do I link this Proxy object to the ui:binder widget without having to instantiate it or without having to pass it around to every widget?
Is it possible to do GIN injection on an interface and then implement that interface via class R which will then somehow contain the objects I'm looking for?
Any solution that work is welcome, just looking for a sample (that a Java n00b can understand) that will basically allow me to connect my front-end with the rest of the services created by ROO.
Thanks
J
Check out the Model, View, Presenter pattern - it solves
this problem. Generally all non-display logic should be kept out
of your views so that 1) the non-display logic can be unit tested without
running inside a (slow to instantiate) browser and 2) different
displays can be plugged into the same application without duplicating
the non-display logic.
Here's an MVP example exhibiting the
behavior you're looking for (note that the style is slightly
different than the Activities & Places implementation).
MyPresenter.java:
public class MyPresenter {
public interface Display extends IsWidget {
void setButtonClickHandler(ClickHandler buttonClickHandler);
}
private final Display display;
private final EventBus eventBus;
#Inject
public MyPresenter(EventBus eventBus,
Display display)
{
this.display = display;
this.eventBus = eventBus;
bind();
}
private void bind() {
display.setButtonClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
eventBus.fireEvent(new MyButtonClickedEvent());
}
});
}
public void go(HasWidgets container) {
container.add(display.asWidget());
}
}
MyView.ui.xml:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:ig='urn:import:com.ig.client.scaffold.ui.widget'>
<g:Button ui:field="myButton"/>
</ui:UiBinder>
MyView.java
public class MyView extends Composite implements MyPresenter.Display {
interface MyViewUiBinder extends UiBinder<Widget, MyView> {}
private static MyViewUiBinder uiBinder = GWT.Create(MyViewUiBinder.class);
private ClickHandler buttonClickHandler = null;
public MyView() {
initWidget(uiBinder.createAndBindUi(this));
}
#UiHandler("myButton")
void onButtonClick(ClickEvent event) {
if (buttonClickHandler != null) {
buttonClickHandler.onClick(event);
}
}
#Override
public void setButtonClickHandler(ClickHandler buttonClickHandler) {
this.buttonClickHandler = buttonClickHandler;
}
}
And in your GIN module: bind(MyPresenter.Display.class).to(MyView.class);