Вы можете скачать последнюю версию библиотеки в разделе Downloads её проекта на github и добавить её в свой проект. Для корректной работы библиотеки, естественно, требуется наличие в проекте jar
-файла совместимой версии mvp4g
и, на данный момент, gwt-log
.
Потенциально библиотека вполне надёжна для использования — сложно-составной пример работает стабильно, а ядро этой идеи (правда, устаревшая и невылизанная версия — актуальную встроить пока нет возможности) работает в нашем проекте.
Поясню, как пользоваться всем этим кодом, если вы решили разработать на его основе проект. Ниже представлены одновременно последовательные и отдельные сценарии — выполнив их по очереди (на некоторых переходя в цикл “повторять несколько раз пока необходимо”) можно написать всё приложение целиком, но и после этого каждое из действий можно выполнять отдельно, по мере потребности изменений в приложении.
Словами описать можно отнюдь не всё, иногда удобнее взглянуть по ссылкам на примеры в приведённой очередности. Не проходите мимо этой возможности :).
тип-объекта/действие
.enum
-файла. Эти четыре enum
-файла — главная и единственная конфигурация структуры страниц и лэйатуов в проекте (они не должны сразу же отражать действительность, но что-то потенциально реальное в них всё же должно быть):
тип-объекта/действие
) и связывания их с лэйаутами. Для каждой страницы автоматически создаётся ID по методу id()
(в примере в качестве ID везде берётся name()
элемента из enum
, но это может быть что угодно) и привязывается к созданному инстансу класса Portal
: для этого enum
должен имплементить интерфейс PortalId
. Также вам понадобится быстрый способ получить значение enum
из идентификатора Portal
: в примере это метод by(Portal page)
, для этого инстансы Portal
хранятся внутри.Group
: возвращать уникальный ID в методе id()
.LayoutId
: возвращать уникальный ID в методе id()
.Place
: возвращать уникальный ID в методе id()
.EntryPoint
вашего проекта и зарегистрировать в нём описанные порталы, причём выполнить это до запуска модуля mvp4g. В дальнейшем тут же нужно будет регистрировать новые лэйауты и лэйаут-билдеры, но в данный момент это необязательно. см. точку входа LayoutingDemo.java в примере.Presenter
главной страницы и отнаследовать его от AMainPresenter. Ничего больше особенного здесь делать не нужно. см. page/main/presenter/MainPresenter.java в примере.View
главной страницы и отнаследовать его от AMainView (см. page/main/view/MainView.java в примере). Методы, которые требуется определить:
getLayoutHolder()
должен возвращать панель, в которую будет “вставляться” лэйаут.getPortalHolder()
может возвращать панель, оборачивающую предыдущую, а может ту же самую. Этот метод применяется только для назначения CSS-классов, классы портала и лэйаута будут назначены одному элементу в последнем случае.getScrollable()
может возвращать область, которая будет скроллиться внутри страницы. Если такой области нет, метод может возвращать null
, но тогда не будет работать подписка на скролл-события страницы по шине событий (addPageScrollHandler
).IsMainEventBus
и перенаправить их в презентер главной страницы . Также нужно создать главный модуль, ничем не отличающийся от главного модуля mvp4g. см. page/main/MainEventBus.java и page/main/MainModule.java в примере.enum
лэйатуов. см. в примере id/L.java.enum
плейсхолдеров. см. в примере id/O.java.ui.xml
. В этом ui.xml
для обозначения мест, куда будут вставляться портлеты (плейсхолдеров) потребуется использовать виджет Outlet. см. layout/LayoutItem.ui.xml в примере. Можно описывать лэйаут и не декларативно, тогда придётся создавать плэйсхолдеры используя конструктор Outlet. Не забудьте, что вам нужен плейсходер для информировании о статусе.prepareOutlet()
возвратите нужный Outlet
по переданному идентификатору. Виджет должен инициироваться прямо в конструкторе. см. layout/LayoutItem.java в примере.Layouts.register()
. см. LayoutingDemo.java:47 в примере.enum
лэйатуов. см. в примере id/L.java.enum
плейсхолдеров. Туда же добавьте плейсхолдер для информирования о состоянии (я назвал его STATUS
), если вы его ещё не завели. см. в примере id/O.java.ui.xml
. В этом ui.xml
для обозначения мест, куда будут вставляться портлеты (плейсхолдеров) потребуется использовать виджет Outlet. Для места, куда будет вставляться сообщение о состоянии тоже подготовьте плэйсхолдер. см. layout/LayoutEdit.ui.xml в примере. Можно описывать лэйаут и не декларативно, тогда придётся создавать плэйсхолдеры используя конструктор Outlet.prepareOutlet()
возвратите нужный Outlet
по переданному идентификатору. В методе prepare(State)
вы можете по переданному состоянию переключать видимость тех или иных виджетов внутри лэйаута и/или делать что-то ещё, если нужно. Виджет должен инициироваться прямо в конструкторе. см. layout/LayoutEdit.java в примере.Layouts.register()
. см. LayoutingDemo.java:47 в примере.enum
для групп. см. в примере id/G.java.ChildModules
главной шины событий. см. в примере page/main/MainEventBus.java.HistoryConverter
и отнаследуйте его от PortalsHistoryConverter. Передайте в родительский конструктор идентификатор группы. Метод convertFromUrl
предназначен для того, чтобы по полученным PortalUrl
/Portal
(используйте метод P.by()
из пункта 1.2.1) вызвать нужный метод в шине событий. см. в примере page/user/history/UserHistoryConverter.java.layout()
вставляет портлеты в плейсходеры и вовращает true
, если всё прошло удачно. здесь также удобно использовать метод P.by()
. см. в примере page/user/layout/UserLayoutBuilder.java.LayoutBuilders.register()
. см. LayoutingDemo.java:62 в примере.enum
для страниц. см. в примере id/P.java.news()
, edit()
и show()
в интерфейсе page/news/NewsEventBus.java.convertFromUrl()
у HistoryConverter
вашего модуля добавьте вызов этого события, если по истории был получен ваш портал. Создайте в конвертере метод on...
для вашего события и возвратите отконвертированные параметры, если они есть — для удобства можно использовать проперти url
конвертера. см. в примере page/news/history/NewsHistoryConverter.Presenter
вашей страницы и отнаследуйте его от класса PortalPresenter. Интерфейс View
должен расширять интерфейс IsPortalView. В конструктор нужно передать идентификатор портала, которому соответствует презентер. У презентера, как и у конвертера, также есть проперти url
, вы можете использовать его для построения URL и передаче их во view
. см. в примере page/news/presenter/NewsEditPresenter.java.View
вашей страницы, отнаследовав его от класса Portal. Для каждой части страницы (виджета), которая будет вставлена в отдельный плейсходер, нужно использовать оборачивающий виджет Plug, независимо от того, используете вы ui.xml
или нет. Корневым элементом для view
должен быть виджет Plugs, который позволяет перечислить внутри нёго несколько виджетов Plug
. см. в примере page/news/view/NewsEditView.java и page/news/view/NewsEditView.ui.xml, в случае NewsEditView
в разные плейсхолдеры будут вставлены infoPlug
(блок с информацией) и savePlug
(кнопка “Save”).LayoutBuilder
вашего модуля. Для сборки зарегистрируйте в шине событий модуля по одному новому событию plug...
(принимающему в параметре Place
) для каждого виджета, который будет вставляться в плейсхолдер. Эти события должны уходить в презентер, созданный в п.3 и вызывать в нём метод plug(Place, view.get...)
, физически вставляя виджеты в плейсхолдеры. Для этого создайте в презентере методы, перехватывающие эти события и вызывающие plug()
с нужной частью view
. Затем, в LayoutBuilder
-е, вызовите созданные события поочерёдно, передавая в параметре соответствующие идентификаторы плейсхолдеров. см. в примере page/news/layout/NewsLayoutBuilder.java, page/news/NewsEventBus.java и page/news/presenter/NewsEditPresenter.java, для NEWS_EDIT
это методы plugItemEditor
и plugSaveButton
.enum
для страниц. см. в примере id/P.java.news()
, edit()
и show()
интерфейса page/news/NewsEventBus.java.convertFromUrl()
у HistoryConverter
вашего модуля добавьте вызов этого события, если по истории был получен ваш портал. Создайте в конвертере метод on...
для вашего события и возвратите отконвертированные параметры, если они есть — для удобства можно использовать проперти url
конвертера. см. в примере page/news/history/NewsHistoryConverter.Presenter
и отнаследуйте каждый от класса PortletPresenter. Интерфейс View
у них должен расширять интерфейс IsPortletView. У презентера, как и у конвертера, также есть проперти url
, вы можете использовать его для построения URL и передаче их во view
. см. в примере page/news/presenter/NewsInfoPresenter.java, page/news/presenter/NewsListPresenter.java и page/news/presenter/UserCardPresenter.java.View
каждого из портлетов должен наследоваться от виджета Portlet. Корневым элементом для этих view
должен быть виджет Plug. см. в примере page/news/view/NewsListView.java, page/news/view/NewsListView.ui.xml, page/news/view/NewsInfoView.java, page/news/view/NewsInfoView.ui.xml и page/news/view/UserCardView.java.LayoutBuilder
вашего модуля. Для сборки зарегистрируйте в шине событий модуля по одному новому событию plug...
(принимающему в параметре Place
) для каждого виджета, который будет вставляться в плейсхолдер. Эти события должны уходить в презентеры, созданные в п.3 и вызывать в них отнаследованный метод plug(Place)
, физически вставляя виджеты в плейсхолдеры. Поскольку в данном случае view
однозначен, переопределять в презентерах ничего не нужно. Затем, в LayoutBuilder
-е, вызовите созданные события поочерёдно, передавая в параметре соответствующие идентификаторы плейсхолдеров. см. в примере page/news/layout/NewsLayoutBuilder.java и page/news/NewsEventBus.java. Для NEWS_SHOW
это методы plugNewsInfo
, plugUserCard
и plugTestWidget
. Для NEWS_LIST
это методы plugNewsList
, plugUserCard
и plugTestWidget
.enum
для страниц. см. в примере id/P.java.users()
, edit()
и show()
интерфейса page/user/UserEventBus.java.convertFromUrl()
у HistoryConverter
вашего модуля добавьте вызов этого события, если по истории был получен ваш портал. Создайте в конвертере метод on...
для вашего события и возвратите отконвертированные параметры, если они есть — для удобства можно использовать проперти url
конвертера. см. в примере page/user/history/UserHistoryConverter.Presenter
вашей страницы и отнаследуйте его от класса StatedPortalPresenter. Интерфейс View
должен расширять интерфейс IsStatedPortalView. В конструктор нужно передать идентификатор портала, которому соответствует презентер. Для изменения состояния вида достаточно вызвать в необходимый момент подходящий метод у проперти state
(например, state.noData()
, state.loading()
, state.noMatches()
, state.gotData()
…). По умолчанию виды с состояниями имеют состояние LOADING
. У презентера, как и у конвертера, также есть проперти url
, вы можете использовать его для построения URL и передаче их во view
. см. в примере page/user/presenter/UserEditPresenter.java.View
вашей страницы, отнаследовав его от класса StatedPortal. Для каждой части страницы (виджета), которая будет вставлена в отдельный плейсходер, нужно использовать оборачивающий виджет Plug, независимо от того, используете вы ui.xml
или нет. Корневым элементом для view
должен быть виджет Plugs, который позволяет перечислить внутри нёго несколько виджетов Plug
. Для каждого из необходимых состояний вида (можно регистрировать/создавать не все) также надо создать отдельный Plug
. После этого, используя метод register(State, Plug)
, их нужно связать с соответствующим им состоянием в методе createView
см. в примере page/user/view/UserEditView.java и page/user/view/UserEditView.ui.xml, в случае UserEditView
в разные плейсхолдеры будут вставлены infoPlug
(блок с информацией), avatarPlug
, agePlug
и testPlug
(просто фраза “Test Widget”); состояниям NO_DATA
и LOADING
соответствуют блоки ifEmpty
и whenLoading
, они регистрируются в методе createView
LayoutBuilder
вашего модуля. В метод layout
кроме всего прочего приходит состояние страницы state
, его можно использовать для построения различных вариантов страницы, лэйаут уже подготовлен. Для сборки зарегистрируйте в шине событий модуля по одному новому событию plug...
(принимающему в параметре Place
) для каждого виджета и для каждого нужного вам состояния, которые будет вставляться в плейсхолдеры. Эти события должны уходить в презентер, созданный в п.3 и вызывать в нём метод plug(Place, view.get...)
, физически вставляя виджеты в плейсхолдеры или уже определённые методы plugEmpty
/plugNoMatches
/plugLoading
для состояний. Для этого создайте в презентере методы, перехватывающие события виджетов и вызывающие plug()
с нужной частью view
. Для событий “подключения” состояний ничего создавать не нужно. Затем, в LayoutBuilder
-е, вызовите созданные события поочерёдно, передавая в параметре соответствующие идентификаторы плейсхолдеров (плейсхолдер состояния для виджета состояния). см. в примере page/user/layout/UserLayoutBuilder.java ветка USER_EDIT
, page/user/UserEventBus.java и page/user/presenter/UserEditPresenter.java, для USER_EDIT
это методы plugInfoEditor
, plugAgeEditor
, plugAvatarEditor
и plugTestWidget
.enum
для страниц. см. в примере id/P.java.users()
, edit()
и show()
интерфейса page/user/UserEventBus.java.convertFromUrl()
у HistoryConverter
вашего модуля добавьте вызов этого события, если по истории был получен ваш портал. Создайте в конвертере метод on...
для вашего события и возвратите отконвертированные параметры, если они есть — для удобства можно использовать проперти url
конвертера. см. в примере page/user/history/UserHistoryConverter.Presenter
и отнаследуйте каждый от класса StatedPortletPresenter (или от PortletPresenter, если у виджета не должно быть состояний). Интерфейс View
у них должен расширять интерфейс IsStatedPortletView (или IsPortletView, если у виджета нет состояний). Для изменения состояния вида портлетов достаточно вызвать в необходимый момент подходящий метод у проперти state
(например, state.noData()
, state.loading()
, state.noMatches()
, state.gotData()
…). По умолчанию виды с состояниями имеют состояние LOADING
. У презентеров, как и у конвертера, также есть проперти url
, вы можете использовать его для построения URL и передаче их во view
. см. в примере page/user/presenter/UserAvatarPresenter.java, page/user/presenter/UserDetailsPresenter.java, page/user/presenter/UserInfoPresenter.java и page/user/UserListPresenter.View
каждого из портлетов должен наследоваться от виджета StatedPortlet (или Portlet, если виджет не имеет состояний). Корневым элементом для view
с состоянием должен быть виджет Plugs, внутри которого должны находиться виджеты Plug с основным и побочными необходимыми вам состояниями. Для того, чтобы связать виджеты состояний с соответствующими им состояниями, используйте метод register(Plug, State)
в реализации createView()
. Для view
без состояний, корневым элементом должен быть Plug, здесь всё проще — он и будет главным видом. см. в примере виды с состояниями: 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, виды без состояний: page/news/view/NewsInfoView.java, page/news/view/NewsInfoView.ui.xmlLayoutBuilder
вашего модуля. Для сборки зарегистрируйте в шине событий модуля по одному новому событию plug...
(принимающему в параметре Place
) для каждого виджета, который будет вставляться в плейсхолдер. Эти события должны уходить в презентеры, созданные в п.3 и вызывать в них отнаследованный метод plug(Place)
, физически вставляя виджеты в плейсхолдеры. Поскольку в данном случае view
однозначен, переопределять в презентерах ничего не нужно. Затем, в LayoutBuilder
-е, вызовите созданные события поочерёдно, передавая в параметре соответствующие идентификаторы плейсхолдеров. см. в примере page/user/layout/UserLayoutBuilder.java и page/user/UserEventBus.java. Для USER_SHOW
это методы plugUserInfo
, plugUserAvatar
и plugUserDetails
. Для USERS_LIST
это методы plugUserInfo
, plugUserAvatar
и plugUsersList
.