/*
* Copyright 2012 Cedric Hauber
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.errai.mvp.client.presenters;
import com.google.gwt.event.shared.GwtEvent.Type;
import com.google.web.bindery.event.shared.EventBus;
import org.jboss.errai.mvp.client.events.ChangeTabEvent;
import org.jboss.errai.mvp.client.events.ChangeTabHandler;
import org.jboss.errai.mvp.client.events.RequestTabsEvent;
import org.jboss.errai.mvp.client.events.RequestTabsHandler;
import org.jboss.errai.mvp.client.proxy.ProxyManager;
import org.jboss.errai.mvp.client.proxy.TabContentProxy;
import org.jboss.errai.mvp.client.views.Tab;
import org.jboss.errai.mvp.client.views.TabPanel;
import org.jboss.errai.mvp.client.views.View;
/**
* A {@link Presenter} that can display many tabs and the content of one of these tabs.
* Note that this presenter is only meant to be used when the content are themselves
* {@link Presenter}, if they are {@link org.jboss.errai.mvp.client.presenters.PresenterWidget} then no special mechanism is
* required and you can rely on a standard widget.
* <p />
* Classes extending {@link TabContainerPresenter} must declare one constant of type
* {@link com.google.gwt.event.shared.GwtEvent.Type Type<RequestTabsHandler>}
* and annotate it with {@link com.gwtplatform.mvp.client.annotations.RequestTabs RequestTabs}.
* For example:
* <pre>
*{@literal @}RequestTabs
* public static final Type<RequestTabsHandler> TYPE_RequestTabs =
* new Type<RequestTabsHandler>();
* </pre>
* {@link Presenter} meant to appear within a {@link TabContainerPresenter} main
* content area should be associated to a
* {@link org.jboss.errai.mvp.client.proxy.TabContentProxy TabContentProxy}
* or a {@link org.jboss.errai.mvp.client.proxy.TabContentProxyPlace TabContentProxyPlace}.
*
* @param <V> The specific type of the {@link org.jboss.errai.mvp.client.views.View}. Must implement {@link org.jboss.errai.mvp.client.views.TabPanel}.
*
* @author Philippe Beaudoin
* @author Christian Goudreau
*/
public abstract class TabContainerPresenter<V extends View & TabPanel>
extends Presenter<V> {
private final Type<RequestTabsHandler> requestTabsEventType;
private final Object tabContentSlot;
/**
* Creates a {@link TabContainerPresenter} that uses automatic binding. This will
* only work when instantiating this object using Guice/GIN dependency injection.
* See {@link org.jboss.errai.mvp.client.presenters.HandlerContainerImpl#HandlerContainerImpl()} for more details on
* automatic binding.
*
* @param eventBus The {@link com.google.web.bindery.event.shared.EventBus}.
* @param view The {@link View}.
* @param tabContentSlot An opaque object identifying the slot in which the
* main content should be displayed.
* @param requestTabsEventType The {@link com.google.gwt.event.shared.GwtEvent.Type} of the object to fire to
* identify all the displayed tabs.
*/
public TabContainerPresenter(EventBus eventBus, V view,
Object tabContentSlot, Type<RequestTabsHandler> requestTabsEventType,
Type<ChangeTabHandler> changeTabType) {
super(eventBus, view);
this.tabContentSlot = tabContentSlot;
this.requestTabsEventType = requestTabsEventType;
if (changeTabType != null) {
eventBus.addHandler(changeTabType, new ChangeTabHandler() {
@Override
public void onChangeTab(ChangeTabEvent event) {
TabContentProxy<?> tabProxy = event.getTabContentProxy();
getView().changeTab(tabProxy.getTab(), tabProxy.getTabData(),
tabProxy.getTargetHistoryToken());
}
});
}
}
/**
* Creates a {@link TabContainerPresenter} that uses automatic binding. This will only work when
* instantiating this object using Guice/GIN dependency injection. See
* {@link HandlerContainerImpl#HandlerContainerImpl()} for more details on automatic binding.
* This version of the constructor does not allow dynamically modifying the tabs after they were
* created.
*
* @param eventBus The {@link com.google.web.bindery.event.shared.EventBus}.
* @param view The {@link View}.
* @param proxy The {@link Proxy}.
* @param tabContentSlot An opaque object identifying the slot in which the
* main content should be displayed.
* @param requestTabsEventType The {@link com.google.gwt.event.shared.GwtEvent.Type} of the object to fire to
* identify all the displayed tabs.
*/
public TabContainerPresenter(EventBus eventBus, V view,
Object tabContentSlot, Type<RequestTabsHandler> requestTabsEventType) {
this(eventBus, view, tabContentSlot, requestTabsEventType, null);
}
/**
* Adds a new tab to this presenter. This is meant to be called by a
* {@link TabContentProxy} in response to a {@link RequestTabsEvent}.
*
* @param tabProxy The {@link TabContentProxy} containing information on the tab to add.
* @return The newly added {@link org.jboss.errai.mvp.client.views.Tab}.
*/
public Tab addTab(final TabContentProxy<?> tabProxy) {
return getView().addTab(tabProxy.getTabData(), tabProxy.getTargetHistoryToken());
}
@Override
public void setInSlot(Object slot, PresenterWidget<?> content) {
super.setInSlot(slot, content);
// TODO: Consider switching this to an event bus based mechanism where the
// child presenter fires an event when it is revealed and the parent highlights the tab.
// If we're setting a presenter attached to an actual slot, then highlight the tab
if (slot == tabContentSlot) {
try {
Presenter<?> presenter = (Presenter<?>) content;
TabContentProxy<?> proxy = (TabContentProxy<?>) ProxyManager.getPresenterProxy(presenter.getClass());
getView().setActiveTab(proxy.getTab());
} catch (Exception e) {
// We can't cast, no worry, we just won't highlight a tab
}
}
}
@Override
protected void onBind() {
super.onBind();
// The following call will trigger a series of call to addTab, so
// we should make sure we clear all the tabs when unbinding.
RequestTabsEvent.fire(this, requestTabsEventType, this);
}
@Override
protected void onUnbind() {
super.onUnbind();
// The tabs are added indirectly in onBind() via the RequestTabsEvent, so we
// clear them now.
getView().removeTabs();
}
}