import org.primefaces.model.TreeTableModel; import org.primefaces.model.TreeNode; import javax.faces.model.DataModel; import javax.faces.event.FacesEvent; import javax.faces.event.PhaseId; import java.util.Collection; import java.util.Arrays; import java.util.Collections; import java.util.Map; import java.util.Iterator; import javax.faces.event.AjaxBehaviorEvent; import org.primefaces.util.Constants; import org.primefaces.event.NodeSelectEvent; import org.primefaces.event.NodeUnselectEvent; import org.primefaces.event.NodeExpandEvent; import org.primefaces.event.NodeCollapseEvent; import org.primefaces.event.ColumnResizeEvent; import org.primefaces.component.column.Column; import java.lang.StringBuilder; import java.util.ArrayList; import java.util.List; import java.util.Locale; import javax.faces.FacesException; import javax.faces.component.UIComponent; import javax.faces.component.UINamingContainer; import javax.faces.context.FacesContext; import org.primefaces.component.api.DynamicColumn; import org.primefaces.component.api.UIColumn; import org.primefaces.component.columngroup.ColumnGroup; import org.primefaces.component.columns.Columns; import org.primefaces.util.ComponentUtils; public final static String CONTAINER_CLASS = "ui-treetable ui-widget"; public final static String RESIZABLE_CONTAINER_CLASS = "ui-treetable ui-treetable-resizable ui-widget"; public final static String HEADER_CLASS = "ui-treetable-header ui-widget-header ui-corner-top"; public final static String DATA_CLASS = "ui-treetable-data ui-widget-content"; public final static String FOOTER_CLASS = "ui-treetable-footer ui-widget-header ui-corner-bottom"; public final static String COLUMN_HEADER_CLASS = "ui-state-default"; public static final String SORTABLE_COLUMN_HEADER_CLASS = "ui-state-default ui-sortable-column"; public final static String ROW_CLASS = "ui-widget-content"; public final static String SELECTED_ROW_CLASS = "ui-widget-content ui-state-highlight ui-selected"; public final static String COLUMN_CONTENT_WRAPPER = "ui-tt-c"; public final static String EXPAND_ICON = "ui-treetable-toggler ui-icon ui-icon-triangle-1-e ui-c"; public final static String COLLAPSE_ICON = "ui-treetable-toggler ui-icon ui-icon-triangle-1-s ui-c"; public static final String SCROLLABLE_CONTAINER_CLASS = "ui-treetable-scrollable"; public static final String SCROLLABLE_HEADER_CLASS = "ui-widget-header ui-treetable-scrollable-header"; public static final String SCROLLABLE_HEADER_BOX_CLASS = "ui-treetable-scrollable-header-box"; public static final String SCROLLABLE_BODY_CLASS = "ui-treetable-scrollable-body"; public static final String SCROLLABLE_FOOTER_CLASS = "ui-widget-header ui-treetable-scrollable-footer"; public static final String SCROLLABLE_FOOTER_BOX_CLASS = "ui-treetable-scrollable-footer-box"; public static final String SELECTABLE_NODE_CLASS = "ui-treetable-selectable-node"; public static final String RESIZABLE_COLUMN_CLASS = "ui-resizable-column"; public static final String INDENT_CLASS = "ui-treetable-indent"; public static final String EMPTY_MESSAGE_ROW_CLASS = "ui-widget-content ui-treetable-empty-message"; public final static String PARTIAL_SELECTED_CLASS = "ui-treetable-partialselected"; public static final String SORTABLE_COLUMN_ICON_CLASS = "ui-sortable-column-icon ui-icon ui-icon-carat-2-n-s"; public static final String SORTABLE_COLUMN_ASCENDING_ICON_CLASS = "ui-sortable-column-icon ui-icon ui-icon ui-icon-carat-2-n-s ui-icon-triangle-1-n"; public static final String SORTABLE_COLUMN_DESCENDING_ICON_CLASS = "ui-sortable-column-icon ui-icon ui-icon ui-icon-carat-2-n-s ui-icon-triangle-1-s"; private static final Collection<String> EVENT_NAMES = Collections.unmodifiableCollection(Arrays.asList("select","unselect", "expand", "collapse", "colResize")); private List<String> selectedRowKeys = new ArrayList<String>(); @Override public Collection<String> getEventNames() { return EVENT_NAMES; } private boolean isRequestSource(FacesContext context) { return this.getClientId(context).equals(context.getExternalContext().getRequestParameterMap().get(Constants.RequestParams.PARTIAL_SOURCE_PARAM)); } public boolean isSelectionRequest(FacesContext context) { return context.getExternalContext().getRequestParameterMap().containsKey(this.getClientId(context) + "_instantSelection"); } public boolean isSortRequest(FacesContext context) { return context.getExternalContext().getRequestParameterMap().containsKey(this.getClientId(context) + "_sorting"); } @Override public void queueEvent(FacesEvent event) { FacesContext context = getFacesContext(); if(isRequestSource(context) && (event instanceof AjaxBehaviorEvent)) { Map<String,String> params = context.getExternalContext().getRequestParameterMap(); String eventName = params.get(Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM); String clientId = this.getClientId(context); FacesEvent wrapperEvent = null; AjaxBehaviorEvent behaviorEvent = (AjaxBehaviorEvent) event; if(eventName.equals("expand")) { String nodeKey = params.get(clientId + "_expand"); this.setRowKey(nodeKey); TreeNode node = this.getRowNode(); wrapperEvent = new NodeExpandEvent(this, behaviorEvent.getBehavior(), node); wrapperEvent.setPhaseId(PhaseId.APPLY_REQUEST_VALUES); } else if(eventName.equals("collapse")) { String nodeKey = params.get(clientId + "_collapse"); this.setRowKey(nodeKey); TreeNode node = this.getRowNode(); node.setExpanded(false); wrapperEvent = new NodeCollapseEvent(this, behaviorEvent.getBehavior(), node); wrapperEvent.setPhaseId(PhaseId.APPLY_REQUEST_VALUES); } else if(eventName.equals("select")) { String nodeKey = params.get(clientId + "_instantSelection"); this.setRowKey(nodeKey); TreeNode node = this.getRowNode(); wrapperEvent = new NodeSelectEvent(this, behaviorEvent.getBehavior(), node); wrapperEvent.setPhaseId(behaviorEvent.getPhaseId()); } else if(eventName.equals("unselect")) { String nodeKey = params.get(clientId + "_instantUnselection"); this.setRowKey(nodeKey); TreeNode node = this.getRowNode(); wrapperEvent = new NodeUnselectEvent(this, behaviorEvent.getBehavior(), node); wrapperEvent.setPhaseId(behaviorEvent.getPhaseId()); } else if(eventName.equals("colResize")) { String columnId = params.get(clientId + "_columnId"); int width = Integer.parseInt(params.get(clientId + "_width")); int height = Integer.parseInt(params.get(clientId + "_height")); wrapperEvent = new ColumnResizeEvent(this, behaviorEvent.getBehavior(), width, height, findColumn(columnId)); } super.queueEvent(wrapperEvent); } else { super.queueEvent(event); } } @Override public void processDecodes(FacesContext context) { if(isToggleRequest(context)) { this.decode(context); } else { super.processDecodes(context); } } public UIColumn findColumn(String clientId) { for(UIColumn column : this.getColumns()) { if(column.getColumnKey().equals(clientId)) { return column; } } FacesContext context = this.getFacesContext(); ColumnGroup headerGroup = this.getColumnGroup("header"); for(UIComponent row : headerGroup.getChildren()) { for(UIComponent col : row.getChildren()) { if(col.getClientId(context).equals(clientId)) { return (UIColumn) col; } } } throw new FacesException("Cannot find column with key: " + clientId); } public boolean hasFooterColumn() { for(UIComponent child : getChildren()) { if(child instanceof Column && child.isRendered()) { Column column = (Column) child; if(column.getFacet("footer") != null || column.getFooterText() != null) return true; } } return false; } private boolean isToggleRequest(FacesContext context) { Map<String,String> params = context.getExternalContext().getRequestParameterMap(); String clientId = getClientId(context); return params.get(clientId + "_expand") != null || params.get(clientId + "_collapse") != null; } public boolean isResizeRequest(FacesContext context) { Map<String,String> params = context.getExternalContext().getRequestParameterMap(); String clientId = getClientId(context); return params.get(clientId + "_colResize") != null; } private int columnsCount = -1; public int getColumnsCount() { if(columnsCount == -1) { columnsCount = 0; for(UIComponent kid : getChildren()) { if(kid.isRendered() && kid instanceof Column) { columnsCount++; } } } return columnsCount; } public String getScrollState() { Map<String,String> params = getFacesContext().getExternalContext().getRequestParameterMap(); String name = this.getClientId() + "_scrollState"; String value = params.get(name); return value == null ? "0,0" : value; } public boolean isCheckboxSelection() { String selectionMode = this.getSelectionMode(); return selectionMode != null && selectionMode.equals("checkbox"); } private UIColumn sortColumn; public void setSortColumn(UIColumn column) { this.sortColumn = column; } public UIColumn getSortColumn() { return this.sortColumn; } public void clearDefaultSorted() { getStateHelper().remove("defaultSorted"); } public void setDefaultSorted() { getStateHelper().put("defaultSorted", "defaultSorted"); } public boolean isDefaultSorted() { return getStateHelper().get("defaultSorted") != null; } public Locale resolveDataLocale() { FacesContext context = this.getFacesContext(); Object userLocale = this.getDataLocale(); if(userLocale != null) { if(userLocale instanceof String) return ComponentUtils.toLocale((String) userLocale); else if(userLocale instanceof java.util.Locale) return (java.util.Locale) userLocale; else throw new IllegalArgumentException("Type:" + userLocale.getClass() + " is not a valid locale type for datatable:" + this.getClientId(context)); } else { return context.getViewRoot().getLocale(); } } public ColumnGroup getColumnGroup(String target) { for(UIComponent child : this.getChildren()) { if(child instanceof ColumnGroup) { ColumnGroup colGroup = (ColumnGroup) child; String type = colGroup.getType(); if(type != null && type.equals(target)) { return colGroup; } } } return null; } private List<UIColumn> columns; public List<UIColumn> getColumns() { if(columns == null) { columns = new ArrayList<UIColumn>(); for(UIComponent child : this.getChildren()) { if(child instanceof Column) { columns.add((UIColumn) child); } } } return columns; }