Fork me on GitHub

How I may use it?

You can download the latest version of library at Downloads section of its project at github and then add it to the project. To make it work correctly, you need of course to have a compatible version of mvp4g in your project (see jar name to know which version is compatible) and, currently, gwt-log.

Potentially this library is quite reliable for usage — a stable-working complex example illustrates it, and the core idea (not actual and totally-fixed one, however) version works in our project

Let me explain how concretely you may use this code if you’ve taken a decision to build a project based on it. You can see a number of scenarios below: they can be used simultaneously as a conseсuitive ones or a separate ones. Executing them one by one (however, you must repeat some actions of those until-it-is-necessary), you can write a complete application, but you can execute each action separately as application changes its need.

It is difficult to describe everything with words, sometimes it is easier to look at code examples by following the links in the order of scenario goes. Don’t hesitate to use this opportunity :).

(My method is to use enum instances to configure project navigation/pages structure, it was applied to implement this framework fast; but later, I suppose, it will be better to change this principle to annotations or xml-files, if you will not find it easy in use)

1. Application skeleton

  1. Think over the navigation system of your project, it is recommended to make it match the object-type/action scheme.
  2. Create four enum-files. These enum-files are the main and the sole page and layouts structure configuration of your project (you don’t need to worry and keep these enums reflecting actual reality, but for sure you need to store there something potentially correct):
  3. Create EntryPoint for your project and register there your enumerated portals; more of that — you need to do this before the start of mvp4g module. In future, you’ll also need to register new layouts and layout-builders here, but it is not required for this moment. See entry point LayoutingDemo.java in example.
  4. Create main page Presenter and extend it from AMainPresenter class. Nothing more special to do here. See example: page/main/presenter/MainPresenter.java.
  5. Create main page View end extend it from AMainView (see example page/main/view/MainView.java). Methods required to define:
  6. Create the main event bus that implements IsMainEventBus. In the main event bus you need to override all the methods from IsMainEventBus interface and redirect them to the main page presenter (it will handle them automatically using the abstract class). Also you need to create a module that has no differences from standard mvp4g module. See example: page/main/MainEventBus.java и page/main/MainModule.java.

2a. Making a new layout

  1. Add a new layout ID to layouts enum. See example id/L.java.
  2. If you have some, add new placeholder IDs to placeholders enum. See example id/O.java.
  3. If you need to describe layout using declarative way, create an according ui.xml file. To mark the places where portlets will be placed (placeholders), it is required to use Outlet widget. See example layout/LayoutItem.ui.xml. If you want to declare layout using standard OOP techninques, then you’ll need to use Outlet constructor.
  4. Create a layout class, inherit it from Layout. Pass a new layout ID to parent constructor. Also, pass the IDs of all placeholders owned by this layout. In the prepareOutlet() overriden method return the appropriate Outlet using the received ID. Widget must be initialized right inside the constructor. See example layout/LayoutItem.java.
  5. Register a layout in entry point using Layouts.register() method. See example LayoutingDemo.java:47.

2b. Making a new layout with state

  1. Add a new layout ID to layouts enum. See example id/L.java.
  2. If you have some, add new placeholder IDs to placeholders enum. Add there a placeholder to inform about state (I’ve called it STATUS), also if you still have no such placeholder. See example id/O.java.
  3. If you need to describe layout using declarative way, create an according ui.xml file. To mark the places where portlets will be placed (placeholders), it is required to use Outlet widget. See example layout/LayoutEdit.ui.xml. If you want to declare layout using standard OOP techninques, then you’ll need to use Outlet constructor. Remember that you’ll need a placeholder to inform about layout status.
  4. Create a layout class, inherit it from LayoutWithState. Pass a new layout ID to parent constructor. Also, pass the IDs of all placeholders owned by this layout. Pass a status placeholder ID as the last parameter. In the prepareOutlet() overriden method return the appropriate Outlet using the received ID. In prepare(State) method you may switch visibility of the inner widgets and/or perform something else using the passed state. Layout Widget must be initialized right inside the constructor. See example layout/LayoutEdit.java.
  5. Register a layout in entry point using Layouts.register() method. See example LayoutingDemo.java:47.

3. Making a page group (module)

  1. Add new group ID to groups enum. See example id/G.java.
  2. Crate a group module, no difference from mvp4g module structure. See example page/user/UserModule.java. Don’t forget to add it to ChildModules annotation of main event bus. See example page/main/MainEventBus.java.
  3. Create an event bus for your group and extend it from ChildEventBus. See example page/user/UserEventBus.java.
  4. Create a HistoryConverter and extend it from PortalsHistoryConverter. Pass a new group ID to parent constructor. Method convertFromUrl is intended to call the required method from event bus depending on the received PortalUrl/Portal (use P.by() from 1.2.1). See example page/user/history/UserHistoryConverter.java.
  5. Create your own LayoutBuilder child to work with new event bus. layout() menthod inserts portlets into placeholders and returns true, if everything gone well. It also useful to use P.by() method here. See example page/user/layout/UserLayoutBuilder.java.
  6. Register that builder in entry point using LayoutBuilders.register() method. See example LayoutingDemo.java:62.

4a. Making a complete page without state support

  1. Add a description of URL to access the page and specify the ID of layout, corresponding to the page, both in the element of pages enum. See example id/P.java.
  2. Register a navigation event for your page in the event bus of the appropriate module. See methods news(), edit() or show() of page/news/NewsEventBus.java interface.
  3. Add a call of this event to the convertFromUrl() method of your module’s HistoryConverter, in case if this portal was received. Create an on... handler method in converter for your event and return the parameters serialized to string, if there any exist — for your convenience you can use url property of the converter to construct and/or parse parameters. See example page/news/history/NewsHistoryConverter.
  4. Create a Presenter for your page and inherit it from PortalPresenter class. View interface must extend IsPortalView interface. You need to pass an ID of the current portal to the parent constructor. Presenters, like converters, has an url property, you may use to construct URLs and pass them into view. See example page/news/presenter/NewsEditPresenter.java.
  5. Create a View for your page, inherit it from Portal class. For every part of a page that planned to be inserted into a separate placeholder (a widget) you need to use a wrapping Plug widget, regardless of whether you use ui.xml or not. The root of such view must be a Plugs widget that allows to enumerate any number of Plug widgets inside it. See example page/news/view/NewsEditView.java and page/news/view/NewsEditView.ui.xml, in case of NewsEditView, the infoPlug (information block) and savePlug (“Save” button) widgets will be placed in different placeholders.
  6. On the basis of the layout you have chosen, add a page construction code to LayoutBuilder of your module. To ease the construction, register in the module’s event bus a new plug... event (taking Place as a parameter) for every widget that will be placed into placeholder. All these events must go to presenter you’ve created at p.3 and call its plug(Place, view.get...) method that physically puts widgets to placeholders. To make this work, creare a methods handling these events in this presenter, that will call a plug() method for the appropriate part of view. Then, in LayoutBuilder, call the events you’ve created one by one, passing the required placeholders IDs in parameter. This way you manage a page structure independently from its content. See example page/news/layout/NewsLayoutBuilder.java, page/news/NewsEventBus.java and page/news/presenter/NewsEditPresenter.java, for NEWS_EDIT such methods are plugItemEditor и plugSaveButton.

4b. Making a page with portlets with no state support

  1. Add a description of URL to access the page and specify the ID of layout, corresponding to the page, both in the element of pages enum. See example id/P.java.
  2. Register a navigation event for your page in the event bus of the appropriate module. See methods news(), edit() or show() of page/news/NewsEventBus.java interface.
  3. Add a call of this event to the convertFromUrl() method of your module’s HistoryConverter, in case if this portal was received. Create an on... handler method in converter for your event and return the parameters serialized to string, if there any exist — for your convenience you can use url property of the converter to construct and/or parse parameters. See example page/news/history/NewsHistoryConverter.
  4. Create a Presenter for every portlet and inherit each one of them from PortletPresenter class. Their View interface must extend IsPortletView interface. Presenters, like converters, has an url property, you may use it to construct URLs and pass them into view. See example page/news/presenter/NewsInfoPresenter.java, page/news/presenter/NewsListPresenter.java and page/news/presenter/UserCardPresenter.java.
  5. View for each of this portlets must be inherited from Portlet widget. The root of these views must be a Plug widget. See example page/news/view/NewsListView.java, page/news/view/NewsListView.ui.xml, page/news/view/NewsInfoView.java, page/news/view/NewsInfoView.ui.xml and page/news/view/UserCardView.java.
  6. On the basis of the layout you have chosen, add a page construction code to LayoutBuilder of your module. To ease the construction, register in the module’s event bus a new plug... event (taking Place as a parameter) for every widget that will be placed into placeholder. All these events must go to the appropriate presenters you’ve created at p.3 and call their inherited plug(Place) method that physically puts widgets to placeholders. In this case the view is unambiguous, you don’t need to override something manually in presenters. Then, in LayoutBuilder, call the events you’ve created one by one, passing the required placeholders IDs in parameter. This way you manage a page structure independently from its content. See example page/news/layout/NewsLayoutBuilder.java and page/news/NewsEventBus.java. For NEWS_SHOW such methods are plugNewsInfo, plugUserCard and plugTestWidget. For NEWS_LIST such methods are plugNewsList, plugUserCard and plugTestWidget.

