public void doListDataChange(ListDataEvent event) { // when this is called _model is never null final ListModel _model = _listbox.getModel(); final int newsz = _model.getSize(), oldsz = _listbox.getItemCount(); int min = event.getIndex0(), max = event.getIndex1(), cnt; switch (event.getType()) { case ListDataEvent.INTERVAL_ADDED: cnt = newsz - oldsz; if (cnt <= 0) throw new UiException("Adding causes a smaller list?"); if ((oldsz <= 0 || cnt > INVALIDATE_THRESHOLD) && !inPagingMold()) _listbox.invalidate(); // Bug 3147518: avoid memory leak // Also better performance (outer better than remove a lot) if (min < 0) if (max < 0) min = 0; else min = max - cnt + 1; if (min > oldsz) min = oldsz; ListitemRenderer renderer = null; final Component next = min < oldsz ? _listbox.getItemAtIndex(min) : null; while (--cnt >= 0) { if (renderer == null) renderer = (ListitemRenderer) getRealRenderer(); _listbox.insertBefore(newUnloadedItem(renderer, min++), next); } break; case ListDataEvent.INTERVAL_REMOVED: cnt = oldsz - newsz; if (cnt <= 0) throw new UiException("Removal causes a larger list?"); if (min >= 0) max = min + cnt - 1; else if (max < 0) max = cnt - 1; // 0 ~ cnt - 1 if (max > oldsz - 1) max = oldsz - 1; if ((newsz <= 0 || cnt > INVALIDATE_THRESHOLD) && !inPagingMold()) _listbox.invalidate(); // Bug 3147518: avoid memory leak // Also better performance (outer better than remove a lot) // detach from end (due to groopfoot issue) Component comp = _listbox.getItemAtIndex(max); while (--cnt >= 0) { Component p = comp.getPreviousSibling(); comp.detach(); comp = p; } break; default: // CONTENTS_CHANGED syncModel(min, max); } }
public void render(final Comboitem item, final Object data, final int index) throws Exception { final Combobox cb = (Combobox) item.getParent(); final ListModel<?> model = cb.getModel(); final int size = model.getSize(); final Template tm = resoloveTemplate(cb, item, data, index, size, "model"); if (tm == null) { item.setLabel(Objects.toString(data)); item.setValue(data); } else { final ForEachStatus iterStatus = new AbstractForEachStatus() { // provide iteration status in this context private static final long serialVersionUID = 1L; public int getIndex() { return index; } public Object getEach() { return data; } public Integer getEnd() { return size; } }; final String var = (String) tm.getParameters().get(EACH_ATTR); final String varnm = var == null ? EACH_VAR : var; // var is not specified, default to "each" final String itervar = (String) tm.getParameters().get(STATUS_ATTR); final String itervarnm = itervar == null ? (var == null ? EACH_STATUS_VAR : varnm + STATUS_POST_VAR) : itervar; // provide default value if not specified // bug 1188, EL when nested var and itervar Object oldVar = cb.getAttribute(varnm); Object oldIter = cb.getAttribute(itervarnm); cb.setAttribute(varnm, data); cb.setAttribute(itervarnm, iterStatus); final Component[] items = tm.create(cb, item, null, null); cb.setAttribute(varnm, oldVar); cb.setAttribute(itervarnm, oldIter); if (items.length != 1) throw new UiException("The model template must have exactly one item, not " + items.length); final Comboitem nci = (Comboitem) items[0]; nci.setAttribute(BinderImpl.VAR, varnm); // for the converter to get the value if (model instanceof ListSubModel) { // ZK-992 wrong item when binding to combbox with submodel implementation // combobox has a internal model as the submodel, // I don't have way to access the submodel, and user doesn't has info to notify model[index] // changed. // so I set the value directly. nci.setAttribute(varnm, data); } else { addItemReference( cb, nci, index, varnm); // kept the reference to the data, before ON_BIND_INIT } nci.setAttribute(itervarnm, iterStatus); // add template dependency addTemplateTracking(cb, nci, data, index, size); if (nci.getValue() == null) // template might set it nci.setValue(data); item.setAttribute("org.zkoss.zul.model.renderAs", nci); // indicate a new item is created to replace the existent one item.detach(); // bug #ZK-677: combobox selection is lost after reload model // binding Comboitem immediately, @see BindUiLifeCycle#afterComponentAttached Events.sendEvent(new Event(BinderImpl.ON_BIND_INIT, nci)); } }
public int getTotalSize() { final ListModel model = _listbox.getModel(); return model != null ? model.getSize() : _listbox.getVisibleItemCount(); }
private void syncModel0(int offset, int limit) { int min = offset; int max = offset + limit - 1; final ListModel _model = _listbox.getModel(); final int newsz = _model.getSize(); final int oldsz = _listbox.getItemCount(); final Paginal _pgi = _listbox.getPaginal(); final boolean inPaging = inPagingMold(); final boolean shallInvalidated = // Bug 3147518: avoid memory leak (min < 0 || min == 0) && (max < 0 || max >= newsz || max >= oldsz); int newcnt = newsz - oldsz; int atg = _pgi != null ? _listbox.getActivePage() : 0; ListitemRenderer renderer = null; Component next = null; if (oldsz > 0) { if (min < 0) min = 0; else if (min > oldsz - 1) min = oldsz - 1; if (max < 0) max = oldsz - 1; else if (max > oldsz - 1) max = oldsz - 1; if (min > max) { int t = min; min = max; max = t; } int cnt = max - min + 1; // # of affected if (_model instanceof GroupsListModel) { // detach all from end to front since groupfoot // must be detached before group newcnt += cnt; // add affected later if ((shallInvalidated || newcnt > INVALIDATE_THRESHOLD) && !inPaging) _listbox.invalidate(); // Bug 3147518: avoid memory leak // Also better performance (outer better than remove a lot) Component comp = _listbox.getItemAtIndex(max); next = comp.getNextSibling(); while (--cnt >= 0) { Component p = comp.getPreviousSibling(); comp.detach(); comp = p; } } else { // ListModel int addcnt = 0; Component item = _listbox.getItemAtIndex(min); while (--cnt >= 0) { next = item.getNextSibling(); if (cnt < -newcnt) { // if shrink, -newcnt > 0 item.detach(); // remove extra } else if (((Listitem) item).isLoaded()) { if (renderer == null) renderer = (ListitemRenderer) getRealRenderer(); item.detach(); // always detach _listbox.insertBefore(newUnloadedItem(renderer, min), next); ++addcnt; } ++min; item = next; // B2100338.,next item could be Paging, don't use Listitem directly } if ((shallInvalidated || addcnt > INVALIDATE_THRESHOLD || addcnt + newcnt > INVALIDATE_THRESHOLD) && !inPagingMold()) _listbox.invalidate(); // Bug 3147518: avoid memory leak // Also better performance (outer better than remove a lot) } } else { min = 0; } for (; --newcnt >= 0; ++min) { if (renderer == null) renderer = (ListitemRenderer) getRealRenderer(); _listbox.insertBefore(newUnloadedItem(renderer, min), next); } if (_pgi != null) { if (atg >= _pgi.getPageCount()) atg = _pgi.getPageCount() - 1; _pgi.setActivePage(atg); } }