All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.v7.client.widget.escalator.FlyweightRow Maven / Gradle / Ivy

There is a newer version: 8.27.3
Show newest version
/*
 * Copyright (C) 2000-2023 Vaadin Ltd
 *
 * This program is available under Vaadin Commercial License and Service Terms.
 *
 * See  for the full
 * license.
 */
package com.vaadin.v7.client.widget.escalator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.dom.client.TableRowElement;

/**
 * An internal implementation of the {@link Row} interface.
 * 

* There is only one instance per Escalator. This is designed to be re-used when * rendering rows. * * @since 7.4 * @author Vaadin Ltd * @see com.vaadin.v7.client.widgets.Escalator.AbstractRowContainer#refreshRow(TableRowElement, * int) Escalator.AbstractRowContainer#refreshRow(TableRowElement, int) */ public class FlyweightRow implements Row { static class CellIterator implements Iterator { /** A defensive copy of the cells in the current row. */ private final List cells; private final boolean cellsAttached; private int cursor = 0; private int skipNext = 0; /** * Creates a new iterator of attached flyweight cells. A cell is * attached if it has a corresponding {@link FlyweightCell#getElement() * DOM element} attached to the row element. * * @param cells * the collection of cells to iterate */ public static CellIterator attached( final Collection cells) { return new CellIterator(cells, true); } /** * Creates a new iterator of unattached flyweight cells. A cell is * unattached if it does not have a corresponding * {@link FlyweightCell#getElement() DOM element} attached to the row * element. * * @param cells * the collection of cells to iterate */ public static CellIterator unattached( final Collection cells) { return new CellIterator(cells, false); } private CellIterator(final Collection cells, final boolean attached) { this.cells = new ArrayList(cells); cellsAttached = attached; } @Override public boolean hasNext() { return cursor + skipNext < cells.size(); } @Override public FlyweightCell next() { // if we needed to skip some cells since the last invocation. for (int i = 0; i < skipNext; i++) { cells.remove(cursor); } skipNext = 0; final FlyweightCell cell = cells.get(cursor++); cell.setup(this); return cell; } @Override public void remove() { throw new UnsupportedOperationException( "Cannot remove cells via iterator"); } /** * Sets the number of cells to skip when {@link #next()} is called the * next time. Cell hiding is also handled eagerly in this method. * * @param colspan * the number of cells to skip on next invocation of * {@link #next()} */ public void setSkipNext(final int colspan) { assert colspan > 0 : "Number of cells didn't make sense: " + colspan; skipNext = colspan; } /** * Gets the next n cells in the iterator, ignoring any * possibly spanned cells. * * @param n * the number of next cells to retrieve * @return A list of next n cells, or less if there aren't * enough cells to retrieve */ public List rawPeekNext(final int n) { final int from = Math.min(cursor, cells.size()); final int to = Math.min(cursor + n, cells.size()); List nextCells = cells.subList(from, to); for (FlyweightCell cell : nextCells) { cell.setup(this); } return nextCells; } public boolean areCellsAttached() { return cellsAttached; } } private static final int BLANK = Integer.MIN_VALUE; private int row; private TableRowElement element; private double[] columnWidths = null; private final List cells = new ArrayList(); public void setup(final TableRowElement e, final int row, double[] columnWidths) { element = e; this.row = row; this.columnWidths = columnWidths; } /** * Tear down the state of the Row. *

* This is an internal check method, to prevent retrieving uninitialized * data by calling {@link #getRow()}, {@link #getElement()} or * {@link #getCells()} at an improper time. *

* This should only be used with asserts (" * assert flyweightRow.teardown() ") so that the code is never * run when asserts aren't enabled. * * @return always true */ public boolean teardown() { element = null; row = BLANK; columnWidths = null; for (final FlyweightCell cell : cells) { assert cell.teardown(); } return true; } @Override public int getRow() { assertSetup(); return row; } @Override public TableRowElement getElement() { assertSetup(); return element; } public void addCells(final int index, final int numberOfColumns) { for (int i = 0; i < numberOfColumns; i++) { final int col = index + i; cells.add(col, new FlyweightCell(this, col)); } updateRestOfCells(index + numberOfColumns); } public void removeCells(final int index, final int numberOfColumns) { cells.subList(index, index + numberOfColumns).clear(); updateRestOfCells(index); } private void updateRestOfCells(final int startPos) { // update the column number for the cells to the right for (int col = startPos; col < cells.size(); col++) { cells.set(col, new FlyweightCell(this, col)); } } /** * Returns flyweight cells for the client code to render. The cells get * their associated {@link FlyweightCell#getElement() elements} from the row * element. *

* Precondition: each cell has a corresponding element in the row * * @return an iterable of flyweight cells * * @see #setup(TableRowElement, int, int[]) * @see #teardown() */ public Iterable getCells() { return getCells(0, cells.size()); } /** * Returns a subrange of flyweight cells for the client code to render. The * cells get their associated {@link FlyweightCell#getElement() elements} * from the row element. *

* Precondition: each cell has a corresponding element in the row * * @param offset * the index of the first cell to return * @param numberOfCells * the number of cells to return * @return an iterable of flyweight cells */ public Iterable getCells(final int offset, final int numberOfCells) { assertSetup(); assert offset >= 0 && offset + numberOfCells <= cells .size() : "Invalid range of cells"; return new Iterable() { @Override public Iterator iterator() { return CellIterator.attached( cells.subList(offset, offset + numberOfCells)); } }; } /** * Returns a subrange of unattached flyweight cells. Unattached cells do not * have {@link FlyweightCell#getElement() elements} associated. Note that * FlyweightRow does not keep track of whether cells in actuality have * corresponding DOM elements or not; it is the caller's responsibility to * invoke this method with correct parameters. *

* Precondition: the range [offset, offset + numberOfCells) must be valid * * @param offset * the index of the first cell to return * @param numberOfCells * the number of cells to return * @return an iterable of flyweight cells */ public Iterable getUnattachedCells(final int offset, final int numberOfCells) { assertSetup(); assert offset >= 0 && offset + numberOfCells <= cells .size() : "Invalid range of cells"; return new Iterable() { @Override public Iterator iterator() { return CellIterator.unattached( cells.subList(offset, offset + numberOfCells)); } }; } /** * Asserts that the flyweight row has properly been set up before trying to * access any of its data. */ private void assertSetup() { assert element != null && row != BLANK && columnWidths != null : "Flyweight row was not " + "properly initialized. Make sure the setup-method is " + "called before retrieving data. This is either a bug " + "in Escalator, or the instance of the flyweight row " + "has been stored and accessed."; } double getColumnWidth(int column) { assertSetup(); return columnWidths[column]; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy