GWT-Platform the basics presenters

All hebraically good day!

I am a novice Java programmer and it just so happened that my career begins with the development of serious applications on GWT. Habré quite a lot of articles on the topic of GWT, but somehow there is no information about the wonderful framework GWT-Platform. Get familiar with this framework you can here, and I will talk briefly about the basics of the example of a simple application.

Our application will contain a navigation bar, which contains buttons for switching the current view. And also two columns in which we will insert the desired content depending on the situation. Two columns I did for clarity. In real life, would need one of course.

If you click on the button in navbar will open either the left part of the application or right with meaningless text.

Opens by default left column, which is a button call the dialog box for entering the name and surname. After pressing the confirm button the data is sent in the right column and displayed.






So, first we need to create a GWT project in the IDE. To work with GWTP, we need to add the library project: guice-2.0.jar, guice-3.0.jar, gwtp-all-1.0.jar, aopalliance.jar, guice-assistedinject-3.0.jar. I also added gwt-bootstrap-2.2.2.0-SNAPSHOT.jar to add “beauty” to the application.



You can install Eclipse gwt-platform plugin. It greatly simplifies life. It can be used to create new projects and ligaments presenter view. Swinging at this link: plugin.gwt-platform.googlecode.com/hg/update

Let's start:
You need to create a client module and a Ginjector. If the application is to create using the plugin, they will be created automatically:
In the method configure (), we will bindit our presenters with the interfaces and implementation of their view.
the
public class ClientModule extends AbstractPresenterModule {

@Override
protected void configure() {
install(new DefaultModule(ClientPlaceManager.class));

bindPresenter(MainPagePresenter.class, MainPagePresenter.MyView.class,
MainPageView.class MainPagePresenter.MyProxy.class);

bindConstant().annotatedWith(DefaultPlace.class).to(NameTokens.main);
}
}


the
 @GinModules({ DispatchAsyncModule.class, ClientModule.class })
public interface ClientGinjector extends Ginjector {

EventBus getEventBus();

GetPlaceManager PlaceManager();

Provider<MainPagePresenter> getMainPagePresenter();
}


Further, our entry point is: Here we say our placemanager go to the current page (place). That is, if we in the browser address bar was introduced some token that defines the desired place, we will get there. Of course, provided that we have access to. (Can be responsible for it for example a GateKeeper).

the
public class HabraTest implements EntryPoint {

private final ClientGinjector ginjector = GWT.create(ClientGinjector.class);

@Override
public void onModuleLoad() {
DelayedBindRegistry.bind(ginjector); 
ginjector.getPlaceManager().revealCurrentPlace();
}
}


Not going to focus on the work place. On habré already there were many wonderful articles on GWT. For example this.

I will show you how you can create a small GWT application without the use of place (more precisely one place).

Let's create the main presenter of our application:

the
public class extends MainPagePresenter
Presenter<MainPagePresenter.MyView MainPagePresenter.MyProxy > implements MainPageUiHandlers, FirstPageEvent.Handler{

public interface MyView extends View, HasUiHandlers<MainPageUiHandlers> {
}

// the IDs of the slots for inserting the respective presenter
public final static Object SLOT_FIRST_PAGE = new Object();
public final static Object SLOT_SECOND_PAGE = new Object();

//nested presenters
private FirstPagePresenter firstPagePresenter;
private SecondPagePresenter secondPagePresenter; 

@ProxyStandard
@NameToken(NameTokens.main)
public interface MyProxy extends ProxyPlace<MainPagePresenter> {
}

private EventBus eventBus;
private final PlaceManager placeManager;

// injectin nested presenters
@Inject
public MainPagePresenter(final EventBus eventBus, final MyView view, 

SecondPagePresenter secondPagePresenter,
final MyProxy proxy, final PlaceManager placeManager) {
super(eventBus, view, proxy);
this.placeManager = placeManager;
this.firstPagePresenter = firstPagePresenter;
this.secondPagePresenter = secondPagePresenter;
this.eventBus = eventBus;
// assign itself an event handler view
getView().setUiHandlers(this);
eventBus.addHandler(FirstPageEvent.getType(), this);
}

// introduce ourselves to the main presenter application
@Override
protected void revealInParent() {
RevealRootContentEvent.fire(this, this);
}

@Override
protected void onBind() {
super.onBind();
// default will be loaded the first page
getView().setInSlot(SLOT_FIRST_PAGE, firstPagePresenter); 
}

// called when clicking the left button in the MainPageView
@Override
public void onRightBtnClicked() {
showRightContent();
MainPageEvent mainPageEvent = new MainPageEvent( MainPageEvent.Action.SHOW_LOREM_IPSUM);
eventBus.fireEvent(mainPageEvent); 
}
// similarly, when you press the right
@Override
public void onLeftBtnClicked() {
showLeftContent();

} 

public void showLeftContent() {
removeFromSlot(SLOT_SECOND_PAGE, secondPagePresenter);
getView().setInSlot(SLOT_FIRST_PAGE, firstPagePresenter); 
}

public void showRightContent() {
removeFromSlot(SLOT_FIRST_PAGE, firstPagePresenter);
getView().setInSlot(SLOT_SECOND_PAGE, secondPagePresenter); 
}

@Override
public void onFirstPageEvent(FirstPageEvent event) {
// close the left and open the right content, which is through event passing the name
showRightContent();
MainPageEvent mainPageEvent = new MainPageEvent( MainPageEvent.Action.SHOW_FORM_RESULT, event.getFirstName(), event.getLastName()); 
eventBus.fireEvent(mainPageEvent);

} 
}


Please note that we sangachali designer FirstPagePresenter firstPagePresenter, SecondPagePresenter secondPagePresenter.
This will be the presenter is the widgets which represent the left and right side of the application (that is, in theory, individual pages);

In GWTP there are three main types of presenters:
the
    the
  • Presenter that are still place
  • the
  • Presenter-widgets(PresenterWidget)
  • the
  • Presenter-widgets, which is a Popup window


Presenter-place ispolzuyutsya to create a separate application pages, navigation which you can use so-called tokens, adding adresses browser.
Each presenter must include an abstract that specifies how the token is bound to the presenter.
In our case we use only one presenter.

To change the "pages" we will use a system of slots and presenter widgets are placed in slots.
Presenter widget is the presenter which is not necessarily a singleton. It can have multiple independent instance.
Thanks to the slots we can endlessly invest presenters to other presenters. To put a presenter widget to another presenter, we need to define slots in the parent presenter and setInSlot override method() in the parent view of the presenter.

In the class MainPagePresenter can be seen that the slot is just Object:

the
 public final static SLOT_FIRST_PAGE Object = new Object();
public final static Object SLOT_SECOND_PAGE = new Object();


In the corresponding view define rules for the insertion of the presenters in the slot:

the
public class MainPageView extends ViewWithUiHandlers<MainPageUiHandlers> implements MainPagePresenter.MyView {

// the main panel of the application
@UiField HTMLPanel main;
// navigation bar
@UiField ResponsiveNavbar navbar;

// navigation buttons
@UiField Button firstPageBtn, secondPageBtn;

private static MainPageViewUiBinder uiBinder = GWT
.create(MainPageViewUiBinder.class);

interface MainPageViewUiBinder extends UiBinder < Widget, MainPageView > {
}

// columns to insert content 
@UiField Column leftColumn, rightColumn;

@Inject
public MainPageView() { 
uiBinder.createAndBindUi(this);
navbar.setInverse(true);
//handlers for the buttons 
firstPageBtn.addClickHandler(new ClickHandler() { 
@Override
public void onClick(ClickEvent event) {
getUiHandlers().onLeftBtnClicked(); 
}
});

secondPageBtn.addClickHandler(new ClickHandler() { 
@Override
public void onClick(ClickEvent event) {
getUiHandlers().onRightBtnClicked(); 
}
}); 
}

@Override
public Widget asWidget() {
return main;
}

// overridable method to insert presenters in the slot
@Override
public void setInSlot(Object slot, IsWidget content) {
if(slot == MainPagePresenter.SLOT_FIRST_PAGE ) {
leftColumn.add(content);
}
else if(slot == MainPagePresenter.SLOT_SECOND_PAGE ){
rightColumn.add(content);
}
else {
super.setInSlot(slot, content);
} 
}

// similar to overriding a method of removing from the slot
@Override
public void removeFromSlot(Object slot, IsWidget content) {
if(slot == MainPagePresenter.SLOT_FIRST_PAGE ) {
leftColumn.remove(content);
}
else if(slot == MainPagePresenter.SLOT_SECOND_PAGE ){
rightColumn.remove(content);
}
else {
super.removeFromSlot(slot, content);
} 
}
}


It's pretty simple: setInSlot() takes the presenter and the corresponding slot.
We just define which widget to place the presenter. In this case, two bootstraps columns leftColumn and rightColumn.

Our next presenter-the widgets and their view:

the
public class extends FirstPagePresenter
PresenterWidget<FirstPagePresenter.MyView> implements FirstPageUiHandlers, PopupEvent.Handler{

public interface MyView extends View, HasUiHandlers<FirstPageUiHandlers> {
}

// popup with form
FirstPagePopupPresenter firstPagePopupPresenter;
EventBus eventBus;

@Inject
public FirstPagePresenter(final EventBus eventBus, final MyView view,
FirstPagePopupPresenter firstPagePopupPresenter ) {
super(eventBus, view);
this.firstPagePopupPresenter = firstPagePopupPresenter;
this.eventBus = eventBus;
getView().setUiHandlers(this);
// assign handler itself PopupEvent
eventBus.addHandler(PopupEvent.getType(), this);
}

@Override
public void onShowFormBtnClicked() {
// show the popup window with the form
showForm(true); 
}

private void showForm(boolean show) {
if(show){
addToPopupSlot(firstPagePopupPresenter, true);
firstPagePopupPresenter.getView().show();
}
else {
removeFromPopupSlot(firstPagePopupPresenter);
} 
}

@Override
public void onPopupEvent(PopupEvent event) {
showForm(false);
eventBus.fireEvent(new FirstPageEvent(event.getFirstName(), event.getLastName())); 
}
}


Please note that I sangachel a FirstPagePopupPresenter firstPagePopupPresenter.(code is below). This is our popup form. Similarly, you can injecting any presenter widgets in any quantity and with any nesting. Important not to disturb the hierarchy.

the
public class FirstPageView extends ViewWithUiHandlers<FirstPageUiHandlers> implements
FirstPagePresenter.MyView {

private final Widget widget;
@UiField Button showFormBtn;

public interface Binder extends UiBinder < Widget, FirstPageView> {
}

@Inject
public FirstPageView(final Binder binder) {
widget = binder.createAndBindUi(this);

showFormBtn.addClickHandler(new ClickHandler() { 
@Override
public void onClick(ClickEvent event) {
getUiHandlers().onShowFormBtnClicked(); 
}
});
}

@Override
public Widget asWidget() {
return widget;
}
}


In view especially anything interesting, except that it inherits the typed class ViewWithUiHandlers.
Since we do not want to violate the principles of MVP, and can't contact the presenter directly from view( opposite can). For this we use interfaces. Clicking a button we share with getUiHandlers().onShowFormBtnClicked();

the
public interface FirstPageUiHandlers extends UiHandlers{

void onShowFormBtnClicked();
}


getUiHandlers() returns us the interface FirstPageUiHandlers in which we specify the methods that must be implemented in the corresponding presenter. Of course the presenter must implement this interface, and invested in it interface MyView needs to inherit a typed interface HasUiHandlers. And don't forget to presentere assign a handler for events view — getView().setUiHandlers(this);

