Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.primefaces.component.api.UITable Maven / Gradle / Ivy
/*
* The MIT License
*
* Copyright (c) 2009-2023 PrimeTek Informatics
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.primefaces.component.api;
import java.text.Collator;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UINamingContainer;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import org.primefaces.component.column.ColumnBase;
import org.primefaces.component.headerrow.HeaderRow;
import org.primefaces.expression.SearchExpressionFacade;
import org.primefaces.expression.SearchExpressionHint;
import org.primefaces.expression.SearchExpressionUtils;
import org.primefaces.model.ColumnMeta;
import org.primefaces.model.FilterMeta;
import org.primefaces.model.SortMeta;
import org.primefaces.util.ComponentUtils;
import org.primefaces.util.LangUtils;
public interface UITable extends ColumnAware, MultiViewStateAware {
/**
* ID of the global filter component
*/
String GLOBAL_FILTER_COMPONENT_ID = "globalFilter";
String getVar();
String getClientId(FacesContext context);
default Map initFilterBy(FacesContext context) {
Map filterBy = new LinkedHashMap<>();
AtomicBoolean filtered = new AtomicBoolean();
// build columns filterBy
forEachColumn(c -> {
FilterMeta meta = FilterMeta.of(context, getVar(), c);
if (meta != null) {
filterBy.put(meta.getColumnKey(), meta);
filtered.set(filtered.get() || meta.isActive());
}
return true;
});
// merge internal filterBy with user filterBy
Object userFilterBy = getFilterBy();
if (userFilterBy != null) {
updateFilterByWithUserFilterBy(context, filterBy, userFilterBy, filtered);
}
// build global filterBy
updateFilterByWithGlobalFilter(context, filterBy, filtered);
// finally set if default filtering is enabled
setDefaultFilter(filtered.get());
setFilterByAsMap(filterBy);
return filterBy;
}
default void updateFilterByWithMVS(FacesContext context, Map tsFilterBy) {
boolean defaultFilter = isDefaultFilter();
for (Map.Entry entry : tsFilterBy.entrySet()) {
FilterMeta intlFilterBy = getFilterByAsMap().get(entry.getKey());
if (intlFilterBy != null) {
FilterMeta tsFilterMeta = entry.getValue();
intlFilterBy.setFilterValue(tsFilterMeta.getFilterValue());
defaultFilter |= intlFilterBy.isActive();
}
// #7325 restore global filter value
if (FilterMeta.GLOBAL_FILTER_KEY.equals(entry.getKey())) {
UIComponent globalFilterComponent = SearchExpressionFacade
.resolveComponent(context, (UIComponent) this, GLOBAL_FILTER_COMPONENT_ID, SearchExpressionUtils.SET_NONE);
if (globalFilterComponent != null && globalFilterComponent instanceof ValueHolder) {
((ValueHolder) globalFilterComponent).setValue(entry.getValue().getFilterValue());
}
}
}
setDefaultFilter(defaultFilter);
}
default void updateFilterByWithUserFilterBy(FacesContext context, Map intlFilterBy, Object usrFilterBy,
AtomicBoolean filtered) {
Collection filterByTmp;
if (usrFilterBy instanceof FilterMeta) {
filterByTmp = Collections.singletonList((FilterMeta) usrFilterBy);
}
else if (!(usrFilterBy instanceof Collection)) {
throw new FacesException("filterBy expects a single or a collection of FilterMeta");
}
else {
filterByTmp = (Collection) usrFilterBy;
}
for (FilterMeta userFM : filterByTmp) {
FilterMeta intlFM = intlFilterBy.values().stream()
.filter(o -> Objects.equals(o.getField(), userFM.getField()) || Objects.equals(o.getColumnKey(), userFM.getColumnKey()))
.findAny()
.orElseThrow(() -> new FacesException("No column with field '" + userFM.getField()
+ "' or columnKey '" + userFM.getColumnKey() + "' has been found"));
ValueExpression filterByVE = userFM.getFilterBy();
if (filterByVE == null) {
filterByVE = UIColumn.createValueExpressionFromField(context, getVar(), userFM.getField());
}
intlFM.setFilterValue(userFM.getFilterValue());
intlFM.setFilterBy(filterByVE);
intlFM.setConstraint(userFM.getConstraint());
intlFM.setMatchMode(userFM.getMatchMode());
filtered.set(filtered.get() || userFM.isActive());
}
}
default void updateFilterByWithGlobalFilter(FacesContext context, Map filterBy, AtomicBoolean filtered) {
// #globalFilter sets the default value, which will be assigned to the "globalFilter" input
String globalFilterDefaultValue = getGlobalFilter();
// if #globalFilter is set, the "globalFilter" is mandatory
Set hint = LangUtils.isBlank(globalFilterDefaultValue)
? SearchExpressionUtils.SET_IGNORE_NO_RESULT
: SearchExpressionUtils.SET_NONE;
UIComponent globalFilterComponent = SearchExpressionFacade
.resolveComponent(context, (UIComponent) this, GLOBAL_FILTER_COMPONENT_ID, hint);
if (globalFilterComponent != null) {
if (globalFilterComponent instanceof ValueHolder) {
((ValueHolder) globalFilterComponent).setValue(globalFilterDefaultValue);
}
FilterMeta globalFilterBy = FilterMeta.of(globalFilterDefaultValue, getGlobalFilterFunction());
filterBy.put(globalFilterBy.getColumnKey(), globalFilterBy);
filtered.set(filtered.get() || globalFilterBy.isActive());
}
}
default boolean isColumnFilterable(FacesContext context, UIColumn column) {
Map filterBy = getFilterByAsMap();
if (filterBy.containsKey(column.getColumnKey())) {
return true;
}
// lazy init - happens in cases where the column is initially not rendered
FilterMeta f = FilterMeta.of(context, getVar(), column);
if (f != null) {
filterBy.put(f.getColumnKey(), f);
}
setFilterByAsMap(filterBy);
return f != null;
}
default void updateFilterByValuesWithFilterRequest(FacesContext context, Map filterBy) {
Map params = context.getExternalContext().getRequestParameterMap();
char separator = UINamingContainer.getSeparatorChar(context);
FilterMeta globalFilter = filterBy.get(FilterMeta.GLOBAL_FILTER_KEY);
if (globalFilter != null) {
globalFilter.setFilterValue(
params.get(((UIComponent) this).getClientId(context) + separator + FilterMeta.GLOBAL_FILTER_KEY));
}
forEachColumn(column -> {
FilterMeta filterMeta = filterBy.get(column.getColumnKey());
if (filterMeta == null || filterMeta.isGlobalFilter()) {
return true;
}
if (column instanceof DynamicColumn) {
((DynamicColumn) column).applyModel();
}
UIComponent filterFacet = column.getFilterComponent();
boolean hasCustomFilter = ComponentUtils.shouldRenderFacet(filterFacet);
Object filterValue;
if (hasCustomFilter) {
filterValue = ((ValueHolder) filterFacet).getLocalValue();
}
else {
String valueHolderClientId = column instanceof DynamicColumn
? column.getContainerClientId(context) + separator + "filter"
: column.getClientId(context) + separator + "filter";
filterValue = params.get(valueHolderClientId);
}
if (filterValue != null) {
// this is not absolutely necessary, but in case the result is null, it prevents to execution of the next statement
filterValue = FilterMeta.resetToNullIfEmpty(filterValue);
}
if (filterValue != null) {
ValueExpression columnFilterValueVE = column.getValueExpression(ColumnBase.PropertyKeys.filterValue.toString());
if (columnFilterValueVE != null && List.class.isAssignableFrom(columnFilterValueVE.getType(context.getELContext()))) {
filterValue = Arrays.asList((Object[]) filterValue);
}
}
filterMeta.setFilterValue(filterValue);
return true;
});
}
default Object getFilterValue(UIColumn column) {
return getFilterByAsMap().get(column.getColumnKey()).getFilterValue();
}
boolean isDefaultFilter();
void setDefaultFilter(boolean defaultFilter);
Object getFilterBy();
void setFilterBy(Object filterBy);
boolean isFilterByAsMapDefined();
Map getFilterByAsMap();
void setFilterByAsMap(Map sortBy);
/**
* Returns actives filter meta.
* @return map with {@link FilterMeta#getField()} as key and {@link FilterMeta} as value
*/
default Map getActiveFilterMeta() {
return getFilterByAsMap().values().stream()
.filter(FilterMeta::isActive)
.collect(Collectors.toMap(FilterMeta::getField, Function.identity()));
}
String getGlobalFilter();
void setGlobalFilter(String globalFilter);
MethodExpression getGlobalFilterFunction();
void setGlobalFilterFunction(MethodExpression globalFilterFunction);
boolean isGlobalFilterOnly();
void setGlobalFilterOnly(boolean globalFilterOnly);
default Map initSortBy(FacesContext context) {
Map sortBy = new LinkedHashMap<>();
AtomicBoolean sorted = new AtomicBoolean();
HeaderRow headerRow = getHeaderRow();
if (headerRow != null) {
SortMeta meta = SortMeta.of(context, getVar(), headerRow);
sortBy.put(meta.getColumnKey(), meta);
sorted.set(true);
}
forEachColumn(c -> {
SortMeta meta = SortMeta.of(context, getVar(), c);
if (meta != null) {
sorted.set(sorted.get() || meta.isActive());
sortBy.put(meta.getColumnKey(), meta);
}
return true;
});
// merge internal sortBy with user sortBy
Object userSortBy = getSortBy();
if (userSortBy != null) {
updateSortByWithUserSortBy(context, sortBy, userSortBy, sorted);
}
setDefaultSort(sorted.get());
setSortByAsMap(sortBy);
return sortBy;
}
default void updateSortByWithMVS(Map tsSortBy) {
boolean defaultSort = isDefaultSort();
for (Map.Entry entry : tsSortBy.entrySet()) {
SortMeta intlSortBy = getSortByAsMap().get(entry.getKey());
if (intlSortBy != null) {
SortMeta tsSortMeta = entry.getValue();
intlSortBy.setPriority(tsSortMeta.getPriority());
intlSortBy.setOrder(tsSortMeta.getOrder());
defaultSort |= intlSortBy.isActive();
}
}
setDefaultSort(defaultSort);
}
default void updateSortByWithUserSortBy(FacesContext context, Map intlSortBy, Object usrSortBy, AtomicBoolean sorted) {
Collection sortBy;
if (usrSortBy instanceof SortMeta) {
sortBy = Collections.singletonList((SortMeta) usrSortBy);
}
else if (!(usrSortBy instanceof Collection)) {
throw new FacesException("sortBy expects a single or a collection of SortMeta");
}
else {
sortBy = (Collection) usrSortBy;
}
for (SortMeta userSM : sortBy) {
SortMeta intlSM = intlSortBy.values().stream()
.filter(o -> Objects.equals(o.getField(), userSM.getField()) || Objects.equals(o.getColumnKey(), userSM.getColumnKey()))
.findAny()
.orElseThrow(() -> new FacesException("No column with field '" + userSM.getField()
+ "' or columnKey '" + userSM.getColumnKey() + "' has been found"));
ValueExpression sortByVE = userSM.getSortBy();
if (sortByVE == null) {
sortByVE = UIColumn.createValueExpressionFromField(context, getVar(), userSM.getField());
}
intlSM.setPriority(userSM.getPriority());
intlSM.setOrder(userSM.getOrder());
intlSM.setSortBy(sortByVE);
intlSM.setFunction(userSM.getFunction());
sorted.set(sorted.get() || userSM.isActive());
}
}
default SortMeta getHighestPriorityActiveSortMeta() {
return getSortByAsMap().values().stream()
.filter(SortMeta::isActive)
.min(Comparator.comparingInt(SortMeta::getPriority))
.orElse(null);
}
/**
* Returns actives sort meta. See {@link SortMeta#compareTo(SortMeta)}
* @return map with {@link SortMeta#getField()} as key and {@link SortMeta} as value
*/
default Map getActiveSortMeta() {
return getSortByAsMap().values().stream()
.filter(SortMeta::isActive)
.sorted()
.collect(Collectors.toMap(SortMeta::getField, Function.identity(), (o1, o2) -> o1, LinkedHashMap::new));
}
default boolean isSortingCurrentlyActive() {
return getSortByAsMap().values().stream().anyMatch(SortMeta::isActive);
}
default boolean isColumnSortable(FacesContext context, UIColumn column) {
Map sortBy = getSortByAsMap();
if (sortBy.containsKey(column.getColumnKey())) {
return true;
}
// lazy init - happens in cases where the column is initially not rendered
SortMeta s = SortMeta.of(context, getVar(), column);
if (s != null) {
sortBy.put(s.getColumnKey(), s);
}
setSortByAsMap(sortBy);
return s != null;
}
default String getSortMetaAsString() {
return getActiveSortMeta().values().stream()
.map(SortMeta::getColumnKey)
.collect(Collectors.joining("','", "['", "']"));
}
default boolean isSortingEnabled() {
return !getSortByAsMap().isEmpty();
}
default HeaderRow getHeaderRow() {
return null;
}
Map getSortByAsMap();
void setSortByAsMap(Map sortBy);
default boolean isFilteringEnabled() {
return isFilterByAsMapDefined() && !getFilterByAsMap().isEmpty();
}
Object getSortBy();
void setSortBy(Object sortBy);
boolean isDefaultSort();
void setDefaultSort(boolean defaultSort);
default void decodeColumnTogglerState(FacesContext context) {
String columnTogglerStateParam = context.getExternalContext().getRequestParameterMap()
.get(getClientId(context) + "_columnTogglerState");
if (columnTogglerStateParam == null) {
return;
}
Map columMeta = getColumnMeta();
columMeta.values().stream().forEach(s -> s.setVisible(null));
if (LangUtils.isNotBlank(columnTogglerStateParam)) {
String[] columnStates = columnTogglerStateParam.split(",");
for (String columnState : columnStates) {
if (LangUtils.isBlank(columnState)) {
continue;
}
int seperatorIndex = columnState.lastIndexOf('_');
String columnKey = columnState.substring(0, seperatorIndex);
boolean visible = Boolean.parseBoolean(columnState.substring(seperatorIndex + 1));
ColumnMeta meta = columMeta.computeIfAbsent(columnKey, k -> new ColumnMeta(k));
meta.setVisible(visible);
}
}
if (isMultiViewState()) {
UITableState state = getMultiViewState(true);
state.setColumnMeta(columMeta);
}
}
default void decodeColumnResizeState(FacesContext context) {
String columnResizeStateParam = context.getExternalContext().getRequestParameterMap()
.get(getClientId(context) + "_resizableColumnState");
if (columnResizeStateParam == null) {
return;
}
Map columMeta = getColumnMeta();
columMeta.values().stream().forEach(s -> s.setWidth(null));
String tableWidth = null;
if (LangUtils.isNotBlank(columnResizeStateParam)) {
String[] columnStates = columnResizeStateParam.split(",");
for (String columnState : columnStates) {
if (LangUtils.isBlank(columnState)) {
continue;
}
if ((getClientId(context) + "_tableWidthState").equals(columnState)) {
tableWidth = columnState;
setWidth(tableWidth);
}
else {
int seperatorIndex = columnState.lastIndexOf('_');
String columnKey = columnState.substring(0, seperatorIndex);
String width = columnState.substring(seperatorIndex + 1);
ColumnMeta meta = columMeta.computeIfAbsent(columnKey, k -> new ColumnMeta(k));
meta.setWidth(width);
}
}
}
if (isMultiViewState()) {
UITableState state = getMultiViewState(true);
state.setWidth(tableWidth);
state.setColumnMeta(columMeta);
}
}
String getWidth();
void setWidth(String width);
default void decodeColumnDisplayOrderState(FacesContext context) {
Map params = context.getExternalContext().getRequestParameterMap();
String columnOrderParam = params.get(getClientId(context) + "_columnOrder");
if (LangUtils.isBlank(columnOrderParam)) {
return;
}
Map columMeta = getColumnMeta();
columMeta.values().stream().forEach(s -> s.setDisplayPriority(0));
String[] columnKeys = columnOrderParam.split(",");
for (int i = 0; i < columnKeys.length; i++) {
String columnKey = columnKeys[i];
if (LangUtils.isBlank(columnKey)) {
continue;
}
ColumnMeta meta = columMeta.computeIfAbsent(columnKey, k -> new ColumnMeta(k));
meta.setDisplayPriority(i);
}
if (isMultiViewState()) {
UITableState ts = getMultiViewState(true);
ts.setColumnMeta(columMeta);
}
}
default String getColumnsWidthForClientSide() {
return getColumnMeta().entrySet()
.stream()
.filter(e -> LangUtils.isNotBlank(e.getValue().getWidth()))
.map(e -> e.getKey() + '_' + e.getValue().getWidth())
.collect(Collectors.joining(","));
}
default Object getFieldValue(FacesContext context, UIColumn column) {
Object value = UIColumn.createValueExpressionFromField(context, getVar(), column.getField()).getValue(context.getELContext());
return value;
}
default String getConvertedFieldValue(FacesContext context, UIColumn column) {
Object value = UIColumn.createValueExpressionFromField(context, getVar(), column.getField()).getValue(context.getELContext());
UIComponent component = column instanceof DynamicColumn ? ((DynamicColumn) column).getColumns() : (UIComponent) column;
Object converter = column instanceof ColumnBase ? ((ColumnBase) column).getConverter() : null;
return ComponentUtils.getConvertedAsString(context, component, converter, value);
}
default boolean isFilteringCurrentlyActive() {
return getFilterByAsMap().values().stream().anyMatch(FilterMeta::isActive);
}
default int compare(FacesContext context, String var, SortMeta sortMeta, Object o1, Object o2,
Collator collator, Locale locale) {
try {
ValueExpression ve = sortMeta.getSortBy();
context.getExternalContext().getRequestMap().put(var, o1);
Object value1 = ve.getValue(context.getELContext());
context.getExternalContext().getRequestMap().put(var, o2);
Object value2 = ve.getValue(context.getELContext());
int result;
if (sortMeta.getFunction() == null) {
//Empty check
if (value1 == null && value2 == null) {
result = 0;
}
else if (value1 == null) {
result = sortMeta.getNullSortOrder();
}
else if (value2 == null) {
result = -1 * sortMeta.getNullSortOrder();
}
else if (value1 instanceof String && value2 instanceof String) {
if (sortMeta.isCaseSensitiveSort()) {
result = collator.compare(value1, value2);
}
else {
String str1 = (((String) value1).toLowerCase(locale));
String str2 = (((String) value2).toLowerCase(locale));
result = collator.compare(str1, str2);
}
}
else {
result = ((Comparable) value1).compareTo(value2);
}
}
else {
result = (Integer) sortMeta.getFunction().invoke(context.getELContext(), new Object[]{value1, value2});
}
return sortMeta.getOrder().isAscending() ? result : -1 * result;
}
catch (Exception e) {
throw new FacesException(e);
}
}
/**
* Recalculates filteredValue after adding, updating or removing object to/from a filtered UITable.
*/
void filterAndSort();
/**
* Resets all column related state after adding/removing/moving columns.
*/
default void resetColumns() {
resetDynamicColumns();
setColumns(null);
setSortByAsMap(null);
setFilterByAsMap(null);
setColumnMeta(null);
}
default boolean hasFooterColumn() {
for (int i = 0; i < getChildCount(); i++) {
UIComponent child = getChildren().get(i);
if (child.isRendered() && (child instanceof UIColumn)) {
UIColumn column = (UIColumn) child;
if (column.getFooterText() != null || ComponentUtils.shouldRenderFacet(column.getFacet("footer"))) {
return true;
}
}
}
return false;
}
int getChildCount();
List getChildren();
}