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)
object-type/action
scheme.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 enum
s reflecting actual reality, but for sure you need to store there something potentially correct):
object-type/action
scheme) and to link them to layouts. Each page gets an ID using id()
method automatically (enum
element’s name()
method serves this purpose in the example, but in fact you may use anything to do this) and gets linked to the prepared Portal
class instance: to use this trick, your enum
must implement PortalId
interface. Also you’ll need an easy way to get proper enum
value from unknown Portal
instance: in example it’s done with method by(Portal page)
, that’s the reason why Portal
instances are kept inside enum
.Group
interface: to return unique ID with id()
method.LayoutId
interface: to return unique ID with id()
method.Place
interface: to return unique ID with id()
method.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.Presenter
and extend it from AMainPresenter class. Nothing more special to do here. See example: page/main/presenter/MainPresenter.java.View
end extend it from AMainView (see example page/main/view/MainView.java). Methods required to define:
getLayoutHolder()
method must return the panel to “hold” a complete layout (it will be “injected” just there).getPortalHolder()
method may return the panel that wraps the previous one, or even the same panel. This method is only used to assign CSS-classes, so portal and layout classes will be assigned to the same element in latter case.getScrollable()
method may return the area to be scrolled inside of a page. If such area is not required, the method may return a null
value, but this behaviour will turn off subscribing page scroll-events using event bus (addPageScrollHandler
).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.enum
. See example id/L.java.enum
. See example id/O.java.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.prepareOutlet()
overriden method return the appropriate Outlet
using the received ID. Widget must be initialized right inside the constructor. See example layout/LayoutItem.java.Layouts.register()
method. See example LayoutingDemo.java:47.enum
. See example id/L.java.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.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.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.Layouts.register()
method. See example LayoutingDemo.java:47.enum
. See example id/G.java.ChildModules
annotation of main event bus. See example page/main/MainEventBus.java.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.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.LayoutBuilders.register()
method. See example LayoutingDemo.java:62.enum
. See example id/P.java.news()
, edit()
or show()
of page/news/NewsEventBus.java interface.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.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.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.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
.enum
. See example id/P.java.news()
, edit()
or show()
of page/news/NewsEventBus.java interface.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.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.View
for each of this portlets must be inherited from Portlet widget. The root of these view
s 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.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
.enum
. See example id/P.java.users()
, edit()
or show()
of page/user/UserEventBus.java interface.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.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.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.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
.enum
. See example id/P.java.users()
, edit()
or show()
of page/user/UserEventBus.java interface.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.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.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.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
.