/* FakerMatrixModel.java
{{IS_NOTE
Purpose:
Description:
History:
Feb 23, 2012 2:29:27 PM , Created by jumperchen
}}IS_NOTE
Copyright (C) 2012 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.support.bivision;
import java.util.AbstractList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.zkoss.lang.Objects;
import org.zkoss.zkmax.zul.MatrixModel;
import org.zkoss.zul.AbstractListModel;
import org.zkoss.zul.event.ListDataEvent;
import org.zkoss.zul.ext.Sortable;
/**
* A faker MatrixModel is used to handle a unlimited big table data.
* @author jumperchen
*/
public class FakerMatrixModel
extends
AbstractListModel implements MatrixModel, Sortable {
// a rendering function
private interface Fun {
public T apply(int index);
}
// A faker of key list implementation that contains a key to speed up the performance.
// Because Java Collection framework didn't handle it well for huge data, it will
// go through whole the list entries to receive the value for those methods,
// hashCode(), equals(), and toString()
private class FakerKeyList extends AbstractList {
final int _size;
Map _updateCache = new HashMap ();
final Fun> _fn;
final String _key;
public FakerKeyList(int size, int key, Fun> fn) {
_size = size;
_key = key + "_" + size;
_fn = fn;
}
@Override
public int size() {
return _size;
}
@Override
public boolean isEmpty() {
return _size == 0;
}
@Override
public T get(int index) {
// if changed, returns the changed value
Object val = _updateCache.get(String.valueOf(index));
if (val != null)
return (T) val;
return (T) _fn.apply(index);
}
@Override
public T set(int index, T element) {
_updateCache.put(String.valueOf(index), element);
return element;
}
@Override
public int hashCode() {
return _key.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
if (obj instanceof FakerKeyList) {
return _key.equals(((FakerKeyList)(obj))._key);
}
return false;
}
@Override
public String toString() {
return _key;
}
}
private int _colSize;
private int _rowSize;
private Map> _rowCache;
private List _headerData;
private Comparator _sorting;
private boolean _sortDir = true;
@SuppressWarnings("unchecked")
public void sort(Comparator cmpr, boolean ascending) {
_sorting = cmpr;
_sortDir = ascending;
fireEvent(ListDataEvent.STRUCTURE_CHANGED, -1, -1);
}
public String getSortDirection(Comparator cmpr) {
if (Objects.equals(_sorting, cmpr))
return _sortDir ? "ascending" : "descending";
return "natural";
}
public FakerMatrixModel(int colSize, int rowSize) {
_colSize = colSize;
_rowSize = rowSize;
_rowCache = new HashMap>();
_headerData = new FakerKeyList(colSize, 0, new Fun() {
public Object apply(int index) {
return "Header x = " + index;
}});
}
public void update(Integer[] axis, String value) {
List list = _rowCache.get(String.valueOf(axis[1]));
list.set(axis[0], value);
this.fireEvent(ListDataEvent.CONTENTS_CHANGED, axis[0], axis[1]);
}
public void setSize(int colSize, int rowSize) {
_colSize = colSize;
_rowSize = rowSize;
this.fireEvent(ListDataEvent.STRUCTURE_CHANGED, -1, -1);
}
@SuppressWarnings("unchecked")
public Row getElementAt(int index) {
final int rowIndex = _sortDir ? index : getSize() - index - 1; // handle the sorting
final String key = String.valueOf(rowIndex);
List value = _rowCache.get(key);
if (value == null) {
value = new FakerKeyList(_colSize, rowIndex, new Fun() {
public Object apply(int index) {
return "y = " + rowIndex;
}});
_rowCache.put(key, value);
}
return (Row) value;
}
public int getSize() {
return _rowSize;
}
public int getColumnSize() {
return _colSize;
}
public int getHeadSize() {
return 1;
}
@SuppressWarnings("unchecked")
public Head getHeadAt(int rowIndex) {
return (Head) _headerData;
}
@SuppressWarnings("unchecked")
public Cell getCellAt(Row rowData, int columnIndex) {
return (Cell) rowData.get(columnIndex);
}
@SuppressWarnings("unchecked")
public Header getHeaderAt(Head headData, int columnIndex) {
return (Header) headData.get(columnIndex);
}
}
|