package de.skuzzle.polly.sdk.httpv2.html;
import java.lang.ref.WeakReference;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import de.skuzzle.polly.http.api.AlternativeAnswerException;
import de.skuzzle.polly.http.api.HttpEvent;
import de.skuzzle.polly.http.api.HttpEvent.RequestMode;
import de.skuzzle.polly.http.api.HttpException;
import de.skuzzle.polly.http.api.HttpSession;
import de.skuzzle.polly.http.api.answers.HttpAnswer;
import de.skuzzle.polly.http.api.answers.HttpAnswers;
import de.skuzzle.polly.http.api.handler.HttpEventHandler;
import de.skuzzle.polly.sdk.FormatManager;
import de.skuzzle.polly.sdk.Messages;
import de.skuzzle.polly.sdk.MyPolly;
import de.skuzzle.polly.sdk.Types;
import de.skuzzle.polly.sdk.User;
import de.skuzzle.polly.sdk.httpv2.GsonHttpAnswer;
import de.skuzzle.polly.sdk.httpv2.SuccessResult;
import de.skuzzle.polly.sdk.httpv2.WebinterfaceManager;
import de.skuzzle.polly.sdk.resources.Constants;
import de.skuzzle.polly.sdk.util.DirectedComparator;
import de.skuzzle.polly.sdk.util.DirectedComparator.SortOrder;
import de.skuzzle.polly.tools.math.MathUtil;
import de.skuzzle.polly.tools.strings.StringUtils;
public class HTMLTable<T> implements HttpEventHandler {
public static class BooleanCellEditor implements CellEditor {
@Override
public HTMLElement renderEditorCell(Object cellContent, boolean forFilter) {
if (forFilter) {
// if filter, cellContent is the filter string!
final String f = (String) cellContent;
final String name = "opt_" + (int) (Math.random() * 1000); //$NON-NLS-1$
final HTMLElement all = new HTMLElement("input") //$NON-NLS-1$
.attr("type", "radio") //$NON-NLS-1$ //$NON-NLS-2$
.attr("name", name) //$NON-NLS-1$
.attr("class", "filter_input") //$NON-NLS-1$ //$NON-NLS-2$
.attr("value", "") //$NON-NLS-1$ //$NON-NLS-2$
.content(Messages.tableFilterAll);
final HTMLElement selected = new HTMLElement("input") //$NON-NLS-1$
.attr("type", "radio") //$NON-NLS-1$ //$NON-NLS-2$
.attr("name", name) //$NON-NLS-1$
.attr("class", "filter_input") //$NON-NLS-1$ //$NON-NLS-2$
.attr("value", "true") //$NON-NLS-1$ //$NON-NLS-2$
.content(Messages.tableFilterTrue);
final HTMLElement unselected = new HTMLElement("input") //$NON-NLS-1$
.attr("type", "radio") //$NON-NLS-1$ //$NON-NLS-2$
.attr("name", name) //$NON-NLS-1$
.attr("class", "filter_input") //$NON-NLS-1$ //$NON-NLS-2$
.attr("value", "false") //$NON-NLS-1$ //$NON-NLS-2$
.content(Messages.tableFilterFalse);
final HTMLElement checked;
if (f.equals("")) { //$NON-NLS-1$
checked = all;
} else if (f.equals("true")) { //$NON-NLS-1$
checked = selected;
} else {
checked = unselected;
}
checked.attr("checked"); //$NON-NLS-1$
return new HTMLElementGroup().add(all).add(selected).add(unselected);
}
final HTMLElement in = new HTMLElement("input").attr("type", "checkbox"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (cellContent != null && (Boolean) cellContent) {
in.attr("checked"); //$NON-NLS-1$
}
return in;
}
@Override
public String getEditIndicator() {
return ""; //$NON-NLS-1$
}
}
public static class DateCellEditor extends TextCellEditor {
@Override
public String getEditIndicator() {
return "<img src=\"/de/skuzzle/polly/sdk/httpv2/html/date_edit.png\" height=\"16\" width=\"16\" style=\"vertical-align:middle\"/>"; //$NON-NLS-1$
}
}
public static class TextCellEditor implements CellEditor {
@Override
public HTMLElement renderEditorCell(Object cellContent, boolean forFilter) {
final String cls = forFilter ? "textbox filter_input" : "textbox edit_input"; //$NON-NLS-1$ //$NON-NLS-2$
final String content = cellContent == null ? "" : cellContent.toString(); //$NON-NLS-1$
return new HTMLElement("input") //$NON-NLS-1$
.attr("type", "text") //$NON-NLS-1$ //$NON-NLS-2$
.attr("class", cls) //$NON-NLS-1$
.attr("style", "width: 85%") //$NON-NLS-1$ //$NON-NLS-2$
.attr("value", content); //$NON-NLS-1$
}
@Override
public String getEditIndicator() {
return
"<img src=\"/de/skuzzle/polly/sdk/httpv2/html/edit.png\" height=\"16\" width=\"16\" style=\"vertical-align:middle\"/>"; //$NON-NLS-1$
}
}
public static class ToStringCellRenderer implements CellRenderer {
private final boolean escape;
private final static Pattern URL_PATTERN = Pattern.compile(
"(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"); //$NON-NLS-1$
public ToStringCellRenderer(boolean escape) {
this.escape = escape;
}
@Override
public String renderCellContent(int column, Object cellValue) {
if (cellValue == null) {
return ""; //$NON-NLS-1$
} else {
String s = cellValue.toString();
s = this.escape ? HTMLTools.escape(s) : s;
final java.util.regex.Matcher m = URL_PATTERN.matcher(s);
final StringBuffer buff = new StringBuffer();
while (m.find()) {
m.appendReplacement(buff, "<a href=\"" + m.group() + "\">" + m.group() + "</a>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
m.appendTail(buff);
s = buff.toString();
return s;
}
}
}
public static class DateCellRenderer implements CellRenderer {
@Override
public String renderCellContent(int column, Object cellValue) {
final Date date = (Date) cellValue;
if (date.getTime() == 0) {
return ""; //$NON-NLS-1$
} else {
final DateFormat df = new SimpleDateFormat("HH:mm:ss dd.MM.yyyy"); //$NON-NLS-1$
return df.format((Date) cellValue);
}
}
}
public static class BooleanCellRenderer implements CellRenderer {
@Override
public String renderCellContent(int column, Object cellValue) {
return new BooleanCellEditor()
.renderEditorCell(cellValue, false).attr("disabled").toString(); //$NON-NLS-1$
}
}
public static class NumberCellRenderer implements CellRenderer {
@Override
public String renderCellContent(int column, Object cellValue) {
final DecimalFormat nf = new DecimalFormat("0.##"); //$NON-NLS-1$
final Number number = (Number) cellValue;
if (number instanceof Integer) {
return "" + number.intValue(); //$NON-NLS-1$
}
return nf.format(number.doubleValue());
}
}
public static class TypesCellRenderer implements CellRenderer {
private final FormatManager formatter;
public TypesCellRenderer(FormatManager formatter) {
this.formatter = formatter;
}
@Override
public String renderCellContent(int column, Object cellValue) {
if (cellValue == null || !(cellValue instanceof Types)) {
return ""; //$NON-NLS-1$
}
final Types t = (Types) cellValue;
return HTMLTools.escape(t.valueString(this.formatter));
}
}
private final static String makeUrl(String baseUrl, Map<String, String> param) {
String append = "&"; //$NON-NLS-1$
if (!baseUrl.contains("?")) { //$NON-NLS-1$
append = "?"; //$NON-NLS-1$
}
final StringBuilder b = new StringBuilder(baseUrl.length());
b.append(baseUrl);
for (final Entry<String, String> e : param.entrySet()) {
b.append(append);
b.append(e.getKey());
b.append("="); //$NON-NLS-1$
b.append(e.getValue());
append = "&"; //$NON-NLS-1$
}
return b.toString();
}
private final static String SORT_COLUMN = "sort"; //$NON-NLS-1$
private final static String UPDATE_ALL = "updateAll"; //$NON-NLS-1$
private final static String SET_PAGE = "page"; //$NON-NLS-1$
private final static String SET_PAGE_SIZE = "pageSize"; //$NON-NLS-1$
private final static String FILTER_VAL = "filterVal"; //$NON-NLS-1$
private final static String FILTER_COL = "filterCol"; //$NON-NLS-1$
private final static String FILTER = "filter"; //$NON-NLS-1$
private final static String FILTER_ALL = "filter_all"; //$NON-NLS-1$
private final static String SET_VALUE = "setValue"; //$NON-NLS-1$
private final static String COLUMN = "col"; //$NON-NLS-1$
private final static String ROW = "row"; //$NON-NLS-1$
private final static String FILTER_TOGGLE = "filterToggle"; //$NON-NLS-1$
private final static int DEFAULT_PAGE_SIZE = 40;
private final class DataHolder {
private List<T> allData;
private List<T> filtered;
private List<T> view;
}
public class TableSettings {
private int sortCol;
private SortOrder[] order;
private String[] filter;
private String filterAll;
private int pageCount;
private int pageSize = DEFAULT_PAGE_SIZE;
private int page;
private boolean filterRowShown;
private WeakReference<DataHolder> data = new WeakReference<DataHolder>(null);
private Map<T, Integer> indexMap;
private String lastRefreshKeyValue;
public boolean isFilterRowShown() {
return this.filterRowShown;
}
public int getSortCol() {
return this.sortCol;
}
public int getPageCount() {
return this.pageCount;
}
public int getPage() {
return this.page;
}
public int getPageSize() {
return this.pageSize;
}
public SortOrder getOrder() {
if (this.sortCol != -1) {
return this.order[this.sortCol];
}
return SortOrder.UNDEFINED;
}
public String[] getFilter() {
return this.filter;
}
public String getFilterAll() {
return this.filterAll;
}
public boolean isFilterSet() {
if (StringUtils.isValid(this.filterAll)) {
return true;
}
for (final String s : this.filter) {
if (StringUtils.isValid(s)) {
return true;
}
}
return false;
}
@Override
public String toString() {
final DataHolder data = this.data.get();
return "[sortCol: " + this.sortCol + //$NON-NLS-1$
", filterRowShown: " + this.filterRowShown + //$NON-NLS-1$
", page: " + this.page + //$NON-NLS-1$
", pageCount: " + this.pageCount + //$NON-NLS-1$
", pageSize: " + this.pageSize + //$NON-NLS-1$
", sortOrder: " + Arrays.toString(this.order) + //$NON-NLS-1$
", filter: " + Arrays.toString(this.filter) + "]" + //$NON-NLS-1$ //$NON-NLS-2$
", all elements: " + (data != null ? data.allData.size() : "0") + //$NON-NLS-1$ //$NON-NLS-2$
", filtered elements: " + (data != null ? data.filtered.size() : "0"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
private final String tableId;
private final Map<String, Object> baseContext;
private HTMLTableModel<T> model;
private HTMLColumnSorter<T> colSorter;
private HTMLColumnFilter filter;
private final Map<Class<?>, CellEditor> editors;
private final Map<Class<?>, CellRenderer> renderers;
private final MyPolly myPolly;
private final List<HTMLModelListener<T>> listeners;
public HTMLTable(String tableId, HTMLTableModel<T> model, MyPolly myPolly) {
this.myPolly = myPolly;
this.tableId = tableId;
this.baseContext = new HashMap<>();
this.model = model;
this.colSorter = new DefaultColumnSorter<>();
this.filter = new DefaultTypeFilter(model, myPolly);
this.listeners = new ArrayList<>();
this.editors = new HashMap<>();
this.editors.put(String.class, new TextCellEditor());
this.editors.put(Object.class, new TextCellEditor());
this.editors.put(Number.class, new TextCellEditor());
this.editors.put(Integer.class, new TextCellEditor());
this.editors.put(Boolean.class, new TextCellEditor());
this.editors.put(Boolean.class, new BooleanCellEditor());
this.editors.put(Date.class, new DateCellEditor());
this.renderers = new HashMap<>();
this.renderers.put(Object.class, new ToStringCellRenderer(false));
this.renderers.put(Number.class, new ToStringCellRenderer(false));
this.renderers.put(String.class, new ToStringCellRenderer(true));
this.renderers.put(Date.class, new DateCellRenderer());
this.renderers.put(Boolean.class, new BooleanCellRenderer());
this.renderers.put(Double.class, new NumberCellRenderer());
this.renderers.put(Number.class, new NumberCellRenderer());
this.renderers.put(Integer.class, new NumberCellRenderer());
this.renderers.put(Types.class, new TypesCellRenderer(myPolly.formatting()));
}
private void fireDataProcessed(List<T> result, HttpEvent e) {
for (final HTMLModelListener<T> listener : this.listeners) {
listener.onDataProcessed(this.model, result, e);
}
}
public void addModelListener(HTMLModelListener<T> listener) {
this.listeners.add(listener);
}
public void removeModelListener(HTMLModelListener<T> listener) {
this.listeners.remove(listener);
}
public void setColumnSorter(HTMLColumnSorter<T> colModel) {
this.colSorter = colModel;
}
public HTMLColumnSorter<T> getColumnSorter() {
return this.colSorter;
}
public void setFilter(HTMLColumnFilter filter) {
this.filter = filter;
}
public Map<String, Object> getBaseContext() {
return this.baseContext;
}
@Override
@SuppressWarnings("unchecked")
public synchronized HttpAnswer handleHttpEvent(String registered, HttpEvent e,
HttpEventHandler next) throws HttpException {
final Map<String, String> params = e.parameterMap(RequestMode.GET);
// current settings for requesting user
final HttpSession s = e.getSession();
final User user = (User) s.get(WebinterfaceManager.USER);
if (!this.myPolly.roles().canAccess(user, this.model)) {
final String permDenied = Messages.htmlTablePermDenied;
throw new AlternativeAnswerException(
HttpAnswers.newStringAnswer("<tr><th colspan=\"" + //$NON-NLS-1$
this.model.getColumnCount() + "\">" + permDenied + "</th></tr>")); //$NON-NLS-1$ //$NON-NLS-2$
}
final String settingsKey = "SETTINGS_"+registered; //$NON-NLS-1$
final TableSettings settings;
synchronized (s) {
if (s.isSet(settingsKey)) {
settings = (TableSettings) s.get(settingsKey);
} else {
settings = new TableSettings();
settings.filterRowShown = true;
settings.sortCol = this.model.getDefaultSortColumn();
settings.filter = new String[this.model.getColumnCount()];
settings.order = new SortOrder[this.model.getColumnCount()];
settings.filterAll = ""; //$NON-NLS-1$
Arrays.fill(settings.filter, ""); //$NON-NLS-1$
Arrays.fill(settings.order, SortOrder.UNDEFINED);
if (settings.sortCol != -1) {
settings.order[settings.sortCol] = this.model.getDefaultSortOrder();
}
s.set(settingsKey, settings);
}
}
// check filter row toggle first because it requires no more data processing
if (params.get(FILTER_TOGGLE) != null) {
settings.filterRowShown = !settings.filterRowShown;
// just return junk answer
return HttpAnswers.newStringAnswer("ok"); //$NON-NLS-1$
}
boolean forceRefresh = false;
if (this.model.getRefreshKey() != null) {
final String refreshValue = params.get(this.model.getRefreshKey());
forceRefresh = refreshValue != settings.lastRefreshKeyValue;
settings.lastRefreshKeyValue = refreshValue;
}
DataHolder data = settings.data.get();
boolean mustRefilter = true;
if (data == null || params.get(UPDATE_ALL) != null || forceRefresh) {
data = new DataHolder();
data.allData = this.model.getData(e);
data.view = data.allData;
data.filtered = data.view;
settings.indexMap = new HashMap<>(data.allData.size());
settings.pageCount = (int) Math.ceil(data.allData.size() / (double) settings.pageSize);
int i = 0;
for (final T t : data.allData) {
settings.indexMap.put(t, i++);
}
settings.data = new WeakReference<HTMLTable<T>.DataHolder>(data);
this.updateFilter(settings, data, e);
this.updateSorting(settings, data);
this.updateViewPort(settings, data);
mustRefilter = false;
}
if (params.get(SORT_COLUMN) != null) {
// this is a sorting request
// column for which to sort
final int newSortCol = Integer.parseInt(params.get(SORT_COLUMN));
if (newSortCol < 0 || newSortCol >= this.model.getColumnCount()) {
// TODO: error
}
// last sort order of this column, reverse
final SortOrder order = settings.order[newSortCol].reverse();
// update setting
settings.order[newSortCol] = order;
settings.sortCol = newSortCol;
// sort data
this.updateSorting(settings, data);
this.updateViewPort(settings, data);
} else if (params.get(FILTER_COL) != null) {
final int filterCol = Integer.parseInt(params.get(FILTER_COL));
if (filterCol < 0 || filterCol >= this.model.getColumnCount()) {
// TODO: error
}
final String filterVal = params.get(FILTER_VAL);
settings.filter[filterCol] = filterVal == null ? "" : filterVal; //$NON-NLS-1$
this.updateFilter(settings, data, e);
this.updateSorting(settings, data);
this.updateViewPort(settings, data);
} else if (params.get(FILTER) != null && Boolean.parseBoolean(params.get(FILTER))) {
for (int i = 0; i < this.model.getColumnCount(); ++i) {
if (params.get(Integer.toString(i)) != null) {
settings.filter[i] = params.get(Integer.toString(i));
} else {
settings.filter[i] = ""; //$NON-NLS-1$
}
}
final String all = params.get(FILTER_ALL) == null
? "" //$NON-NLS-1$
: params.get(FILTER_ALL);
settings.filterAll = all;
this.updateFilter(settings, data, e);
this.updateSorting(settings, data);
this.updateViewPort(settings, data);
} else if (params.get(SET_PAGE) != null) {
final int page = Integer.parseInt(params.get(SET_PAGE));
settings.page = MathUtil.limit(page, 0, Math.max(settings.pageCount - 1, 0));
this.updateViewPort(settings, data);
} else if (params.get(SET_VALUE) != null) {
final String value = params.get(SET_VALUE);
final int col = Integer.parseInt(params.get(COLUMN));
final int row = Integer.parseInt(params.get(ROW));
final T element = this.model.getData(e).get(row);
final SuccessResult r = this.model.setCellValue(col, element,
value, user, this.myPolly);
return new GsonHttpAnswer(200, r);
} else if (e.get(SET_PAGE_SIZE) != null) {
final int pageSize = Integer.parseInt(e.get(SET_PAGE_SIZE));
settings.pageSize = pageSize;
this.updateViewPort(settings, data);
} else if (mustRefilter) {
this.updateFilter(settings, data, e);
this.updateSorting(settings, data);
this.updateViewPort(settings, data);
}
if (this.model.isFilterOnly()) {
// data should only be loaded if a filter is active
boolean hasFilter = !settings.filterAll.equals(""); //$NON-NLS-1$
for (final String filter : settings.filter) {
hasFilter |= !filter.equals(""); //$NON-NLS-1$
}
if (!hasFilter) {
// no filter is active and this is no filter request
final Map<String, Object> c = this.createContext(settings, registered, e);
c.put("noFilter", true); //$NON-NLS-1$
return HttpAnswers.newTemplateAnswer(
"de/skuzzle/polly/sdk/httpv2/html/table.html", c); //$NON-NLS-1$
}
}
final Map<String, Object> c = this.createContext(settings, registered, e);
return HttpAnswers.newTemplateAnswer(
"de/skuzzle/polly/sdk/httpv2/html/table.html", c); //$NON-NLS-1$
}
private void updateSorting(TableSettings settings, DataHolder data) {
if (settings.sortCol != -1 && this.model.isSortable(settings.sortCol)) {
if (settings.order[settings.sortCol] != SortOrder.UNDEFINED) {
final Comparator<? super T> c =
this.colSorter.getComparator(settings.sortCol, this.model);
Collections.sort(data.filtered, new DirectedComparator<>(settings.getOrder(), c));
}
}
}
private void updateViewPort(TableSettings settings, DataHolder data) {
settings.pageCount = (int) Math.ceil(data.filtered.size() / (double) settings.pageSize);
final int firstIdx = MathUtil.limit(settings.page * settings.pageSize, 0, data.filtered.size()) ;
final int lastIdx = Math.min(data.filtered.size(), firstIdx + settings.pageSize);
data.view = data.filtered.subList(firstIdx, lastIdx);
}
private void updateFilter(TableSettings s, DataHolder data, HttpEvent e) {
// filter full data
final int colCount = this.model.getColumnCount();
data.filtered = new ArrayList<>(data.allData.size());
// preprocess filters: parse each filter string
final Object[] filters = new Object[s.filter.length];
final boolean[] negate = new boolean[s.filter.length];
for (int i = 0; i < filters.length; ++i) {
if (this.model.isFilterable(i) && !s.filter[i].equals("")) { //$NON-NLS-1$
negate[i] = s.filter[i].startsWith("!"); //$NON-NLS-1$
String f = s.filter[i];
if (negate[i]) {
f = f.substring(1); // strip ! off the beginning
}
filters[i] = this.filter.getAcceptor(i).parseFilter(f);
}
}
Pattern FILTER_ALL;
final boolean negateFilterAll = s.filterAll.startsWith("!"); //$NON-NLS-1$
final String f = negateFilterAll ? s.filterAll.substring(1) : s.filterAll;
final String filterAllString = ".*" + f + ".*"; //$NON-NLS-1$ //$NON-NLS-2$
final boolean doFilterAll = !s.filterAll.equals(""); //$NON-NLS-1$
try {
FILTER_ALL = Pattern.compile(filterAllString, Pattern.CASE_INSENSITIVE);
} catch (Exception e1) {
FILTER_ALL = Pattern.compile(".*", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
}
int originalIdx = -1;
for (final T element : data.allData) {
++originalIdx; // index of current element in the original data
boolean acceptedByAll = false;
if (doFilterAll) {
for (int i = 0; i < colCount; ++i) {
if (model.isFilterable(i)) {
final Object cellContent = this.model.getCellValue(i, element);
boolean all = FILTER_ALL.matcher(cellContent.toString()).find();
if (negateFilterAll) {
all = !all;
}
acceptedByAll |= all;
if (acceptedByAll) {
break;
}
}
}
}
boolean acceptRow = true;
for (int i = 0; i < colCount; ++i) {
boolean acceptCol = true;
if (!this.model.isFilterable(i)) {
// column is not filterable
acceptCol = true;
} else {
final Object cellContent = this.model.getCellValue(i, element);
final Object colFilter = filters[i];
final boolean doFilterCol = colFilter != null;
if (doFilterCol) {
final Acceptor acceptor = this.filter.getAcceptor(i);
final boolean acceptedByCol = acceptor.accept(colFilter, cellContent);
acceptCol = doFilterAll
? acceptedByAll && acceptedByCol
: acceptedByCol;
acceptCol = negate[i] ? !acceptCol : acceptCol;
} else {
acceptCol = doFilterAll ? acceptedByAll : true;
}
}
acceptRow &= acceptCol;
}
// all filters applied, each accepted the element
// map index within the filtered- to index in the full collection
if (acceptRow) {
s.indexMap.put(element, originalIdx);
data.filtered.add(element);
}
}
this.fireDataProcessed(data.filtered, e);
}
private Map<String, Object> createContext(TableSettings settings, String registered,
HttpEvent e) {
final int minPage = Math.max(0, settings.page - 3);
final int maxPage = Math.max(0, Math.min(settings.pageCount - 1, Math.max(settings.page + 3, 6)));
final Map<String, Object> c = new HashMap<>();
HTMLTools.gainFieldAccess(c, Messages.class, "MSG"); //$NON-NLS-1$
c.put("Messages", Constants.class); //$NON-NLS-1$
c.put("settings", settings); //$NON-NLS-1$
c.put("tableModel", this.model); //$NON-NLS-1$
c.put("colSorter", this.colSorter); //$NON-NLS-1$
c.put("renderers", this.renderers); //$NON-NLS-1$
c.put("filter", this.filter); //$NON-NLS-1$
c.put("editors", this.editors); //$NON-NLS-1$
c.put("baseUrl", makeUrl(registered, this.model.getRequestParameters(e))); //$NON-NLS-1$
c.put("tId", this.tableId); //$NON-NLS-1$
c.put("data", settings.data.get().view); //$NON-NLS-1$
c.put("indexMap", settings.indexMap); //$NON-NLS-1$
c.put("requestParams", this.model.getRequestParameters(e)); //$NON-NLS-1$
c.put("minPage", minPage); //$NON-NLS-1$
c.put("maxPage", maxPage); //$NON-NLS-1$
c.put("all", settings.data.get().allData.size()); //$NON-NLS-1$
c.put("filteredSize", settings.data.get().filtered.size()); //$NON-NLS-1$
c.putAll(this.baseContext);
return c;
}
}