package pl.touk.tola.gwt.client.widgets; import com.extjs.gxt.ui.client.Style.SortDir; import com.extjs.gxt.ui.client.data.*; import com.extjs.gxt.ui.client.store.ListStore; import com.extjs.gxt.ui.client.widget.form.ComboBox; import com.extjs.gxt.ui.client.widget.form.Field; import com.extjs.gxt.ui.client.widget.form.Validator; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.rpc.AsyncCallback; import pl.touk.wonderfulsecurity.gwt.client.model.PagedQueryResultReader; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import pl.touk.wonderfulsecurity.gwt.client.ui.table.provider.impl.DefaultPagingRpcProxyProvider; /** * Combo, ktore jest zasilane beanami hibernate'owymi * <p/> * Mozna go uzyc np tak: * new ComboFromDao("blabla","nazwa",pl.touk.nsw.fe.shared.model.products.SimpleProductBean.class); * * TODO: nie ma sensu ładować przy każdym kliknięciu listy z DAO * TODO: trzeba jeszcze dopracować ten komponent i lepiej opisać * * @author rpt * @author mpr * @author bzd */ public class ComboFromDao extends ComboBox<ModelData> { private static final int NO_LIMIT = 9999999; Map<String, Object> parametersToQuery = new HashMap<String, Object>(); private String lazyId; private String lazyIdProperty; private final String sortField; private String displayField; private final boolean withTips; private boolean triggerClicked = false; private final SortDir sortDir; private RemoteDataFilter dataFilter; public ComboFromDao(String label, String displayField, Class clazz, boolean editable, boolean withTips) { this(label, displayField, displayField, clazz, editable, withTips); } public ComboFromDao(String label, String displayField, Class clazz, boolean editable) { this(label, displayField, displayField, clazz, editable, false); } public ComboFromDao(String label, String displayField, String sortField, Class clazz, boolean editable, boolean withTips) { this(label, displayField, sortField, clazz, editable, withTips, SortDir.NONE); } /** * Tworzy combo o podanych parametrach. * @param label nazwa comboboxa * @param displayField pole z beana, które bedzie wyswietlane * @param sortField pole z beana, po ktorym bedzie sortowanie * @param clazz klasa z mapowaniem hiberante * @param editable czy combo ma byc edytowalne * @param withTips czy mają być podpowiedzi? * @param sortDirection kierunek sortowania (SortDir.ASC, SortDir.DESC, SortDir.NONE) */ public ComboFromDao(String label, String displayField, String sortField, Class clazz, boolean editable, boolean withTips, SortDir sortDirection) { PagingLoader<PagingLoadResult<ModelData>> loader = createLoader(sortField, clazz); setStore(new ListStore(loader)); setUpCombo(label, displayField); setEditable(editable); setTypeAhead(editable); if (editable) { setValidator(createNotNullDictionaryValidator(displayField)); } this.sortField = sortField; this.displayField = displayField; this.withTips = withTips; this.sortDir = sortDirection; this.setLazyRender(!editable); //gdy edytowalne, to wyłaczamy lazyInit'a checkForRegisteredResultFactory(clazz); } private void checkForRegisteredResultFactory(Class clazz) { BeanModelFactory beanFactory = BeanModelLookup.get().getFactory(clazz); if (beanFactory == null) { throw new RuntimeException("No BeanModelFactory found for " + clazz.getName() + " add @BeanModelMarker or implement BeanModelTag"); } } /** * Tworzy edytowalne combo o podanych parametrach. * @param label nazwa comboboxa * @param displayField pole z beana, które bedzie wyswietlane * @param clazz klasa z mapowaniem hiberante */ public ComboFromDao(String label, String displayField, Class clazz) { this(label, displayField, clazz, true); } private Validator createNotNullDictionaryValidator(final String propertyToValidate) { return new Validator() { public String validate(Field<?> field, String value) { ModelData tempValue = ComboFromDao.this.getValue(); if (tempValue == null || tempValue.get(propertyToValidate) == null) { return "Nie ma takiej wartości (spróbuj wybrać wartość z listy)."; } return null; } }; } public void load() { getStore().getLoader().load(); } private void setUpCombo(String label, String displayField) { setFieldLabel(label); setValueField(displayField); setDisplayField(displayField); } private PagingLoader<PagingLoadResult<ModelData>> createLoader(String sortField, Class clazz) { RpcProxy proxy = createProxy(clazz); PagingLoader<PagingLoadResult<ModelData>> loader = new BasePagingLoader(proxy, new PagedQueryResultReader(clazz)); return loader; } public void doQuery(String q, boolean forceAll) { triggerClicked = forceAll; super.doQuery(q, forceAll); } public RpcProxy createProxy(final Class clazz) { final DefaultPagingRpcProxyProvider defaultPagingRpcProxyProvider = new DefaultPagingRpcProxyProvider(); RpcProxy proxy = new RpcProxy() { protected void load(Object loadConfig, final AsyncCallback asyncCallback) { GWT.log("combo from dao loading: " + parametersToQuery); BasePagingLoadConfig basePagingLoadConfig = new BasePagingLoadConfig(); basePagingLoadConfig.setSortField(sortField); basePagingLoadConfig.setSortDir(sortDir); //to ponizsze musi zostac, bo inaczej jest max 50 rekordów basePagingLoadConfig.setLimit(NO_LIMIT); basePagingLoadConfig.setOffset(0); if (withTips) { if (!triggerClicked) { String newValue = getRawValue(); parametersToQuery.put(displayField + "@#LIKE_MATCH_START", newValue); } else { parametersToQuery.remove(displayField + "@#LIKE_MATCH_START"); } triggerClicked = false; } defaultPagingRpcProxyProvider.fetchPagedData(clazz, parametersToQuery, basePagingLoadConfig, getCallback(asyncCallback)); } }; return proxy; } /** * Ustawia parametr, ktory pojdzie do zapytania hibernate * * @param propertyName * @param propertyValue */ public void addQueryParameter(String propertyName, Object propertyValue) { parametersToQuery.put(propertyName, propertyValue); } /** * Usuwa juz ustawiony parametr z zapytania do bazy. * * @param propertyName */ public void removeQueryParameter(String propertyName) { parametersToQuery.remove(propertyName); } public void clearQueryParameters() { parametersToQuery.clear(); } protected AsyncCallback getCallback(final AsyncCallback original) { GWT.log("return from combo" + lazyIdProperty); return new AsyncCallback() { public void onFailure(Throwable throwable) { original.onFailure(throwable); } public void onSuccess(Object data) { original.onSuccess(filterData(data)); GWT.log("return from combo " + getStore().getCount() + " lazyIdProperty: " + lazyIdProperty + " lazyId " + lazyId); updateIdFromLazy(); } }; } private Object filterData(Object data) { if (dataFilter == null) { return data; } return dataFilter.filter(data); } public void updateIdFromLazy() { if (lazyIdProperty == null || lazyId == null) { return; } for (ModelData modelData : getStore().getModels()) { GWT.log("Found id=" + modelData.get(lazyIdProperty)); if (lazyId.equals(modelData.get(lazyIdProperty).toString())) { GWT.log("Found id=" + lazyId + " in comboBox, selecting"); setSelection(Arrays.asList(modelData)); return; } } } //TODO: o co chodzi z tym lazy ? Opisać to public void setLazyId(String lazyId) { this.lazyId = lazyId; updateIdFromLazy(); } public void setLazyIdProperty(String lazyIdProperty) { this.lazyIdProperty = lazyIdProperty; } public Long getPropertyFromSelectionAsLong(String property) { ModelData selectedModel = this.getValue(); if (selectedModel != null) { return (Long) selectedModel.get(property); } return null; } public void setDataFilter(RemoteDataFilter dataFilter) { this.dataFilter = dataFilter; } }