package hu.sch.web.wicket.components.tables;
import hu.sch.domain.Membership;
import hu.sch.domain.interfaces.MembershipTableEntry;
import hu.sch.util.HungarianStringComparator;
import hu.sch.web.wicket.components.CheckBoxHelper;
import hu.sch.web.wicket.components.CheckBoxHolder;
import hu.sch.web.wicket.components.customlinks.UserLink;
import java.io.Serializable;
import java.util.*;
import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxNavigationToolbar;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.convert.IConverter;
/**
* Egy felhasználókat listázó táblázat, amely olyan objektumokat tud listázni,
* melyek implementálják a {@link MembershipTableEntry} interfészt. Azért van
* erre szükség, mert lehet, hogy sima {@link hu.sch.domain.Membership}
* objektumokat akarunk listázni, de lehet, hogy egy wrapper segítségével
* kívánjuk mindezt megtenni.
*
* @author messo
* @since 2.3.1
* @see AjaxFallbackDefaultDataTable
*/
public abstract class MembershipTable<T extends MembershipTableEntry> implements Serializable {
protected AjaxFallbackDefaultDataTable<T, String> table;
// Ezek azért vannak itt, nem pedig a Provider-ben, hogy kívülről is hozzá lehessen
// férni, és ehhez ne kelljen az egész Providert kifelé láthatóvá tenni
public static final String SORT_BY_NAME = "name";
public static final String SORT_BY_NICKNAME = "nickname";
public static final String SORT_BY_MEMBERSHIP = "membership";
public static final String SORT_BY_SVIE = "svie";
public static final String SORT_BY_MEMBERSHIP_DURATION = "membershipStartEnd";
/**
* Konstruktor, amely létrehoz egy {@link AjaxFallbackDefaultDataTable}
* táblázatot néhány oszloppal, illetve lehetőséget ad arra, hogy egy
* konkrét osztályban még több oszlopot adhassunk hozzá. Amennyiben az
* elemek implementálják a {@link SelectableEntry} interfészt, akkor a
* táblázat jobb szélén megjelenik 1-1 checkbox, hogy ki lehessen jelölni az
* adott bejegyzést.
*
* @param id táblázat wicket id-ja
* @param items az itemek amiket listázni szeretnénk
* @param rowsPerPage hány oldal jelenjen meg egy oldal?
* @param c az elemek Class objektuma, azért, hogy lekérdezhessük,
* hogy implementálja-e a {@link SelectableEntry} interfészt
*/
public MembershipTable(String id, List<T> items, int rowsPerPage, Class<T> c) {
List<IColumn<T, String>> columns = new ArrayList<IColumn<T, String>>();
columns.add(new PanelColumn<T>("Felhasználó neve", SORT_BY_NAME) {
@Override
protected Panel getPanel(String componentId, T obj) {
return new UserLink(componentId, obj.getMembership().getUser());
}
});
columns.add(new PropertyColumn<T, String>(new Model<String>("Becenév"), SORT_BY_NICKNAME, "membership.user.nickName"));
columns.add(new PropertyColumn<T, String>(new Model<String>("Betöltött poszt"), SORT_BY_MEMBERSHIP, "membership"));
onPopulateColumns(columns);
if (SelectableEntry.class.isAssignableFrom(c)) {
columns.add(new PanelColumn<T>("") {
@Override
protected Panel getPanel(String componentId, T obj) {
return new CheckBoxHolder<T>(componentId, obj, "selected");
}
@Override
public Component getHeader(String componentId) {
return new CheckBoxHelper(componentId);
}
});
}
table = new AjaxFallbackDefaultDataTable<T, String>(id, columns,
new SortableMembershipDataProvider<T>(items), rowsPerPage);
table.addBottomToolbar(new AjaxNavigationToolbar(table));
}
/**
* Alapértelmezetten 50 emberkét jelenítsünk meg.
*
* @param id táblázat wicket id-ja
* @param items az itemek amiket listázni szeretnénk
* @param c az elemek Class objektuma, azért, hogy lekérdezhessük, hogy
* implementálja-e a {@link SelectableEntry} interfészt
* @see MembershipTable#MembershipTable(java.lang.String, java.util.List,
* int, java.lang.Class)
*/
public MembershipTable(String id, List<T> items, Class<T> c) {
this(id, items, 50, c);
}
/**
* Ezt kell a konkrét osztályokban megvalósítani, hogy egyedi oszlopokat is
* hozzáadhassunk a meglévőkhöz
*
* @param columns az oszloplista, amihez új oszlopokat adhatunk
*/
public abstract void onPopulateColumns(List<IColumn<T, String>> columns);
/**
* Lekérjük a tényleges táblázatot, ami egy {@link AjaxFallbackDefaultDataTable}
* típusú táblázat. Ezt akkor hívjuk meg praktikusan, amikor hozzáakarjuk
* adni a DOM-hoz a kész táblázatot.
*
* @return táblázat
*/
public AjaxFallbackDefaultDataTable<T, String> getDataTable() {
return table;
}
class SortableMembershipDataProvider<T extends MembershipTableEntry> extends SortableDataProvider<T, String> {
private List<T> items;
public SortableMembershipDataProvider(List<T> items) {
this.items = items;
setSort(SORT_BY_NAME, SortOrder.ASCENDING);
}
@Override
public Iterator<T> iterator(final long first, final long count) {
SortParam<String> sp = getSort();
return getIndex(sp.getProperty(), sp.isAscending()).subList((int) first, (int) (first + count)).iterator();
}
@Override
public long size() {
return items.size();
}
public List<T> getIndex(String prop, boolean asc) {
// ha növekvő 1 (nem változik az irány), ha csökkenő, akkor minden
// eredményt negálunk.
final int r = asc ? 1 : -1;
if (prop == null) {
return items;
}
if (prop.equals(SORT_BY_NAME)) {
Collections.sort(items, new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return r * o1.getMembership().getUser().compareTo(o2.getMembership().getUser());
}
});
} else if (prop.equals(SORT_BY_NICKNAME)) {
Collections.sort(items, new Comparator<T>() {
@Override
public int compare(T t0, T t1) {
// bezavar a buliba, ha valamelyik null. Ezeket inkább kézzel
// lekezeljük: rakjuk ezeket a sor elejére a ""-vel együtt.
String s0 = t0.getMembership().getUser().getNickName();
String s1 = t1.getMembership().getUser().getNickName();
if (s0 == null) {
return r * -1;
}
if (s1 == null) {
return r * 1;
}
return r * HungarianStringComparator.scompare(s0, s1);
}
});
} else if (prop.equals(SORT_BY_MEMBERSHIP)) {
final IConverter ms = Application.get().getConverterLocator().getConverter(Membership.class);
final Locale hu = new Locale("hu");
Collections.sort(items, new Comparator<T>() {
@Override
public int compare(T t0, T t1) {
return r * ms.convertToString(t0.getMembership(), hu).compareTo(ms.convertToString(t1.getMembership(), hu));
}
});
} else if (prop.equals(SORT_BY_SVIE)) {
Collections.sort(items, new Comparator<T>() {
@Override
public int compare(T t0, T t1) {
return r * t0.getMembership().getUser().compareToBySvieMemberText(t1.getMembership().getUser(),
t0.getMembership());
}
});
} else if (prop.equals(SORT_BY_MEMBERSHIP_DURATION)) {
Collections.sort(items, new Comparator<T>() {
@Override
public int compare(T t0, T t1) {
int ret = t0.getMembership().getStart().compareTo(t1.getMembership().getStart());
if (ret == 0 && t0.getMembership().getEnd() != null) {
return r * t0.getMembership().getEnd().compareTo(t1.getMembership().getEnd());
} else {
return r * ret;
}
}
});
} else {
throw new RuntimeException("uknown sort option [" + prop
+ "]. valid options: [name] , [svieMembershipType]");
}
return items;
}
@Override
public IModel<T> model(T object) {
return new Model<T>(object);
}
}
}