Next, the presenter and the corresponding view of the second page:

the
public class extends SecondPagePresenter
PresenterWidget<SecondPagePresenter.MyView> implements MainPageEvent.Handler {

public interface MyView extends View {
void showLoremIpsum();
void showFormInfo(String firstName, String lastName);
}

EventBus eventBus;

@Inject
public SecondPagePresenter(final EventBus eventBus, final MyView view) {
super(eventBus, view);
this.eventBus = eventBus;
eventBus.addHandler(MainPageEvent.getType(), this);
}

@Override
public void onMainPageEvent(MainPageEvent event) {
switch(event.getAction()) {
case SHOW_FORM_RESULT:
showFormInfoWidget(event.getFirstName(), event.getLastName());
break;
case SHOW_LOREM_IPSUM:
showLoremIpsumWidget();
break;
default:
break; 
} 
}

private void showLoremIpsumWidget() {
getView().showLoremIpsum(); 
}

private void showFormInfoWidget(String firstName, String lastName) {
getView().showFormInfo( firstName, lastName); 
}


the
public class SecondPageView extends ViewImpl implements
SecondPagePresenter.MyView {

private final Widget widget;

@UiField FlowPanel contentPanel;

public interface Binder extends UiBinder < Widget, SecondPageView> {
}

@Inject
public SecondPageView(final Binder binder) {
widget = binder.createAndBindUi(this);
}

@Override
public Widget asWidget() {
return widget;
}

@Override
public void showLoremIpsum() {
contentPanel.clear();
contentPanel.add(new LoremIpsumWidget()); 
}

@Override
public void showFormInfo(String firstName, String lastName) {
contentPanel.clear();
contentPanel.add(new FormInfoWidget(firstName, lastName)); 
}
}


Here especially anything interesting and new developer for GWT. Communication between the presenters going through the standard events ( GwtEvent ).

And finally popup with a form:

the
public class extends FirstPagePopupPresenter
PresenterWidget<FirstPagePopupPresenter.MyView> implements PopupUiHandlers {

public interface MyView extends PopupView , HasUiHandlers<PopupUiHandlers>{
}

EventBus eventBus;

@Inject
public FirstPagePopupPresenter(final EventBus eventBus, final MyView view) {
super(eventBus, view);
this.eventBus = eventBus;
getView().setUiHandlers(this);
}

@Override
public void onSubmitBtnClicked(String firstName, String lastName) {
eventBus.fireEvent(new PopupEvent(firstName, lastName)); 
}
}


the
public class FirstPagePopupView extends PopupViewWithUiHandlers<PopupUiHandlers> implements
FirstPagePopupPresenter.MyView {

@UiField PopupPanel main;
@UiField Button submitBtn;
@UiField TextBox firstName, lastName;

public interface Binder extends UiBinder < Widget, FirstPagePopupView> {


@Inject
public FirstPagePopupView(final EventBus eventBus, final Binder binder) {
super(eventBus);
binder.createAndBindUi(this);
main.setAnimationEnabled(true);
main.setModal(true);
main.setGlassEnabled(true);
submitBtn.addClickHandler(new ClickHandler() {

@Override
public void onClick(ClickEvent event) {
getUiHandlers().onSubmitBtnClicked(firstName.getValue(), lastName.getValue()); 
}
});
}

@Override
public Widget asWidget() {
return main;
}
}


As can be seen in popup too, is the presenter-widget, but the interface it should inherit view PopupView. And the main view panel should be PopupPanel or a heir of this class. Another difference from the usual presenter-widgets — to show popup, the page does not need a slot and the panel to insert. It is sufficient to use the method addToPopupSlot();

Also all the ligaments of the presenter view used uibinder. Appropriate *ui.xml files I don't post. There's basically nothing for GWT developers interesting there.

The project will be available some time this address

And so now go over the project that would describe what is happening and how to contact the presenters:

When you download MainPagePresenter in the override onBind() we immediately put in the presenter slot of the first page:

the
 @Override
protected void onBind() {
super.onBind();
getView().setInSlot(SLOT_FIRST_PAGE, firstPagePresenter); 
}


(About the life cycle of the presenters and methods of onBind(), onUnbind, onReveal(), onReset(), onHide() I'd like to tell you in the next article.)

Accordingly, in the left part of the screen appears a view FirstPagePresenter'. On button click we call the implementation method onShowFormBtnClicked() in FirstPagePresenter described in the interface FirstPageUiHandlers

Challenge:
the
 showFormBtn.addClickHandler(new ClickHandler() { 
@Override
public void onClick(ClickEvent event) {
getUiHandlers().onShowFormBtnClicked(); 
}
});


in FirstPagePresenter' e, the following occurs:

the
 addToPopupSlot(firstPagePopupPresenter, true);


We cetim presenter pop-up when PC in slot. As I mentioned, pop-UPS, the game does not need to be identified. The only condition that the presenter is invoked which should popup itself is in a slot of the parent and so on up the chain. The second parameter in the method addToPopupSlot() specifies whether to center the popup in the application window(the method has several overloads and this option is in General optional).

After the popup appears at the window, we can enter some data and click confirm. Next, in a similar way view pop-up when PC via getUiHandlers() calls a handler in your presenter, and he in turn throws through the EventBus event that is subscribed to FirstPagePresenter (if anyone's interested, something about events in GWT I could tell in the next post):

the
 @Override
public void onPopupEvent(PopupEvent event) {
showForm(false);
eventBus.fireEvent(new FirstPageEvent(event.getFirstName(), event.getLastName())); 
}


First, in the method showForm() we remove the popup from the slot

the
removeFromPopupSlot(firstPagePopupPresenter);


Then, throw new event ( now FirstPageEvent) on. Having our MainPagePresenter:

the
 @Override
public void onFirstPageEvent(FirstPageEvent event) {
// close the left and open the right content , which is through event passing the name
showRightContent();
MainPageEvent mainPageEvent = new MainPageEvent( MainPageEvent.Action.SHOW_FORM_RESULT, event.getFirstName(), event.getLastName());
eventBus.fireEvent(mainPageEvent);
}


After receiving his MainPagePresenter removes the slot from the first page and inserts the second

the
 public void showRightContent() {
removeFromSlot(SLOT_FIRST_PAGE, firstPagePresenter);
getView().setInSlot(SLOT_SECOND_PAGE, secondPagePresenter); 
}


He further polylam already MainPageEvent on. It setit is not only the name but also Action.

Our SecondPagePresenter received event in the method onMainPageEvent() decides what to show on the page. In this case, the normal widgets without presenters.

the
 @Override
public void onMainPageEvent(MainPageEvent event) {
switch(event.getAction()) {
case SHOW_FORM_RESULT:
showFormInfoWidget(event.getFirstName(), event.getLastName());
break;
case SHOW_LOREM_IPSUM:
showLoremIpsumWidget();
break;
default:
break; 
} 
}


That's all. Perhaps to some it may seem that for such a simple action, too much code, but:
the
  • We do not break principles of MVP view should know nothing about your presenter
  • the
  • Dividing an application into modules code becomes more reusable and flexible


  • Also for sure some will be outraged — why such a long chain of transmission events? However, we notice that the received event, the presenter, before sending the next, making any operations. For example, remove unnecessary presenters or handles once the received data.

    In General, I hope this article will be to someone the useful and will turn his gaze in the direction of GWT-Platform.

    PS: I apologize for some of the narrative confusion and possible errors. This is my first post on IT themes. Criticism and tips are very welcome.
    Article based on information from habrahabr.ru

    Комментарии

    Популярные сообщения из этого блога

    ODBC Firebird, Postgresql, executing queries in Powershell

    garage48 for the first time in Kiev!

    The Ministry of communications wants to ban phones without GLONASS