📄 grid.java
字号:
/* Grid.java{{IS_NOTE Purpose: Description: History: Tue Oct 25 15:40:35 2005, Created by tomyeh}}IS_NOTECopyright (C) 2005 Potix Corporation. All Rights Reserved.{{IS_RIGHT This program is distributed under GPL Version 2.0 in the hope that it will be useful, but WITHOUT ANY WARRANTY.}}IS_RIGHT*/package org.zkoss.zul;import java.util.Collection;import java.util.AbstractCollection;import java.util.List;import java.util.LinkedList;import java.util.ListIterator;import java.util.Iterator;import java.util.Set;import org.zkoss.lang.D;import org.zkoss.lang.Objects;import org.zkoss.lang.Classes;import org.zkoss.lang.Exceptions;import org.zkoss.util.logging.Log;import org.zkoss.xml.HTMLs;import org.zkoss.zk.ui.Component;import org.zkoss.zk.ui.UiException;import org.zkoss.zk.ui.ext.client.RenderOnDemand;import org.zkoss.zk.ui.ext.client.InnerWidth;import org.zkoss.zk.ui.event.Event;import org.zkoss.zk.ui.event.EventListener;import org.zkoss.zk.ui.event.Events;import org.zkoss.zul.impl.XulElement;import org.zkoss.zul.ext.Paginal;import org.zkoss.zul.event.ListDataEvent;import org.zkoss.zul.event.ListDataListener;import org.zkoss.zul.event.ZulEvents;import org.zkoss.zul.event.PagingEvent;/** * A grid is an element that contains both rows and columns elements. * It is used to create a grid of elements. * Both the rows and columns are displayed at once although only one will * typically contain content, while the other may provide size information. * * <p>Besides creating {@link Row} programmingly, you can assign * a data model (a {@link ListModel} instance) to a grid via * {@link #setModel} and then the grid will retrieve data * by calling {@link ListModel#getElementAt} when necessary. * * <p>Besides assign a list model, you could assign a renderer * (a {@link RowRenderer} instance) to a grid, such that * the grid will use this * renderer to render the data returned by {@link ListModel#getElementAt}. * If not assigned, the default renderer, which assumes a label per row, * is used. * In other words, the default renderer adds a label to * a row by calling toString against the object returned * by {@link ListModel#getElementAt} * * <p>There are two ways to handle long content: scrolling and paging. * If {@link #getMold} is "default", scrolling is used if {@link #setHeight} * is called and too much content to display. * If {@link #getMold} is "paging", paging is used if two or more pages are * required. To control the number of rows to display in a page, use * {@link #setPageSize}. * * <p>If paging is used, the page controller is either created automatically * or assigned explicity by {@link #setPaginal}. * The paging controller specified explicitly by {@link #setPaginal} is called * the external page controller. It is useful if you want to put the paging * controller at different location (other than as a child component), or * you want to use the same controller to control multiple grids. * * <p>Default {@link #getSclass}: grid. * * <p>To have a grid without stripping, you can specify a non-existent * style class to {@link #setOddRowSclass}. * If you want to disable all striping, you can specify the style: * <pre><code> tr.odd td.gc { background: white; } * </code></pre> * * @author tomyeh * @see ListModel * @see RowRenderer * @see RowRendererExt */public class Grid extends XulElement { private static final Log log = Log.lookup(Grid.class); private transient Rows _rows; private transient Columns _cols; private transient Foot _foot; private transient Collection _heads; private String _align; private ListModel _model; private RowRenderer _renderer; private transient ListDataListener _dataListener; /** The paging controller, used only if mold = "paging". */ private transient Paginal _pgi; /** The paging controller, used only if mold = "paging" and user * doesn't assign a controller via {@link #setPaginal}. * If exists, it is the last child. */ private transient Paging _paging; private transient EventListener _pgListener, _pgImpListener; /** The style class of the odd row. */ private String _scOddRow = "odd"; /** the # of rows to preload. */ private int _preloadsz = 7; private String _innerWidth = "100%"; public Grid() { setSclass("grid"); init(); } private void init() { _heads = new AbstractCollection() { public int size() { int sz = getChildren().size(); if (_rows != null) --sz; if (_foot != null) --sz; if (_paging != null) --sz; return sz; } public Iterator iterator() { return new Iter(); } }; } /** Returns the rows. */ public Rows getRows() { return _rows; } /** Returns the columns. */ public Columns getColumns() { return _cols; } /** Returns the foot. */ public Foot getFoot() { return _foot; } /** Returns a collection of heads, including {@link #getColumns} * and auxiliary heads ({@link Auxhead}) (never null). * * @since 3.0.0 */ public Collection getHeads() { return _heads; } /** Returns the specified cell, or null if not available. * @param row which row to fetch (starting at 0). * @param col which column to fetch (starting at 0). */ public Component getCell(int row, int col) { final Rows rows = getRows(); if (rows == null) return null; List children = rows.getChildren(); if (children.size() <= row) return null; children = ((Row)children.get(row)).getChildren(); return children.size() <= col ? null: (Component)children.get(col); } /** Returns the horizontal alignment of the whole grid. * <p>Default: null (system default: left unless CSS specified). */ public String getAlign() { return _align; } /** Sets the horizontal alignment of the whole grid. * <p>Allowed: "left", "center", "right" */ public void setAlign(String align) { if (!Objects.equals(_align, align)) { _align = align; smartUpdate("align", _align); } } //--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 grid 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(); _pgi.setTotalSize(_rows != null ? _rows.getChildren().size(): 0); 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(_rows != null ? _rows.getChildren().size(): 0); 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 void onEvent(Event event) { final PagingEvent evt = (PagingEvent)event; Events.postEvent( new PagingEvent(evt.getName(), Grid.this, evt.getPageable(), evt.getActivePage())); } }; pgi.addEventListener(ZulEvents.ON_PAGING, _pgListener); if (_pgImpListener == null) _pgImpListener = new EventListener() { public void onEvent(Event event) { if (_rows != null && _model != null && inPagingMold()) { //theorectically, _rows shall not be null if _model is not null when //this method is called. But, just in case -- if sent manually final Renderer renderer = new Renderer(); try { final Paginal pgi = getPaginal(); int pgsz = pgi.getPageSize(); final int ofs = pgi.getActivePage() * pgsz; for (final Iterator it = _rows.getChildren().listIterator(ofs); --pgsz >= 0 && it.hasNext();) renderer.render((Row)it.next()); } catch (Throwable ex) { renderer.doCatch(ex); } finally { renderer.doFinally(); } } if (_rows != null) _rows.invalidate(); } }; pgi.addEventListener("onPagingImpl", _pgImpListener); } /** Removes the event listener for the onPaging event. */ private void removePagingListener(Paginal pgi) { pgi.removeEventListener(ZulEvents.ON_PAGING, _pgListener); pgi.removeEventListener("onPagingImpl", _pgImpListener); } /** 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 rows 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 rows 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 grid is in the paging mold. */ /*package*/ boolean inPagingMold() { return "paging".equals(getMold()); } //-- ListModel dependent codes --// /** Returns the list model associated with this grid, or null * if this grid is not associated with any list data model. */ public ListModel getModel() { return _model; } /** Sets the list model associated with this grid. * 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -