在点击每个主model,下方会出现几个sub tab,如下图所示,在之前的文章中分析过每个Mianmodel 的XXlistModel 之间的关系。现在来分析下sub tab的 model 又究竟是怎么一回事?
以虚拟机的mainModel为例 ,选 中一个虚拟后,下方出现了8个sub tab,
protected void initDetailModels()
{
super.initDetailModels();
ObservableCollection<EntityModel> list = new ObservableCollection<EntityModel>();
list.add(new VmGeneralModel());
list.add(new VmInterfaceListModel());
VmDiskListModel diskListModel = new VmDiskListModel();
diskListModel.setSystemTreeContext(this);
list.add(diskListModel);
list.add(new VmSnapshotListModel());
list.add(new VmEventListModel());
list.add(new VmAppListModel());
list.add(new PermissionListModel());
list.add(new VmAffinityGroupListModel());
list.add(new VmSessionsModel());
setDetailModels(list);
}
在VmlistModel,在构造方法中会调用 如上方法,初始化每个DetailMdoels的实例,以VmGeneralModel为例,该model就在ListModel中实例化,而该类中主要的逻辑为对用户行为的逻辑处理,如某个button,或者选中某个items 等。
而在所有的mainTab的Presenter的父类 AbstractMainTabWithDetailsPresenter中,在初始化时注册界面items change变化的handler,onBind实现如下
@Override
protected void onBind() {
super.onBind();
registerHandler(getTable().getSelectionModel()
.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
// Update main model selection
modelProvider.setSelectedItems(getSelectedItems());
// Let others know that the table selection has changed
fireTableSelectionChangeEvent();
// Reveal the appropriate place based on selection
handlePlaceTransition();
}
}));
}
1)首先调用model的setSelectedItems
在这一步中,
public void setSelectedItem(T value)
{
if (selectedItem != value)
{
onSelectedItemChanging(value, selectedItem);
selectedItem = value;
onSelectedItemChanged();
getSelectedItemChangedEvent().raise(this, EventArgs.EMPTY);
onPropertyChanged(new PropertyChangedEventArgs("SelectedItem")); //$NON-NLS-1$
}
}
在onSelecttedItemChanged()方法中,
根据Activate的DeatilModel
activeDetailModel.setEntity(provideDetailModelEntity(getSelectedItem()));
而setEntity,就调用
public void setEntity(T value)
{
if (entity != value)
{
entityChanging(value, entity);
entity = value;
onEntityChanged();
// EntityChanged(this, EventArgs.Empty);
getEntityChangedEvent().raise(this, EventArgs.EMPTY);
onPropertyChanged(new PropertyChangedEventArgs("Entity")); //$NON-NLS-1$
}
}
最终调用onEntityChanged()方法,从而调用具体subTab model的updateProperity()
2)发布SelectionChangeEvent,
@Override
protected void fireTableSelectionChangeEvent() {
VirtualMachineSelectionChangeEvent.fire(this, getSelectedItems());
}
而在相应的subTab的 Presenter中,就是通过
@ProxyEvent
public void onVirtualMachineSelectionChange(VirtualMachineSelectionChangeEvent event) {
updateMainTabSelection(event.getSelectedItems());
}
根据gwt注解相应的逻辑,从而调用subTab中的on**SelectionChange方法,如下 而后执行,最终调用view的 setMainTab方法,
/**
* Notifies this sub tab presenter that the main tab selection has changed.
*/
protected void updateMainTabSelection(List<T> mainTabSelectedItems) {
this.mainTabSelectedItems = mainTabSelectedItems;
T firstSelectedItem = getMainTabSelectedItem();
// Notify view of selection change
if (firstSelectedItem != null) {
getView().setMainTabSelectedItem(firstSelectedItem);
}
}
从而找到view的 方法
@Override
public void setMainTabSelectedItem(VM selectedItem) {
form.update();
}
3) 界面的显示渲染
protected void handlePlaceTransition() {
if (hasSelection()) {
// Sub tab panel is shown upon revealing the sub tab, in order to avoid
// the 'flicker' effect due to the panel still showing previous content
placeManager.revealPlace(getSubTabRequest());
} else {
// Hide sub tab panel when there is nothing selected
setSubTabPanelVisible(false);
placeManager.revealPlace(getMainTabRequest());
}
}
而后会发布 事件
protected void doRevealPlace(PlaceRequest request, boolean updateBrowserUrl) {
PlaceRequestInternalEvent requestEvent = new PlaceRequestInternalEvent(request,
updateBrowserUrl);
fireEvent(requestEvent);
if (!requestEvent.isHandled()) {
unlock();
error(tokenFormatter.toHistoryToken(placeHierarchy));
} else if (!requestEvent.isAuthorized()) {
unlock();
illegalAccess(tokenFormatter.toHistoryToken(placeHierarchy));
}
}
而对于Event的事件处理流程,简单要介绍下,
在Event的定义中,会定义一个对应handler的type,在注册时,key为type,value为handler。
public static Type<PlaceRequestInternalHandler> getType() {
if (TYPE == null) {
TYPE = new Type<PlaceRequestInternalHandler>();
}
return TYPE;
}
而fireEvent,通过EventBus,找到handler
List<H> handlers = getDispatchList(event.getAssociatedType(), source);
而后通过 event的回调disaptcher,从而执行handler的方法。
protected static <H> void dispatchEvent(Event<H> event, H handler) {
event.dispatch(handler);
}
Handler的注册
而针对 上述的handler是在何处注册,这就涉及到gwt的代理的机制,在该类中注册
ProxyPlaceAbstract,如下,就着就会处理相应的事件。
@Inject
protected void bind(final PlaceManager placeManager, EventBus eventBus) {
this.placeManager = placeManager;
this.eventBus = eventBus;
addRegisteredHandler(PlaceRequestInternalEvent.getType(), new PlaceRequestInternalHandler() {
@Override
public void onPlaceRequest(PlaceRequestInternalEvent event) {
if (event.isHandled()) {
return;
}
PlaceRequest request = event.getRequest();
if (matchesRequest(request)) {
event.setHandled();
if (canReveal()) {
handleRequest(request, event.shouldUpdateBrowserHistory());
} else {
event.setUnauthorized();
}
}
}
});
接着往下跟会发现,而这里的proxy,就是P中的成员 proxyDef. 最终将subTab的页面显示出来。