/**
*
*/
package org.richfaces.component;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.event.AjaxEvent;
import org.ajax4jsf.model.ExtendedDataModel;
import org.richfaces.event.extdt.ChangeColumnVisibilityEvent;
import org.richfaces.event.extdt.ColumnResizeEvent;
import org.richfaces.event.extdt.DragDropEvent;
import org.richfaces.event.extdt.ExtTableFilterEvent;
import org.richfaces.event.extdt.ExtTableSortEvent;
import org.richfaces.model.ExtendedDataTableModifiableModel;
import org.richfaces.model.ExtendedTableDataModel;
import org.richfaces.model.FilterField;
import org.richfaces.model.ModifiableModel;
import org.richfaces.model.SortField2;
/**
* JSF component class
*
*/
public abstract class UIExtendedDataTable extends UIDataTable implements
Selectable, Filterable, Sortable2 {
/**
* COMPONENT_TYPE
*/
public static final String COMPONENT_TYPE = "org.richfaces.ExtendedDataTable";
/**
* COMPONENT_FAMILY
*/
public static final String COMPONENT_FAMILY = "org.richfaces.ExtendedDataTable";
protected ExtendedDataTableState state;
public abstract Object getActiveRowKey();
public abstract void setActiveRowKey(Object activeRowKey);
public void broadcast(FacesEvent event) throws AbortProcessingException {
super.broadcast(event);
if (event instanceof AjaxEvent) {
//TODO nick - add regions from component too
AjaxContext.getCurrentInstance().addComponentToAjaxRender(this);
} else if (event instanceof DragDropEvent) {
processDradDrop((DragDropEvent) event);
} else if (event instanceof ChangeColumnVisibilityEvent) {
processChangeColumnVisibility((ChangeColumnVisibilityEvent) event);
} else if (event instanceof ColumnResizeEvent) {
processColumnResize((ColumnResizeEvent) event);
} else if (event instanceof ExtTableSortEvent) {
processSortingChange((ExtTableSortEvent) event);
} else if (event instanceof ExtTableFilterEvent) {
processFilteringChange((ExtTableFilterEvent) event);
}
}
public void queueEvent(FacesEvent event) {
if(event.getSource() instanceof UIExtendedDataTable) {
if (event instanceof AjaxEvent) {
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else if (event instanceof DragDropEvent) {
new AjaxEvent(this).queue();
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else if (event instanceof ChangeColumnVisibilityEvent) {
new AjaxEvent(this).queue();
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else if (event instanceof ColumnResizeEvent) {
event.setPhaseId(PhaseId.RENDER_RESPONSE);
} else if (event instanceof ExtTableSortEvent) {
new AjaxEvent(this).queue();
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
} else if (event instanceof ExtTableFilterEvent) {
new AjaxEvent(this).queue();
event.setPhaseId(PhaseId.APPLY_REQUEST_VALUES);
}
}
super.queueEvent(event);
}
public Iterator<UIColumn> getSortedColumns() {
return new SortedColumnsIterator(this);
}
public Iterator<UIColumn> getChildColumns() {
return new ExtendedTableColumnsIterator(this);
}
public void processDradDrop(DragDropEvent event) {
String dragValue = event.getDragValue().toString();// dnd_drag_script
String dropValue = event.getDropValue().toString();// dnd_drop_script
ensureTableStateInitialized();
state.changeColumnsOrder(dragValue, dropValue, event.isDropBefore());
state.publishChanges(getFacesContext(), this);
getFacesContext().renderResponse();
}
public List<UIComponent> getSortedChildren() {
ensureTableStateInitialized();
return state.sortColumns(getFacesContext(), super.getChildren());
}
public void ensureTableStateInitialized() {
if (state == null) {
state = ExtendedDataTableState.getExtendedDataTableState(this);
}
}
public void processChangeColumnVisibility(ChangeColumnVisibilityEvent event) {
ensureTableStateInitialized();
state.toggleColumnVisibility(this, event.getColumnId());
state.publishChanges(getFacesContext(), this);
getFacesContext().renderResponse();
}// processChangeColumnVisibility
public void processSortingChange(ExtTableSortEvent event) {
resetModel();
getFacesContext().renderResponse();
}
public void processFilteringChange(ExtTableFilterEvent event) {
resetModel();
resetGroupVisibilityState();
getFacesContext().renderResponse();
}
public boolean isColumnVisible(UIComponent column) {
ensureTableStateInitialized();
return state.isColumnVisible(column.getId());
}// isColumnVisible
public void processColumnResize(ColumnResizeEvent event) {
ensureTableStateInitialized();
state.changeColumnSize(this, event.getColumnWidths());
state.publishChanges(getFacesContext(), this);
getFacesContext().renderResponse();
}// processChangeColumnVisibility
public String getColumnSize(UIComponent column) {
ensureTableStateInitialized();
return state.getColumnSize(column);
}
public boolean isGroupingOn() {
ensureTableStateInitialized();
return state.isGroupingOn();
}
public String getGroupingColumnId() {
ensureTableStateInitialized();
return state.getGroupingColumnId();
}
public UIColumn getGroupingColumn() {
String groupingColumnId = getGroupingColumnId();
if (groupingColumnId == null)
return null;
for (Iterator<UIColumn> columns = getChildColumns(); columns.hasNext();) {
UIColumn child = columns.next();
if (groupingColumnId.equalsIgnoreCase(child.getId())) {
return child;
}
}
return null;
}// getGroupingColumn
public void setGroupingColumn(org.richfaces.component.UIColumn column) {
ensureTableStateInitialized();
if (column == null) {
state.disableGrouping();
} else {
state.groupBy(column.getId(), column.getSortOrder());
}
state.publishChanges(getFacesContext(), this);
}
protected void resetGroupVisibilityState() {
ensureTableStateInitialized();
state.resetGroupVisibilityState();
}
public void disableGrouping() {
ensureTableStateInitialized();
state.disableGrouping();
state.publishChanges(getFacesContext(), this);
}
public boolean groupIsExpanded(int index) {
ensureTableStateInitialized();
return state.groupIsExpanded(index);
}
public void toggleGroup(int index) {
ensureTableStateInitialized();
state.toggleGroup(index);
state.publishChanges(getFacesContext(), this);
}
public Collection<Object> getSortPriority() {
Collection<Object> priority = super.getSortPriority();
if (isGroupingOn()) {// grouping is on
String groupColId = getGroupingColumnId();
// try to add group column id as first
//TODO nick - is it ok to change user's priorities collection here?
if (priority.contains(groupColId)) {
priority.remove(groupColId);
}
if (priority instanceof List) {
((List<Object>) priority).add(0, groupColId);
} else {
priority.add(groupColId);
}
}
return priority;
}
public Object saveState(FacesContext context) {
Object values[] = new Object[2];
values[0] = super.saveState(context);
values[1] = state;
return values;
}
public void restoreState(FacesContext context, Object state) {
Object values[] = (Object[]) state;
super.restoreState(context, values[0]);
this.state = (ExtendedDataTableState) values[1];
}
public int getVisibleColumnsCount() {
int count = 0;
for (Iterator<UIColumn> iter = getChildColumns(); iter.hasNext();) {
UIColumn column = iter.next();
if (column.isRendered())
count++;
}// for
return count;
}// getVisibleColumnnCount
// @Override
@SuppressWarnings("unchecked")
protected ExtendedDataModel createDataModel() {
List<FilterField> filterFields = new LinkedList<FilterField>();
Map<String, SortField2> sortFieldsMap = new LinkedHashMap<String, SortField2>();
List<UIComponent> list = getChildren();
for (Iterator<UIComponent> iterator = list.iterator(); iterator
.hasNext();) {
UIComponent component = iterator.next();
if (component instanceof org.richfaces.component.UIColumn) {
org.richfaces.component.UIColumn column = (org.richfaces.component.UIColumn) component;
FilterField filterField = column.getFilterField();
if (filterField != null) {
filterFields.add(filterField);
}
SortField2 sortField = column.getSortField();
if (sortField != null) {
sortFieldsMap.put(component.getId(), sortField);
}
}
}
List<SortField2> sortFields = new LinkedList<SortField2>();
Collection<Object> sortPriority = getSortPriority();
if (sortPriority != null) {
for (Object object : sortPriority) {
if (object instanceof String) {
String id = (String) object;
SortField2 sortField = sortFieldsMap.get(id);
if (sortField != null) {
sortFields.add(sortField);
sortFieldsMap.remove(id);
}
}
}
}
sortFields.addAll(sortFieldsMap.values());
setFilterFields(filterFields);
setSortFields(sortFields);
ExtendedDataModel dataModel = (ExtendedDataModel) super.getDataModel();
if (dataModel instanceof ExtendedTableDataModel<?>) {
ExtendedTableDataModel<?> tableDataModel = (ExtendedTableDataModel<?>) dataModel;
return new ExtendedDataTableModifiableModel(tableDataModel,
getVar(), getFilterFields(), getSortFields());
} else {
ModifiableModel modifiableModel = new ModifiableModel(dataModel,
getVar());
modifiableModel.modify(getFilterFields(), getSortFields());
return modifiableModel;
}
}
/**
* Original version of this method is defined in
* {@link org.ajax4jsf.component.UIDataAdaptor} and is called before
* RENDER_RESPONSE phase. In that version data model is reseted which causes
* need to sort and filter every time component is rendered.
*/
// @Override
protected void resetDataModel() {
// Do not reset only for ExtendedTableDataModel model
if (!(getDataModel() instanceof ExtendedTableDataModel<?>)) {
super.resetDataModel();
}
}
/**
* Method resets data model by calling
* {@link org.ajax4jsf.component.UIDataAdaptor#resetDataModel()}. This
* method is called on sort and filter action.
*/
protected void resetModel() {
super.resetDataModel();
}
}