4c. Making a complete page with state support

  1. Add a description of URL to access the page and specify the ID of layout, corresponding to the page, both in the element of pages enum. See example id/P.java.
  2. Register a navigation event for your page in the event bus of the appropriate module. See methods users(), edit() or show() of page/user/UserEventBus.java interface.
  3. Add a call of this event to the convertFromUrl() method of your module’s HistoryConverter, in case if this portal was received from history. Create an on... handler method in converter for your event and return the parameters serialized to string, if there any exist — for your convenience you can use url property of the converter to construct and/or parse parameters. See example page/user/history/UserHistoryConverter.
  4. Create a Presenter for your page and inherit it from StatedPortalPresenter class. View interface must extend IsStatedPortalView interface. You need to pass an ID of the current portal to the parent constructor. To change view state, you just need to call the corresponding method of state property in the given moment (i.e. state.noData(), state.loading(), state.noMatches(), state.gotData()…). By default, all view supporting states are in the LOADING state. Presenters, like converters, has an url property, you may use to construct URLs and pass them into view. See example page/user/presenter/UserEditPresenter.java.
  5. Create a View for your page, inherit from StatedPortal class. For every part of a page that planned to be inserted into a separate placeholder (a widget) you need to use a wrapping Plug widget, regardless of whether you use ui.xml or not. The root of such view must be a Plugs widget that allows to enumerate any number of Plug widgets inside it. For each of supported states of the view, (you are not required to create/register all of the possible states) you also need to create a separate Plug. After this, in createView method, using register(State, Plug) method, you need to bind them to the corresponding states. See example page/user/view/UserEditView.java and page/user/view/UserEditView.ui.xml, in case of UserEditView, the infoPlug (information block), avatarPlug, agePlug and testPlug (just a “Test Widget” phrase) widgets will be placed in different placeholders; ifEmpty and whenLoading blocks are correspond to NO_DATA and LOADING states, they are registered in createView method.
  6. On the basis of the layout you have chosen, add a page construction code to LayoutBuilder of your module. The state of the page comes to layout method as parameter, among with others, you may use it to build a different variants of the page, layout is ready for it. To ease the construction, register in the module’s event bus a new plug... event (taking Place as a parameter) for every widget and for every supported state that will be placed into placeholder. All these events must go to presenter you’ve created at p.3 and call its plug(Place, view.get...) method that physically puts widgets to placeholders or one the plugEmpty/plugNoMatches/plugLoading methods for the states, the latter ones are already defined. To make this work, creare a methods handling these events in this presenter, that will call a plug() method for the appropriate part of view. Once again, for the event that plug states, you don’t need to create anything in presenters. Then, in LayoutBuilder, call the events you’ve created one by one, passing the required placeholders IDs in parameter (STATUS placeholder for any state-widget). This way you manage a page structure and state independently from its content. See example page/user/layout/UserLayoutBuilder.java ветка USER_EDIT, page/user/UserEventBus.java и page/user/presenter/UserEditPresenter.java, for USER_EDIT such methods are plugInfoEditor, plugAgeEditor, plugAvatarEditor are plugTestWidget.

4d. Making a complete page containing portlets, where all or some of them have state support

  1. Add a description of URL to access the page and specify the ID of layout, corresponding to the page, both in the element of pages enum. See example id/P.java.
  2. Register a navigation event for your page in the event bus of the appropriate module. See methods users(), edit() or show() of page/user/UserEventBus.java interface.
  3. Add a call of this event to the convertFromUrl() method of your module’s HistoryConverter, in case if this portal was received from history. Create an on... handler method in converter for your event and return the parameters serialized to string, if there any exist — for your convenience you can use url property of the converter to construct and/or parse parameters. See example page/user/history/UserHistoryConverter.
  4. Create a Presenter for every portlet and inherit each one of them from StatedPortletPresenter (or PortletPresenter, if don’t need state support for this widget) class. To change the state of portlet view you just need to call the corresponding method of state property in the given moment (i.e. state.noData(), state.loading(), state.noMatches(), state.gotData()…). By default, all view supporting states are in a LOADING state. Their View interface must extend IsPortletView interface. Presenters, like converters, has an url property, you may use it to construct URLs and pass them into view. See example page/user/presenter/UserAvatarPresenter.java, page/user/presenter/UserDetailsPresenter.java, page/user/presenter/UserInfoPresenter.java и page/user/UserListPresenter.
  5. View for each of this portlets must be inherited from StatedPortlet widget (or Portlet, if this widget has no states). The root element of the view with state must be a Plugs widget, containing a Plug widgets with the main and secondary supported states. To bind the state widgets to the corresponding states, use register(Plug, State) methods inside the createView realization. For stateless view, the root element must be a Plug, it will be a main view itself, so everything is simple here. See example views with states: page/user/view/UserAvatarView.java, page/user/view/UserAvatarView.ui.xml, page/user/view/UserDetailsView.java, page/user/view/UserDetailsView.ui.xml, page/user/view/UserInfoView.java, page/user/view/UserInfoView.ui.xml, without states: page/news/view/NewsInfoView.java, page/news/view/NewsInfoView.ui.xml.
  6. On the basis of the layout you have chosen, add a page construction code to LayoutBuilder of your module. To ease the construction, register in the module’s event bus a new plug... event (taking Place as a parameter) for every widget that will be placed into placeholder. All these events must go to the appropriate presenters you’ve created at p.3 and call their inherited plug(Place) method that physically puts widgets to placeholders. In this case the view is unambiguous, you don’t need to override something manually in presenters. Then, in LayoutBuilder, call the events you’ve created one by one, passing the required placeholders IDs in parameter. This way you manage a page structure independently from its content. See example page/user/layout/UserLayoutBuilder.java и page/user/UserEventBus.java. For USER_SHOW such methods are plugUserInfo, plugUserAvatar and plugUserDetails. For USERS_LIST such methods are plugUserInfo, plugUserAvatar and plugUsersList.

[Contents]