📄 listbox.java
字号:
final Listitem newItem = (Listitem)newChild; final int jfrom = newItem.getParent() == this ? newItem.getIndex(): -1; if (super.insertBefore(newChild, refChild)) { final List children = getChildren(); if (_hdcnt > 0 && children.get(_hdcnt) == newChild) invalidate(); //we place listhead/auxhead and treeitem at different div, so //this case requires invalidate (because we use insert-after) //Maintain _items final int jto = refChild instanceof Listitem ? ((Listitem)refChild).getIndex(): -1, fixFrom = jfrom < 0 || (jto >= 0 && jfrom > jto) ? jto: jfrom; //jfrom < 0: use jto //jto < 0: use jfrom //otherwise: use min(jfrom, jto) if (fixFrom < 0) newItem.setIndexDirectly(_items.size() - 1); else fixItemIndices(fixFrom); //Maintain selected final int newIndex = newItem.getIndex(); if (newItem.isSelected()) { if (_jsel < 0) { _jsel = newIndex; if (!inSelectMold()) smartUpdate("z.selId", getSelectedId()); _selItems.add(newItem); } else if (_multiple) { if (_jsel > newIndex) { _jsel = newIndex; if (!inSelectMold()) smartUpdate("z.selId", getSelectedId()); } _selItems.add(newItem); } else { //deselect newItem.setSelectedDirectly(false); } } else { final int oldjsel = _jsel; if (jfrom < 0) { //no existent child if (_jsel >= newIndex) ++_jsel; } else if (_jsel >= 0) { //any selected if (jfrom > _jsel) { //from below if (jto >= 0 && jto <= _jsel) ++_jsel; } else { //from above if (jto < 0 || jto > _jsel) --_jsel; } } if (oldjsel != _jsel && !inSelectMold()) smartUpdate("z.selId", getSelectedId()); } return true; } return false; } else if (newChild instanceof Listhead) { if (_listhead != null && _listhead != newChild) throw new UiException("Only one listhead is allowed: "+this); final boolean added = _listhead == null; refChild = fixRefChildForHeader(refChild); _listhead = (Listhead)newChild; if (super.insertBefore(newChild, refChild)) { if (added) ++_hdcnt; //it may be moved, not inserted invalidate(); //required since it might be the first child return true; } return false; } else if (newChild instanceof Auxhead) { final boolean added = newChild.getParent() != this; refChild = fixRefChildForHeader(refChild); if (super.insertBefore(newChild, refChild)) { if (added) ++_hdcnt; //it may be moved, not inserted //not need to invalidate since auxhead visible only //with _listhead return true; } return false; } else if (newChild instanceof Listfoot) { if (_listfoot != null && _listfoot != newChild) throw new UiException("Only one listfoot is allowed: "+this); if (inSelectMold()) log.warning("Mold select ignores listfoot"); invalidate(); //we place listfoot and treeitem at different div, so... _listfoot = (Listfoot)newChild; refChild = _paging; //the last two: listfoot and paging return super.insertBefore(newChild, refChild); } else if (newChild instanceof Paging) { if (_paging != null && _paging != newChild) throw new UiException("Only one paging is allowed: "+this); if (_pgi != null) throw new UiException("External paging cannot coexist with child paging"); if (!inPagingMold()) throw new UiException("The child paging is allowed only in the paging mold"); invalidate(); _pgi = _paging = (Paging)newChild; refChild = null; //the last: paging return super.insertBefore(newChild, refChild); } else { throw new UiException("Unsupported child for Listbox: "+newChild); } } private Component fixRefChildForHeader(Component refChild) { if (refChild != null && refChild.getParent() != this) refChild = null; //try the first listitem if (refChild == null || (refChild != _listhead && !(refChild instanceof Auxhead))) refChild = getChildren().size() > _hdcnt ? (Component)getChildren().get(_hdcnt): null; //try listfoot or paging if no listem refChild = fixRefChildBeforeFoot(refChild); return refChild; } private Component fixRefChildBeforeFoot(Component refChild) { if (refChild == null) { if (_listfoot != null) refChild = _listfoot; else refChild = _paging; } else if (refChild == _paging && _listfoot != null) { refChild = _listfoot; } return refChild; } public boolean removeChild(Component child) { if (!super.removeChild(child)) return false; if (_listhead == child) { _listhead = null; --_hdcnt; } else if (_listfoot == child) { _listfoot = null; } else if (child instanceof Listitem) { //maintain items final Listitem item = (Listitem)child; final int index = item.getIndex(); item.setIndexDirectly(-1); //mark fixItemIndices(index); //Maintain selected if (item.isSelected()) { _selItems.remove(item); if (_jsel == index) { fixSelectedIndex(index); if (!inSelectMold()) smartUpdate("z.selId", getSelectedId()); } } else { if (_jsel >= index) { --_jsel; if (!inSelectMold()) smartUpdate("z.selId", getSelectedId()); } } return true; } else if (_paging == child) { _paging = null; if (_pgi == child) _pgi = null; } else if (child instanceof Auxhead) { --_hdcnt; } invalidate(); return true; } /** Fix the selected index, _jsel, assuming there are no selected one * before (and excludes) j-the item. */ private void fixSelectedIndex(int j) { if (!_selItems.isEmpty()) { for (Iterator it = _items.listIterator(j); it.hasNext(); ++j) { final Listitem item = (Listitem)it.next(); if (item.isSelected()) { _jsel = j; return; } } } _jsel = -1; } /** Fix Childitem._index since j-th item. */ private void fixItemIndices(int j) { for (Iterator it = _items.listIterator(j); it.hasNext(); ++j) ((Listitem)it.next()).setIndexDirectly(j); } //-- ListModel dependent codes --// /** Returns the list model associated with this listbox, or null * if this listbox is not associated with any list data model. */ public ListModel getModel() { return _model; } /** Sets the list model associated with this listbox. * If a non-null model is assigned, no matter whether it is the same as * the previous, it will always cause re-render. * * @param model the list model to associate, or null to dis-associate * any previous model. * @exception UiException if failed to initialize with the model */ public void setModel(ListModel model) { if (model != null) { if (_model != model) { if (_model != null) { _model.removeListDataListener(_dataListener); } else { getItems().clear(); //Bug 1807414 if (!inSelectMold()) smartUpdate("z.model", "true"); } _model = model; initDataListener(); } //Always syncModel because it is easier for user to enfore reload syncModel(-1, -1); postOnInitRender(); //Since user might setModel and setRender separately or repeatedly, //we don't handle it right now until the event processing phase //such that we won't render the same set of data twice //-- //For better performance, we shall load the first few row now //(to save a roundtrip) } else if (_model != null) { _model.removeListDataListener(_dataListener); _model = null; getItems().clear(); if (!inSelectMold()) smartUpdate("z.model", null); } } /** Returns the renderer to render each item, or null if the default * renderer is used. */ public ListitemRenderer getItemRenderer() { return _renderer; } /** Sets the renderer which is used to render each item * if {@link #getModel} is not null. * * <p>Note: changing a render will not cause the listbox to re-render. * If you want it to re-render, you could assign the same model again * (i.e., setModel(getModel())), or fire an {@link ListDataEvent} event. * * @param renderer the renderer, or null to use the default. * @exception UiException if failed to initialize with the model */ public void setItemRenderer(ListitemRenderer renderer) { _renderer = renderer; } /** Sets the renderer by use of a class name. * It creates an instance automatically. */ public void setItemRenderer(String clsnm) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, java.lang.reflect.InvocationTargetException { if (clsnm != null) setItemRenderer((ListitemRenderer)Classes.newInstanceByThread(clsnm)); } /** Returns the number of items to preload when receiving * the rendering request from the client. * * <p>Default: 7. * * <p>It is used only if live data ({@link #setModel} and * not paging ({@link #getPaging}. * * @since 2.4.1 */ public int getPreloadSize() { return _preloadsz; } /** Sets the number of items to preload when receiving * the rendering request from the client. * <p>It is used only if live data ({@link #setModel} and * not paging ({@link #getPaging}. * * @param sz the number of items to preload. If zero, no preload * at all. * @exception UiException if sz is negative * @since 2.4.1 */ public void setPreloadSize(int sz) { if (sz < 0) throw new UiException("nonnegative is required: "+sz); _preloadsz = sz; } /** Synchronizes the listbox to be consistent with the specified model. * @param min the lower index that a range of invalidated items * @param max the higher index that a range of invalidated items */ private void syncModel(int min, int max) { ListitemRenderer renderer = null; final int newsz = _model.getSize(); final int oldsz = getItemCount(); if (oldsz > 0) { if (newsz > 0 && min < oldsz) { if (max < 0 || max >= oldsz) max = oldsz - 1; if (max >= newsz) max = newsz - 1; if (min < 0) min = 0; for (Iterator it = _items.listIterator(min); min <= max && it.hasNext(); ++min) { final Listitem item = (Listitem)it.next(); if (item.isLoaded()) { if (renderer == null) renderer = getRealRenderer(); unloadItem(renderer, item); } } } for (int j = newsz; j < oldsz; ++j) getItemAtIndex(newsz).detach(); //detach and remove } for (int j = oldsz; j < newsz; ++j) { if (renderer == null) renderer = getRealRenderer(); newUnloadedItem(renderer).setParent(this); } } /** Creates an new and unloaded listitem. */ private final Listitem newUnloadedItem(ListitemRenderer renderer) { Listitem item = null; if (renderer instanceof ListitemRendererExt) item = ((ListitemRendererExt)renderer).newListitem(this); if (item == null) { item = new Listitem(); item.applyProperties(); } item.setLoaded(false); newUnloadedCell(renderer, item); return item; } private Listcell newUnloadedCell(ListitemRenderer renderer, Listitem item) { Listcell cell = null; if (renderer instanceof ListitemRendererExt) cell = ((ListitemRendererExt)renderer).newListcell(item); if (cell == null) { cell = new Listcell(); cell.applyProperties(); } cell.setParent(item); return cell; } /** Clears a listitem as if it is not loaded. */ private final void unloadItem(ListitemRenderer renderer, Listitem item) { if (!(renderer instanceof ListitemRendererExt) || (((ListitemRendererExt)renderer).getControls() & ListitemRendererExt.DETACH_ON_UNLOAD) == 0) { //re-use (default) final List cells = item.getChildren(); if (cells.isEmpty()) { newUnloadedCell(renderer, item); } else { //detach and remove all but the first cell for (Iterator it = cells.listIterator(1); it.hasNext();) { it.next(); it.remove(); } final Listcell listcell = (Listcell)cells.get(0); listcell.getChildren().clear(); //another renderer might do diff listcell.setLabel(null); listcell.setImage(null); } item.setLoaded(false); } else { //detach item.getParent().insertBefore(newUnloadedItem(renderer), item); item.detach(); } } /** Handles a private event, onInitRender. It is used only for * implementation, and you rarely need to invoke it explicitly. */ public void onInitRender() { final Renderer renderer = new Renderer(); try { int pgsz, ofs; if (inPagingMold()) { pgsz = _pgi.getPageSize(); ofs = _pgi.getActivePage() * pgsz; final int cnt = getItemCount(); if (ofs >= cnt) { //not possible; just in case ofs = cnt - pgsz; if (ofs < 0) ofs = 0; } } else { pgsz = inSelectMold() ? getItemCount(): _rows > 0 ? _rows: 20; ofs = 0; //we don't know # of visible rows, so a 'smart' guess //It is OK since client will send back request if not enough } int j = 0; for (Iterator it = getItems().listIterator(ofs); j < pgsz && it.hasNext(); ++j) renderer.render((Listitem)it.next()); } catch (Throwable ex) { renderer.doCatch(ex); } finally { renderer.doFinally(); } } private void postOnInitRender() { Events.postEvent("onInitRender", this, null); smartUpdate("z.render", true); } /** Handles when the list model's content changed. */ private void onListDataChange(ListDataEvent event) { if (inSelectMold()) { invalidate(); syncModel(-1, -1); postOnInitRender(); return; } //when this is called _model is never null final int newsz = _model.getSize(), oldsz = getItemCount(); int min = event.getIndex0(), max = event.getIndex1(); if (min < 0) min = 0; boolean done = false; switch (event.getType()) { case ListDataEvent.INTERVAL_ADDED: if (max < 0) max = newsz - 1; if ((max - min + 1) != (newsz - oldsz)) { log.warning("Conflict event: number of added items not matched: "+event); break; //handle it as CONTENTS_CHANGED } ListitemRenderer renderer = null; final Listitem before = min < oldsz ? getItemAtIndex(min): null; for (int j = min; j <= max; ++j) { if (renderer == null) renderer = getRealRenderer(); insertBefore(newUnloadedItem(renderer), before); } done = true; break; case ListDataEvent.INTERVAL_REMOVED: if (max < 0) max = oldsz - 1; int cnt = max - min + 1; if (cnt != (oldsz - newsz)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -