Разумно взять метод и испытать его. При неудаче честно
признайтесь в этом и попробуйте другой метод. Но главное,
делайте что-нибудь.
ФРАНКЛИН Д. РУЗВЕЛЬТ
Dynamic tabs ( IceFaces 1.8.2 )
Создание универсальных динамических табов (разных классов), довольно не простая задача, с которой мне пришлось столкнуться.
Дело в том, что компонент panelTabSet использует в качестве табов список объектов одного класса, а от сюда следует, что либо нужно создать большой класс, который включал бы в себя поля, нужные во всех табах, либо табы кастить динамически к нужным нам классам. Что я решил и сделать.При использовании моего решения, вы можете часто ловить java.lang.ClassCastException, если не будете отслеживать текущий открытый таб.
Приступим...
Создадим абстрактный класс Tab, унаследовав его от компонента Ice Faces - PanelTab. На основе Tab мы будем создавать классы наших табов.
Tab.java
package workflow.common.controls.ui.tabs;
import com.icesoft.faces.component.paneltabset.PanelTab;
import javax.faces.event.ActionEvent;
import static workflow.common.controls.ui.tabs.TabSetBean.*;
/**
* @author nicola
* @version 2.1.0 (Feb 17, 2010)
*/
public abstract class Tab extends PanelTab {
private int type;
private boolean deleted;
private String name;
private int index;
public Tab() {
this(TYPE_NONE, "", "", -1);
}
public Tab(int tabType, String tabName, String tabTitle, int index) {
setName(tabName);
setTitle(tabTitle);
this.type = tabType;
this.index = index;
this.deleted = false;
}
public void setType(int type) {
this.type = type;
}
public int getType() {
return type;
}
public boolean isDeleted() {
return deleted;
}
public void closeTab() {
this.deleted = true;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
@Override
public int hashCode() {
return super.hashCode();
}
public abstract void reload(ActionEvent event);
@Override
public boolean equals(Object object) {
......
}
}
А теперь создадим классы наших табов.
PersonTab.java
package workflow.contactmanager.beans.tabs;
import workflow.common.controls.ui.tabs.Tab;
import javax.faces.event.ActionEvent;
import static workflow.contactmanager.beans.tabs.ContactTabSetBean.*;
/**
* @author nicola
* @version 2.1.0 (Feb 17, 2010)
*/
public class PersonTab extends Tab {
private PersonTabBean personTabBean;
public PersonTab() {
this("", "", -1);
this.personTabBean = new PersonTabBean();
}
private PersonTab(String tabName, String tabTitle, int index) {
super(TYPE_PERSONS, tabName, tabTitle, index);
}
public PersonTabBean getPersonTabBean() {
return personTabBean;
}
public void setPersonTabBean(PersonTabBean personTabBean) {
this.personTabBean = personTabBean;
}
@Override
public void reload(ActionEvent event) {
this.personTabBean = new PersonTabBean();
}
}
OrganizationTab.java
package workflow.contactmanager.beans.tabs;
import workflow.common.controls.ui.tabs.Tab;
import javax.faces.event.ActionEvent;
import static workflow.contactmanager.beans.tabs.ContactTabSetBean.*;
/**
* @author nicola
* @version 2.1.0 (Feb 17, 2010)
*/
public class OrganizationTab extends Tab {
private OrganizationTabBean organizationTabBean;
public OrganizationTab() {
this("", "", -1);
this.organizationTabBean = new OrganizationTabBean();
}
private OrganizationTab(String tabName, String tabTitle, int index) {
super(TYPE_ORGANIZATIONS, tabName, tabTitle, index);
}
public OrganizationTabBean getOrganizationTabBean() {
return organizationTabBean;
}
public void setOrganizationTabBean(OrganizationTabBean organizationTabBean) {
this.organizationTabBean = organizationTabBean;
}
@Override
public void reload(ActionEvent event) {
this.organizationTabBean = new OrganizationTabBean();
}
}
Теперь нам нужно создать универсальный tabSet и унаследовать от него наш класс для управления табами.
TabSetBean.java
package workflow.common.controls.ui.tabs;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
/**
* @author nicola
* @version 2.1.0 (Feb 17, 2010)
*/
public class TabSetBean {
private static final Logger LOG = Logger.getLogger(TabSetBean.class.getName());
public static final int TYPE_NONE = -1;
private int selectedTabIndex = 0;
private List<Tab> tabs;
public TabSetBean() {
this.tabs = new ArrayList<Tab>();
}
public <T extends Tab> void addTab(T tab) {
try {
this.tabs.add(tab);
this.selectedTabIndex = this.tabs != null ? this.tabs.size() - 1 : 0;
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
public List<Tab> getTabs() {
return tabs;
}
public void setTabs(List<Tab> tabs) {
this.tabs = tabs;
}
public int getTypeNone() {
return TYPE_NONE;
}
public int getSelectedTabIndex() {
return selectedTabIndex;
}
public void setSelectedTabIndex(int selectedTabIndex) {
this.selectedTabIndex = selectedTabIndex;
}
public void removeDeletedTab() {
if (this.tabs != null) {
Iterator it = this.tabs.iterator();
int removedTabIndex = -1;
while (it.hasNext()) {
Tab tab = (Tab) it.next();
if (tab.isDeleted()) {
removedTabIndex = tab.getIndex();
it.remove();
if (this.selectedTabIndex == removedTabIndex) {
this.selectedTabIndex = (removedTabIndex == this.tabs.size())
? (removedTabIndex - 1)
: removedTabIndex;
} else {
this.selectedTabIndex--;
}
}
}
if (this.selectedTabIndex < 0) {
this.selectedTabIndex = 0;
}
reindexTabs();
}
}
public void reindexTabs() {
for (int i = 0; i < tabs.size(); i++) {
((Tab) tabs.get(i)).setIndex(i);
}
}
public int getSizeTabs() {
return (this.tabs != null ? this.tabs.size() : 0);
}
}
ContactTabSetBean.java
package workflow.contactmanager.beans.tabs;
import workflow.common.controls.ui.tabs.TabSetBean;
import workflow.common.controls.ui.tabs.Tab;
import workflow.common.controls.ui.FacesUtils;
import com.icesoft.faces.component.paneltabset.TabChangeEvent;
import com.icesoft.faces.component.paneltabset.TabChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.apache.log4j.Logger;
/**
* @author nicola
* @version 2.1.0 (Feb 17, 2010)
*/
public class ContactTabSetBean extends TabSetBean implements TabChangeListener {
private static final Logger LOG = Logger.getLogger(ContactTabSetBean.class.getName());
public static final int TYPE_ORGANIZATIONS = 1;
public static final int TYPE_PERSONS = 2;
private Tab currentTab;
public ContactTabSetBean() {
initTabs();
}
@Override
public void processTabChange(TabChangeEvent event) {
setSelectedTabIndex(event.getNewTabIndex());
this.currentTab = getCurrentTab();
}
private void initTabs() {
List<Tab> tabs = new ArrayList<Tab>();
Tab organizationContactTab = new OrganizationTab();
organizationContactTab.setType(TYPE_ORGANIZATIONS);
organizationContactTab.setName(FacesUtils.getLocalizedMessage("menu.organizations"));
organizationContactTab.setTitle(FacesUtils.getLocalizedMessage("menu.organizations"));
organizationContactTab.setIndex(tabs.size());
tabs.add(organizationContactTab);
Tab personsContactTab = new PersonTab();
personsContactTab.setType(TYPE_PERSONS);
personsContactTab.setName(FacesUtils.getLocalizedMessage("menu.persons"));
personsContactTab.setTitle(FacesUtils.getLocalizedMessage("menu.persons"));
personsContactTab.setIndex(tabs.size());
tabs.add(personsContactTab);
setTabs(tabs);
}
@Override
public void addTab(Tab tab) {
boolean hasTab = false;
try {
List<Tab> tabs = getTabs();
for (Tab tabItem : tabs){
if (tabItem != null && tabItem.equals(tab)) {
setSelectedTabIndex(tabItem.getIndex());
this.currentTab = tab;
hasTab = true;
break;
}
}
if (!hasTab) {
tab.setIndex(getTabs().size());
getTabs().add(tab);
setSelectedTabIndex(tab.getIndex());
this.currentTab = tab;
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
public void addPersonTab(ActionEvent event) {
try {
PersonTab tab = new PersonTab();
addTab(tab);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
public void addOrganizationTab(ActionEvent event) {
try {
OrganizationTab tab = new OrganizationTab();
addTab(tab);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
public int getTypeOrganizations() {
return TYPE_ORGANIZATIONS;
}
public int getTypePersons() {
return TYPE_PERSONS;
}
public OrganizationTab getOrganizationCurrenTab() {
return ( OrganizationTab )this.currentTab;
}
public PersonTab getPersonCurrenTab() {
return ( PersonTab )this.currentTab;
}
private Tab getCurrentTab() {
FacesContext context = FacesContext.getCurrentInstance();
Tab tab = null;
try {
tab = ( Tab )context.getExternalContext().getRequestMap().get( "currentTab" );
if (tab == null) {
tab = ( Tab )getTabs().get(getSelectedTabIndex());
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return tab;
}
public void closeTab(ActionEvent event) {
try {
String tabIndex = FacesUtils.getActionAttribute(event, "tabIndex");
LOG.info("tabIndex " + tabIndex);
Tab closingTab = null;
closingTab = ( Tab )getTabs().get(Integer.valueOf(tabIndex).intValue());
closingTab.closeTab();
removeDeletedTab();
this.currentTab = ( Tab )getTabs().get(getSelectedTabIndex());
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
}
}
Собственно, основные классы готовы. Пропишем теперь в faces-config.xml
<managed-bean>
<managed-bean-name>contactTabset</managed-bean-name>
<managed-bean-class>
workflow.contactmanager.beans.tabs.ContactTabSetBean
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
Теперь наш jspx сможет работать с нашим бином табов. Осталось совсем немного, прописать ice faces компонент в jspx и настроить отоброжение табов.
index.jspx
<?xml version="1.0" encoding="UTF-8" ?>
<ui:component xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ui="http://java.sun.com/jsf/facelets"
version="2.0">
<ui:composition template="/template.jspx">
<ui:define name="title">#{msgs['menu.contacts']}</ui:define>
<ui:define name="body">
<ice:panelTabSet id="contactTabSet"
immediate="true"
value="#{contactTabset.tabs}"
tabChangeListener="#{contactTabset.processTabChange}"
selectedIndex="#{contactTabset.selectedTabIndex}"
var="currentTab"
>
<ice:panelTab title="#{currentTab.title}">
<f:facet name="label">
<ice:panelGrid columns="2">
<ice:outputText value="#{currentTab.name}"/>
<ice:commandButton rendered="#{contactTabset.sizeTabs gt 1}"
image="#{styleBean.imageDirectory}cal_off.gif"
actionListener="#{contactTabset.closeTab}">
<f:attribute name="tabIndex" value="#{currentTab.index}" />
</ice:commandButton>
</ice:panelGrid>
</f:facet>
<ice:panelGroup rendered="#{currentTab.type == contactTabset.typeOrganizations}">
<ui:include src="organizations.jspx"/>
</ice:panelGroup>
<ice:panelGroup rendered="#{currentTab.type == contactTabset.typePersons}">
<ui:include src="persons.jspx"/>
</ice:panelGroup>
</ice:panelTab>
</ice:panelTabSet>
</ui:define>
</ui:composition>
</ui:component>
Код persons.jspx и organizations.jspx я не привожу, но покажу как добираться до бинов нужного вам класса.
Пример:
#{contactTabset.personCurrenTab.personTabBean.renderedPersonsPaginator}"
Собственно и все. В дальнейшем я расскажу, как повесить меню на табы и сделать их "drag and drop". В этом посте я лишь хотел показать логику создания универсальных табов, исходные классы были порезаны, поэтому могут вкраться ошибки.
Рад буду услышать Ваши отзывы.