📄 grid.java
字号:
if (_model != model) { if (_model != null) { _model.removeListDataListener(_dataListener); } else { if (_rows != null) _rows.getChildren().clear(); //Bug 1807414 smartUpdate("z.model", "true"); } initDataListener(); _model = model; _model.addListDataListener(_dataListener); } //Always syncModel because it is easier for user to enfore reload syncModel(-1, -1); //create rows if necessary 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; if (_rows != null) _rows.getChildren().clear(); smartUpdate("z.model", null); } } private void initDataListener() { if (_dataListener == null) _dataListener = new ListDataListener() { public void onChange(ListDataEvent event) { onListDataChange(event); } }; } /** Returns the renderer to render each row, or null if the default * renderer is used. */ public RowRenderer getRowRenderer() { return _renderer; } /** Sets the renderer which is used to render each row * if {@link #getModel} is not null. * * <p>Note: changing a render will not cause the grid 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 setRowRenderer(RowRenderer renderer) { _renderer = renderer; } /** Sets the renderer by use of a class name. * It creates an instance automatically. */ public void setRowRenderer(String clsnm) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, java.lang.reflect.InvocationTargetException { if (clsnm != null) setRowRenderer((RowRenderer)Classes.newInstanceByThread(clsnm)); } /** Returns the number of rows 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 rows 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 rows 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; } /** * Sets the inner width of this component. * The inner width is the width of the inner table. * By default, it is 100%. That is, it is the same as the width * of this component. However, it is changed when the user * is sizing the column's width. * * <p>Application developers rarely call this method, unless * they want to preserve the widths of sizable columns * changed by the user. * To preserve the widths, the developer have to store the widths of * all columns and the inner width ({@link #getInnerWidth}), * and then restore them when re-creating this component. * * @param innerWidth the inner width. If null, "100%" is assumed. * @since 3.0.0 */ public void setInnerWidth(String innerWidth) { if (innerWidth == null) innerWidth = "100%"; if (!_innerWidth.equals(innerWidth)) { _innerWidth = innerWidth; smartUpdate("z.innerWidth", innerWidth); } } /** * Returns the inner width of this component. * The inner width is the width of the inner table. * <p>Default: "100%" * @see #setInnerWidth * @since 3.0.0 */ public String getInnerWidth() { return _innerWidth; } /** Synchronizes the grid to be consistent with the specified model. * * @param min the lower index that a range of invalidated rows * @param max the higher index that a range of invalidated rows */ private void syncModel(int min, int max) { RowRenderer renderer = null; final int newsz = _model.getSize(); final int oldsz = _rows != null ? _rows.getChildren().size(): 0; 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 = _rows.getChildren().listIterator(min); min <= max && it.hasNext(); ++min) { final Row row = (Row)it.next(); if (row.isLoaded()) { if (renderer == null) renderer = getRealRenderer(); unloadRow(renderer, row); } } } //detach and remove if (oldsz > newsz) { for (Iterator it = _rows.getChildren().listIterator(newsz); it.hasNext();) { it.next(); it.remove(); } } } //auto create but it means <grid model="xx"><rows/>... will fail if (_rows == null) new Rows().setParent(this); for (int j = oldsz; j < newsz; ++j) { if (renderer == null) renderer = getRealRenderer(); newUnloadedRow(renderer).setParent(_rows); } } /** Creates an new and unloaded row. */ private final Row newUnloadedRow(RowRenderer renderer) { Row row = null; if (renderer instanceof RowRendererExt) row = ((RowRendererExt)renderer).newRow(this); if (row == null) { row = new Row(); row.applyProperties(); } row.setLoaded(false); newUnloadedCell(renderer, row); return row; } private Component newUnloadedCell(RowRenderer renderer, Row row) { Component cell = null; if (renderer instanceof RowRendererExt) cell = ((RowRendererExt)renderer).newCell(row); if (cell == null) { cell = newRenderLabel(null); cell.applyProperties(); } cell.setParent(row); return cell; } /** Returns the label for the cell generated by the default renderer. */ private static Label newRenderLabel(String value) { final Label label = new Label(value != null && value.length() > 0 ? value: " "); label.setPre(true); //to make sure is generated, and then occupies some space return label; } /** Clears a row as if it is not loaded. */ private final void unloadRow(RowRenderer renderer, Row row) { if (!(renderer instanceof RowRendererExt) || (((RowRendererExt)renderer).getControls() & RowRendererExt.DETACH_ON_UNLOAD) == 0) { //re-use (default) final List cells = row.getChildren(); boolean bNewCell = cells.isEmpty(); if (!bNewCell) { //detach and remove all but the first cell for (Iterator it = cells.listIterator(1); it.hasNext();) { it.next(); it.remove(); } final Component cell = (Component)cells.get(0); bNewCell = !(cell instanceof Label); if (bNewCell) { cell.detach(); } else { ((Label)cell).setValue(""); } } if (bNewCell) newUnloadedCell(renderer, row); row.setLoaded(false); } else { //detach _rows.insertBefore(newUnloadedRow(renderer), row); row.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 = _rows.getChildren().size(); if (ofs >= cnt) { //not possible; just in case ofs = cnt - pgsz; if (ofs < 0) ofs = 0; } } else { pgsz = 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 = _rows.getChildren().listIterator(ofs); j < pgsz && it.hasNext(); ++j) renderer.render((Row)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) { //when this is called _model is never null final int newsz = _model.getSize(), oldsz = _rows.getChildren().size(); 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 rows not matched: "+event); break; //handle it as CONTENTS_CHANGED } RowRenderer renderer = null; final Row before = min < oldsz ? (Row)_rows.getChildren().get(min): null; for (int j = min; j <= max; ++j) { if (renderer == null) renderer = getRealRenderer(); _rows.insertBefore(newUnloadedRow(renderer), before); } done = true; break; case ListDataEvent.INTERVAL_REMOVED: if (max < 0) max = oldsz - 1; int cnt = max - min + 1; if (cnt != (oldsz - newsz)) { log.warning("Conflict event: number of removed rows not matched: "+event); break; //handle it as CONTENTS_CHANGED } //detach and remove for (Iterator it = _rows.getChildren().listIterator(min); --cnt >= 0 && it.hasNext();) { it.next(); it.remove(); } done = true; break; } if (!done) //CONTENTS_CHANGED syncModel(min, max); postOnInitRender(); //to improve performance } private static final RowRenderer getDefaultRowRenderer() { return _defRend; } private static final RowRenderer _defRend = new RowRenderer() { public void render(Row row, Object data) { final Label label = newRenderLabel(Objects.toString(data)); label.applyProperties(); label.setParent(row); row.setValue(data); } }; /** Returns the renderer used to render rows. */ private RowRenderer getRealRenderer() { return _renderer != null ? _renderer: getDefaultRowRenderer(); } /** Used to render row if _model is specified. */ private class Renderer implements java.io.Serializable {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -