📄 listbox.java
字号:
* and removeItemFromSelection might be called interchangeably. */ private void smartUpdateSelection() { final StringBuffer sb = new StringBuffer(80); for (Iterator it = _selItems.iterator(); it.hasNext();) { if (sb.length() > 0) sb.append(','); sb.append(((Listitem)it.next()).getUuid()); } smartUpdate("chgSel", sb.toString()); } /** If the specified item is selected, it is deselected. * If it is not selected, it is selected. Other items in the list box * that are selected are not affected, and retain their selected state. */ public void toggleItemSelection(Listitem item) { if (item.isSelected()) removeItemFromSelection(item); else addItemToSelection(item); } /** Clears the selection. */ public void clearSelection() { if (!_selItems.isEmpty()) { for (Iterator it = _selItems.iterator(); it.hasNext();) { final Listitem item = (Listitem)it.next(); item.setSelectedDirectly(false); } _selItems.clear(); _jsel = -1; smartUpdate("selectedIndex", "-1"); } } /** Selects all items. */ public void selectAll() { if (!_multiple) throw new UiException("Appliable only to the multiple seltype: "+this); if (_items.size() != _selItems.size()) { for (Iterator it = _items.iterator(); it.hasNext();) { final Listitem item = (Listitem)it.next(); _selItems.add(item); item.setSelectedDirectly(true); } _jsel = _items.isEmpty() ? -1: 0; smartUpdate("selectAll", "true"); } } /** Returns the selected item. */ public Listitem getSelectedItem() { return _jsel >= 0 ? getItemAtIndex(_jsel): null; } /** Deselects all of the currently selected items and selects * the given item. * <p>It is the same as {@link #selectItem}. */ public void setSelectedItem(Listitem item) { selectItem(item); } /** Returns all selected items. */ public Set getSelectedItems() { return Collections.unmodifiableSet(_selItems); } /** Returns the number of items being selected. */ public int getSelectedCount() { return _selItems.size(); } /** Appends an item. */ public Listitem appendItem(String label, String value) { final Listitem item = new Listitem(label, value); item.applyProperties(); item.setParent(this); return item; } /** Removes the child item in the list box at the given index. * @return the removed item. */ public Listitem removeItemAt(int index) { final Listitem item = getItemAtIndex(index); removeChild(item); return item; } /** Re-initialize the listbox at the client (actually, re-calculate * the column width at the client). */ /*package*/ void initAtClient() { if (!inSelectMold() && !inPagingMold()) smartUpdate("z.init", true); } //--Paging--// /** Returns the paging controller, or null if not available. * Note: the paging controller is used only if {@link #getMold} is "paging". * * <p>If mold is "paging", this method never returns null, because * a child paging controller is created automcatically (if not specified * by developers with {@link #setPaginal}). * * <p>If a paging controller is specified (either by {@link #setPaginal}, * or by {@link #setMold} with "paging"), * the listbox will rely on the paging controller to handle long-content * instead of scrolling. */ public Paginal getPaginal() { return _pgi; } /* Specifies the paging controller. * Note: the paging controller is used only if {@link #getMold} is "paging". * * <p>It is OK, though without any effect, to specify a paging controller * even if mold is not "paging". * * @param pgi the paging controller. If null and {@link #getMold} is "paging", * a paging controller is created automatically as a child component * (see {@link #getPaging}). */ public void setPaginal(Paginal pgi) { if (!Objects.equals(pgi, _pgi)) { final Paginal old = _pgi; _pgi = pgi; if (inPagingMold()) { if (old != null) removePagingListener(old); if (_pgi == null) { if (_paging != null) _pgi = _paging; else newInternalPaging(); } else { //_pgi != null if (_pgi != _paging) { if (_paging != null) _paging.detach(); addPagingListener(_pgi); } } } } } /** Creates the internal paging component. */ private void newInternalPaging() { assert D.OFF || inPagingMold(): "paging mold only"; assert D.OFF || (_paging == null && _pgi == null); final Paging paging = new Paging(); paging.setAutohide(true); paging.setDetailed(true); paging.setTotalSize(getItemCount()); paging.setParent(this); addPagingListener(_pgi); } /** Adds the event listener for the onPaging event. */ private void addPagingListener(Paginal pgi) { if (_pgListener == null) _pgListener = new EventListener() { public boolean isAsap() { return true; } public void onEvent(Event event) { final PagingEvent evt = (PagingEvent)event; Events.postEvent( new PagingEvent(evt.getName(), Listbox.this, evt.getPaginal(), evt.getActivePage())); } }; pgi.addEventListener(ZulEvents.ON_PAGING, _pgListener); } /** Removes the event listener for the onPaging event. */ private void removePagingListener(Paginal pgi) { pgi.removeEventListener(ZulEvents.ON_PAGING, _pgListener); } /** Called when the onPaging event is received (from {@link #getPaginal}). * * <p>Default: re-render, if live data, and invalidate(). */ public void onPaging() { if (_model != null && inPagingMold()) { final Renderer renderer = new Renderer(); try { final Paginal pgi = getPaginal(); int pgsz = pgi.getPageSize(); final int ofs = pgi.getActivePage() * pgsz; for (final Iterator it = getItems().listIterator(ofs); --pgsz >= 0 && it.hasNext();) renderer.render((Listitem)it.next()); } catch (Throwable ex) { renderer.doCatch(ex); } finally { renderer.doFinally(); } } invalidate(); } /** Returns the child paging controller that is created automatically, * or null if mold is not "paging", or the controller is specified externally * by {@link #setPaginal}. */ public Paging getPaging() { return _paging; } /** Returns the page size, aka., the number items per page. * @exception IllegalStateException if {@link #getPaginal} returns null, * i.e., mold is not "paging" and no external controller is specified. */ public int getPageSize() { if (_pgi == null) throw new IllegalStateException("Available only the paging mold"); return _pgi.getPageSize(); } /** Sets the page size, aka., the number items per page. * @exception IllegalStateException if {@link #getPaginal} returns null, * i.e., mold is not "paging" and no external controller is specified. */ public void setPageSize(int pgsz) { if (_pgi == null) throw new IllegalStateException("Available only the paging mold"); _pgi.setPageSize(pgsz); } /** Returns whether this listbox is in the paging mold. */ /*package*/ boolean inPagingMold() { return "paging".equals(getMold()); } /** Returns the index of the first visible child. * <p>Used only for component development, not for application developers. */ public int getVisibleBegin() { if (!inPagingMold()) return 0; final Paginal pgi = getPaginal(); return pgi.getActivePage() * pgi.getPageSize(); } /** Returns the index of the last visible child. * <p>Used only for component development, not for application developers. */ public int getVisibleEnd() { if (!inPagingMold()) return Integer.MAX_VALUE; final Paginal pgi = getPaginal(); return (pgi.getActivePage() + 1) * pgi.getPageSize() - 1; //inclusive } //-- Component --// public void smartUpdate(String attr, String value) { if (!_noSmartUpdate) super.smartUpdate(attr, value); } /** When detached from a page, it is detached from the model * (by invoking {@link #setModel} with null) automatically. */ public void setPage(Page page) { super.setPage(page); if (page == null && _model != null) { _model.removeListDataListener(_dataListener); _model = null; } } public void onChildAdded(Component child) { super.onChildAdded(child); if (inSelectMold()) invalidate(); //Both IE and Mozilla are buggy if we insert options by innerHTML else if(inPagingMold() && (child instanceof Listitem)) _pgi.setTotalSize(getItemCount()); } public void onChildRemoved(Component child) { super.onChildRemoved(child); if (inSelectMold()) invalidate(); //Both IE and Mozilla are buggy if we remove options by outerHTML //CONSIDER: use special command to remove items //Cons: if user remove a lot of items it is slower else if(inPagingMold() && (child instanceof Listitem)) _pgi.setTotalSize(getItemCount()); } public boolean insertBefore(Component newChild, Component refChild) { if (newChild instanceof Listitem) { if (refChild == null) { if (_listfoot != null) refChild = _listfoot; //listfoot as last else if (_paging != null) refChild = _paging; //_paging as last } else if (refChild == _listhead) { throw new UiException("Unable to insert before listhead: "+newChild); } final boolean existChild = newChild.getParent() == this; if (super.insertBefore(newChild, refChild)) { final List children = getChildren(); if (_listhead != null && children.get(1) == newChild) invalidate(); //we place listhead and treeitem at different div, so //this case requires invalidate (because we use insert-after) //Maintain _items final Listitem childItem = (Listitem)newChild; int fixFrom = childItem.getIndex(); if (refChild != null && refChild != _listfoot && refChild != _paging && refChild.getParent() == this) { final int k = ((Listitem)refChild).getIndex(); if (fixFrom < 0 || k < fixFrom) fixFrom = k; } if (fixFrom < 0) childItem.setIndex(_items.size() - 1); else fixItemIndices(fixFrom); //Maintain selected final int childIndex = childItem.getIndex(); if (childItem.isSelected()) { if (_jsel < 0) { _jsel = childIndex; if (!inSelectMold()) smartUpdate("z.selId", getSelectedId()); _selItems.add(childItem); } else if (_multiple) { if (_jsel > childIndex) { _jsel = childIndex; if (!inSelectMold()) smartUpdate("z.selId", getSelectedId()); } _selItems.add(childItem); } else { //deselect childItem.setSelectedDirectly(false); childItem.invalidate(); } } else { if (_jsel >= childIndex) { ++_jsel; if (!inSelectMold()) smartUpdate("z.selId", getSelectedId()); } } initAtClient(); return true; } return false; } else if (newChild instanceof Listhead) { if (_listhead != null && _listhead != newChild) throw new UiException("Only one listhead is allowed: "+this); if (!getChildren().isEmpty()) refChild = (Component)getChildren().get(0); //always makes listhead as the first child if (inSelectMold()) log.warning("Mold select ignores listhead"); invalidate(); //we place listhead and treeitem at different div, so... _listhead = (Listhead)newChild; return super.insertBefore(newChild, refChild); } 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); } } public boolean removeChild(Component child) { if (!super.removeChild(child)) return false; if (_listhead == child) { _listhead = null; } else if (_listfoot == child) { _listfoot = null; } else if (child instanceof Listitem) { //maintain items final Listitem childItem = (Listitem)child; final int childIndex = childItem.getIndex(); childItem.setIndex(-1); //mark fixItemIndices(childIndex); //Maintain selected if (childItem.isSelected()) { _selItems.remove(childItem); if (_jsel == childIndex) { fixSelectedIndex(childIndex); if (!inSelectMold()) smartUpdate("z.selId", getSelectedId()); } } else { if (_jsel >= childIndex) { --_jsel; if (!inSelectMold()) smartUpdate("z.selId", getSelectedId()); } } initAtClient(); return true; } else if (_paging == child) { _paging = null; if (_pgi == child) _pgi = null; } 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()).setIndex(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 { if (!inSelectMold()) smartUpdate("z.model", "true"); } initDataListener(); _model = model; _model.addListDataListener(_dataListener); } //Always syncModel because it is easier for user to enfore reload syncModel(-1, -1); Events.postEvent("onInitRender", this, null); //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) { if (_renderer != renderer) _renderer = renderer; } /** Sets the renderer by use of a class name. * It creates an instance automatically. */ public void setItemRenderer(String clsnm)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -