in Test.ui.xml
<g:DialogBox ui:field="wishlistDialogBox" autoHide="true">
<g:caption>Test</g:caption>
<g:HTMLPanel> some widgets..</g:HTMLPanel>
</g:DialogBox>
After running, the application still show the DialogBox, so I tried to set hide for "wishlistDialogBox" in TestView.java but it didn't work.
#UiField DialogBox wishlistDialogBox;
#Inject
public TestView(final Binder binder) {
widget = binder.createAndBindUi(this);
wishlistDialogBox.hide();
}
Then i set hide for it in TestPresenter.java but it still didn't work
#Override
protected void onBind() {
super.onBind();
getView().getWishlistDialogBox().hide();
}
What's wrong, Goodle didn't explain it at all.
In addition, how to reuse the DialogBox?
DialogBox (and PopupPanels in general) does not work like any other widget when speaking about adding them to the DOM. You should never attach them directly to it (i.e., panel.add(yourDialogBox) or inside a UiBinder XML file) as you did. Instead you should create them, and simply call hide()/show(), and the like methods, to get it displayed/hidden (i.e., attached/detached at the end of/from the DOM).
Something that works for me is creating a Dialogbox separately from any other widgets. So it has its own Java file and its own ui.xml file :
UiBinder xml file:
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:DialogBox ui:field="dialog">
<g:caption>My Dialog</g:caption>
<g:HTMLPanel>
<g:Button ui:field="closeButton" text="close" />
</g:HTMLPanel>
</g:DialogBox>
</ui:UiBinder>
Java file:
public class MyDialog { // here you do not inherit anything
private static MyDialogUiBinder uiBinder = GWT.create(MyDialogUiBinder.class);
interface MyDialogUiBinder extends UiBinder<Widget, MyDialog> {
}
#UiField
DialogBox dialog;
#UiField
Button closeButton;
public MyDialog() {
// make cast to DialogBox
dialog = (DialogBox) (uiBinder.createAndBindUi(this));
}
public void hide() {
dialog.hide();
}
public void show() {
dialog.center();
}
#UiHandler("closeButton")
public void onClick(ClickEvent event) {
hide();
}
}
Finally i figured out a way, that is to put the DialogBox into a invisible HTMLPanel
<g:HTMLPanel visible="false">
<g:DialogBox ui:field="wishlistDialogBox" autoHide="true">
<g:caption>Test</g:caption>
<g:HTMLPanel> some widgets..</g:HTMLPanel>
</g:DialogBox>
</g:HTMLPanel>
Then just call show & hide DialogBox as usual & it will show the DialogBox even the DialogBox was wrapped inside an invisible HTMLPanel.
getView().getWishlistDialogBox().show();
Related
I have simple view. There are uiBinder and class themselves:
public class NewNotePopupPanel extends Composite implements NewNoteView {
interface NewNotePopupPanelUiBinder extends UiBinder<PopupPanel, NewNotePopupPanel> {
}
private static NewNotePopupPanelUiBinder ourUiBinder = GWT.create(NewNotePopupPanelUiBinder.class);
#UiField
PopupPanel popupPanel;
#UiField
VerticalPanel newNoteMainPanel;
#UiField
HorizontalPanel newNoteHeader;
#UiField
Label storedNoteTitle;
#UiField
DateLabel noteCreatedDate;
#UiField
VerticalPanel contentPanel;
#UiField
TextBox currentNoteTitle;
#UiField
RichTextArea contentTextArea;
#UiField
HorizontalPanel newNoteFooter;
#UiField
CheckBox favorite;
#UiField
Button save;
#UiField
Button close;
private Presenter presenter;
static {
Resources.INSTANCE.style().ensureInjected();
}
public NewNotePopupPanel() {
initWidget(ourUiBinder.createAndBindUi(this));
}
#UiHandler("favorite")
void onFavoriteCheckBoxClicked(ClickEvent event) {
if (presenter != null) {
presenter.onFavoriteCheckBoxClicked();
}
}
#UiHandler("save")
void onApplyButtonClicked(ClickEvent event) {
if (presenter != null) {
presenter.onApplyButtonClicked();
}
}
#UiHandler("close")
void onCancelButtonClicked(ClickEvent event) {
popupPanel.hide();
}
}
UiBinder:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'>
<ui:with field="res" type="ru.beleychev.notes.client.ui.Resources"/>
<g:PopupPanel ui:field="popupPanel" width="600px" modal="true" title="Edit Note" addStyleNames="{res.style.mainPanel}">
<g:VerticalPanel ui:field="newNoteMainPanel">
<g:HorizontalPanel ui:field="newNoteHeader">
<g:Label ui:field="storedNoteTitle" addStyleNames="{res.style.label}"/>
<g:DateLabel ui:field="noteCreatedDate" customFormat="EEE, MMM d, yyyy"
addStyleNames="{res.style.label}"/>
</g:HorizontalPanel>
<g:VerticalPanel ui:field="contentPanel">
<g:TextBox ui:field="currentNoteTitle" addStyleNames="{res.style.searchBox}"/>
<g:RichTextArea ui:field="contentTextArea" focus="true"/>
</g:VerticalPanel>
<g:HorizontalPanel ui:field="newNoteFooter">
<g:CheckBox ui:field="favorite"/>
<g:Button ui:field="save" text="Save" addStyleNames="{res.style.button}"/>
<g:Button ui:field="close" text="Close" addStyleNames="{res.style.button}"/>
</g:HorizontalPanel>
</g:VerticalPanel>
</g:PopupPanel>
This popup window opens from another view. And there is all ok.
I have no problems with interface. But, unfortunately, "Close" button doesn't close popup. It's simple (easy-peasy). What is the problem? ) Looking forward to your suggestions, guys. Thank you in advance.
from why can't i hide DialogBox in UiBinder in GWT?
DialogBox (and PopupPanels in general) does not work like any other widget when speaking about adding them to the DOM. You should never attach them directly to it (i.e., panel.add(yourDialogBox) or inside a UiBinder XML file) as you did. Instead you should create them, and simply call hide()/show(), and the like methods, to get it displayed/hidden (i.e., attached/detached at the end of/from the DOM)
I am constructiong an webapp with Google Web Toolkit using GWT-Platform and GWT-Bootstrap frameworks. Mostly it has been almost flawless until I tried to implement a popup. These frameworks' undestanding of popups seems to be quite different.
GWT-Platform expects a popup widget itself to be an instance of com.google.gwt.user.client.ui.PopupPanel when using the GWTP's RevealRootPopupContentEvent.fire(source, content) or a presenter's addToPopupSlot(child) method.
GWT-Bootstrap's Modal is used like any other widget that is added to the underlying panel but my goal is it to have a separate presenter and view and to possibly fetch it asynchrously with AsyncProvider.
I have tried to make it as a PresenterWidget and using addToSlot(slot, content) to reveal it but it doesn't look quite right. Not all of the styles are applied this way and the close icon (×), doesn't work for example.
I think I am not the first one trying to do something like that so maybe someone has figured out a proper way to make it work.
Thanks!
You have to create a view:
public class MyPopupView extends PopupViewImpl implements MyView {
protected Widget widget;
public interface MyPopupViewUiBinder extends
UiBinder<Widget, MyPopupView> {
}
#UiField(provided = true)
Modal dialogBox;
private MyPresenter presenter;
#Inject
public MyPopupView(final MyPopupViewUiBinder uiBinder,
final EventBus eventBus) {
super(eventBus);
setUpDialog(); // Provides UiField => Before initWidgets
initWidget(uiBinder.createAndBindUi(this));
}
// DialogBox must be overridden to let the presenter handle changes onUnload
private void setUpDialog() {
dialogBox = new Modal() {
#Override
protected void onUnload() {
MyPopupView.this.hide();
}
};
dialogBox.setTitle("Some title");
}
#Override
public void setPresenter(final MyPresenter presenter) {
this.presenter = presenter;
}
#Override
public final void hide() {
dialogBox.hide();
presenter.hide();
}
#Override
public void setAutoHideOnNavigationEventEnabled(final boolean autoHide) {
// TODO Auto-generated method stub
}
#Override
public void setCloseHandler(
final PopupViewCloseHandler popupViewCloseHandler) {
// TODO Auto-generated method stub
}
#Override
public void setPosition(final int left, final int top) {
// TODO Auto-generated method stub
}
#Override
public void show() {
dialogBox.show();
}
#Override
public void center() {
dialogBox.show();
}
#Override
public Widget asWidget() {
return widget;
}
protected final void initWidget(final Widget widget) {
this.widget = widget;
}
}
And a UIBinder file:
<!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'>
<b:Modal title="Some Title" ui:field="dialogBox">
<!-- Your content -->
</b:Modal>
</ui:UiBinder>
Your gwtp popup presenter has a view that extends PopUpViewImpl which implements PopupView, and uses a lot of the methods of that interface for displaying the popup (asPopupPanel(), show(), center(), etc).
I'm just starting to get to know gwt-bootstrap (looks great +caalos0), but it seems that Modal doesn't implement PopupView, and therefore cannot be passed to addToPopupSlot in a way it would be displayed automatically by gwtp.
as for the addToSlot() issue, are you using RootLayoutPanel or RootPanel?
it could be the reason for addToSlot not working properly, since the gwt-bootstrap Modal widget is attached to the RootPanel on initialization, this can cause weird layout behavior along with an application using RootLayoutPanel as base.
I would try to extend the Modal component, let it implement PopUpView, add it as a field on the PopUpViewImpl attached to your popup presenter, and override the PopUpViewImpl asPopupPanel() function to return the new extended Modal.
Based on the answer by #dominik I did some improvements, see my Gist. It contains some abstract base classes that can be used for any Modal/PopupView implementation. It's a bit more complex but also cleaner because we don't pass the whole Presenter to the View. The interface for the View to interact with the Presenter when the modal is closed is HasModalUnbind.
You would use these classes as follows. Example presenter:
public class ErrorModalPresenter extends ModalPopupPresenter<ErrorModalPresenter.MyView> {
public interface MyView extends ModalPopupView {
DivElement getErrorMessage();
}
private final ErrorEvent error;
#Inject
public ErrorModalPresenter(final EventBus eventBus,
final MyView view,
#Assisted final ErrorEvent error) {
super(eventBus, view);
this.error = error;
}
#Override
public void unbindModal() {
ErrorDismissEvent.fire(this, this);
}
#Override
protected void onBind() {
super.onBind();
//noinspection ThrowableResultOfMethodCallIgnored
getView().getErrorMessage().setInnerText(error.getCause().getMessage());
}
}
Example view:
public class ErrorModalView extends ModalPopupViewImpl implements ErrorModalPresenter.MyView {
#UiField(provided = true)
Modal errorModal;
#UiField
DivElement errorMessage;
interface Binder extends UiBinder<Widget, ErrorModalView> {}
#Inject
public ErrorModalView(final EventBus eventBus,
final Binder uiBinder) {
super(eventBus);
errorModal = initModal();
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public DivElement getErrorMessage() {
return errorMessage;
}
}
And the UiBinder XML just for the record:
<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'>
<b:Modal ui:field='errorModal' title='Error'>
<g:HTML>
<div ui:field='errorMessage'/>
</g:HTML>
<b:ModalFooter>
<b:Button text='Close' dismiss='MODAL'/>
</b:ModalFooter>
</b:Modal>
</ui:UiBinder>
In unbindModal() of ErrorModalPresenter I fire an event which is caught by the parent presenter of ErrorModalPresenter. There the modal presenter is removed from a container and then unbind() is called on the presenter. Of course any other solution is possible in unbindModal().
The base classes assume that modals are one-shot modals that will be removed once they're hidden. This behaviour can be changed in initModal() of ModalPopupViewImpl.
I believe you will have to made some Glue Code to made it works.
I never used GWT-Platform popups, so I dont know exactly how, but I believe you will have to made a new Class extending PopupPresenter, and made what's needed to made it work.
Also, I was thinking about GWT-Platform days ago... and I'm pretty sure that when first release of GWT-Platform is out, I'll create a new project to made these necessary glue codes.
If you need any help with this, please contact me.
Thanks, sorry about the poor gwt-platform support.
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.
For testing purposes, I want to use a DialogBox for logging into my application.
Here's the uibinder file:
<!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">
<ui:style>
</ui:style>
<g:HTMLPanel>
<g:Label>Username</g:Label>
<g:TextBox ui:field="username"></g:TextBox>
<g:Label>Password</g:Label>
<g:PasswordTextBox ui:field="password"></g:PasswordTextBox>
<g:Button ui:field="login">Login</g:Button>
</g:HTMLPanel>
</ui:UiBinder>
And here's my implementation of it:
public class Login extends DialogBox {
private static LoginUiBinder uiBinder = GWT.create(LoginUiBinder.class);
interface LoginUiBinder extends UiBinder<Widget, Login> {}
#UiField
TextBox username;
#UiField
PasswordTextBox password;
#UiField
Button login;
public Login() {
setHTML("Login");
setWidget(uiBinder.createAndBindUi(this));
}
}
Now my question is: Is this the correct way to do it? The documentation doesn't seem to say anything on how to do this sort of thing...
That's what I do, and it's been working great in production for months. It's super easy to understand and reuse.
I made an abstract dialog with the same pattern that has an abstract method onConfirm and a built-in confirm button. I also include in the UiBinder a panel to accept a widget, and override the setWidget function to put the widget into that interior panel. Then, whenever I need a new dialog for something, I can just write:
final CustomWidget whicheverWidgetINeedRightNow = xyz;
CustomDialog dialog = new CustomDialog()
{
#Override
protected void onConfirm()
{
process(whicheverWidgetINeedRightNow.getData());
}
};
dialog.setWidget(whicheverWidgetINeedRightNow);
The ok button in the template UiBinder is hard-wired to call onConfirm when it's pressed. Nifty! For more complex cases, I'd subclass CustomDialog in its own named class.
It's worked well for me in maybe 5 or 6 different situations in my app, and I don't have to re-style or re-code anything.
I am a newbie trying to use a MenuBar to swap the displayed panel in a DeckPanel.
I have 2 classes and 2 associated uibinder XML files:
ApplicationUi.java
ApplicationUi.ui.xml
ApplicationMenu.java
ApplicationMenu.ui.xml
In ApplicationUi.java and the UI XML, the root is bound to a DockLayoutPanel. The ApplicationMenu is meant to be in the North section of the DockLayoutPanel. The MenuBar options will affect the DeckPanel in the Center section.
In ApplicationMenu, how can I get a reference to the DeckPanel so I can call showWidget() to swap the displayed panel?
Also, since I'm a newb, any suggestions or reviews of this code are welcome. I've done the best I can on Google, but alot of what I'm looking for doesn't seem to be out there.
(This is a followup to Replace GWT DockLayoutPanel Contents).
Source:
ApplicationUi.java
import org.jason.datacenter.client.forms.NewRequirementForm;
public class ApplicationUi extends Composite {
private static final Binder binder = GWT.create(Binder.class);
interface Binder extends UiBinder<Widget, ApplicationUi> {
}
#UiField DockLayoutPanel dlp;
#UiField VerticalSplitPanel headerPanel;
#UiField DeckPanel deckPanel;
public ApplicationUi() {
initWidget(binder.createAndBindUi(this));
// add the NewRequirementForm to the deckpanel as index #0
deckPanel.add(new NewRequirementForm());
}
public void switchDeck(int newIndex) {
deckPanel.showWidget(newIndex);
}
}
ApplicationUi.ui.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!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'>
<ui:style>
.panel {
background-color: ivory;
}
</ui:style>
<g:DockLayoutPanel ui:field="dlp">
<g:north size="800">
<g:VerticalSplitPanel ui:field="headerPanel">
</g:VerticalSplitPanel>
</g:north>
<g:center>
<g:DeckPanel ui:field="deckPanel" />
</g:center>
</g:DockLayoutPanel>
</ui:UiBinder>
ApplicationMenu.java:
public class ApplicationMenu extends Composite {
private static final Binder binder = GWT.create(Binder.class);
interface Binder extends UiBinder<Widget, ApplicationMenu> {
}
#UiField MenuBar applicationMenu;
#UiField MenuItem mitmNewPower;
public ApplicationMenu() {
initWidget(binder.createAndBindUi(this));
mitmNewPower.setCommand(new Command() {
#Override
public void execute() {
RootLayoutPanel rlp = RootLayoutPanel.get();
DockLayoutPanel dlp = (DockLayoutPanel) rlp.getWidget(0);
}
});
}
}
ApplicationMenu.ui.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!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'>
<ui:style>
.panel {
background-color: ivory;
}
</ui:style>
<g:MenuBar ui:field="applicationMenu">
<g:MenuItem>
Process
<g:MenuBar>
<g:MenuItem ui:field="mitmNewPower" />
</g:MenuBar>
</g:MenuItem>
</g:MenuBar>
</ui:UiBinder>
One way you could do this would be to use an EventBus. Create an event type and have your ApplicationMenu fire an event of that type when a menu item gets clicked. The ApplicationUi object can subscribe to that event and respond to it by updating the contents of the DeckPanel. This avoids the menu object needing to know about the DeckPanel at all.